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 /include | |
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 'include')
-rw-r--r-- | include/asm-generic/sections.h | 2 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 51 |
2 files changed, 46 insertions, 7 deletions
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 79a7ff925bf8..4ce48e878530 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h | |||
@@ -9,7 +9,7 @@ extern char __bss_start[], __bss_stop[]; | |||
9 | extern char __init_begin[], __init_end[]; | 9 | extern char __init_begin[], __init_end[]; |
10 | extern char _sinittext[], _einittext[]; | 10 | extern char _sinittext[], _einittext[]; |
11 | extern char _end[]; | 11 | extern char _end[]; |
12 | extern char __per_cpu_start[], __per_cpu_end[]; | 12 | extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[]; |
13 | extern char __kprobes_text_start[], __kprobes_text_end[]; | 13 | extern char __kprobes_text_start[], __kprobes_text_end[]; |
14 | extern char __initdata_begin[], __initdata_end[]; | 14 | extern char __initdata_begin[], __initdata_end[]; |
15 | extern char __start_rodata[], __end_rodata[]; | 15 | extern char __start_rodata[], __end_rodata[]; |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index c61fab1dd2f8..fc2f55f2dcd6 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -430,12 +430,51 @@ | |||
430 | *(.initcall7.init) \ | 430 | *(.initcall7.init) \ |
431 | *(.initcall7s.init) | 431 | *(.initcall7s.init) |
432 | 432 | ||
433 | #define PERCPU(align) \ | 433 | #define PERCPU_PROLOG(vaddr) \ |
434 | . = ALIGN(align); \ | 434 | VMLINUX_SYMBOL(__per_cpu_load) = .; \ |
435 | VMLINUX_SYMBOL(__per_cpu_start) = .; \ | 435 | .data.percpu vaddr : AT(__per_cpu_load - LOAD_OFFSET) { \ |
436 | .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \ | 436 | VMLINUX_SYMBOL(__per_cpu_start) = .; |
437 | |||
438 | #define PERCPU_EPILOG(phdr) \ | ||
439 | VMLINUX_SYMBOL(__per_cpu_end) = .; \ | ||
440 | } phdr \ | ||
441 | . = __per_cpu_load + SIZEOF(.data.percpu); | ||
442 | |||
443 | /** | ||
444 | * PERCPU_VADDR - define output section for percpu area | ||
445 | * @vaddr: explicit base address (optional) | ||
446 | * @phdr: destination PHDR (optional) | ||
447 | * | ||
448 | * Macro which expands to output section for percpu area. If @vaddr | ||
449 | * is not blank, it specifies explicit base address and all percpu | ||
450 | * symbols will be offset from the given address. If blank, @vaddr | ||
451 | * always equals @laddr + LOAD_OFFSET. | ||
452 | * | ||
453 | * @phdr defines the output PHDR to use if not blank. Be warned that | ||
454 | * output PHDR is sticky. If @phdr is specified, the next output | ||
455 | * section in the linker script will go there too. @phdr should have | ||
456 | * a leading colon. | ||
457 | * | ||
458 | * This macro defines three symbols, __per_cpu_load, __per_cpu_start | ||
459 | * and __per_cpu_end. The first one is the vaddr of loaded percpu | ||
460 | * init data. __per_cpu_start equals @vaddr and __per_cpu_end is the | ||
461 | * end offset. | ||
462 | */ | ||
463 | #define PERCPU_VADDR(vaddr, phdr) \ | ||
464 | PERCPU_PROLOG(vaddr) \ | ||
437 | *(.data.percpu.page_aligned) \ | 465 | *(.data.percpu.page_aligned) \ |
438 | *(.data.percpu) \ | 466 | *(.data.percpu) \ |
439 | *(.data.percpu.shared_aligned) \ | 467 | *(.data.percpu.shared_aligned) \ |
440 | } \ | 468 | PERCPU_EPILOG(phdr) |
441 | VMLINUX_SYMBOL(__per_cpu_end) = .; | 469 | |
470 | /** | ||
471 | * PERCPU - define output section for percpu area, simple version | ||
472 | * @align: required alignment | ||
473 | * | ||
474 | * Align to @align and outputs output section for percpu area. This | ||
475 | * macro doesn't maniuplate @vaddr or @phdr and __per_cpu_load and | ||
476 | * __per_cpu_start will be identical. | ||
477 | */ | ||
478 | #define PERCPU(align) \ | ||
479 | . = ALIGN(align); \ | ||
480 | PERCPU_VADDR( , ) | ||