From: Jan Beulich Date: Wed, 18 Jun 2014 13:53:27 +0000 (+0200) Subject: x86/EFI: allow FPU/XMM use in runtime service functions X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~4837 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=e0fe297dabc96d8161d568f19a99722c4739b9f9;p=xen.git x86/EFI: allow FPU/XMM use in runtime service functions UEFI spec update 2.4B developed a requirement to enter runtime service functions with CR0.TS (and CR0.EM) clear, thus making feasible the already previously stated permission for these functions to use some of the XMM registers. Enforce this requirement (along with the connected ones on FPU control word and MXCSR) by going through a full FPU save cycle (if the FPU was dirty) in efi_rs_enter() (along with loading the specified values into the other two registers). Note that the UEFI spec mandates that extension registers other than XMM ones (for our purposes all that get restored eagerly) are preserved across runtime function calls, hence there's nothing we need to restore in efi_rs_leave() (they do get saved, but just for simplicity's sake). Signed-off-by: Jan Beulich --- diff --git a/xen/arch/x86/efi/runtime.c b/xen/arch/x86/efi/runtime.c index d7c884b1ca..166852decc 100644 --- a/xen/arch/x86/efi/runtime.c +++ b/xen/arch/x86/efi/runtime.c @@ -10,6 +10,8 @@ DEFINE_XEN_GUEST_HANDLE(CHAR16); #ifndef COMPAT +# include +# include # include const bool_t efi_enabled = 1; @@ -45,8 +47,14 @@ const struct efi_pci_rom *__read_mostly efi_pci_roms; unsigned long efi_rs_enter(void) { + static const u16 fcw = FCW_DEFAULT; + static const u32 mxcsr = MXCSR_DEFAULT; unsigned long cr3 = read_cr3(); + save_fpu_enable(); + asm volatile ( "fldcw %0" :: "m" (fcw) ); + asm volatile ( "ldmxcsr %0" :: "m" (mxcsr) ); + spin_lock(&efi_rs_lock); /* prevent fixup_page_fault() from doing anything */ @@ -82,6 +90,7 @@ void efi_rs_leave(unsigned long cr3) } irq_exit(); spin_unlock(&efi_rs_lock); + stts(); } unsigned long efi_get_time(void) diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c index bd72138878..a372e0b503 100644 --- a/xen/arch/x86/i387.c +++ b/xen/arch/x86/i387.c @@ -266,10 +266,10 @@ void vcpu_restore_fpu_lazy(struct vcpu *v) * On each context switch, save the necessary FPU info of VCPU being switch * out. It dispatches saving operation based on CPU's capability. */ -void vcpu_save_fpu(struct vcpu *v) +static bool_t _vcpu_save_fpu(struct vcpu *v) { if ( !v->fpu_dirtied && !v->arch.nonlazy_xstate_used ) - return; + return 0; ASSERT(!is_idle_vcpu(v)); @@ -284,9 +284,22 @@ void vcpu_save_fpu(struct vcpu *v) fpu_fsave(v); v->fpu_dirtied = 0; + + return 1; +} + +void vcpu_save_fpu(struct vcpu *v) +{ + _vcpu_save_fpu(v); stts(); } +void save_fpu_enable(void) +{ + if ( !_vcpu_save_fpu(current) ) + clts(); +} + /* Initialize FPU's context save area */ int vcpu_init_fpu(struct vcpu *v) { diff --git a/xen/include/asm-x86/i387.h b/xen/include/asm-x86/i387.h index 38dbcae1a9..150a09e41f 100644 --- a/xen/include/asm-x86/i387.h +++ b/xen/include/asm-x86/i387.h @@ -38,6 +38,7 @@ struct ix87_state { void vcpu_restore_fpu_eager(struct vcpu *v); void vcpu_restore_fpu_lazy(struct vcpu *v); void vcpu_save_fpu(struct vcpu *v); +void save_fpu_enable(void); int vcpu_init_fpu(struct vcpu *v); void vcpu_destroy_fpu(struct vcpu *v);