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

[Xen-changelog] [xen master] x86emul: support VME and PVI



commit c437fa17290934ddf347f65d09b83d7fc0eaef84
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Fri Jan 13 15:25:52 2017 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Fri Jan 13 15:25:52 2017 +0100

    x86emul: support VME and PVI
    
    ... affecting PUSHF, POPF, CLI, and STI.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
 xen/arch/x86/x86_emulate/x86_emulate.c | 85 +++++++++++++++++++++++++++++-----
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c 
b/xen/arch/x86/x86_emulate/x86_emulate.c
index 490eec9..195aa04 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -433,6 +433,8 @@ typedef union {
 #define CR0_EM    (1<<2)
 #define CR0_TS    (1<<3)
 
+#define CR4_VME        (1<<0)
+#define CR4_PVI        (1<<1)
 #define CR4_TSD        (1<<2)
 #define CR4_OSFXSR     (1<<9)
 #define CR4_OSXMMEXCPT (1<<10)
@@ -1180,6 +1182,15 @@ _mode_iopl(
     fail_if(_iopl < 0);                         \
     _iopl;                                      \
 })
+#define mode_vif() ({                                        \
+    unsigned long cr4 = 0;                                   \
+    if ( ops->read_cr && get_cpl(ctxt, ops) == 3 )           \
+    {                                                        \
+        rc = ops->read_cr(4, &cr4, ctxt);                    \
+        if ( rc != X86EMUL_OKAY ) goto done;                 \
+    }                                                        \
+    !!(cr4 & (_regs._eflags & EFLG_VM ? CR4_VME : CR4_PVI)); \
+})
 
 static int ioport_access_check(
     unsigned int first_port,
@@ -3268,20 +3279,44 @@ x86_emulate(
         break;
 
     case 0x9c: /* pushf */
-        generate_exception_if((_regs._eflags & EFLG_VM) &&
-                              MASK_EXTR(_regs._eflags, EFLG_IOPL) != 3,
-                              EXC_GP, 0);
-        src.val = _regs.r(flags) & ~(EFLG_VM | EFLG_RF);
+        if ( (_regs._eflags & EFLG_VM) &&
+             MASK_EXTR(_regs._eflags, EFLG_IOPL) != 3 )
+        {
+            unsigned long cr4 = 0;
+
+            if ( op_bytes == 2 && ops->read_cr )
+            {
+                rc = ops->read_cr(4, &cr4, ctxt);
+                if ( rc != X86EMUL_OKAY )
+                    goto done;
+            }
+            generate_exception_if(!(cr4 & CR4_VME), EXC_GP, 0);
+            src.val = (_regs.flags & ~EFLG_IF) | EFLG_IOPL;
+            if ( _regs._eflags & EFLG_VIF )
+                src.val |= EFLG_IF;
+        }
+        else
+            src.val = _regs.r(flags) & ~(EFLG_VM | EFLG_RF);
         goto push;
 
     case 0x9d: /* popf */ {
         uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
+        unsigned long cr4 = 0;
 
         if ( !mode_ring0() )
         {
-            generate_exception_if((_regs._eflags & EFLG_VM) &&
-                                  MASK_EXTR(_regs._eflags, EFLG_IOPL) != 3,
-                                  EXC_GP, 0);
+            if ( _regs._eflags & EFLG_VM )
+            {
+                if ( op_bytes == 2 && ops->read_cr )
+                {
+                    rc = ops->read_cr(4, &cr4, ctxt);
+                    if ( rc != X86EMUL_OKAY )
+                        goto done;
+                }
+                generate_exception_if(!(cr4 & CR4_VME) &&
+                                      MASK_EXTR(_regs._eflags, EFLG_IOPL) != 3,
+                                      EXC_GP, 0);
+            }
             mask |= EFLG_IOPL;
             if ( !mode_iopl() )
                 mask |= EFLG_IF;
@@ -3293,7 +3328,20 @@ x86_emulate(
                               &dst.val, op_bytes, ctxt, ops)) != 0 )
             goto done;
         if ( op_bytes == 2 )
+        {
             dst.val = (uint16_t)dst.val | (_regs._eflags & 0xffff0000u);
+            if ( cr4 & CR4_VME )
+            {
+                if ( dst.val & EFLG_IF )
+                {
+                    generate_exception_if(_regs._eflags & EFLG_VIP, EXC_GP, 0);
+                    dst.val |= EFLG_VIF;
+                }
+                else
+                    dst.val &= ~EFLG_VIF;
+                mask &= ~EFLG_VIF;
+            }
+        }
         dst.val &= EFLAGS_MODIFIABLE;
         _regs._eflags &= mask;
         _regs._eflags |= (dst.val & ~mask) | EFLG_MBS;
@@ -4400,16 +4448,29 @@ x86_emulate(
         break;
 
     case 0xfa: /* cli */
-        generate_exception_if(!mode_iopl(), EXC_GP, 0);
-        _regs._eflags &= ~EFLG_IF;
+        if ( mode_iopl() )
+            _regs._eflags &= ~EFLG_IF;
+        else
+        {
+            generate_exception_if(!mode_vif(), EXC_GP, 0);
+            _regs._eflags &= ~EFLG_VIF;
+        }
         break;
 
     case 0xfb: /* sti */
-        generate_exception_if(!mode_iopl(), EXC_GP, 0);
-        if ( !(_regs._eflags & EFLG_IF) )
+        if ( mode_iopl() )
         {
+            if ( !(_regs._eflags & EFLG_IF) )
+                ctxt->retire.sti = true;
             _regs._eflags |= EFLG_IF;
-            ctxt->retire.sti = true;
+        }
+        else
+        {
+            generate_exception_if((_regs._eflags & EFLG_VIP) || !mode_vif(),
+                                  EXC_GP, 0);
+            if ( !(_regs._eflags & EFLG_VIF) )
+                ctxt->retire.sti = true;
+            _regs._eflags |= EFLG_VIF;
         }
         break;
 
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

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