diff options
author | Brian Gerst <brgerst@gmail.com> | 2009-01-18 22:21:28 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2009-01-19 22:29:20 -0500 |
commit | 947e76cdc34c782fc947313d4331380686eebbad (patch) | |
tree | de5d424c4760269fd7800bc745e48b060c725300 | |
parent | 8c7e58e690ae60ab4215b025f433ed4af261e103 (diff) |
x86: move stack_canary into irq_stack
Impact: x86_64 percpu area layout change, irq_stack now at the beginning
Now that the PDA is empty except for the stack canary, it can be removed.
The irqstack is moved to the start of the per-cpu section. If the stack
protector is enabled, the canary overlaps the bottom 48 bytes of the irqstack.
tj: * updated subject
* dropped asm relocation of irq_stack_ptr
* updated comments a bit
* rebased on top of stack canary changes
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | arch/x86/include/asm/pda.h | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/percpu.h | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 23 | ||||
-rw-r--r-- | arch/x86/include/asm/stackprotector.h | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/system.h | 4 | ||||
-rw-r--r-- | arch/x86/kernel/asm-offsets_64.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/head_64.S | 13 | ||||
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 34 | ||||
-rw-r--r-- | arch/x86/kernel/vmlinux_64.lds.S | 8 |
10 files changed, 46 insertions, 62 deletions
diff --git a/arch/x86/include/asm/pda.h b/arch/x86/include/asm/pda.h index b473e952439a..ba46416634f0 100644 --- a/arch/x86/include/asm/pda.h +++ b/arch/x86/include/asm/pda.h | |||
@@ -17,9 +17,6 @@ struct x8664_pda { | |||
17 | unsigned long unused4; | 17 | unsigned long unused4; |
18 | int unused5; | 18 | int unused5; |
19 | unsigned int unused6; /* 36 was cpunumber */ | 19 | unsigned int unused6; /* 36 was cpunumber */ |
20 | unsigned long stack_canary; /* 40 stack canary value */ | ||
21 | /* gcc-ABI: this canary MUST be at | ||
22 | offset 40!!! */ | ||
23 | short in_bootmem; /* pda lives in bootmem */ | 20 | short in_bootmem; /* pda lives in bootmem */ |
24 | } ____cacheline_aligned_in_smp; | 21 | } ____cacheline_aligned_in_smp; |
25 | 22 | ||
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 165d5272ece1..ce980db5e59d 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h | |||
@@ -133,12 +133,6 @@ do { \ | |||
133 | /* We can use this directly for local CPU (faster). */ | 133 | /* We can use this directly for local CPU (faster). */ |
134 | DECLARE_PER_CPU(unsigned long, this_cpu_off); | 134 | DECLARE_PER_CPU(unsigned long, this_cpu_off); |
135 | 135 | ||
136 | #ifdef CONFIG_X86_64 | ||
137 | extern void load_pda_offset(int cpu); | ||
138 | #else | ||
139 | static inline void load_pda_offset(int cpu) { } | ||
140 | #endif | ||
141 | |||
142 | #endif /* !__ASSEMBLY__ */ | 136 | #endif /* !__ASSEMBLY__ */ |
143 | 137 | ||
144 | #ifdef CONFIG_SMP | 138 | #ifdef CONFIG_SMP |
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index f511246fa6cd..48676b943b92 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -379,8 +379,29 @@ union thread_xstate { | |||
379 | #ifdef CONFIG_X86_64 | 379 | #ifdef CONFIG_X86_64 |
380 | DECLARE_PER_CPU(struct orig_ist, orig_ist); | 380 | DECLARE_PER_CPU(struct orig_ist, orig_ist); |
381 | 381 | ||
382 | DECLARE_PER_CPU(char[IRQ_STACK_SIZE], irq_stack); | 382 | union irq_stack_union { |
383 | char irq_stack[IRQ_STACK_SIZE]; | ||
384 | /* | ||
385 | * GCC hardcodes the stack canary as %gs:40. Since the | ||
386 | * irq_stack is the object at %gs:0, we reserve the bottom | ||
387 | * 48 bytes of the irq stack for the canary. | ||
388 | */ | ||
389 | struct { | ||
390 | char gs_base[40]; | ||
391 | unsigned long stack_canary; | ||
392 | }; | ||
393 | }; | ||
394 | |||
395 | DECLARE_PER_CPU(union irq_stack_union, irq_stack_union); | ||
383 | DECLARE_PER_CPU(char *, irq_stack_ptr); | 396 | DECLARE_PER_CPU(char *, irq_stack_ptr); |
397 | |||
398 | static inline void load_gs_base(int cpu) | ||
399 | { | ||
400 | /* Memory clobbers used to order pda/percpu accesses */ | ||
401 | mb(); | ||
402 | wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu)); | ||
403 | mb(); | ||
404 | } | ||
384 | #endif | 405 | #endif |
385 | 406 | ||
386 | extern void print_cpu_info(struct cpuinfo_x86 *); | 407 | extern void print_cpu_info(struct cpuinfo_x86 *); |
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index 2383e5bb475c..36a700acaf2b 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define _ASM_STACKPROTECTOR_H 1 | 2 | #define _ASM_STACKPROTECTOR_H 1 |
3 | 3 | ||
4 | #include <asm/tsc.h> | 4 | #include <asm/tsc.h> |
5 | #include <asm/pda.h> | 5 | #include <asm/processor.h> |
6 | 6 | ||
7 | /* | 7 | /* |
8 | * Initialize the stackprotector canary value. | 8 | * Initialize the stackprotector canary value. |
@@ -19,7 +19,7 @@ static __always_inline void boot_init_stack_canary(void) | |||
19 | * Build time only check to make sure the stack_canary is at | 19 | * Build time only check to make sure the stack_canary is at |
20 | * offset 40 in the pda; this is a gcc ABI requirement | 20 | * offset 40 in the pda; this is a gcc ABI requirement |
21 | */ | 21 | */ |
22 | BUILD_BUG_ON(offsetof(struct x8664_pda, stack_canary) != 40); | 22 | BUILD_BUG_ON(offsetof(union irq_stack_union, stack_canary) != 40); |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * We both use the random pool and the current TSC as a source | 25 | * We both use the random pool and the current TSC as a source |
@@ -32,7 +32,7 @@ static __always_inline void boot_init_stack_canary(void) | |||
32 | canary += tsc + (tsc << 32UL); | 32 | canary += tsc + (tsc << 32UL); |
33 | 33 | ||
34 | current->stack_canary = canary; | 34 | current->stack_canary = canary; |
35 | write_pda(stack_canary, canary); | 35 | percpu_write(irq_stack_union.stack_canary, canary); |
36 | } | 36 | } |
37 | 37 | ||
38 | #endif | 38 | #endif |
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index b77bd8bd3cc2..52eb748a68af 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h | |||
@@ -89,10 +89,10 @@ do { \ | |||
89 | #ifdef CONFIG_CC_STACKPROTECTOR | 89 | #ifdef CONFIG_CC_STACKPROTECTOR |
90 | #define __switch_canary \ | 90 | #define __switch_canary \ |
91 | "movq %P[task_canary](%%rsi),%%r8\n\t" \ | 91 | "movq %P[task_canary](%%rsi),%%r8\n\t" \ |
92 | "movq %%r8,%%gs:%P[pda_canary]\n\t" | 92 | "movq %%r8,%%gs:%P[gs_canary]\n\t" |
93 | #define __switch_canary_param \ | 93 | #define __switch_canary_param \ |
94 | , [task_canary] "i" (offsetof(struct task_struct, stack_canary)) \ | 94 | , [task_canary] "i" (offsetof(struct task_struct, stack_canary)) \ |
95 | , [pda_canary] "i" (offsetof(struct x8664_pda, stack_canary)) | 95 | , [gs_canary] "i" (offsetof(union irq_stack_union, stack_canary)) |
96 | #else /* CC_STACKPROTECTOR */ | 96 | #else /* CC_STACKPROTECTOR */ |
97 | #define __switch_canary | 97 | #define __switch_canary |
98 | #define __switch_canary_param | 98 | #define __switch_canary_param |
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index 64c834a39aa8..94f9c8b39d20 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c | |||
@@ -48,10 +48,6 @@ int main(void) | |||
48 | #endif | 48 | #endif |
49 | BLANK(); | 49 | BLANK(); |
50 | #undef ENTRY | 50 | #undef ENTRY |
51 | #define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry)) | ||
52 | DEFINE(pda_size, sizeof(struct x8664_pda)); | ||
53 | BLANK(); | ||
54 | #undef ENTRY | ||
55 | #ifdef CONFIG_PARAVIRT | 51 | #ifdef CONFIG_PARAVIRT |
56 | BLANK(); | 52 | BLANK(); |
57 | OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled); | 53 | OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled); |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f83a4d6160f0..098934e72a16 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -881,12 +881,13 @@ __setup("clearcpuid=", setup_disablecpuid); | |||
881 | #ifdef CONFIG_X86_64 | 881 | #ifdef CONFIG_X86_64 |
882 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; | 882 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; |
883 | 883 | ||
884 | DEFINE_PER_CPU_PAGE_ALIGNED(char[IRQ_STACK_SIZE], irq_stack); | 884 | DEFINE_PER_CPU_FIRST(union irq_stack_union, |
885 | irq_stack_union) __aligned(PAGE_SIZE); | ||
885 | #ifdef CONFIG_SMP | 886 | #ifdef CONFIG_SMP |
886 | DEFINE_PER_CPU(char *, irq_stack_ptr); /* will be set during per cpu init */ | 887 | DEFINE_PER_CPU(char *, irq_stack_ptr); /* will be set during per cpu init */ |
887 | #else | 888 | #else |
888 | DEFINE_PER_CPU(char *, irq_stack_ptr) = | 889 | DEFINE_PER_CPU(char *, irq_stack_ptr) = |
889 | per_cpu_var(irq_stack) + IRQ_STACK_SIZE - 64; | 890 | per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64; |
890 | #endif | 891 | #endif |
891 | 892 | ||
892 | DEFINE_PER_CPU(unsigned long, kernel_stack) = | 893 | DEFINE_PER_CPU(unsigned long, kernel_stack) = |
@@ -960,7 +961,7 @@ void __cpuinit cpu_init(void) | |||
960 | 961 | ||
961 | loadsegment(fs, 0); | 962 | loadsegment(fs, 0); |
962 | loadsegment(gs, 0); | 963 | loadsegment(gs, 0); |
963 | load_pda_offset(cpu); | 964 | load_gs_base(cpu); |
964 | 965 | ||
965 | #ifdef CONFIG_NUMA | 966 | #ifdef CONFIG_NUMA |
966 | if (cpu != 0 && percpu_read(node_number) == 0 && | 967 | if (cpu != 0 && percpu_read(node_number) == 0 && |
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 98ea26a2fca1..a0a2b5ca9b7d 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
@@ -242,13 +242,10 @@ ENTRY(secondary_startup_64) | |||
242 | 242 | ||
243 | /* Set up %gs. | 243 | /* Set up %gs. |
244 | * | 244 | * |
245 | * On SMP, %gs should point to the per-cpu area. For initial | 245 | * The base of %gs always points to the bottom of the irqstack |
246 | * boot, make %gs point to the init data section. For a | 246 | * union. If the stack protector canary is enabled, it is |
247 | * secondary CPU,initial_gs should be set to its pda address | 247 | * located at %gs:40. Note that, on SMP, the boot cpu uses |
248 | * before the CPU runs this code. | 248 | * init data section till per cpu areas are set up. |
249 | * | ||
250 | * On UP, initial_gs points to PER_CPU_VAR(__pda) and doesn't | ||
251 | * change. | ||
252 | */ | 249 | */ |
253 | movl $MSR_GS_BASE,%ecx | 250 | movl $MSR_GS_BASE,%ecx |
254 | movq initial_gs(%rip),%rax | 251 | movq initial_gs(%rip),%rax |
@@ -281,7 +278,7 @@ ENTRY(secondary_startup_64) | |||
281 | #ifdef CONFIG_SMP | 278 | #ifdef CONFIG_SMP |
282 | .quad __per_cpu_load | 279 | .quad __per_cpu_load |
283 | #else | 280 | #else |
284 | .quad PER_CPU_VAR(__pda) | 281 | .quad PER_CPU_VAR(irq_stack_union) |
285 | #endif | 282 | #endif |
286 | __FINITDATA | 283 | __FINITDATA |
287 | 284 | ||
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index efbafbbff584..90b8e154bb53 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -77,30 +77,6 @@ static void __init setup_node_to_cpumask_map(void); | |||
77 | static inline void setup_node_to_cpumask_map(void) { } | 77 | static inline void setup_node_to_cpumask_map(void) { } |
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | /* | ||
81 | * Define load_pda_offset() and per-cpu __pda for x86_64. | ||
82 | * load_pda_offset() is responsible for loading the offset of pda into | ||
83 | * %gs. | ||
84 | * | ||
85 | * On SMP, pda offset also duals as percpu base address and thus it | ||
86 | * should be at the start of per-cpu area. To achieve this, it's | ||
87 | * preallocated in vmlinux_64.lds.S directly instead of using | ||
88 | * DEFINE_PER_CPU(). | ||
89 | */ | ||
90 | #ifdef CONFIG_X86_64 | ||
91 | void __cpuinit load_pda_offset(int cpu) | ||
92 | { | ||
93 | /* Memory clobbers used to order pda/percpu accesses */ | ||
94 | mb(); | ||
95 | wrmsrl(MSR_GS_BASE, cpu_pda(cpu)); | ||
96 | mb(); | ||
97 | } | ||
98 | #ifndef CONFIG_SMP | ||
99 | DEFINE_PER_CPU(struct x8664_pda, __pda); | ||
100 | #endif | ||
101 | EXPORT_PER_CPU_SYMBOL(__pda); | ||
102 | #endif /* CONFIG_SMP && CONFIG_X86_64 */ | ||
103 | |||
104 | #ifdef CONFIG_X86_64 | 80 | #ifdef CONFIG_X86_64 |
105 | 81 | ||
106 | /* correctly size the local cpu masks */ | 82 | /* correctly size the local cpu masks */ |
@@ -207,15 +183,13 @@ void __init setup_per_cpu_areas(void) | |||
207 | per_cpu(cpu_number, cpu) = cpu; | 183 | per_cpu(cpu_number, cpu) = cpu; |
208 | #ifdef CONFIG_X86_64 | 184 | #ifdef CONFIG_X86_64 |
209 | per_cpu(irq_stack_ptr, cpu) = | 185 | per_cpu(irq_stack_ptr, cpu) = |
210 | (char *)per_cpu(irq_stack, cpu) + IRQ_STACK_SIZE - 64; | 186 | per_cpu(irq_stack_union.irq_stack, cpu) + IRQ_STACK_SIZE - 64; |
211 | /* | 187 | /* |
212 | * CPU0 modified pda in the init data area, reload pda | 188 | * Up to this point, CPU0 has been using .data.init |
213 | * offset for CPU0 and clear the area for others. | 189 | * area. Reload %gs offset for CPU0. |
214 | */ | 190 | */ |
215 | if (cpu == 0) | 191 | if (cpu == 0) |
216 | load_pda_offset(0); | 192 | load_gs_base(cpu); |
217 | else | ||
218 | memset(cpu_pda(cpu), 0, sizeof(*cpu_pda(cpu))); | ||
219 | #endif | 193 | #endif |
220 | 194 | ||
221 | DBG("PERCPU: cpu %4d %p\n", cpu, ptr); | 195 | DBG("PERCPU: cpu %4d %p\n", cpu, ptr); |
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index a09abb8fb97f..c9740996430a 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S | |||
@@ -220,8 +220,7 @@ SECTIONS | |||
220 | * so that it can be accessed as a percpu variable. | 220 | * so that it can be accessed as a percpu variable. |
221 | */ | 221 | */ |
222 | . = ALIGN(PAGE_SIZE); | 222 | . = ALIGN(PAGE_SIZE); |
223 | PERCPU_VADDR_PREALLOC(0, :percpu, pda_size) | 223 | PERCPU_VADDR(0, :percpu) |
224 | per_cpu____pda = __per_cpu_start; | ||
225 | #else | 224 | #else |
226 | PERCPU(PAGE_SIZE) | 225 | PERCPU(PAGE_SIZE) |
227 | #endif | 226 | #endif |
@@ -262,3 +261,8 @@ SECTIONS | |||
262 | */ | 261 | */ |
263 | ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), | 262 | ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), |
264 | "kernel image bigger than KERNEL_IMAGE_SIZE") | 263 | "kernel image bigger than KERNEL_IMAGE_SIZE") |
264 | |||
265 | #ifdef CONFIG_SMP | ||
266 | ASSERT((per_cpu__irq_stack_union == 0), | ||
267 | "irq_stack_union is not at start of per-cpu area"); | ||
268 | #endif | ||