]> xenbits.xensource.com Git - xen.git/commitdiff
x86/emul: Fix the emulation of invlpga
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 6 Mar 2018 15:17:48 +0000 (16:17 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 6 Mar 2018 15:17:48 +0000 (16:17 +0100)
The instruction requires EFER.SVME set to be usable in the first place.

Furthermore, the emulation doesn't handle ASIDs, so avoid giving the
impression that they work.  Permit ASID 0 which is reserved for non-root
mode (in which case the instruction is identical to invlpg), but raise #UD for
any other ASID.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: a91b2ec337a45d5d98e5a4387aa6563bc5cdc4c9
master date: 2018-02-05 18:17:22 +0000

xen/arch/x86/x86_emulate/x86_emulate.c

index 51d4dddfeb60087d259bce8627279e5e542578e2..256604c17ca7ca877043658585e5e900fcf07d93 100644 (file)
@@ -362,6 +362,7 @@ typedef union {
 #define MSR_EFER         0xc0000080
 #define EFER_SCE         (1u<<0)
 #define EFER_LMA         (1u<<10)
+#define EFER_SVME        (1u<<12)
 #define MSR_STAR         0xc0000081
 #define MSR_LSTAR        0xc0000082
 #define MSR_CSTAR        0xc0000083
@@ -3989,14 +3990,24 @@ x86_emulate(
 
         switch( modrm )
         {
-        case 0xdf: /* invlpga */
-            generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1);
+        case 0xdf: /* invlpga */ {
+            uint64_t msr_val;
+
+            fail_if(!ops->read_msr);
+            if ( (rc = ops->read_msr(MSR_EFER,
+                                     &msr_val, ctxt)) != X86EMUL_OKAY )
+                goto done;
+            /* Finding SVME set implies vcpu_has_svm(). */
+            generate_exception_if(!(msr_val & EFER_SVME) ||
+                                  !in_protmode(ctxt, ops), EXC_UD, -1);
             generate_exception_if(!mode_ring0(), EXC_GP, 0);
+            generate_exception_if((uint32_t)_regs.ecx, EXC_UD, -1); /* TODO: Support ASIDs. */
             fail_if(ops->invlpg == NULL);
             if ( (rc = ops->invlpg(x86_seg_none, truncate_ea(_regs.eax),
                                    ctxt)) )
                 goto done;
             goto no_writeback;
+        }
         case 0xf9: /* rdtscp */ {
             uint64_t tsc_aux;
             fail_if(ops->read_msr == NULL);