From a235af5f2f1d731db358d301a465686070fe4187 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 4 Oct 2002 02:45:04 +0000 Subject: 2002-10-03 Roland McGrath * 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. --- i386/i386/pcb.c | 16 +++++------- i386/i386/thread.h | 3 ++- i386/i386/user_ldt.c | 72 +++++++++++++++++++++++++++++++++++++++------------- 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 #include #include +#include "gdt.h" #include @@ -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; +} -- cgit v1.2.3