Skip to content

Commit 1dcc917

Browse files
committed
x86/idt: Rework IDT setup for boot CPU
A basic IDT setup for the boot CPU has to be done before invoking cpu_init() because that might trigger #GP when accessing certain MSRs. This setup cannot install the IST variants on 64-bit because the TSS setup which is required for ISTs to work happens in cpu_init(). That leaves a theoretical window where a NMI would invoke the ASM entry point which relies on IST being enabled on the kernel stack which is undefined behaviour. This setup logic has never worked correctly, but on the other hand a NMI hitting the boot CPU before it has fully set up the IDT would be fatal anyway. So the small window between the wrong NMI gate and the IST based NMI gate is not really adding a substantial amount of risk. But the setup logic is nevertheless more convoluted than necessary. The recent separation of the TSS setup into a separate function to ensure that setup so it can setup TSS first, then initialize IDT with the IST variants before invoking cpu_init() and get rid of the post cpu_init() IST setup. Move the invocation of cpu_init_exception_handling() ahead of idt_setup_traps() and merge the IST setup into the default setup table. Reported-by: Lai Jiangshan <laijs@linux.alibaba.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Lai Jiangshan <laijs@linux.alibaba.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20210507114000.569244755@linutronix.de
1 parent b1efd0f commit 1dcc917

3 files changed

Lines changed: 15 additions & 34 deletions

File tree

arch/x86/include/asm/desc.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,8 @@ extern bool idt_is_f00f_address(unsigned long address);
421421

422422
#ifdef CONFIG_X86_64
423423
extern void idt_setup_early_pf(void);
424-
extern void idt_setup_ist_traps(void);
425424
#else
426425
static inline void idt_setup_early_pf(void) { }
427-
static inline void idt_setup_ist_traps(void) { }
428426
#endif
429427

430428
extern void idt_invalidate(void *addr);

arch/x86/kernel/idt.c

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@
3535
#define SYSG(_vector, _addr) \
3636
G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL3, __KERNEL_CS)
3737

38+
#ifdef CONFIG_X86_64
3839
/*
3940
* Interrupt gate with interrupt stack. The _ist index is the index in
4041
* the tss.ist[] array, but for the descriptor it needs to start at 1.
4142
*/
4243
#define ISTG(_vector, _addr, _ist) \
4344
G(_vector, _addr, _ist + 1, GATE_INTERRUPT, DPL0, __KERNEL_CS)
45+
#else
46+
#define ISTG(_vector, _addr, _ist) INTG(_vector, _addr)
47+
#endif
4448

4549
/* Task gate */
4650
#define TSKG(_vector, _gdt) \
@@ -74,7 +78,7 @@ static const __initconst struct idt_data early_idts[] = {
7478
*/
7579
static const __initconst struct idt_data def_idts[] = {
7680
INTG(X86_TRAP_DE, asm_exc_divide_error),
77-
INTG(X86_TRAP_NMI, asm_exc_nmi),
81+
ISTG(X86_TRAP_NMI, asm_exc_nmi, IST_INDEX_NMI),
7882
INTG(X86_TRAP_BR, asm_exc_bounds),
7983
INTG(X86_TRAP_UD, asm_exc_invalid_op),
8084
INTG(X86_TRAP_NM, asm_exc_device_not_available),
@@ -91,12 +95,16 @@ static const __initconst struct idt_data def_idts[] = {
9195
#ifdef CONFIG_X86_32
9296
TSKG(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS),
9397
#else
94-
INTG(X86_TRAP_DF, asm_exc_double_fault),
98+
ISTG(X86_TRAP_DF, asm_exc_double_fault, IST_INDEX_DF),
9599
#endif
96-
INTG(X86_TRAP_DB, asm_exc_debug),
100+
ISTG(X86_TRAP_DB, asm_exc_debug, IST_INDEX_DB),
97101

98102
#ifdef CONFIG_X86_MCE
99-
INTG(X86_TRAP_MC, asm_exc_machine_check),
103+
ISTG(X86_TRAP_MC, asm_exc_machine_check, IST_INDEX_MCE),
104+
#endif
105+
106+
#ifdef CONFIG_AMD_MEM_ENCRYPT
107+
ISTG(X86_TRAP_VC, asm_exc_vmm_communication, IST_INDEX_VC),
100108
#endif
101109

102110
SYSG(X86_TRAP_OF, asm_exc_overflow),
@@ -221,22 +229,6 @@ static const __initconst struct idt_data early_pf_idts[] = {
221229
INTG(X86_TRAP_PF, asm_exc_page_fault),
222230
};
223231

224-
/*
225-
* The exceptions which use Interrupt stacks. They are setup after
226-
* cpu_init() when the TSS has been initialized.
227-
*/
228-
static const __initconst struct idt_data ist_idts[] = {
229-
ISTG(X86_TRAP_DB, asm_exc_debug, IST_INDEX_DB),
230-
ISTG(X86_TRAP_NMI, asm_exc_nmi, IST_INDEX_NMI),
231-
ISTG(X86_TRAP_DF, asm_exc_double_fault, IST_INDEX_DF),
232-
#ifdef CONFIG_X86_MCE
233-
ISTG(X86_TRAP_MC, asm_exc_machine_check, IST_INDEX_MCE),
234-
#endif
235-
#ifdef CONFIG_AMD_MEM_ENCRYPT
236-
ISTG(X86_TRAP_VC, asm_exc_vmm_communication, IST_INDEX_VC),
237-
#endif
238-
};
239-
240232
/**
241233
* idt_setup_early_pf - Initialize the idt table with early pagefault handler
242234
*
@@ -254,14 +246,6 @@ void __init idt_setup_early_pf(void)
254246
idt_setup_from_table(idt_table, early_pf_idts,
255247
ARRAY_SIZE(early_pf_idts), true);
256248
}
257-
258-
/**
259-
* idt_setup_ist_traps - Initialize the idt table with traps using IST
260-
*/
261-
void __init idt_setup_ist_traps(void)
262-
{
263-
idt_setup_from_table(idt_table, ist_idts, ARRAY_SIZE(ist_idts), true);
264-
}
265249
#endif
266250

267251
static void __init idt_map_in_cea(void)

arch/x86/kernel/traps.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,10 +1160,9 @@ void __init trap_init(void)
11601160
/* Init GHCB memory pages when running as an SEV-ES guest */
11611161
sev_es_init_vc_handling();
11621162

1163-
idt_setup_traps();
1164-
1163+
/* Initialize TSS before setting up traps so ISTs work */
11651164
cpu_init_exception_handling();
1165+
/* Setup traps as cpu_init() might #GP */
1166+
idt_setup_traps();
11661167
cpu_init();
1167-
1168-
idt_setup_ist_traps();
11691168
}

0 commit comments

Comments
 (0)