Index: sys/amd64/amd64/mp_machdep.c =================================================================== --- sys/amd64/amd64/mp_machdep.c +++ sys/amd64/amd64/mp_machdep.c @@ -103,6 +103,7 @@ static char *mce_stack; static char *nmi_stack; static char *dbg_stack; +void *bootpcpu; extern u_int mptramp_la57; extern u_int mptramp_nx; @@ -197,10 +198,8 @@ /* Update microcode before doing anything else. */ ucode_load_ap(cpu); - /* Get per-cpu data and save */ - pc = &__pcpu[cpu]; - - /* prime data page for it to use */ + /* Initialize the PCPU area. */ + pc = bootpcpu; pcpu_init(pc, cpu, sizeof(struct pcpu)); dpcpu_init(dpcpu, cpu); pc->pc_apic_id = cpu_apic_ids[cpu]; @@ -262,8 +261,8 @@ lgdt(&ap_gdt); /* does magic intra-segment return */ wrmsr(MSR_FSBASE, 0); /* User value */ - wrmsr(MSR_GSBASE, (u_int64_t)pc); - wrmsr(MSR_KGSBASE, (u_int64_t)pc); /* XXX User value while we're in the kernel */ + wrmsr(MSR_GSBASE, (uint64_t)pc); + wrmsr(MSR_KGSBASE, 0); /* User value */ fix_cpuid(); lidt(&r_idt); @@ -431,6 +430,7 @@ dpcpu = (void *)kmem_malloc_domainset(DOMAINSET_PREF(domain), DPCPU_SIZE, M_WAITOK | M_ZERO); + bootpcpu = &__pcpu[cpu]; bootSTK = (char *)bootstacks[cpu] + kstack_pages * PAGE_SIZE - 8; bootAP = cpu; Index: sys/amd64/amd64/mpboot.S =================================================================== --- sys/amd64/amd64/mpboot.S +++ sys/amd64/amd64/mpboot.S @@ -260,4 +260,21 @@ .p2align 4,0 entry_64: movq bootSTK, %rsp + + /* + * Initialize the segment register used for the PCPU area. The PCPU + * area will be initialized by init_secondary(), but it should be + * accessible before that to support sanitizer instrumentation which + * accesses per-CPU variables. + * + * Note that GS.base is loaded again in init_secondary(). This is not + * redundant: lgdt() loads a selector into %gs and this has the side + * effect of clearing GS.base. + */ + movl $MSR_GSBASE, %ecx + movq bootpcpu, %rax + movq %rax, %rdx + shrq $32, %rdx + wrmsr + jmp init_secondary