Commit 520d0308 authored by Joerg Roedel's avatar Joerg Roedel Committed by Borislav Petkov
Browse files

x86/smpboot: Load TSS and getcpu GDT entry before loading IDT



The IDT on 64-bit contains vectors which use paranoid_entry() and/or IST
stacks. To make these vectors work, the TSS and the getcpu GDT entry need
to be set up before the IDT is loaded.

Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20200907131613.12703-68-joro@8bytes.org
parent 8940ac9c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -696,6 +696,7 @@ extern void load_direct_gdt(int);
extern void load_fixmap_gdt(int);
extern void load_percpu_segment(int);
extern void cpu_init(void);
extern void cpu_init_exception_handling(void);
extern void cr4_init(void);

static inline unsigned long get_debugctlmsr(void)
+23 −0
Original line number Diff line number Diff line
@@ -1862,6 +1862,29 @@ static inline void tss_setup_io_bitmap(struct tss_struct *tss)
#endif
}

/*
 * Setup everything needed to handle exceptions from the IDT, including the IST
 * exceptions which use paranoid_entry().
 */
void cpu_init_exception_handling(void)
{
	struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
	int cpu = raw_smp_processor_id();

	/* paranoid_entry() gets the CPU number from the GDT */
	setup_getcpu(cpu);

	/* IST vectors need TSS to be set up. */
	tss_setup_ist(tss);
	tss_setup_io_bitmap(tss);
	set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);

	load_TR_desc();

	/* Finally load the IDT */
	load_current_idt();
}

/*
 * cpu_init() initializes state that is per-CPU. Some data is already
 * initialized (naturally) in the bootstrap process, such as the GDT
+1 −1
Original line number Diff line number Diff line
@@ -227,7 +227,7 @@ static void notrace start_secondary(void *unused)
	load_cr3(swapper_pg_dir);
	__flush_tlb_all();
#endif
	load_current_idt();
	cpu_init_exception_handling();
	cpu_init();
	x86_cpuinit.early_percpu_clock_init();
	preempt_disable();