diff options
author | Brian Gerst <brgerst@gmail.com> | 2009-02-08 09:58:39 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-09 04:30:30 -0500 |
commit | 2add8e235cbe0dcd672c33fc322754e15500238c (patch) | |
tree | 3cf9abe886432ac82fc08e99241ec7254dc20193 /arch/x86 | |
parent | d3770449d3cb058b94ca1d050d5ced4a66c75ce4 (diff) |
x86: use linker to offset symbols by __per_cpu_load
Impact: cleanup and bug fix
Use the linker to create symbols for certain per-cpu variables
that are offset by __per_cpu_load. This allows the removal of
the runtime fixup of the GDT pointer, which fixes a bug with
resume reported by Jiri Slaby.
Reported-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/percpu.h | 22 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/head_64.S | 21 | ||||
-rw-r--r-- | arch/x86/kernel/vmlinux_64.lds.S | 8 |
5 files changed, 35 insertions, 24 deletions
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 0b64af4f13ac..aee103b26d01 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h | |||
@@ -34,6 +34,12 @@ | |||
34 | #define PER_CPU_VAR(var) per_cpu__##var | 34 | #define PER_CPU_VAR(var) per_cpu__##var |
35 | #endif /* SMP */ | 35 | #endif /* SMP */ |
36 | 36 | ||
37 | #ifdef CONFIG_X86_64_SMP | ||
38 | #define INIT_PER_CPU_VAR(var) init_per_cpu__##var | ||
39 | #else | ||
40 | #define INIT_PER_CPU_VAR(var) per_cpu__##var | ||
41 | #endif | ||
42 | |||
37 | #else /* ...!ASSEMBLY */ | 43 | #else /* ...!ASSEMBLY */ |
38 | 44 | ||
39 | #include <linux/stringify.h> | 45 | #include <linux/stringify.h> |
@@ -45,6 +51,22 @@ | |||
45 | #define __percpu_arg(x) "%" #x | 51 | #define __percpu_arg(x) "%" #x |
46 | #endif | 52 | #endif |
47 | 53 | ||
54 | /* | ||
55 | * Initialized pointers to per-cpu variables needed for the boot | ||
56 | * processor need to use these macros to get the proper address | ||
57 | * offset from __per_cpu_load on SMP. | ||
58 | * | ||
59 | * There also must be an entry in vmlinux_64.lds.S | ||
60 | */ | ||
61 | #define DECLARE_INIT_PER_CPU(var) \ | ||
62 | extern typeof(per_cpu_var(var)) init_per_cpu_var(var) | ||
63 | |||
64 | #ifdef CONFIG_X86_64_SMP | ||
65 | #define init_per_cpu_var(var) init_per_cpu__##var | ||
66 | #else | ||
67 | #define init_per_cpu_var(var) per_cpu_var(var) | ||
68 | #endif | ||
69 | |||
48 | /* For arch-specific code, we can use direct single-insn ops (they | 70 | /* For arch-specific code, we can use direct single-insn ops (they |
49 | * don't give an lvalue though). */ | 71 | * don't give an lvalue though). */ |
50 | extern void __bad_percpu_size(void); | 72 | extern void __bad_percpu_size(void); |
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 656d02ea509b..373d3f628d24 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -393,6 +393,8 @@ union irq_stack_union { | |||
393 | }; | 393 | }; |
394 | 394 | ||
395 | DECLARE_PER_CPU(union irq_stack_union, irq_stack_union); | 395 | DECLARE_PER_CPU(union irq_stack_union, irq_stack_union); |
396 | DECLARE_INIT_PER_CPU(irq_stack_union); | ||
397 | |||
396 | DECLARE_PER_CPU(char *, irq_stack_ptr); | 398 | DECLARE_PER_CPU(char *, irq_stack_ptr); |
397 | #endif | 399 | #endif |
398 | 400 | ||
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 0f73ea423089..41b0de6df873 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -902,12 +902,8 @@ struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; | |||
902 | 902 | ||
903 | DEFINE_PER_CPU_FIRST(union irq_stack_union, | 903 | DEFINE_PER_CPU_FIRST(union irq_stack_union, |
904 | irq_stack_union) __aligned(PAGE_SIZE); | 904 | irq_stack_union) __aligned(PAGE_SIZE); |
905 | #ifdef CONFIG_SMP | ||
906 | DEFINE_PER_CPU(char *, irq_stack_ptr); /* will be set during per cpu init */ | ||
907 | #else | ||
908 | DEFINE_PER_CPU(char *, irq_stack_ptr) = | 905 | DEFINE_PER_CPU(char *, irq_stack_ptr) = |
909 | per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64; | 906 | init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64; |
910 | #endif | ||
911 | 907 | ||
912 | DEFINE_PER_CPU(unsigned long, kernel_stack) = | 908 | DEFINE_PER_CPU(unsigned long, kernel_stack) = |
913 | (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE; | 909 | (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE; |
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index a0a2b5ca9b7d..2e648e3a5ea4 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
@@ -205,19 +205,6 @@ ENTRY(secondary_startup_64) | |||
205 | pushq $0 | 205 | pushq $0 |
206 | popfq | 206 | popfq |
207 | 207 | ||
208 | #ifdef CONFIG_SMP | ||
209 | /* | ||
210 | * Fix up static pointers that need __per_cpu_load added. The assembler | ||
211 | * is unable to do this directly. This is only needed for the boot cpu. | ||
212 | * These values are set up with the correct base addresses by C code for | ||
213 | * secondary cpus. | ||
214 | */ | ||
215 | movq initial_gs(%rip), %rax | ||
216 | cmpl $0, per_cpu__cpu_number(%rax) | ||
217 | jne 1f | ||
218 | addq %rax, early_gdt_descr_base(%rip) | ||
219 | 1: | ||
220 | #endif | ||
221 | /* | 208 | /* |
222 | * We must switch to a new descriptor in kernel space for the GDT | 209 | * We must switch to a new descriptor in kernel space for the GDT |
223 | * because soon the kernel won't have access anymore to the userspace | 210 | * because soon the kernel won't have access anymore to the userspace |
@@ -275,11 +262,7 @@ ENTRY(secondary_startup_64) | |||
275 | ENTRY(initial_code) | 262 | ENTRY(initial_code) |
276 | .quad x86_64_start_kernel | 263 | .quad x86_64_start_kernel |
277 | ENTRY(initial_gs) | 264 | ENTRY(initial_gs) |
278 | #ifdef CONFIG_SMP | 265 | .quad INIT_PER_CPU_VAR(irq_stack_union) |
279 | .quad __per_cpu_load | ||
280 | #else | ||
281 | .quad PER_CPU_VAR(irq_stack_union) | ||
282 | #endif | ||
283 | __FINITDATA | 266 | __FINITDATA |
284 | 267 | ||
285 | ENTRY(stack_start) | 268 | ENTRY(stack_start) |
@@ -425,7 +408,7 @@ NEXT_PAGE(level2_spare_pgt) | |||
425 | early_gdt_descr: | 408 | early_gdt_descr: |
426 | .word GDT_ENTRIES*8-1 | 409 | .word GDT_ENTRIES*8-1 |
427 | early_gdt_descr_base: | 410 | early_gdt_descr_base: |
428 | .quad per_cpu__gdt_page | 411 | .quad INIT_PER_CPU_VAR(gdt_page) |
429 | 412 | ||
430 | ENTRY(phys_base) | 413 | ENTRY(phys_base) |
431 | /* This must match the first entry in level2_kernel_pgt */ | 414 | /* This must match the first entry in level2_kernel_pgt */ |
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index 07f62d287ff0..087a7f2c639b 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S | |||
@@ -257,6 +257,14 @@ SECTIONS | |||
257 | DWARF_DEBUG | 257 | DWARF_DEBUG |
258 | } | 258 | } |
259 | 259 | ||
260 | /* | ||
261 | * Per-cpu symbols which need to be offset from __per_cpu_load | ||
262 | * for the boot processor. | ||
263 | */ | ||
264 | #define INIT_PER_CPU(x) init_per_cpu__##x = per_cpu__##x + __per_cpu_load | ||
265 | INIT_PER_CPU(gdt_page); | ||
266 | INIT_PER_CPU(irq_stack_union); | ||
267 | |||
260 | /* | 268 | /* |
261 | * Build-time check on the image size: | 269 | * Build-time check on the image size: |
262 | */ | 270 | */ |