diff options
Diffstat (limited to 'i386/i386/pcb.c')
-rw-r--r-- | i386/i386/pcb.c | 175 |
1 files changed, 142 insertions, 33 deletions
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c index 23585323..e8901550 100644 --- a/i386/i386/pcb.c +++ b/i386/i386/pcb.c @@ -51,6 +51,7 @@ #include "eflags.h" #include "gdt.h" #include "ldt.h" +#include "msr.h" #include "ktss.h" #include "pcb.h" @@ -144,16 +145,28 @@ void switch_ktss(pcb_t pcb) * won`t save the v86 segments, so we leave room. */ +#if !defined(__x86_64__) || defined(USER32) pcb_stack_top = (pcb->iss.efl & EFL_VM) ? (long) (&pcb->iss + 1) : (long) (&pcb->iss.v86_segs); +#else + pcb_stack_top = (vm_offset_t) (&pcb->iss + 1); +#endif + +#ifdef __x86_64__ + assert((pcb_stack_top & 0xF) == 0); +#endif #ifdef MACH_RING1 /* No IO mask here */ if (hyp_stack_switch(KERNEL_DS, pcb_stack_top)) panic("stack_switch"); #else /* MACH_RING1 */ +#ifdef __x86_64__ + curr_ktss(mycpu)->tss.rsp0 = pcb_stack_top; +#else /* __x86_64__ */ curr_ktss(mycpu)->tss.esp0 = pcb_stack_top; +#endif /* __x86_64__ */ #endif /* MACH_RING1 */ } @@ -215,6 +228,11 @@ void switch_ktss(pcb_t pcb) pcb->ims.user_gdt, sizeof pcb->ims.user_gdt); #endif /* MACH_PV_DESCRIPTORS */ +#if defined(__x86_64__) && !defined(USER32) + wrmsr(MSR_REG_FSBASE, pcb->ims.sbs.fsbase); + wrmsr(MSR_REG_GSBASE, pcb->ims.sbs.gsbase); +#endif + db_load_context(pcb); /* @@ -298,7 +316,7 @@ void stack_handoff( stack = current_stack(); old->kernel_stack = 0; new->kernel_stack = stack; - active_threads[mycpu] = new; + percpu_assign(active_thread, new); /* * Switch exception link to point to new @@ -325,7 +343,7 @@ void load_context(thread_t new) */ thread_t switch_context( thread_t old, - void (*continuation)(), + continuation_t continuation, thread_t new) { /* @@ -365,14 +383,13 @@ thread_t switch_context( * Load the rest of the user state for the new thread */ switch_ktss(new->pcb); - return Switch_context(old, continuation, new); } void pcb_module_init(void) { - kmem_cache_init(&pcb_cache, "pcb", sizeof(struct pcb), 0, - NULL, 0); + kmem_cache_init(&pcb_cache, "pcb", sizeof(struct pcb), + KERNEL_STACK_ALIGN, NULL, 0); fpu_module_init(); } @@ -400,10 +417,12 @@ void pcb_init(task_t parent_task, thread_t thread) */ pcb->iss.cs = USER_CS; pcb->iss.ss = USER_DS; +#if !defined(__x86_64__) || defined(USER32) pcb->iss.ds = USER_DS; pcb->iss.es = USER_DS; pcb->iss.fs = USER_DS; pcb->iss.gs = USER_DS; +#endif pcb->iss.efl = EFL_USER_SET; thread->pcb = pcb; @@ -435,8 +454,7 @@ void pcb_terminate(thread_t thread) * Attempt to free excess pcb memory. */ -void pcb_collect(thread) - const thread_t thread; +void pcb_collect(__attribute__((unused)) const thread_t thread) { } @@ -474,10 +492,12 @@ kern_return_t thread_setstatus( */ state->cs &= 0xffff; state->ss &= 0xffff; +#if !defined(__x86_64__) || defined(USER32) state->ds &= 0xffff; state->es &= 0xffff; state->fs &= 0xffff; state->gs &= 0xffff; +#endif if (state->cs == 0 || (state->cs & SEL_PL) != SEL_PL_U || state->ss == 0 || (state->ss & SEL_PL) != SEL_PL_U) @@ -489,6 +509,27 @@ kern_return_t thread_setstatus( /* * General registers */ +#if defined(__x86_64__) && !defined(USER32) + saved_state->r8 = state->r8; + saved_state->r9 = state->r9; + saved_state->r10 = state->r10; + saved_state->r11 = state->r11; + saved_state->r12 = state->r12; + saved_state->r13 = state->r13; + saved_state->r14 = state->r14; + saved_state->r15 = state->r15; + saved_state->edi = state->rdi; + saved_state->esi = state->rsi; + saved_state->ebp = state->rbp; + saved_state->uesp = state->ursp; + saved_state->ebx = state->rbx; + saved_state->edx = state->rdx; + saved_state->ecx = state->rcx; + saved_state->eax = state->rax; + saved_state->eip = state->rip; + saved_state->efl = (state->rfl & ~EFL_USER_CLEAR) + | EFL_USER_SET; +#else saved_state->edi = state->edi; saved_state->esi = state->esi; saved_state->ebp = state->ebp; @@ -500,11 +541,13 @@ kern_return_t thread_setstatus( saved_state->eip = state->eip; saved_state->efl = (state->efl & ~EFL_USER_CLEAR) | EFL_USER_SET; +#endif /* __x86_64__ && !USER32 */ +#if !defined(__x86_64__) || defined(USER32) /* * Segment registers. Set differently in V8086 mode. */ - if (state->efl & EFL_VM) { + if (saved_state->efl & EFL_VM) { /* * Set V8086 mode segment registers. */ @@ -528,20 +571,23 @@ kern_return_t thread_setstatus( * Hardware assist on. */ thread->pcb->ims.v86s.flags = - state->efl & (EFL_TF | EFL_IF); + saved_state->efl & (EFL_TF | EFL_IF); } - } - else if (flavor == i386_THREAD_STATE) { + } else +#endif + if (flavor == i386_THREAD_STATE) { /* * 386 mode. Set segment registers for flat * 32-bit address space. */ saved_state->cs = USER_CS; saved_state->ss = USER_DS; +#if !defined(__x86_64__) || defined(USER32) saved_state->ds = USER_DS; saved_state->es = USER_DS; saved_state->fs = USER_DS; saved_state->gs = USER_DS; +#endif } else { /* @@ -552,10 +598,12 @@ kern_return_t thread_setstatus( */ saved_state->cs = state->cs; saved_state->ss = state->ss; +#if !defined(__x86_64__) || defined(USER32) saved_state->ds = state->ds; saved_state->es = state->es; saved_state->fs = state->fs; saved_state->gs = state->gs; +#endif } break; } @@ -597,7 +645,7 @@ kern_return_t thread_setstatus( #endif break; } - +#if !defined(__x86_64__) || defined(USER32) case i386_V86_ASSIST_STATE: { struct i386_v86_assist_state *state; @@ -611,10 +659,10 @@ kern_return_t thread_setstatus( int_table = state->int_table; int_count = state->int_count; - if (int_table >= VM_MAX_ADDRESS || + if (int_table >= VM_MAX_USER_ADDRESS || int_table + int_count * sizeof(struct v86_interrupt_table) - > VM_MAX_ADDRESS) + > VM_MAX_USER_ADDRESS) return KERN_INVALID_ARGUMENT; thread->pcb->ims.v86s.int_table = int_table; @@ -624,7 +672,7 @@ kern_return_t thread_setstatus( USER_REGS(thread)->efl & (EFL_TF | EFL_IF); break; } - +#endif case i386_DEBUG_STATE: { struct i386_debug_state *state; @@ -639,7 +687,23 @@ kern_return_t thread_setstatus( return ret; break; } - +#if defined(__x86_64__) && !defined(USER32) + case i386_FSGS_BASE_STATE: + { + struct i386_fsgs_base_state *state; + if (count < i386_FSGS_BASE_STATE_COUNT) + return KERN_INVALID_ARGUMENT; + + state = (struct i386_fsgs_base_state *) tstate; + thread->pcb->ims.sbs.fsbase = state->fs_base; + thread->pcb->ims.sbs.gsbase = state->gs_base; + if (thread == current_thread()) { + wrmsr(MSR_REG_FSBASE, state->fs_base); + wrmsr(MSR_REG_GSBASE, state->gs_base); + } + break; + } +#endif default: return(KERN_INVALID_ARGUMENT); } @@ -661,13 +725,20 @@ kern_return_t thread_getstatus( { switch (flavor) { case THREAD_STATE_FLAVOR_LIST: - if (*count < 4) +#if !defined(__x86_64__) || defined(USER32) + unsigned int ncount = 4; +#else + unsigned int ncount = 3; +#endif + if (*count < ncount) return (KERN_INVALID_ARGUMENT); tstate[0] = i386_THREAD_STATE; tstate[1] = i386_FLOAT_STATE; tstate[2] = i386_ISA_PORT_MAP_STATE; +#if !defined(__x86_64__) || defined(USER32) tstate[3] = i386_V86_ASSIST_STATE; - *count = 4; +#endif + *count = ncount; break; case i386_THREAD_STATE: @@ -685,6 +756,27 @@ kern_return_t thread_getstatus( /* * General registers. */ +#if defined(__x86_64__) && !defined(USER32) + state->r8 = saved_state->r8; + state->r9 = saved_state->r9; + state->r10 = saved_state->r10; + state->r11 = saved_state->r11; + state->r12 = saved_state->r12; + state->r13 = saved_state->r13; + state->r14 = saved_state->r14; + state->r15 = saved_state->r15; + state->rdi = saved_state->edi; + state->rsi = saved_state->esi; + state->rbp = saved_state->ebp; + state->rbx = saved_state->ebx; + state->rdx = saved_state->edx; + state->rcx = saved_state->ecx; + state->rax = saved_state->eax; + state->rip = saved_state->eip; + state->ursp = saved_state->uesp; + state->rfl = saved_state->efl; + state->rsp = 0; /* unused */ +#else state->edi = saved_state->edi; state->esi = saved_state->esi; state->ebp = saved_state->ebp; @@ -693,11 +785,14 @@ kern_return_t thread_getstatus( state->ecx = saved_state->ecx; state->eax = saved_state->eax; state->eip = saved_state->eip; - state->efl = saved_state->efl; state->uesp = saved_state->uesp; + state->efl = saved_state->efl; + state->esp = 0; /* unused */ +#endif /* __x86_64__ && !USER32 */ state->cs = saved_state->cs; state->ss = saved_state->ss; +#if !defined(__x86_64__) || defined(USER32) if (saved_state->efl & EFL_VM) { /* * V8086 mode. @@ -714,10 +809,9 @@ kern_return_t thread_getstatus( if ((thread->pcb->ims.v86s.flags & (EFL_IF|V86_IF_PENDING)) == 0) - state->efl &= ~EFL_IF; + saved_state->efl &= ~EFL_IF; } - } - else { + } else { /* * 386 mode. */ @@ -726,6 +820,7 @@ kern_return_t thread_getstatus( state->fs = saved_state->fs & 0xffff; state->gs = saved_state->gs & 0xffff; } +#endif *count = i386_THREAD_STATE_COUNT; break; } @@ -763,7 +858,7 @@ kern_return_t thread_getstatus( *count = i386_ISA_PORT_MAP_STATE_COUNT; break; } - +#if !defined(__x86_64__) || defined(USER32) case i386_V86_ASSIST_STATE: { struct i386_v86_assist_state *state; @@ -778,7 +873,7 @@ kern_return_t thread_getstatus( *count = i386_V86_ASSIST_STATE_COUNT; break; } - +#endif case i386_DEBUG_STATE: { struct i386_debug_state *state; @@ -792,7 +887,20 @@ kern_return_t thread_getstatus( *count = i386_DEBUG_STATE_COUNT; break; } - +#if defined(__x86_64__) && !defined(USER32) + case i386_FSGS_BASE_STATE: + { + struct i386_fsgs_base_state *state; + if (*count < i386_FSGS_BASE_STATE_COUNT) + return KERN_INVALID_ARGUMENT; + + state = (struct i386_fsgs_base_state *) tstate; + state->fs_base = thread->pcb->ims.sbs.fsbase; + state->gs_base = thread->pcb->ims.sbs.gsbase; + *count = i386_FSGS_BASE_STATE_COUNT; + break; + } +#endif default: return(KERN_INVALID_ARGUMENT); } @@ -822,27 +930,28 @@ thread_set_syscall_return( vm_offset_t user_stack_low(vm_size_t stack_size) { - return (VM_MAX_ADDRESS - stack_size); + return (VM_MAX_USER_ADDRESS - stack_size); } /* * Allocate argument area and set registers for first user thread. */ vm_offset_t -set_user_regs(stack_base, stack_size, exec_info, arg_size) - vm_offset_t stack_base; /* low address */ - vm_offset_t stack_size; - const struct exec_info *exec_info; - vm_size_t arg_size; +set_user_regs(vm_offset_t stack_base, /* low address */ + vm_offset_t stack_size, + const struct exec_info *exec_info, + vm_size_t arg_size) { vm_offset_t arg_addr; struct i386_saved_state *saved_state; - arg_size = (arg_size + sizeof(int) - 1) & ~(sizeof(int)-1); + assert(P2ALIGNED(stack_size, USER_STACK_ALIGN)); + assert(P2ALIGNED(stack_base, USER_STACK_ALIGN)); + arg_size = P2ROUND(arg_size, USER_STACK_ALIGN); arg_addr = stack_base + stack_size - arg_size; saved_state = USER_REGS(current_thread()); - saved_state->uesp = (long)arg_addr; + saved_state->uesp = (rpc_vm_offset_t)arg_addr; saved_state->eip = exec_info->entry; return (arg_addr); |