summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-10-04 02:45:04 +0000
committerThomas Schwinge <tschwinge@gnu.org>2009-06-17 23:50:19 +0200
commita235af5f2f1d731db358d301a465686070fe4187 (patch)
treed8b679d07cb401b04fbfc5db61171506c212f111
parente6a314ad454d7f4c07ba61436a320a9c919e050a (diff)
2002-10-03 Roland McGrath <roland@frob.com>
* i386/include/mach/i386/mach_i386.defs (i386_set_gdt, i386_get_gdt): New routines. * i386/i386/user_ldt.c (i386_set_gdt, i386_get_gdt): New functions. * i386/i386/gdt.h (USER_GDT, USER_GDT_SLOTS): New macros. * i386/i386/thread.h (struct i386_machine_state): New member user_gdt. * i386/i386/pcb.c (switch_ktss): Copy those slots into the GDT. Remove magic %gs:0 pseudo-register support. * i386/i386/ldt.h (USER_GS): Macro removed. * i386/i386/pcb.c (pcb_init): Set gs to USER_DS, not USER_GS. (thread_setstatus): Likewise. * i386/i386/mp_desc.h (struct mp_desc_table): Remove member `user_thread_register'. * i386/i386/thread.h (struct i386_machine_state): Likewise. * i386/i386/mp_desc.c (mp_desc_init): Don't set up USER_GS in LDT. * i386/i386/ldt.c (ldt_init): Likewise. * i386/intel/pmap.c (pmap_bootstrap): Don't give users access to direct-mapped pages. * i386/i386/user_ldt.c (i386_set_ldt): Don't cap segment limits.
-rw-r--r--i386/i386/pcb.c16
-rw-r--r--i386/i386/thread.h3
-rw-r--r--i386/i386/user_ldt.c72
3 files changed, 64 insertions, 27 deletions
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
index a9937bdc..cd9ecdc6 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -126,13 +126,9 @@ vm_offset_t stack_detach(thread)
#if NCPUS > 1
#define curr_gdt(mycpu) (mp_gdt[mycpu])
#define curr_ktss(mycpu) (mp_ktss[mycpu])
-#define curr_user_thread_reg(mycpu) \
- (mp_desc_table[mycpu].user_thread_register)
#else
#define curr_gdt(mycpu) (gdt)
#define curr_ktss(mycpu) ((struct task_tss *)&base_tss)
-#define curr_user_thread_reg(mycpu) (user_thread_register)
-natural_t user_thread_register;
#endif
#define gdt_desc_p(mycpu,sel) \
@@ -182,9 +178,11 @@ switch_ktss(pcb_t old_pcb, pcb_t pcb)
}
}
- if (old_pcb)
- old_pcb->ims.user_thread_register = curr_user_thread_reg(mycpu);
- curr_user_thread_reg(mycpu) = pcb->ims.user_thread_register;
+ /* Copy in the per-thread GDT slots. No reloading is necessary
+ because just restoring the segment registers on the way back to
+ user mode reloads the shadow registers from the in-memory GDT. */
+ memcpy (gdt_desc_p (mycpu, USER_GDT),
+ pcb->ims.user_gdt, sizeof pcb->ims.user_gdt);
/*
* Load the floating-point context, if necessary.
@@ -363,7 +361,7 @@ void pcb_init(thread)
pcb->iss.ds = USER_DS;
pcb->iss.es = USER_DS;
pcb->iss.fs = USER_DS;
- pcb->iss.gs = USER_GS;
+ pcb->iss.gs = USER_DS;
pcb->iss.eflags = EFL_USER_SET;
thread->pcb = pcb;
@@ -497,7 +495,7 @@ kern_return_t thread_setstatus(thread, flavor, tstate, count)
saved_state->ds = USER_DS;
saved_state->es = USER_DS;
saved_state->fs = USER_DS;
- saved_state->gs = USER_GS;
+ saved_state->gs = USER_DS;
}
else {
/*
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
index c5ae3c51..f653eed5 100644
--- a/i386/i386/thread.h
+++ b/i386/i386/thread.h
@@ -36,6 +36,7 @@
#include <mach/boolean.h>
#include <mach/machine/vm_types.h>
#include <mach/machine/fp_reg.h>
+#include "gdt.h"
#include <kern/lock.h>
@@ -130,7 +131,7 @@ struct i386_machine_state {
struct user_ldt * ldt;
struct i386_fpsave_state *ifps;
struct v86_assist_state v86s;
- natural_t user_thread_register;
+ struct x86_desc user_gdt[USER_GDT_SLOTS];
};
typedef struct pcb {
diff --git a/i386/i386/user_ldt.c b/i386/i386/user_ldt.c
index 9db6da5d..a59b1769 100644
--- a/i386/i386/user_ldt.c
+++ b/i386/i386/user_ldt.c
@@ -170,23 +170,6 @@ i386_set_ldt(thread, first_selector, desc_list, count, desc_list_inline)
case ACC_P | ACC_PL_U | ACC_CODE_CR:
case ACC_P | ACC_PL_U | ACC_CALL_GATE_16:
case ACC_P | ACC_PL_U | ACC_CALL_GATE:
- /* Silently cap the segment's limit at VM_MAX_ADDRESS. */
- {
- unsigned base = ((dp->base_high << 24)
- | (dp->base_med << 16) | dp->base_low);
- unsigned limit
- = ((dp->limit_high << 16) | dp->limit_low);
- if (dp->granularity & SZ_G)
- limit <<= 12;
- if (base > VM_MAX_ADDRESS)
- {
- fill_descriptor_base(dp, 0);
- fill_descriptor_limit(dp, 0);
- }
- else if (base + limit > VM_MAX_ADDRESS
- || base + limit < base)
- fill_descriptor_limit(dp, VM_MAX_ADDRESS - base);
- }
break;
default:
return KERN_INVALID_ARGUMENT;
@@ -416,3 +399,58 @@ user_ldt_free(user_ldt)
user_ldt->desc.limit_low + 1
+ sizeof(struct x86_desc));
}
+
+
+kern_return_t
+i386_set_gdt (thread_t thread, int *selector, struct x86_desc *desc)
+{
+ int idx;
+
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ if (*selector == -1)
+ {
+ for (idx = sel_idx (USER_GDT); idx < sel_idx (USER_GDT) + USER_GDT_SLOTS;
+ ++idx)
+ if ((thread->pcb->ims.user_gdt[idx].access & ACC_P) == 0)
+ {
+ *selector = (idx << 3) | SEL_PL_U;
+ break;
+ }
+ if (idx == sel_idx (USER_GDT) + USER_GDT_SLOTS)
+ return KERN_NO_SPACE; /* ? */
+ }
+ else if ((*selector & (SEL_LDT|SEL_PL)) != SEL_PL_U
+ || sel_idx (*selector) < USER_GDT
+ || sel_idx (*selector) >= USER_GDT + USER_GDT_SLOTS)
+ return KERN_INVALID_ARGUMENT;
+ else
+ idx = sel_idx (*selector);
+
+ if ((desc->access & ACC_P) == 0)
+ memset (&thread->pcb->ims.user_gdt[idx], 0,
+ sizeof thread->pcb->ims.user_gdt[idx]);
+ else if ((desc->access & (ACC_TYPE|ACC_PL)) != (ACC_TYPE_USER|ACC_PL_U))
+ return KERN_INVALID_ARGUMENT;
+ else
+ thread->pcb->ims.user_gdt[idx] = *desc;
+
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+i386_get_gdt (thread_t thread, int selector, struct x86_desc *desc)
+{
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ if ((selector & (SEL_LDT|SEL_PL)) != SEL_PL_U
+ || sel_idx (selector) < USER_GDT
+ || sel_idx (selector) >= USER_GDT + USER_GDT_SLOTS)
+ return KERN_INVALID_ARGUMENT;
+
+ *desc = thread->pcb->ims.user_gdt[sel_idx (selector)];
+
+ return KERN_SUCCESS;
+}