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

[Xen-devel] [PATCH for-4.12 v4 2/3] x86/svm: Drop enum instruction_index and simplify svm_get_insn_len()



Passing a 32-bit integer index into an array with entries containing less than
32 bits of data is wasteful, and creates an unnecessary error condition of
passing an out-of-range index.

The width of the X86EMUL_OPC() encoding is currently 20 bits for the
instructions used, which leaves room for a modrm byte.  Drop opc_tab[]
entirely, and encode the expected opcode/modrm information directly.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Wei Liu <wei.liu2@xxxxxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
CC: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
CC: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
CC: Brian Woods <brian.woods@xxxxxxx>
CC: Juergen Gross <jgross@xxxxxxxx>

The internals of X86EMUL_OPC() mean that we can't actually check for overflows
with BUILD_BUG_ON(), but if the opcode encoding does changes and overflow,
then the resulting fallout will be very obvious in debug builds of Xen.

v3:
 * New
v4:
 * Drop MODRM(), use Octal instead.
---
 xen/arch/x86/hvm/svm/emulate.c        | 51 +++++++--------------------------
 xen/include/asm-x86/hvm/svm/emulate.h | 53 +++++++++++++++++++----------------
 2 files changed, 39 insertions(+), 65 deletions(-)

diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c
index 7799908..fb0d823 100644
--- a/xen/arch/x86/hvm/svm/emulate.c
+++ b/xen/arch/x86/hvm/svm/emulate.c
@@ -54,36 +54,6 @@ static unsigned long svm_nextrip_insn_length(struct vcpu *v)
     return vmcb->nextrip - vmcb->rip;
 }
 
-static const struct {
-    unsigned int opcode;
-    struct {
-        unsigned int rm:3;
-        unsigned int reg:3;
-        unsigned int mod:2;
-#define MODRM(mod, reg, rm) { rm, reg, mod }
-    } modrm;
-} opc_tab[INSTR_MAX_COUNT] = {
-    [INSTR_PAUSE]   = { X86EMUL_OPC_F3(0, 0x90) },
-    [INSTR_INT3]    = { X86EMUL_OPC(   0, 0xcc) },
-    [INSTR_ICEBP]   = { X86EMUL_OPC(   0, 0xf1) },
-    [INSTR_HLT]     = { X86EMUL_OPC(   0, 0xf4) },
-    [INSTR_XSETBV]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 2, 1) },
-    [INSTR_VMRUN]   = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 0) },
-    [INSTR_VMCALL]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 1) },
-    [INSTR_VMLOAD]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 2) },
-    [INSTR_VMSAVE]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 3) },
-    [INSTR_STGI]    = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 4) },
-    [INSTR_CLGI]    = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 5) },
-    [INSTR_INVLPGA] = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 3, 7) },
-    [INSTR_RDTSCP]  = { X86EMUL_OPC(0x0f, 0x01), MODRM(3, 7, 1) },
-    [INSTR_INVD]    = { X86EMUL_OPC(0x0f, 0x08) },
-    [INSTR_WBINVD]  = { X86EMUL_OPC(0x0f, 0x09) },
-    [INSTR_WRMSR]   = { X86EMUL_OPC(0x0f, 0x30) },
-    [INSTR_RDTSC]   = { X86EMUL_OPC(0x0f, 0x31) },
-    [INSTR_RDMSR]   = { X86EMUL_OPC(0x0f, 0x32) },
-    [INSTR_CPUID]   = { X86EMUL_OPC(0x0f, 0xa2) },
-};
-
 /*
  * First-gen SVM didn't have the NextRIP feature, meaning that when we take a
  * fault-style vmexit, we have to decode the instruction stream to calculate
@@ -93,12 +63,13 @@ static const struct {
  * hardware reported instruction length (if available) with the result from
  * x86_decode_insn().
  */
-unsigned int svm_get_insn_len(struct vcpu *v, enum instruction_index insn)
+unsigned int svm_get_insn_len(struct vcpu *v, unsigned int instr_enc)
 {
     struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
     struct hvm_emulate_ctxt ctxt;
     struct x86_emulate_state *state;
     unsigned long nrip_len, emul_len;
+    unsigned int instr_opcode, instr_modrm;
     unsigned int modrm_rm, modrm_reg;
     int modrm_mod;
 
@@ -131,20 +102,18 @@ unsigned int svm_get_insn_len(struct vcpu *v, enum 
instruction_index insn)
     }
 #endif
 
-    if ( insn >= ARRAY_SIZE(opc_tab) )
-    {
-        ASSERT_UNREACHABLE();
-        return 0;
-    }
+    /* Extract components from instr_enc. */
+    instr_modrm  = instr_enc & 0xff;
+    instr_opcode = instr_enc >> 8;
 
-    if ( opc_tab[insn].opcode == ctxt.ctxt.opcode )
+    if ( instr_opcode == ctxt.ctxt.opcode )
     {
-        if ( !opc_tab[insn].modrm.mod )
+        if ( !instr_modrm )
             return emul_len;
 
-        if ( modrm_mod == opc_tab[insn].modrm.mod &&
-             (modrm_rm & 7) == opc_tab[insn].modrm.rm &&
-             (modrm_reg & 7) == opc_tab[insn].modrm.reg )
+        if ( modrm_mod       == MASK_EXTR(instr_modrm, 0300) &&
+             (modrm_reg & 7) == MASK_EXTR(instr_modrm, 0070) &&
+             (modrm_rm  & 7) == MASK_EXTR(instr_modrm, 0007) )
             return emul_len;
     }
 
diff --git a/xen/include/asm-x86/hvm/svm/emulate.h 
b/xen/include/asm-x86/hvm/svm/emulate.h
index 82359ec..9af1006 100644
--- a/xen/include/asm-x86/hvm/svm/emulate.h
+++ b/xen/include/asm-x86/hvm/svm/emulate.h
@@ -19,33 +19,38 @@
 #ifndef __ASM_X86_HVM_SVM_EMULATE_H__
 #define __ASM_X86_HVM_SVM_EMULATE_H__
 
-/* Enumerate some standard instructions that we support */
-enum instruction_index {
-    INSTR_INVD,
-    INSTR_WBINVD,
-    INSTR_CPUID,
-    INSTR_RDMSR,
-    INSTR_WRMSR,
-    INSTR_VMCALL,
-    INSTR_HLT,
-    INSTR_INT3,
-    INSTR_RDTSC,
-    INSTR_RDTSCP,
-    INSTR_PAUSE,
-    INSTR_XSETBV,
-    INSTR_VMRUN,
-    INSTR_VMLOAD,
-    INSTR_VMSAVE,
-    INSTR_STGI,
-    INSTR_CLGI,
-    INSTR_INVLPGA,
-    INSTR_ICEBP,
-    INSTR_MAX_COUNT /* Must be last - Number of instructions supported */
-};
+/*
+ * Encoding for svm_get_insn_len().  We take X86EMUL_OPC() for the main
+ * opcode, shifted left to make room for the ModRM byte.
+ *
+ * The Grp7 instructions have their ModRM byte expressed in octal for easier
+ * cross referencing with the opcode extension table.
+ */
+#define INSTR_ENC(opc, modrm) (((opc) << 8) | (modrm))
+
+#define INSTR_PAUSE       INSTR_ENC(X86EMUL_OPC_F3(0, 0x90), 0)
+#define INSTR_INT3        INSTR_ENC(X86EMUL_OPC(   0, 0xcc), 0)
+#define INSTR_ICEBP       INSTR_ENC(X86EMUL_OPC(   0, 0xf1), 0)
+#define INSTR_HLT         INSTR_ENC(X86EMUL_OPC(   0, 0xf4), 0)
+#define INSTR_XSETBV      INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0321)
+#define INSTR_VMRUN       INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0330)
+#define INSTR_VMCALL      INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0331)
+#define INSTR_VMLOAD      INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0332)
+#define INSTR_VMSAVE      INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0333)
+#define INSTR_STGI        INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0334)
+#define INSTR_CLGI        INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0335)
+#define INSTR_INVLPGA     INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0337)
+#define INSTR_RDTSCP      INSTR_ENC(X86EMUL_OPC(0x0f, 0x01), 0371)
+#define INSTR_INVD        INSTR_ENC(X86EMUL_OPC(0x0f, 0x08), 0)
+#define INSTR_WBINVD      INSTR_ENC(X86EMUL_OPC(0x0f, 0x09), 0)
+#define INSTR_WRMSR       INSTR_ENC(X86EMUL_OPC(0x0f, 0x30), 0)
+#define INSTR_RDTSC       INSTR_ENC(X86EMUL_OPC(0x0f, 0x31), 0)
+#define INSTR_RDMSR       INSTR_ENC(X86EMUL_OPC(0x0f, 0x32), 0)
+#define INSTR_CPUID       INSTR_ENC(X86EMUL_OPC(0x0f, 0xa2), 0)
 
 struct vcpu;
 
-unsigned int svm_get_insn_len(struct vcpu *v, enum instruction_index instr);
+unsigned int svm_get_insn_len(struct vcpu *v, unsigned int instr_enc);
 
 #endif /* __ASM_X86_HVM_SVM_EMULATE_H__ */
 
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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