diff options
author | Andy Lutomirski <luto@kernel.org> | 2017-12-04 09:07:26 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-12-17 08:27:51 -0500 |
commit | 40e7f949e0d9a33968ebde5d67f7e3a47c97742a (patch) | |
tree | 1e6b3fa11c7a8bd23a3e9d955181a8cb1c20f7dd | |
parent | 3386bc8aed825e9f1f65ce38df4b109b2019b71a (diff) |
x86/entry/64: Move the IST stacks into struct cpu_entry_area
The IST stacks are needed when an IST exception occurs and are accessed
before any kernel code at all runs. Move them into struct cpu_entry_area.
The IST stacks are unlike the rest of cpu_entry_area: they're used even for
entries from kernel mode. This means that they should be set up before we
load the final IDT. Move cpu_entry_area setup to trap_init() for the boot
CPU and set it up for all possible CPUs at once in native_smp_prepare_cpus().
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Borislav Petkov <bpetkov@suse.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Laight <David.Laight@aculab.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Eduardo Valentin <eduval@amazon.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: aliguori@amazon.com
Cc: daniel.gruss@iaik.tugraz.at
Cc: hughd@google.com
Cc: keescook@google.com
Link: https://lkml.kernel.org/r/20171204150606.480598743@linutronix.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/fixmap.h | 12 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 74 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 3 |
3 files changed, 57 insertions, 32 deletions
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 6a699474c2c7..451da7d9a502 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h | |||
@@ -63,10 +63,22 @@ struct cpu_entry_area { | |||
63 | struct tss_struct tss; | 63 | struct tss_struct tss; |
64 | 64 | ||
65 | char entry_trampoline[PAGE_SIZE]; | 65 | char entry_trampoline[PAGE_SIZE]; |
66 | |||
67 | #ifdef CONFIG_X86_64 | ||
68 | /* | ||
69 | * Exception stacks used for IST entries. | ||
70 | * | ||
71 | * In the future, this should have a separate slot for each stack | ||
72 | * with guard pages between them. | ||
73 | */ | ||
74 | char exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]; | ||
75 | #endif | ||
66 | }; | 76 | }; |
67 | 77 | ||
68 | #define CPU_ENTRY_AREA_PAGES (sizeof(struct cpu_entry_area) / PAGE_SIZE) | 78 | #define CPU_ENTRY_AREA_PAGES (sizeof(struct cpu_entry_area) / PAGE_SIZE) |
69 | 79 | ||
80 | extern void setup_cpu_entry_areas(void); | ||
81 | |||
70 | /* | 82 | /* |
71 | * Here we define all the compile-time 'special' virtual | 83 | * Here we define all the compile-time 'special' virtual |
72 | * addresses. The point is to have a constant address at | 84 | * addresses. The point is to have a constant address at |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 430f950b0b7f..fb01a8e5e9b7 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -466,24 +466,36 @@ void load_percpu_segment(int cpu) | |||
466 | load_stack_canary_segment(); | 466 | load_stack_canary_segment(); |
467 | } | 467 | } |
468 | 468 | ||
469 | static void set_percpu_fixmap_pages(int fixmap_index, void *ptr, | ||
470 | int pages, pgprot_t prot) | ||
471 | { | ||
472 | int i; | ||
473 | |||
474 | for (i = 0; i < pages; i++) { | ||
475 | __set_fixmap(fixmap_index - i, | ||
476 | per_cpu_ptr_to_phys(ptr + i * PAGE_SIZE), prot); | ||
477 | } | ||
478 | } | ||
479 | |||
480 | #ifdef CONFIG_X86_32 | 469 | #ifdef CONFIG_X86_32 |
481 | /* The 32-bit entry code needs to find cpu_entry_area. */ | 470 | /* The 32-bit entry code needs to find cpu_entry_area. */ |
482 | DEFINE_PER_CPU(struct cpu_entry_area *, cpu_entry_area); | 471 | DEFINE_PER_CPU(struct cpu_entry_area *, cpu_entry_area); |
483 | #endif | 472 | #endif |
484 | 473 | ||
474 | #ifdef CONFIG_X86_64 | ||
475 | /* | ||
476 | * Special IST stacks which the CPU switches to when it calls | ||
477 | * an IST-marked descriptor entry. Up to 7 stacks (hardware | ||
478 | * limit), all of them are 4K, except the debug stack which | ||
479 | * is 8K. | ||
480 | */ | ||
481 | static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = { | ||
482 | [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ, | ||
483 | [DEBUG_STACK - 1] = DEBUG_STKSZ | ||
484 | }; | ||
485 | |||
486 | static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks | ||
487 | [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); | ||
488 | #endif | ||
489 | |||
490 | static void __init | ||
491 | set_percpu_fixmap_pages(int idx, void *ptr, int pages, pgprot_t prot) | ||
492 | { | ||
493 | for ( ; pages; pages--, idx--, ptr += PAGE_SIZE) | ||
494 | __set_fixmap(idx, per_cpu_ptr_to_phys(ptr), prot); | ||
495 | } | ||
496 | |||
485 | /* Setup the fixmap mappings only once per-processor */ | 497 | /* Setup the fixmap mappings only once per-processor */ |
486 | static inline void setup_cpu_entry_area(int cpu) | 498 | static void __init setup_cpu_entry_area(int cpu) |
487 | { | 499 | { |
488 | #ifdef CONFIG_X86_64 | 500 | #ifdef CONFIG_X86_64 |
489 | extern char _entry_trampoline[]; | 501 | extern char _entry_trampoline[]; |
@@ -532,15 +544,31 @@ static inline void setup_cpu_entry_area(int cpu) | |||
532 | PAGE_KERNEL); | 544 | PAGE_KERNEL); |
533 | 545 | ||
534 | #ifdef CONFIG_X86_32 | 546 | #ifdef CONFIG_X86_32 |
535 | this_cpu_write(cpu_entry_area, get_cpu_entry_area(cpu)); | 547 | per_cpu(cpu_entry_area, cpu) = get_cpu_entry_area(cpu); |
536 | #endif | 548 | #endif |
537 | 549 | ||
538 | #ifdef CONFIG_X86_64 | 550 | #ifdef CONFIG_X86_64 |
551 | BUILD_BUG_ON(sizeof(exception_stacks) % PAGE_SIZE != 0); | ||
552 | BUILD_BUG_ON(sizeof(exception_stacks) != | ||
553 | sizeof(((struct cpu_entry_area *)0)->exception_stacks)); | ||
554 | set_percpu_fixmap_pages(get_cpu_entry_area_index(cpu, exception_stacks), | ||
555 | &per_cpu(exception_stacks, cpu), | ||
556 | sizeof(exception_stacks) / PAGE_SIZE, | ||
557 | PAGE_KERNEL); | ||
558 | |||
539 | __set_fixmap(get_cpu_entry_area_index(cpu, entry_trampoline), | 559 | __set_fixmap(get_cpu_entry_area_index(cpu, entry_trampoline), |
540 | __pa_symbol(_entry_trampoline), PAGE_KERNEL_RX); | 560 | __pa_symbol(_entry_trampoline), PAGE_KERNEL_RX); |
541 | #endif | 561 | #endif |
542 | } | 562 | } |
543 | 563 | ||
564 | void __init setup_cpu_entry_areas(void) | ||
565 | { | ||
566 | unsigned int cpu; | ||
567 | |||
568 | for_each_possible_cpu(cpu) | ||
569 | setup_cpu_entry_area(cpu); | ||
570 | } | ||
571 | |||
544 | /* Load the original GDT from the per-cpu structure */ | 572 | /* Load the original GDT from the per-cpu structure */ |
545 | void load_direct_gdt(int cpu) | 573 | void load_direct_gdt(int cpu) |
546 | { | 574 | { |
@@ -1385,20 +1413,6 @@ DEFINE_PER_CPU(unsigned int, irq_count) __visible = -1; | |||
1385 | DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT; | 1413 | DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT; |
1386 | EXPORT_PER_CPU_SYMBOL(__preempt_count); | 1414 | EXPORT_PER_CPU_SYMBOL(__preempt_count); |
1387 | 1415 | ||
1388 | /* | ||
1389 | * Special IST stacks which the CPU switches to when it calls | ||
1390 | * an IST-marked descriptor entry. Up to 7 stacks (hardware | ||
1391 | * limit), all of them are 4K, except the debug stack which | ||
1392 | * is 8K. | ||
1393 | */ | ||
1394 | static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = { | ||
1395 | [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ, | ||
1396 | [DEBUG_STACK - 1] = DEBUG_STKSZ | ||
1397 | }; | ||
1398 | |||
1399 | static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks | ||
1400 | [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); | ||
1401 | |||
1402 | /* May not be marked __init: used by software suspend */ | 1416 | /* May not be marked __init: used by software suspend */ |
1403 | void syscall_init(void) | 1417 | void syscall_init(void) |
1404 | { | 1418 | { |
@@ -1607,7 +1621,7 @@ void cpu_init(void) | |||
1607 | * set up and load the per-CPU TSS | 1621 | * set up and load the per-CPU TSS |
1608 | */ | 1622 | */ |
1609 | if (!oist->ist[0]) { | 1623 | if (!oist->ist[0]) { |
1610 | char *estacks = per_cpu(exception_stacks, cpu); | 1624 | char *estacks = get_cpu_entry_area(cpu)->exception_stacks; |
1611 | 1625 | ||
1612 | for (v = 0; v < N_EXCEPTION_STACKS; v++) { | 1626 | for (v = 0; v < N_EXCEPTION_STACKS; v++) { |
1613 | estacks += exception_stack_sizes[v]; | 1627 | estacks += exception_stack_sizes[v]; |
@@ -1633,8 +1647,6 @@ void cpu_init(void) | |||
1633 | initialize_tlbstate_and_flush(); | 1647 | initialize_tlbstate_and_flush(); |
1634 | enter_lazy_tlb(&init_mm, me); | 1648 | enter_lazy_tlb(&init_mm, me); |
1635 | 1649 | ||
1636 | setup_cpu_entry_area(cpu); | ||
1637 | |||
1638 | /* | 1650 | /* |
1639 | * Initialize the TSS. sp0 points to the entry trampoline stack | 1651 | * Initialize the TSS. sp0 points to the entry trampoline stack |
1640 | * regardless of what task is running. | 1652 | * regardless of what task is running. |
@@ -1694,8 +1706,6 @@ void cpu_init(void) | |||
1694 | initialize_tlbstate_and_flush(); | 1706 | initialize_tlbstate_and_flush(); |
1695 | enter_lazy_tlb(&init_mm, curr); | 1707 | enter_lazy_tlb(&init_mm, curr); |
1696 | 1708 | ||
1697 | setup_cpu_entry_area(cpu); | ||
1698 | |||
1699 | /* | 1709 | /* |
1700 | * Initialize the TSS. Don't bother initializing sp0, as the initial | 1710 | * Initialize the TSS. Don't bother initializing sp0, as the initial |
1701 | * task never enters user mode. | 1711 | * task never enters user mode. |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index ee9ca0ad4388..3e29aad5c7cc 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -947,6 +947,9 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | |||
947 | 947 | ||
948 | void __init trap_init(void) | 948 | void __init trap_init(void) |
949 | { | 949 | { |
950 | /* Init cpu_entry_area before IST entries are set up */ | ||
951 | setup_cpu_entry_areas(); | ||
952 | |||
950 | idt_setup_traps(); | 953 | idt_setup_traps(); |
951 | 954 | ||
952 | /* | 955 | /* |