diff mbox series

[kvm-unit-tests,v2,06/10] x86: efi: Stop using UEFI-provided %gs for percpu storage

Message ID 20220412173407.13637-7-varad.gautam@suse.com (mailing list archive)
State New, archived
Headers show
Series SMP Support for x86 UEFI Tests | expand

Commit Message

Varad Gautam April 12, 2022, 5:34 p.m. UTC
UEFI tests do not update MSR_GS_BASE during bringup, and continue
using the GS_BASE set up by the UEFI implementation for percpu
storage.

Update this MSR during setup_segments64() to allow storing percpu
data at a sane location reserved by the testcase, and ensure that
this happens before any operation that ends up storing to the percpu
space.

Signed-off-by: Varad Gautam <varad.gautam@suse.com>
---
 lib/x86/setup.c      | 9 ++++++---
 x86/efi/efistart64.S | 7 +++++++
 2 files changed, 13 insertions(+), 3 deletions(-)

Comments

Sean Christopherson April 13, 2022, 4:23 p.m. UTC | #1
On Tue, Apr 12, 2022, Varad Gautam wrote:
> UEFI tests do not update MSR_GS_BASE during bringup, and continue
> using the GS_BASE set up by the UEFI implementation for percpu
> storage.
> 
> Update this MSR during setup_segments64() to allow storing percpu
> data at a sane location reserved by the testcase, and ensure that
> this happens before any operation that ends up storing to the percpu
> space

It's worth noting in the changelog that reset_apic() needs to be moved below
setup_gdt_tss() as it depends on per-cpu setup.  That definitely won't be obvious
to most people.

> Signed-off-by: Varad Gautam <varad.gautam@suse.com>
> ---
>  lib/x86/setup.c      | 9 ++++++---
>  x86/efi/efistart64.S | 7 +++++++
>  2 files changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/x86/setup.c b/lib/x86/setup.c
> index 7dd6677..5d32d3f 100644
> --- a/lib/x86/setup.c
> +++ b/lib/x86/setup.c
> @@ -170,7 +170,8 @@ void setup_multiboot(struct mbi_bootinfo *bi)
>  #ifdef CONFIG_EFI
>  
>  /* From x86/efi/efistart64.S */
> -extern void setup_segments64(void);
> +extern void setup_segments64(u64 gs_base);
> +extern u8 stacktop;
>  
>  static efi_status_t setup_memory_allocator(efi_bootinfo_t *efi_bootinfo)
>  {
> @@ -271,12 +272,14 @@ static void setup_page_table(void)
>  static void setup_gdt_tss(void)
>  {
>  	size_t tss_offset;
> +	u64 gs_base;
>  
>  	/* 64-bit setup_tss does not use the stacktop argument.  */
>  	tss_offset = setup_tss(NULL);
>  	load_gdt_tss(tss_offset);
>  
> -	setup_segments64();
> +	gs_base = (u64)(&stacktop) - (PAGE_SIZE * (pre_boot_apic_id() + 1));

Rather than follow the (IMO awful) non-EFI behavior of hijacking a chunk of the
stack, which is a symptom of doing everything in asm, since this is now C we
can declare a proper percpu array and index that.  Disclaimer, this has only been
tested with smp=1 at this point, haven't reached the end of the series :-)

diff --git a/lib/x86/setup.c b/lib/x86/setup.c
index 6131ea2..91a06f7 100644
--- a/lib/x86/setup.c
+++ b/lib/x86/setup.c
@@ -169,6 +169,8 @@ void setup_multiboot(struct mbi_bootinfo *bi)

 #ifdef CONFIG_EFI

+static struct percpu_data __percpu_data[MAX_TEST_CPUS];
+
 static efi_status_t setup_memory_allocator(efi_bootinfo_t *efi_bootinfo)
 {
        int i;
@@ -285,6 +287,8 @@ static void setup_gdt_tss(void)
                     "1:"
                     :: "r" ((u64)KERNEL_DS), "i" (KERNEL_CS)
        );
+
+       wrmsr(MSR_GS_BASE, (u64)&__percpu_data[pre_boot_apic_id()]);
 }

 efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
@@ -326,8 +330,8 @@ efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
                return status;
        }

-       reset_apic();
        setup_gdt_tss();
+       reset_apic();
        setup_idt();
        load_idt();
        mask_pic_interrupts();
diff mbox series

Patch

diff --git a/lib/x86/setup.c b/lib/x86/setup.c
index 7dd6677..5d32d3f 100644
--- a/lib/x86/setup.c
+++ b/lib/x86/setup.c
@@ -170,7 +170,8 @@  void setup_multiboot(struct mbi_bootinfo *bi)
 #ifdef CONFIG_EFI
 
 /* From x86/efi/efistart64.S */
-extern void setup_segments64(void);
+extern void setup_segments64(u64 gs_base);
+extern u8 stacktop;
 
 static efi_status_t setup_memory_allocator(efi_bootinfo_t *efi_bootinfo)
 {
@@ -271,12 +272,14 @@  static void setup_page_table(void)
 static void setup_gdt_tss(void)
 {
 	size_t tss_offset;
+	u64 gs_base;
 
 	/* 64-bit setup_tss does not use the stacktop argument.  */
 	tss_offset = setup_tss(NULL);
 	load_gdt_tss(tss_offset);
 
-	setup_segments64();
+	gs_base = (u64)(&stacktop) - (PAGE_SIZE * (pre_boot_apic_id() + 1));
+	setup_segments64(gs_base);
 }
 
 efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
@@ -318,8 +321,8 @@  efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
 		return status;
 	}
 
-	reset_apic();
 	setup_gdt_tss();
+	reset_apic();
 	setup_idt();
 	load_idt();
 	mask_pic_interrupts();
diff --git a/x86/efi/efistart64.S b/x86/efi/efistart64.S
index cb08230..1c38355 100644
--- a/x86/efi/efistart64.S
+++ b/x86/efi/efistart64.S
@@ -44,6 +44,13 @@  setup_segments64:
 	mov %ax, %gs
 	mov %ax, %ss
 
+	/* Setup percpu base */
+	MSR_GS_BASE = 0xc0000101
+	mov %rdi, %rax
+	mov $0, %edx
+	mov $MSR_GS_BASE, %ecx
+	wrmsr
+
 	/*
 	 * 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