diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index a0b11f8..99d6716 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -266,7 +266,7 @@ store_seg: movl %es,PCB_ES(%r8) movl %fs,PCB_FS(%r8) jmp done_store_seg -2: movq PCB_GS32P(%r8),%rax +2: movq PCPU(GS32P),%rax movq (%rax),%rax movq %rax,PCB_GS32SD(%r8) jmp 1b @@ -283,7 +283,7 @@ load_seg: movl PCB_FS(%r8),%fs jmp done_load_seg /* Restore userland %gs while preserving kernel gsbase */ -2: movq PCB_GS32P(%r8),%rax +2: movq PCPU(GS32P),%rax movq PCB_GS32SD(%r8),%rcx movq %rcx,(%rax) jmp 1b diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index fec0380..f749dd6 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -147,7 +147,6 @@ ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags)); ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save)); ASSYM(PCB_SAVEFPU_SIZE, sizeof(struct savefpu)); ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault)); -ASSYM(PCB_GS32P, offsetof(struct pcb, pcb_gs32p)); ASSYM(PCB_GS32SD, offsetof(struct pcb, pcb_gs32sd)); ASSYM(PCB_SIZE, sizeof(struct pcb)); @@ -199,6 +198,7 @@ ASSYM(PC_SCRATCH_RSP, offsetof(struct pcpu, pc_scratch_rsp)); ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap)); ASSYM(PC_TSSP, offsetof(struct pcpu, pc_tssp)); ASSYM(PC_RSP0, offsetof(struct pcpu, pc_rsp0)); +ASSYM(PC_GS32P, offsetof(struct pcpu, pc_gs32p)); ASSYM(LA_VER, offsetof(struct LAPIC, version)); ASSYM(LA_TPR, offsetof(struct LAPIC, tpr)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index f3c41f7..988b039 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -803,7 +803,7 @@ cpu_setregs(void) * Initialize segments & interrupt table */ -struct user_segment_descriptor gdt[NGDT * MAXCPU];/* global descriptor table */ +struct user_segment_descriptor gdt[NGDT * MAXCPU];/* global descriptor tables */ static struct gate_descriptor idt0[NIDT]; struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ @@ -870,7 +870,7 @@ struct soft_segment_descriptor gdt_segs[] = { /* GPROC0_SEL 6 Proc 0 Tss Descriptor */ { 0x0, /* segment base address */ - sizeof(struct amd64tss)-1,/* length - all address space */ + sizeof(struct amd64tss)-1,/* length */ SDT_SYSTSS, /* segment type */ SEL_KPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ @@ -1347,6 +1347,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) PCPU_SET(curthread, &thread0); PCPU_SET(curpcb, thread0.td_pcb); PCPU_SET(tssp, &common_tss[0]); + PCPU_SET(gs32p, &gdt[GUGS32_SEL]); /* * Initialize mutexes. diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 304deaa..2de63e3 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -436,7 +436,8 @@ init_secondary(void) { struct pcpu *pc; u_int64_t msr, cr0; - int cpu, gsel_tss; + int cpu, gsel_tss, x; + struct region_descriptor ap_gdt; /* Set by the startup code for us to use */ cpu = bootAP; @@ -447,11 +448,17 @@ init_secondary(void) common_tss[cpu].tss_iobase = sizeof(struct amd64tss); common_tss[cpu].tss_ist1 = (long)&doublefault_stack[PAGE_SIZE]; + /* Prepare private GDT */ gdt_segs[GPROC0_SEL].ssd_base = (long) &common_tss[cpu]; ssdtosyssd(&gdt_segs[GPROC0_SEL], - (struct system_segment_descriptor *)&gdt[GPROC0_SEL]); - - lgdt(&r_gdt); /* does magic intra-segment return */ + (struct system_segment_descriptor *)&gdt[NGDT * cpu + GPROC0_SEL]); + for (x = 0; x < NGDT; x++) { + if (x != GPROC0_SEL && x != (GPROC0_SEL + 1)) + ssdtosd(&gdt_segs[x], &gdt[NGDT * cpu + x]); + } + ap_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; + ap_gdt.rd_base = (long) &gdt[NGDT * cpu]; + lgdt(&ap_gdt); /* does magic intra-segment return */ /* Get per-cpu data */ pc = &__pcpu[cpu]; @@ -463,6 +470,7 @@ init_secondary(void) pc->pc_curthread = 0; pc->pc_tssp = &common_tss[cpu]; pc->pc_rsp0 = 0; + pc->pc_gs32p = &gdt[NGDT * cpu + GUGS32_SEL]; wrmsr(MSR_FSBASE, 0); /* User value */ wrmsr(MSR_GSBASE, (u_int64_t)pc); diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 00e596f..8d710cd 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -692,7 +692,8 @@ trap_fatal(frame, eva) code = frame->tf_err; type = frame->tf_trapno; - sdtossd(&gdt[IDXSEL(frame->tf_cs & 0xffff)], &softseg); + sdtossd(&gdt[NGDT * PCPU_GET(cpuid) + IDXSEL(frame->tf_cs & 0xffff)], + &softseg); if (type <= MAX_TRAP_MSG) msg = trap_msg[type]; diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h index 647d5c9..43b59e5 100644 --- a/sys/amd64/include/pcb.h +++ b/sys/amd64/include/pcb.h @@ -77,7 +77,6 @@ struct pcb { caddr_t pcb_onfault; /* copyin/out fault recovery */ /* 32-bit segment descriptor */ - struct user_segment_descriptor *pcb_gs32p; struct user_segment_descriptor pcb_gs32sd; }; diff --git a/sys/amd64/include/pcpu.h b/sys/amd64/include/pcpu.h index fe811c5..e9faf28 100644 --- a/sys/amd64/include/pcpu.h +++ b/sys/amd64/include/pcpu.h @@ -48,7 +48,8 @@ register_t pc_rsp0; \ register_t pc_scratch_rsp; /* User %rsp in syscall */ \ u_int pc_apic_id; \ - u_int pc_acpi_id /* ACPI CPU id */ + u_int pc_acpi_id; /* ACPI CPU id */ \ + struct user_segment_descriptor *pc_gs32p #ifdef _KERNEL diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h index 891404c..1c83d1c 100644 --- a/sys/amd64/include/segments.h +++ b/sys/amd64/include/segments.h @@ -201,7 +201,7 @@ struct region_descriptor { #define GUDATA_SEL 4 /* User 32/64 bit Data Descriptor */ #define GUCODE_SEL 5 /* User 64 bit Code Descriptor */ #define GPROC0_SEL 6 /* TSS for entering kernel etc */ -/* slot 6 is second half of GPROC0_SEL */ +/* slot 7 is second half of GPROC0_SEL */ #define GUGS32_SEL 8 /* User 32 bit GS Descriptor */ #define NGDT 9 diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index 6f1401c..aecf869 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -694,7 +694,6 @@ linux_clone(struct thread *td, struct linux_clone_args *args) #endif td2->td_pcb->pcb_gsbase = (register_t)info.base_addr; td2->td_pcb->pcb_gs32sd = sd; - td2->td_pcb->pcb_gs32p = &gdt[GUGS32_SEL]; td2->td_pcb->pcb_gs = GSEL(GUGS32_SEL, SEL_UPL); td2->td_pcb->pcb_flags |= PCB_GS32BIT | PCB_32BIT; } @@ -1352,9 +1351,8 @@ linux_set_thread_area(struct thread *td, critical_enter(); td->td_pcb->pcb_gsbase = (register_t)info.base_addr; - td->td_pcb->pcb_gs32sd = gdt[GUGS32_SEL] = sd; - td->td_pcb->pcb_gs32p = &gdt[GUGS32_SEL]; - td->td_pcb->pcb_flags |= PCB_32BIT; + td->td_pcb->pcb_gs32sd = *PCPU_GET(gs32p) = sd; + td->td_pcb->pcb_flags |= PCB_32BIT | PCB_GS32BIT; wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase); critical_exit();