Message ID | 57F3CD250200007800114EAC@prv-mh.provo.novell.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 04/10/16 14:39, Jan Beulich wrote: > @@ -770,9 +773,23 @@ static int _get_fpu( > unsigned long cr0; > > fail_if(!ops->read_cr); > + if ( type >= X86EMUL_FPU_xmm ) > + { > + unsigned long cr4; > + > + rc = ops->read_cr(4, &cr4, ctxt); > + if ( rc != X86EMUL_OKAY ) > + return rc; > + generate_exception_if(!(cr4 & ((type == X86EMUL_FPU_xmm) > + ? CR4_OSFXSR : CR4_OSXSAVE)), > + EXC_UD, -1); > + } > + > rc = ops->read_cr(0, &cr0, ctxt); > if ( rc != X86EMUL_OKAY ) > return rc; > + if ( !(cr0 & CR0_PE) || (ctxt->regs->eflags & EFLG_VM) ) > + generate_exception_if(type >= X86EMUL_FPU_ymm, EXC_UD, -1); Is this an appropriate check to do here? This restriction is because the VEX prefix isn't permitted in real/vm86 mode. Instead of a generate_exception_if(), I would instead have an ASSERT() that we don't actually reach this point. ~Andrew
>>> On 04.10.16 at 15:58, <andrew.cooper3@citrix.com> wrote: > On 04/10/16 14:39, Jan Beulich wrote: >> @@ -770,9 +773,23 @@ static int _get_fpu( >> unsigned long cr0; >> >> fail_if(!ops->read_cr); >> + if ( type >= X86EMUL_FPU_xmm ) >> + { >> + unsigned long cr4; >> + >> + rc = ops->read_cr(4, &cr4, ctxt); >> + if ( rc != X86EMUL_OKAY ) >> + return rc; >> + generate_exception_if(!(cr4 & ((type == X86EMUL_FPU_xmm) >> + ? CR4_OSFXSR : CR4_OSXSAVE)), >> + EXC_UD, -1); >> + } >> + >> rc = ops->read_cr(0, &cr0, ctxt); >> if ( rc != X86EMUL_OKAY ) >> return rc; >> + if ( !(cr0 & CR0_PE) || (ctxt->regs->eflags & EFLG_VM) ) >> + generate_exception_if(type >= X86EMUL_FPU_ymm, EXC_UD, -1); > > Is this an appropriate check to do here? This restriction is because > the VEX prefix isn't permitted in real/vm86 mode. > > Instead of a generate_exception_if(), I would instead have an ASSERT() > that we don't actually reach this point. Hmm, that's right. Jan
--- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -129,6 +129,13 @@ static int cpuid( (edx & (1U << 26)) != 0; \ }) +#define cpu_has_xsave ({ \ + unsigned int eax = 1, ecx = 0; \ + cpuid(&eax, &eax, &ecx, &eax, NULL); \ + /* Intentionally checking OSXSAVE here. */ \ + (ecx & (1U << 27)) != 0; \ +}) + static inline uint64_t xgetbv(uint32_t xcr) { uint32_t lo, hi; @@ -169,6 +176,11 @@ static int read_cr( case 0: *val = 0x00000001; /* PE */ return X86EMUL_OKAY; + + case 4: + /* OSFXSR, OSXMMEXCPT, and maybe OSXSAVE */ + *val = 0x00000600 | (cpu_has_xsave ? 0x00040000 : 0); + return X86EMUL_OKAY; } return X86EMUL_UNHANDLEABLE; --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1631,20 +1631,11 @@ static int hvmemul_get_fpu( { case X86EMUL_FPU_fpu: case X86EMUL_FPU_wait: - break; case X86EMUL_FPU_mmx: - if ( !cpu_has_mmx ) - return X86EMUL_UNHANDLEABLE; - break; case X86EMUL_FPU_xmm: - if ( !(curr->arch.hvm_vcpu.guest_cr[4] & X86_CR4_OSFXSR) ) - return X86EMUL_UNHANDLEABLE; break; case X86EMUL_FPU_ymm: - if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) || - (ctxt->regs->eflags & X86_EFLAGS_VM) || - !(curr->arch.hvm_vcpu.guest_cr[4] & X86_CR4_OSXSAVE) || - !(curr->arch.xcr0 & XSTATE_SSE) || + if ( !(curr->arch.xcr0 & XSTATE_SSE) || !(curr->arch.xcr0 & XSTATE_YMM) ) return X86EMUL_UNHANDLEABLE; break; --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -424,8 +424,11 @@ typedef union { #define CR0_MP (1<<1) #define CR0_EM (1<<2) #define CR0_TS (1<<3) -#define CR4_TSD (1<<2) -#define CR4_UMIP (1<<11) + +#define CR4_TSD (1<<2) +#define CR4_OSFXSR (1<<9) +#define CR4_UMIP (1<<11) +#define CR4_OSXSAVE (1<<18) /* EFLAGS bit definitions. */ #define EFLG_VIP (1<<20) @@ -770,9 +773,23 @@ static int _get_fpu( unsigned long cr0; fail_if(!ops->read_cr); + if ( type >= X86EMUL_FPU_xmm ) + { + unsigned long cr4; + + rc = ops->read_cr(4, &cr4, ctxt); + if ( rc != X86EMUL_OKAY ) + return rc; + generate_exception_if(!(cr4 & ((type == X86EMUL_FPU_xmm) + ? CR4_OSFXSR : CR4_OSXSAVE)), + EXC_UD, -1); + } + rc = ops->read_cr(0, &cr0, ctxt); if ( rc != X86EMUL_OKAY ) return rc; + if ( !(cr0 & CR0_PE) || (ctxt->regs->eflags & EFLG_VM) ) + generate_exception_if(type >= X86EMUL_FPU_ymm, EXC_UD, -1); if ( cr0 & CR0_EM ) { generate_exception_if(type == X86EMUL_FPU_fpu, EXC_NM, -1);