mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 12:21:22 -05:00
KVM: x86: Refactor REX prefix handling in instruction emulation
Restructure how to represent and interpret REX fields, preparing for handling of both REX2 and VEX. REX uses the upper four bits of a single byte as a fixed identifier, and the lower four bits containing the data. VEX and REX2 extends this so that the first byte identifies the prefix and the rest encode additional bits; and while VEX only has the same four data bits as REX, eight zero bits are a valid value for the data bits of REX2. So, stop storing the REX byte as-is. Instead, store only the low bits of the REX prefix and track separately whether a REX-like prefix was used. No functional changes intended. Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com> Message-ID: <20251110180131.28264-11-chang.seok.bae@intel.com> [Extracted from APX series; removed bitfields and REX2-specific default. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Link: https://patch.msgid.link/20251114003633.60689-9-pbonzini@redhat.com [sean: name REX_{BXRW} enum "rex_bits"] Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
committed by
Sean Christopherson
parent
4cb21be4c3
commit
825f0aece0
@@ -239,6 +239,13 @@ enum x86_transfer_type {
|
||||
X86_TRANSFER_TASK_SWITCH,
|
||||
};
|
||||
|
||||
enum rex_bits {
|
||||
REX_B = 1,
|
||||
REX_X = 2,
|
||||
REX_R = 4,
|
||||
REX_W = 8,
|
||||
};
|
||||
|
||||
static void writeback_registers(struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
unsigned long dirty = ctxt->regs_dirty;
|
||||
@@ -919,7 +926,7 @@ static void *decode_register(struct x86_emulate_ctxt *ctxt, u8 modrm_reg,
|
||||
int byteop)
|
||||
{
|
||||
void *p;
|
||||
int highbyte_regs = (ctxt->rex_prefix == 0) && byteop;
|
||||
int highbyte_regs = (ctxt->rex_prefix == REX_NONE) && byteop;
|
||||
|
||||
if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8)
|
||||
p = (unsigned char *)reg_rmw(ctxt, modrm_reg & 3) + 1;
|
||||
@@ -1110,7 +1117,7 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
|
||||
if (ctxt->d & ModRM)
|
||||
reg = ctxt->modrm_reg;
|
||||
else
|
||||
reg = (ctxt->b & 7) | ((ctxt->rex_prefix & 1) << 3);
|
||||
reg = (ctxt->b & 7) | (ctxt->rex_bits & REX_B ? 8 : 0);
|
||||
|
||||
__decode_register_operand(ctxt, op, reg);
|
||||
}
|
||||
@@ -1129,9 +1136,9 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
|
||||
int rc = X86EMUL_CONTINUE;
|
||||
ulong modrm_ea = 0;
|
||||
|
||||
ctxt->modrm_reg = ((ctxt->rex_prefix << 1) & 8); /* REX.R */
|
||||
index_reg = (ctxt->rex_prefix << 2) & 8; /* REX.X */
|
||||
base_reg = (ctxt->rex_prefix << 3) & 8; /* REX.B */
|
||||
ctxt->modrm_reg = (ctxt->rex_bits & REX_R ? 8 : 0);
|
||||
index_reg = (ctxt->rex_bits & REX_X ? 8 : 0);
|
||||
base_reg = (ctxt->rex_bits & REX_B ? 8 : 0);
|
||||
|
||||
ctxt->modrm_mod = (ctxt->modrm & 0xc0) >> 6;
|
||||
ctxt->modrm_reg |= (ctxt->modrm & 0x38) >> 3;
|
||||
@@ -2464,7 +2471,7 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt)
|
||||
|
||||
setup_syscalls_segments(&cs, &ss);
|
||||
|
||||
if ((ctxt->rex_prefix & 0x8) != 0x0)
|
||||
if (ctxt->rex_bits & REX_W)
|
||||
usermode = X86EMUL_MODE_PROT64;
|
||||
else
|
||||
usermode = X86EMUL_MODE_PROT32;
|
||||
@@ -4850,7 +4857,8 @@ 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;
|
||||
ctxt->rex_prefix = ctxt->b;
|
||||
ctxt->rex_prefix = REX_PREFIX;
|
||||
ctxt->rex_bits = ctxt->b & 0xf;
|
||||
continue;
|
||||
case 0xf0: /* LOCK */
|
||||
ctxt->lock_prefix = 1;
|
||||
@@ -4864,15 +4872,15 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int
|
||||
}
|
||||
|
||||
/* Any legacy prefix after a REX prefix nullifies its effect. */
|
||||
|
||||
ctxt->rex_prefix = 0;
|
||||
ctxt->rex_prefix = REX_NONE;
|
||||
ctxt->rex_bits = 0;
|
||||
}
|
||||
|
||||
done_prefixes:
|
||||
|
||||
/* REX prefix. */
|
||||
if (ctxt->rex_prefix & 8)
|
||||
ctxt->op_bytes = 8; /* REX.W */
|
||||
if (ctxt->rex_bits & REX_W)
|
||||
ctxt->op_bytes = 8;
|
||||
|
||||
/* Opcode byte(s). */
|
||||
if (ctxt->b == 0x0f) {
|
||||
@@ -5138,7 +5146,8 @@ void init_decode_cache(struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
/* Clear fields that are set conditionally but read without a guard. */
|
||||
ctxt->rip_relative = false;
|
||||
ctxt->rex_prefix = 0;
|
||||
ctxt->rex_prefix = REX_NONE;
|
||||
ctxt->rex_bits = 0;
|
||||
ctxt->lock_prefix = 0;
|
||||
ctxt->op_prefix = false;
|
||||
ctxt->rep_prefix = 0;
|
||||
|
||||
@@ -319,6 +319,14 @@ typedef void (*fastop_t)(struct fastop *);
|
||||
#define NR_EMULATOR_GPRS 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Distinguish between no prefix, REX, or in the future REX2.
|
||||
*/
|
||||
enum rex_type {
|
||||
REX_NONE,
|
||||
REX_PREFIX,
|
||||
};
|
||||
|
||||
struct x86_emulate_ctxt {
|
||||
void *vcpu;
|
||||
const struct x86_emulate_ops *ops;
|
||||
@@ -360,7 +368,8 @@ struct x86_emulate_ctxt {
|
||||
int (*check_perm)(struct x86_emulate_ctxt *ctxt);
|
||||
|
||||
bool rip_relative;
|
||||
u8 rex_prefix;
|
||||
enum rex_type rex_prefix;
|
||||
u8 rex_bits;
|
||||
u8 lock_prefix;
|
||||
u8 rep_prefix;
|
||||
/* bitmaps of registers in _regs[] that can be read */
|
||||
|
||||
Reference in New Issue
Block a user