diff options
| author | Tejun Heo <tj@kernel.org> | 2009-01-13 06:41:35 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-01-16 08:19:14 -0500 |
| commit | 3e5d8f978435bb9ba4dfe3f4514e65e7885db1a9 (patch) | |
| tree | 1ce55b2ec16a0bd59a29857e05215960d463a1d8 /arch/x86/kernel/head_64.S | |
| parent | a698c823e15149941b0f0281527d0c0d1daf2639 (diff) | |
x86: make percpu symbols zerobased on SMP
[ Based on original patch from Christoph Lameter and Mike Travis. ]
This patch makes percpu symbols zerobased on x86_64 SMP by adding
PERCPU_VADDR() to vmlinux.lds.h which helps setting explicit vaddr on
the percpu output section and using it in vmlinux_64.lds.S. A new
PHDR is added as existing ones cannot contain sections near address
zero. PERCPU_VADDR() also adds a new symbol __per_cpu_load which
always points to the vaddr of the loaded percpu data.init region.
The following adjustments have been made to accomodate the address
change.
* code to locate percpu gdt_page in head_64.S is updated to add the
load address to the gdt_page offset.
* __per_cpu_load is used in places where access to the init data area
is necessary.
* pda->data_offset is initialized soon after C code is entered as zero
value doesn't work anymore.
This patch is mostly taken from Mike Travis' "x86_64: Base percpu
variables at zero" patch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/head_64.S')
| -rw-r--r-- | arch/x86/kernel/head_64.S | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 0e275d495563..7ee0363871e8 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
| @@ -204,6 +204,23 @@ ENTRY(secondary_startup_64) | |||
| 204 | pushq $0 | 204 | pushq $0 |
| 205 | popfq | 205 | popfq |
| 206 | 206 | ||
| 207 | #ifdef CONFIG_SMP | ||
| 208 | /* | ||
| 209 | * early_gdt_base should point to the gdt_page in static percpu init | ||
| 210 | * data area. Computing this requires two symbols - __per_cpu_load | ||
| 211 | * and per_cpu__gdt_page. As linker can't do no such relocation, do | ||
| 212 | * it by hand. As early_gdt_descr is manipulated by C code for | ||
| 213 | * secondary CPUs, this should be done only once for the boot CPU | ||
| 214 | * when early_gdt_descr_base contains zero. | ||
| 215 | */ | ||
| 216 | movq early_gdt_descr_base(%rip), %rax | ||
| 217 | testq %rax, %rax | ||
| 218 | jnz 1f | ||
| 219 | movq $__per_cpu_load, %rax | ||
| 220 | addq $per_cpu__gdt_page, %rax | ||
| 221 | movq %rax, early_gdt_descr_base(%rip) | ||
| 222 | 1: | ||
| 223 | #endif | ||
| 207 | /* | 224 | /* |
| 208 | * We must switch to a new descriptor in kernel space for the GDT | 225 | * We must switch to a new descriptor in kernel space for the GDT |
| 209 | * because soon the kernel won't have access anymore to the userspace | 226 | * because soon the kernel won't have access anymore to the userspace |
| @@ -401,7 +418,12 @@ NEXT_PAGE(level2_spare_pgt) | |||
| 401 | .globl early_gdt_descr | 418 | .globl early_gdt_descr |
| 402 | early_gdt_descr: | 419 | early_gdt_descr: |
| 403 | .word GDT_ENTRIES*8-1 | 420 | .word GDT_ENTRIES*8-1 |
| 404 | .quad per_cpu__gdt_page | 421 | #ifdef CONFIG_SMP |
| 422 | early_gdt_descr_base: | ||
| 423 | .quad 0x0000000000000000 | ||
| 424 | #else | ||
| 425 | .quad per_cpu__gdt_page | ||
| 426 | #endif | ||
| 405 | 427 | ||
| 406 | ENTRY(phys_base) | 428 | ENTRY(phys_base) |
| 407 | /* This must match the first entry in level2_kernel_pgt */ | 429 | /* This must match the first entry in level2_kernel_pgt */ |
