Skip to content

Commit 5da7936

Browse files
ardbiesheuvelIngo Molnar
authored andcommitted
x86/boot/64: Simplify global variable accesses in GDT/IDT programming
There are two code paths in the startup code to program an IDT: one that runs from the 1:1 mapping and one that runs from the virtual kernel mapping. Currently, these are strictly separate because fixup_pointer() is used on the 1:1 path, which will produce the wrong value when used while executing from the virtual kernel mapping. Switch to RIP_REL_REF() so that the two code paths can be merged. Also, move the GDT and IDT descriptors to the stack so that they can be referenced directly, rather than via RIP_REL_REF(). Rename startup_64_setup_env() to startup_64_setup_gdt_idt() while at it, to make the call from assembler self-documenting. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lore.kernel.org/r/20240221113506.2565718-19-ardb+git@google.com
1 parent 2e5fc47 commit 5da7936

File tree

3 files changed

+32
-49
lines changed

3 files changed

+32
-49
lines changed

arch/x86/include/asm/setup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ extern unsigned long saved_video_mode;
4848
extern void reserve_standard_io_resources(void);
4949
extern void i386_reserve_resources(void);
5050
extern unsigned long __startup_64(unsigned long physaddr, struct boot_params *bp);
51-
extern void startup_64_setup_env(unsigned long physbase);
51+
extern void startup_64_setup_gdt_idt(void);
5252
extern void early_setup_idt(void);
5353
extern void __init do_early_exception(struct pt_regs *regs, int trapnr);
5454

arch/x86/kernel/head64.c

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/cc_platform.h>
2323
#include <linux/pgtable.h>
2424

25+
#include <asm/asm.h>
2526
#include <asm/processor.h>
2627
#include <asm/proto.h>
2728
#include <asm/smp.h>
@@ -76,15 +77,6 @@ static struct desc_struct startup_gdt[GDT_ENTRIES] __initdata = {
7677
[GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(DESC_DATA64, 0, 0xfffff),
7778
};
7879

79-
/*
80-
* Address needs to be set at runtime because it references the startup_gdt
81-
* while the kernel still uses a direct mapping.
82-
*/
83-
static struct desc_ptr startup_gdt_descr __initdata = {
84-
.size = sizeof(startup_gdt)-1,
85-
.address = 0,
86-
};
87-
8880
static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
8981
{
9082
return ptr - (void *)_text + (void *)physaddr;
@@ -569,68 +561,61 @@ void __init __noreturn x86_64_start_reservations(char *real_mode_data)
569561
*/
570562
static gate_desc bringup_idt_table[NUM_EXCEPTION_VECTORS] __page_aligned_data;
571563

572-
static struct desc_ptr bringup_idt_descr = {
573-
.size = (NUM_EXCEPTION_VECTORS * sizeof(gate_desc)) - 1,
574-
.address = 0, /* Set at runtime */
575-
};
576-
577-
static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
564+
/* This may run while still in the direct mapping */
565+
static void __head startup_64_load_idt(void *vc_handler)
578566
{
579-
#ifdef CONFIG_AMD_MEM_ENCRYPT
567+
struct desc_ptr desc = {
568+
.address = (unsigned long)&RIP_REL_REF(bringup_idt_table),
569+
.size = sizeof(bringup_idt_table) - 1,
570+
};
580571
struct idt_data data;
581-
gate_desc desc;
582-
583-
init_idt_data(&data, n, handler);
584-
idt_init_desc(&desc, &data);
585-
native_write_idt_entry(idt, n, &desc);
586-
#endif
587-
}
572+
gate_desc idt_desc;
588573

589-
/* This runs while still in the direct mapping */
590-
static void __head startup_64_load_idt(unsigned long physbase)
591-
{
592-
struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
593-
gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
594-
595-
596-
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
597-
void *handler;
598-
599-
/* VMM Communication Exception */
600-
handler = fixup_pointer(vc_no_ghcb, physbase);
601-
set_bringup_idt_handler(idt, X86_TRAP_VC, handler);
574+
/* @vc_handler is set only for a VMM Communication Exception */
575+
if (vc_handler) {
576+
init_idt_data(&data, X86_TRAP_VC, vc_handler);
577+
idt_init_desc(&idt_desc, &data);
578+
native_write_idt_entry((gate_desc *)desc.address, X86_TRAP_VC, &idt_desc);
602579
}
603580

604-
desc->address = (unsigned long)idt;
605-
native_load_idt(desc);
581+
native_load_idt(&desc);
606582
}
607583

608584
/* This is used when running on kernel addresses */
609585
void early_setup_idt(void)
610586
{
611-
/* VMM Communication Exception */
587+
void *handler = NULL;
588+
612589
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
613590
setup_ghcb();
614-
set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb);
591+
handler = vc_boot_ghcb;
615592
}
616593

617-
bringup_idt_descr.address = (unsigned long)bringup_idt_table;
618-
native_load_idt(&bringup_idt_descr);
594+
startup_64_load_idt(handler);
619595
}
620596

621597
/*
622598
* Setup boot CPU state needed before kernel switches to virtual addresses.
623599
*/
624-
void __head startup_64_setup_env(unsigned long physbase)
600+
void __head startup_64_setup_gdt_idt(void)
625601
{
602+
void *handler = NULL;
603+
604+
struct desc_ptr startup_gdt_descr = {
605+
.address = (unsigned long)&RIP_REL_REF(startup_gdt),
606+
.size = sizeof(startup_gdt) - 1,
607+
};
608+
626609
/* Load GDT */
627-
startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
628610
native_load_gdt(&startup_gdt_descr);
629611

630612
/* New GDT is live - reload data segment registers */
631613
asm volatile("movl %%eax, %%ds\n"
632614
"movl %%eax, %%ss\n"
633615
"movl %%eax, %%es\n" : : "a"(__KERNEL_DS) : "memory");
634616

635-
startup_64_load_idt(physbase);
617+
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))
618+
handler = &RIP_REL_REF(vc_no_ghcb);
619+
620+
startup_64_load_idt(handler);
636621
}

arch/x86/kernel/head_64.S

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,14 @@ SYM_CODE_START_NOALIGN(startup_64)
6868
/* Set up the stack for verify_cpu() */
6969
leaq (__end_init_task - PTREGS_SIZE)(%rip), %rsp
7070

71-
leaq _text(%rip), %rdi
72-
7371
/* Setup GSBASE to allow stack canary access for C code */
7472
movl $MSR_GS_BASE, %ecx
7573
leaq INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
7674
movl %edx, %eax
7775
shrq $32, %rdx
7876
wrmsr
7977

80-
call startup_64_setup_env
78+
call startup_64_setup_gdt_idt
8179

8280
/* Now switch to __KERNEL_CS so IRET works reliably */
8381
pushq $__KERNEL_CS

0 commit comments

Comments
 (0)