Index: amd64/amd64/mp_machdep.c =================================================================== --- amd64/amd64/mp_machdep.c (revision 191739) +++ amd64/amd64/mp_machdep.c (working copy) @@ -91,9 +91,10 @@ /* Free these after use */ void *bootstacks[MAXCPU]; -/* Temporary holder for double fault stack */ +/* Temporary variables for init_secondary() */ char *doublefault_stack; char *nmi_stack; +uintptr_t dpcpu; /* Hotwire a 0->4MB V==P mapping */ extern pt_entry_t *KPTphys; @@ -601,6 +602,9 @@ pc->pc_ldt = (struct system_segment_descriptor *)&gdt[NGDT * cpu + GUSERLDT_SEL]; + pc->pc_dynamic = dpcpu; + dpcpu_init(pc, DPCPU_SIZE); + /* Save the per-cpu pointer for use by the NMI handler. */ np->np_pcpu = (register_t) pc; @@ -881,6 +885,8 @@ bootstacks[cpu] = (void *)kmem_alloc(kernel_map, KSTACK_PAGES * PAGE_SIZE); doublefault_stack = (char *)kmem_alloc(kernel_map, PAGE_SIZE); nmi_stack = (char *)kmem_alloc(kernel_map, PAGE_SIZE); + dpcpu = kmem_alloc(kernel_map, + roundup2(DPCPU_SIZE, PAGE_SIZE)); bootSTK = (char *)bootstacks[cpu] + KSTACK_PAGES * PAGE_SIZE - 8; bootAP = cpu; Index: amd64/amd64/machdep.c =================================================================== --- amd64/amd64/machdep.c (revision 191739) +++ amd64/amd64/machdep.c (working copy) @@ -1368,6 +1368,7 @@ struct pcpu *pc; struct nmi_pcpu *np; u_int64_t msr; + uintptr_t dpcpu; char *env; thread0.td_kstack = physfree + KERNBASE; @@ -1428,6 +1429,10 @@ PCPU_SET(ldt, (struct system_segment_descriptor *)&gdt[GUSERLDT_SEL]); PCPU_SET(fs32p, &gdt[GUFS32_SEL]); PCPU_SET(gs32p, &gdt[GUGS32_SEL]); + dpcpu = physfree + KERNBASE; + physfree += roundup2(DPCPU_SIZE, PAGE_SIZE); + PCPU_SET(dynamic, dpcpu); + dpcpu_init(pc, DPCPU_SIZE); /* * Initialize mutexes. Index: sys/pcpu.h =================================================================== --- sys/pcpu.h (revision 191739) +++ sys/pcpu.h (working copy) @@ -45,6 +45,61 @@ struct pcb; struct thread; +/* + * Define a set for pcpu data. + * + * We don't use SET_DECLARE because it defines the set as 'a' when we + * want 'aw'. GCC considers uninitialized data in a seperate section + * writable and there is no generic zero initializer that works for + * structs and scalars. + */ +extern uintptr_t *__start_set_pcpu; +extern uintptr_t *__stop_set_pcpu; +__asm__(".section set_pcpu, \"aw\", @progbits"); +__asm__(".previous"); + +/* + * Array of dynamic pcpu base values. Indexed by id. + */ +extern uintptr_t dpcpu_ptrs[]; + +/* + * Convenience defines. + */ +#define DPCPU_NAME(n) pcpu_entry_##n +#define DPCPU_START (uintptr_t)&__start_set_pcpu +#define DPCPU_STOP (uintptr_t)&__stop_set_pcpu +#define DPCPU_SIZE (DPCPU_STOP - DPCPU_START) +#define DPCPU_OFFSET(n) ((uintptr_t)&DPCPU_NAME(n) - DPCPU_START) + +/* + * Declaration and definition. + */ +#define DPCPU_DECLARE(t, n) extern t DPCPU_NAME(n) +#define DPCPU_DEFINE(t, n) t DPCPU_NAME(n) __section("set_pcpu") __used + +/* + * Accessors with a given base. + */ +#define _DPCPU_PTR(b, n) \ + (__typeof(DPCPU_NAME(n))*)((b) + DPCPU_OFFSET(n)) +#define _DPCPU_GET(b, n) (*_DPCPU_PTR(b, n)) +#define _DPCPU_SET(b, n, v) (*_DPCPU_PTR(b, n) = v) + +/* + * Accessors for the current cpu. + */ +#define DPCPU_PTR(n) _DPCPU_PTR(PCPU_GET(dynamic), n) +#define DPCPU_GET(n) (*DPCPU_PTR(n)) +#define DPCPU_SET(n, v) (*DPCPU_PTR(n) = v) + +/* + * Accessors for remote cpus. + */ +#define DPCPU_ID_PTR(i, n) _DPCPU_PTR(dpcpu_ptrs[(i)], n) +#define DPCPU_ID_GET(i, n) (*DPCPU_ID_PTR(i, n)) +#define DPCPU_ID_SET(i, n, v) (*DPCPU_ID_PTR(i, n) = v) + /* * XXXUPS remove as soon as we have per cpu variable * linker sets and can define rm_queue in _rm_lock.h @@ -96,6 +151,11 @@ struct rm_queue pc_rm_queue; /* + * Dynamic per-cpu data area. + */ + uintptr_t pc_dynamic; + + /* * Keep MD fields last, so that CPU-specific variations on a * single architecture don't result in offset variations of * the machine-independent fields of the pcpu. Even though @@ -136,6 +196,7 @@ void pcpu_destroy(struct pcpu *pcpu); struct pcpu *pcpu_find(u_int cpuid); void pcpu_init(struct pcpu *pcpu, int cpuid, size_t size); +void dpcpu_init(struct pcpu *pcpu, size_t size); #endif /* _KERNEL */ Index: kern/subr_pcpu.c =================================================================== --- kern/subr_pcpu.c (revision 191739) +++ kern/subr_pcpu.c (working copy) @@ -56,6 +56,9 @@ #include #include +DPCPU_DEFINE(int, id); + +uintptr_t dpcpu_ptrs[MAXCPU]; struct pcpu *cpuid_to_pcpu[MAXCPU]; struct cpuhead cpuhead = SLIST_HEAD_INITIALIZER(cpuhead); @@ -82,6 +85,23 @@ } +void +dpcpu_init(struct pcpu *pcpu, size_t size) +{ + + /* + * Initialize defaults from our linker section. + */ + memcpy((void *)pcpu->pc_dynamic, (void *)DPCPU_START, DPCPU_SIZE); + + /* + * Place it in the global pcpu array. + */ + dpcpu_ptrs[pcpu->pc_cpuid] = (uintptr_t)pcpu->pc_dynamic; + + DPCPU_ID_SET(pcpu->pc_cpuid, id, pcpu->pc_cpuid); +} + /* * Destroy a struct pcpu. */ @@ -91,6 +111,7 @@ SLIST_REMOVE(&cpuhead, pcpu, pcpu, pc_allcpu); cpuid_to_pcpu[pcpu->pc_cpuid] = NULL; + dpcpu_ptrs[pcpu->pc_cpuid] = 0; } /* @@ -110,7 +131,9 @@ { struct thread *td; - db_printf("cpuid = %d\n", pc->pc_cpuid); + db_printf("cpuid = %d (%d)\n", + pc->pc_cpuid, DPCPU_ID_GET(pc->pc_cpuid, id)); + db_printf("curcpuid = %d\n", DPCPU_GET(id)); db_printf("curthread = "); td = pc->pc_curthread; if (td != NULL)