x86: Use faster accessors for MSR_KERNEL_GS_BASE
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 8 Nov 2016 22:17:25 +0000 (17:17 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 7 Dec 2016 22:46:48 +0000 (14:46 -0800)
Accessing kern_gsbase is usually a read_msr or write_msr.  write_msr is
especially expensive.  However, on hardware that has access to the
instructions that access FS/GS base directly, we can use swap_gs and
gs_base accessors to work with kern_gs_base.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/fsgsbase.h
kern/arch/x86/trap.c

index 42fd433..7684e49 100644 (file)
@@ -46,3 +46,35 @@ static inline void write_gsbase(uintptr_t base)
        }
        asm volatile ("wrgsbase %0" : : "r"(base));
 }
+
+/* If we have fast FS/GS access, we can use swapgs to quickly access
+ * kern_gsbase. */
+static inline uintptr_t read_kern_gsbase(void)
+{
+       uintptr_t base;
+       int8_t irq_state = 0;
+
+       if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE))
+               return read_msr(MSR_KERNEL_GS_BASE);
+       disable_irqsave(&irq_state);
+       swap_gs();
+       base = read_gsbase();
+       swap_gs();
+       enable_irqsave(&irq_state);
+       return base;
+}
+
+static inline void write_kern_gsbase(uintptr_t base)
+{
+       int8_t irq_state = 0;
+
+       if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) {
+               write_msr(MSR_KERNEL_GS_BASE, base);
+               return;
+       }
+       disable_irqsave(&irq_state);
+       swap_gs();
+       write_gsbase(base);
+       swap_gs();
+       enable_irqsave(&irq_state);
+}
index 2780b4f..75ab49d 100644 (file)
@@ -1128,16 +1128,16 @@ void handle_vmexit(struct vm_trapframe *tf)
  * loaded with the current GS (the kernel's). */
 static void x86_finalize_hwtf(struct hw_trapframe *tf)
 {
-       tf->tf_gsbase = read_msr(MSR_KERNEL_GS_BASE);
-       write_msr(MSR_KERNEL_GS_BASE, read_gsbase());
+       tf->tf_gsbase = read_kern_gsbase();
+       write_kern_gsbase(read_gsbase());
        tf->tf_fsbase = read_fsbase();
        x86_hwtf_clear_partial(tf);
 }
 
 static void x86_finalize_swtf(struct sw_trapframe *tf)
 {
-       tf->tf_gsbase = read_msr(MSR_KERNEL_GS_BASE);
-       write_msr(MSR_KERNEL_GS_BASE, read_gsbase());
+       tf->tf_gsbase = read_kern_gsbase();
+       write_kern_gsbase(read_gsbase());
        tf->tf_fsbase = read_fsbase();
        x86_swtf_clear_partial(tf);
 }