From: Zixuan Wang <zixuanwang@xxxxxxxxxx> Global Descriptor Table (GDT) defines x86 memory areas, e.g. memory area for data or code. UEFI has a different GDT compared to KVM-Unit-Tests, e.g., in UEFI, 3rd GDT entry defines a code segment, while in KVM-Unit-Tests, 3rd GDT entry is data segment. Without loading KVM-Unit-Tests GDT, the UEFI GDT is used and is incompatible with KVM-Unit-Tests. This causes QEMU to silently crash when a test case changes segments. This commit fixes this issue by loading KVM-Unit-Tests GDT to replace UEFI GDT. And since Task State Segment (TSS) is tightly coupled with GDT, this commit also loads TSS on boot-up. In this commit, x86/debug.c can run in UEFI and pass all sub-tests. Co-developed-by: Varad Gautam <varad.gautam@xxxxxxxx> Signed-off-by: Varad Gautam <varad.gautam@xxxxxxxx> Signed-off-by: Zixuan Wang <zixuanwang@xxxxxxxxxx> --- lib/x86/setup.c | 10 ++++++++++ x86/efi/efistart64.S | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/lib/x86/setup.c b/lib/x86/setup.c index 8606fe8..f4f9e1b 100644 --- a/lib/x86/setup.c +++ b/lib/x86/setup.c @@ -165,10 +165,20 @@ void setup_multiboot(struct mbi_bootinfo *bi) /* From x86/efi/efistart64.S */ extern void load_idt(void); +extern void load_gdt_tss(size_t tss_offset); + +static void setup_gdt_tss(void) +{ + size_t tss_offset; + + tss_offset = setup_tss(); + load_gdt_tss(tss_offset); +} void setup_efi(void) { reset_apic(); + setup_gdt_tss(); setup_idt(); load_idt(); mask_pic_interrupts(); diff --git a/x86/efi/efistart64.S b/x86/efi/efistart64.S index 41e9185..57299a5 100644 --- a/x86/efi/efistart64.S +++ b/x86/efi/efistart64.S @@ -1,7 +1,22 @@ /* Startup code and pre-defined data structures */ +#include "apic-defs.h" +#include "asm-generic/page.h" #include "crt0-efi-x86_64.S" +.globl ring0stacktop +.globl ring0stacksize + +max_cpus = MAX_TEST_CPUS +ring0stacksize = PAGE_SIZE + +.bss + +.globl ring0stacktop + . = . + ring0stacksize * max_cpus + .align 16 +ring0stacktop: + .section .init .code64 .text @@ -10,3 +25,30 @@ load_idt: lidtq idt_descr(%rip) retq + +.globl load_gdt_tss +load_gdt_tss: + /* Load GDT */ + lgdt gdt64_desc(%rip) + + /* Load TSS */ + mov %rdi, %rax + ltr %ax + + /* Update data segments */ + mov $0x10, %ax /* 3rd entry in gdt64: 32/64-bit data segment */ + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* + * Update the code segment by putting it on the stack before the return + * address, then doing a far return: this will use the new code segment + * along with the address. + */ + popq %rdi + pushq $0x08 /* 2nd entry in gdt64: 64-bit code segment */ + pushq %rdi + lretq -- 2.33.0