[PATCH v5 10/20] KVM: x86: Support EGPR accessing and tracking for emulator

From: Chang S. Bae

Date: Mon Jul 20 2026 - 13:48:10 EST


Extend the emulator context and GPR accessors to handle EGPRs before
adding support for REX2-prefixed instructions. Like VCPU cache, the
emulator can uniformly cache and track all GPRs.

Also replace `1 << reg` with `BIT(reg)` in reg_read()/reg_write(). The
former performs a signed 32-bit shift, which becomes undefined for R31.
BIT() instead shifts an unsigned value that is suitable for all indices.

Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx>
---
V4 -> V5: Fix possible shift-out-of-bounds (review bot [*])

[*]: locally running Sashiko with gemini-3.1-pro-preview
---
arch/x86/kvm/kvm_emulate.h | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
index 3e375af15c03..b1498f618c81 100644
--- a/arch/x86/kvm/kvm_emulate.h
+++ b/arch/x86/kvm/kvm_emulate.h
@@ -109,13 +109,13 @@ struct x86_instruction_info {
struct x86_emulate_ops {
void (*vm_bugged)(struct x86_emulate_ctxt *ctxt);
/*
- * read_gpr: read a general purpose register (rax - r15)
+ * read_gpr: read a general purpose register (rax - r31)
*
* @reg: gpr number.
*/
ulong (*read_gpr)(struct x86_emulate_ctxt *ctxt, unsigned reg);
/*
- * write_gpr: write a general purpose register (rax - r15)
+ * write_gpr: write a general purpose register (rax - r31)
*
* @reg: gpr number.
* @val: value to write.
@@ -321,7 +321,9 @@ typedef void (*fastop_t)(struct fastop *);
* also uses _eip, RIP cannot be a register operand nor can it be an operand in
* a ModRM or SIB byte.
*/
-#ifdef CONFIG_X86_64
+#if defined(CONFIG_KVM_APX)
+#define NR_EMULATOR_GPRS 32
+#elif defined(CONFIG_X86_64)
#define NR_EMULATOR_GPRS 16
#else
#define NR_EMULATOR_GPRS 8
@@ -381,9 +383,9 @@ struct x86_emulate_ctxt {
u8 lock_prefix;
u8 rep_prefix;
/* bitmaps of registers in _regs[] that can be read */
- u16 regs_valid;
+ u32 regs_valid;
/* bitmaps of registers in _regs[] that have been written */
- u16 regs_dirty;
+ u32 regs_dirty;
/* modrm */
u8 modrm;
u8 modrm_mod;
@@ -547,8 +549,8 @@ static inline ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr)
if (KVM_EMULATOR_BUG_ON(nr >= NR_EMULATOR_GPRS, ctxt))
nr &= NR_EMULATOR_GPRS - 1;

- if (!(ctxt->regs_valid & (1 << nr))) {
- ctxt->regs_valid |= 1 << nr;
+ if (!(ctxt->regs_valid & BIT(nr))) {
+ ctxt->regs_valid |= BIT(nr);
ctxt->_regs[nr] = ctxt->ops->read_gpr(ctxt, nr);
}
return ctxt->_regs[nr];
@@ -562,8 +564,8 @@ static inline ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr)
BUILD_BUG_ON(sizeof(ctxt->regs_dirty) * BITS_PER_BYTE < NR_EMULATOR_GPRS);
BUILD_BUG_ON(sizeof(ctxt->regs_valid) * BITS_PER_BYTE < NR_EMULATOR_GPRS);

- ctxt->regs_valid |= 1 << nr;
- ctxt->regs_dirty |= 1 << nr;
+ ctxt->regs_valid |= BIT(nr);
+ ctxt->regs_dirty |= BIT(nr);
return &ctxt->_regs[nr];
}

--
2.53.0