[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH 1/6] plat: check for and enable extended CPU features



Signed-off-by: Florian Schmidt <florian.schmidt@xxxxxxxxx>
---
 plat/common/include/x86/cpu_defs.h | 22 +++++++++++
 plat/kvm/x86/entry64.S             | 54 +++++++++++++++++++++----
 plat/kvm/x86/setup.c               | 15 -------
 plat/xen/x86/entry64.S             | 63 +++++++++++++++++++++++++++---
 plat/xen/x86/setup.c               | 15 -------
 5 files changed, 126 insertions(+), 43 deletions(-)

diff --git a/plat/common/include/x86/cpu_defs.h 
b/plat/common/include/x86/cpu_defs.h
index 9ecec96..78821b5 100644
--- a/plat/common/include/x86/cpu_defs.h
+++ b/plat/common/include/x86/cpu_defs.h
@@ -58,6 +58,7 @@
  */
 #define X86_CR0_MP              (1 << 1)    /* Monitor Coprocessor */
 #define X86_CR0_EM              (1 << 2)    /* Emulation */
+#define X86_CR0_TS              (1 << 2)    /* Task Switched */
 #define X86_CR0_NE              (1 << 5)    /* Numeric Exception */
 #define X86_CR0_PG              (1 << 31)   /* Paging */
 
@@ -67,10 +68,31 @@
 #define X86_CR4_PAE             (1 << 5)    /* enable PAE */
 #define X86_CR4_OSFXSR          (1 << 9)    /* OS support for FXSAVE/FXRSTOR */
 #define X86_CR4_OSXMMEXCPT      (1 << 10)   /* OS support for FP exceptions */
+#define X86_CR4_FSGSBASE        (1 << 16)   /* enable FSGSBASE*/
+#define X86_CR4_OSXSAVE         (1 << 18)   /* enable XSAVE, extended states */
 
 /*
  * Intel CPU features in EFER
  */
 #define X86_EFER_LME            (1 << 8)    /* Long mode enable (R/W) */
 
+/* CPUID feature bits in ECX and EDX when EAX=1 */
+#define X86_CPUID1_ECX_XSAVE    (1 << 26)
+#define X86_CPUID1_ECX_OSXSAVE  (1 << 27)
+#define X86_CPUID1_ECX_AVX      (1 << 28)
+#define X86_CPUID1_EDX_FPU      (1 << 0)
+#define X86_CPUID1_EDX_FXSR     (1 << 24)
+#define X86_CPUID1_EDX_SSE      (1 << 25)
+/* CPUID feature bits in EBX and ECX when EAX=7 */
+#define X86_CPUID7_EBX_FSGSBASE (1 << 0)
+/* CPUID feature bits when EAX=0xd, EXC=1 */
+#define X86_CPUIDD1_EAX_XSAVEOPT (1<<0)
+
+/*
+ * Extended Control Register 0 (XCR0)
+ */
+#define X86_XCR0_X87            (1 << 0)
+#define X86_XCR0_XMM            (1 << 1)
+#define X86_XCR0_YMM            (1 << 2)
+
 #endif /* __PLAT_CMN_X86_CPU_DEFS_H__ */
diff --git a/plat/kvm/x86/entry64.S b/plat/kvm/x86/entry64.S
index dc3614a..e4c2b89 100644
--- a/plat/kvm/x86/entry64.S
+++ b/plat/kvm/x86/entry64.S
@@ -172,15 +172,53 @@ ENTRY(_libkvmplat_start64)
        movq $bootstack, %rsp
        xorq %rbp, %rbp
 
-       /* enable FPU and SSE units */
-       movq %cr0, %rax
-       andq $(~X86_CR0_EM), %rax
-       orq $(X86_CR0_MP | X86_CR0_NE), %rax
-       movq %rax, %cr0
-       movq %cr4, %rax
-       orq $(X86_CR4_OSXMMEXCPT | X86_CR4_OSFXSR), %rax
-       movq %rax, %cr4
+       /* We will work on cr0 and cr4 multiple times.
+        * We put cr0 into r8 and cr4 into r9, because cpuid and xgetbv/xsetbv
+        * work on eax/ebx/ecx/edx. */
+       movq %cr0, %r8
+       movq %cr4, %r9
+       /* FPU and SSE are part of base x86-64, so no need to check for their
+        * availability before enabling and initializing. */
+       andq $(~(X86_CR0_EM | X86_CR0_TS)), %r8
+       orq $(X86_CR0_MP | X86_CR0_NE), %r8
+       movq %r8, %cr0
+       fninit
+       orq $(X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT), %r9
+       movq %r9, %cr4
        ldmxcsr (mxcsr_ptr)
+       /* Check capabilities subject to availability as indicated by cpuid.
+        * First, start off with "standard features" */
+       movl $0x1, %eax
+       cpuid
+       /* ecx and edx now contain capability information, so we can now
+        * enable capabilities based on the indicated features */
+       /* OSXSAVE needs to be enabled before AVX */
+       testl $(X86_CPUID1_ECX_XSAVE), %ecx
+       jz noxsave
+       orq $(X86_CR4_OSXSAVE), %r9
+       movq %r9, %cr4
+       /* now enable AVX. This needs to be last checking cpuid features from
+        * the eax=1 cpuid call, because it clobbers ecx */
+       testl $(X86_CPUID1_ECX_AVX), %ecx
+       jz noavx
+       xorl %ecx, %ecx
+       xgetbv
+       orl $(X86_XCR0_XMM | X86_XCR0_YMM), %eax
+       xsetbv
+noavx:
+noxsave:
+       /* Now, check for extended features. */
+       movl $0x7, %eax
+       movl $0x1, %ecx
+       cpuid
+       /* ebx, ecx, edx now contain extended capabilties information. */
+       /* check for and enable FS/GSBASE */
+       testl $(X86_CPUID7_EBX_FSGSBASE), %ebx
+       jz nofsgsbase
+       orq $(X86_CR4_FSGSBASE), %r9
+       movq %r9, %cr4
+nofsgsbase:
+       /* done setting up CPU capabilities */
 
        /* read multiboot info pointer */
        movq -8(%rsp), %rdi
diff --git a/plat/kvm/x86/setup.c b/plat/kvm/x86/setup.c
index e02886d..47a78dc 100644
--- a/plat/kvm/x86/setup.c
+++ b/plat/kvm/x86/setup.c
@@ -109,20 +109,6 @@ static inline void _mb_init_mem(struct multiboot_info *mi)
        _libkvmplat_stack_top  = (void *) (max_addr - __STACK_SIZE);
 }
 
-static inline void _init_cpufeatures(void)
-{
-#if __SSE__
-       unsigned long sse_status = 0x1f80;
-#endif
-
-       /* FPU */
-       asm volatile("fninit");
-
-#if __SSE__
-       asm volatile("ldmxcsr %0" : : "m"(sse_status));
-#endif
-}
-
 static void _libkvmplat_entry2(void *arg __attribute__((unused)))
 {
        ukplat_entry_argp(NULL, cmdline, sizeof(cmdline));
@@ -133,7 +119,6 @@ void _libkvmplat_entry(void *arg)
        struct multiboot_info *mi = (struct multiboot_info *)arg;
 
        _libkvmplat_init_console();
-       _init_cpufeatures();
        traps_init();
        intctrl_init();
 
diff --git a/plat/xen/x86/entry64.S b/plat/xen/x86/entry64.S
index c266804..02cfbd4 100644
--- a/plat/xen/x86/entry64.S
+++ b/plat/xen/x86/entry64.S
@@ -25,6 +25,7 @@
 
 #include <uk/arch/types.h>
 #include <uk/arch/limits.h>
+#include <x86/cpu_defs.h>
 #include <x86/traps.h>
 #include <uk/config.h>
 #include <xen/xen.h>
@@ -60,11 +61,63 @@ _libxenplat_start:
 #include "entry_hvm.S"
 
 #endif
-        cld
-        movq stack_start(%rip),%rsp
-        andq $(~(__STACK_SIZE-1)), %rsp
-        movq %rsi,%rdi
-        call _libxenplat_x86entry
+       cld
+       movq stack_start(%rip),%rsp
+       andq $(~(__STACK_SIZE-1)), %rsp
+       movq %rsi,%rdi
+       /* We will work on cr0 and cr4 multiple times.
+        * We put cr0 into r8 and cr4 into r9, because cpuid and xgetbv/xsetbv
+        * work on eax/ebx/ecx/edx. */
+       movq %cr0, %r8
+       movq %cr4, %r9
+       /* FPU and SSE are part of base x86-64, so no need to check for their
+        * availability before enabling and initializing. */
+       andq $(~(X86_CR0_EM | X86_CR0_TS)), %r8
+       orq $(X86_CR0_MP | X86_CR0_NE), %r8
+       movq %r8, %cr0
+       fninit
+       orq $(X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT), %r9
+       movq %r9, %cr4
+       ldmxcsr (mxcsr_ptr)
+       /* Check capabilities subject to availability as indicated by cpuid.
+        * First, start off with "standard features" */
+       movl $0x1, %eax
+       cpuid
+       /* ecx and edx now contain capability information, so we can now
+        * enable capabilities based on the indicated features */
+       /* OSXSAVE needs to be enabled before AVX */
+       testl $(X86_CPUID1_ECX_XSAVE), %ecx
+       jz noxsave
+       orq $(X86_CR4_OSXSAVE), %r9
+       movq %r9, %cr4
+       /* now enable AVX. This needs to be last checking cpuid features from
+        * the eax=1 cpuid call, because it clobbers ecx */
+       testl $(X86_CPUID1_ECX_AVX), %ecx
+       jz noavx
+       xorl %ecx, %ecx
+       xgetbv
+       orl $(X86_XCR0_XMM | X86_XCR0_YMM), %eax
+       xsetbv
+noavx:
+noxsave:
+       /* Now, check for extended features. */
+       movl $0x7, %eax
+       movl $0x1, %ecx
+       cpuid
+       /* ebx, ecx, edx now contain extended capabilties information. */
+       /* check for and enable FS/GSBASE */
+       testl $(X86_CPUID7_EBX_FSGSBASE), %ebx
+       jz nofsgsbase
+       orq $(X86_CR4_FSGSBASE), %r9
+       movq %r9, %cr4
+nofsgsbase:
+       /* Done setting up CPU capabilities, hand over to C entry point. */
+       call _libxenplat_x86entry
+
+.type mxcsr_ptr, @object
+mxcsr_ptr:
+       .long 0x1f80                    /* Intel SDM power-on default */
+
 
 stack_start:
         .quad _libxenplat_bootstack + (2*__STACK_SIZE)
diff --git a/plat/xen/x86/setup.c b/plat/xen/x86/setup.c
index 35fdd35..a41d5cb 100644
--- a/plat/xen/x86/setup.c
+++ b/plat/xen/x86/setup.c
@@ -113,20 +113,6 @@ static inline void _init_traps(void)
        traps_init();
 }
 
-static inline void _init_cpufeatures(void)
-{
-#if __SSE__
-       unsigned long sse_status = 0x1f80;
-#endif
-
-       /* FPU */
-       asm volatile("fninit");
-
-#if __SSE__
-       asm volatile("ldmxcsr %0" : : "m"(sse_status));
-#endif
-}
-
 static inline void _init_shared_info(void)
 {
        int ret;
@@ -184,7 +170,6 @@ void _libxenplat_x86entry(void *start_info) __noreturn;
 void _libxenplat_x86entry(void *start_info)
 {
        _init_traps();
-       _init_cpufeatures();
        HYPERVISOR_start_info = (start_info_t *)start_info;
        _libxenplat_prepare_console(); /* enables buffering for console */
 
-- 
2.19.1


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.