diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index b8a946cbd587..c62d21de14cb 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4479,6 +4479,8 @@ static const struct opcode opcode_map_0f_38[256] = { N, N, X4(N), X8(N) }; +static const struct opcode undefined = D(Undefined); + #undef D #undef N #undef G @@ -4765,6 +4767,11 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, return rc; } +static inline bool emul_egpr_enabled(struct x86_emulate_ctxt *ctxt __maybe_unused) +{ + return false; +} + int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int emulation_type) { int rc = X86EMUL_CONTINUE; @@ -4817,7 +4824,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int ctxt->op_bytes = def_op_bytes; ctxt->ad_bytes = def_ad_bytes; - /* Legacy prefixes. */ + /* Legacy and REX/REX2 prefixes. */ for (;;) { switch (ctxt->b = insn_fetch(u8, ctxt)) { case 0x66: /* operand-size override */ @@ -4860,9 +4867,29 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int case 0x40 ... 0x4f: /* REX */ if (mode != X86EMUL_MODE_PROT64) goto done_prefixes; + if (ctxt->rex_prefix == REX2_PREFIX) { + opcode = undefined; + goto decode_done; + } ctxt->rex_prefix = REX_PREFIX; ctxt->rex = 0x0f & ctxt->b; continue; + case 0xd5: /* REX2 */ + if (mode != X86EMUL_MODE_PROT64) + goto done_prefixes; + if ((ctxt->rex_prefix == REX2_PREFIX && (ctxt->rex & REX_M) == 0) || + (ctxt->rex_prefix == REX_PREFIX) || + (!emul_egpr_enabled(ctxt))) { + opcode = undefined; + goto decode_done; + } + ctxt->rex_prefix = REX2_PREFIX; + ctxt->rex = insn_fetch(u8, ctxt); + ctxt->b = insn_fetch(u8, ctxt); + if (ctxt->rex & REX_M) + goto decode_twobytes; + else + goto decode_onebyte; case 0xf0: /* LOCK */ ctxt->lock_prefix = 1; break; @@ -4889,6 +4916,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int if (ctxt->b == 0x0f) { /* Escape byte: start two-byte opcode sequence */ ctxt->b = insn_fetch(u8, ctxt); +decode_twobytes: if (ctxt->b == 0x38 && ctxt->rex_prefix != REX2_PREFIX) { /* Three-byte opcode */ ctxt->opcode_len = 3; @@ -4900,10 +4928,12 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int opcode = twobyte_table[ctxt->b]; } } else { +decode_onebyte: /* Single-byte opcode */ ctxt->opcode_len = 1; opcode = opcode_table[ctxt->b]; } +decode_done: ctxt->d = opcode.flags; if (ctxt->d & NoRex2 && ctxt->rex_prefix == REX2_PREFIX)