[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250923050942.206116-21-Neeraj.Upadhyay@amd.com>
Date: Tue, 23 Sep 2025 10:39:27 +0530
From: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
To: <kvm@...r.kernel.org>, <seanjc@...gle.com>, <pbonzini@...hat.com>
CC: <linux-kernel@...r.kernel.org>, <Thomas.Lendacky@....com>,
<nikunj@....com>, <Santosh.Shukla@....com>, <Vasant.Hegde@....com>,
<Suravee.Suthikulpanit@....com>, <bp@...en8.de>, <David.Kaplan@....com>,
<huibo.wang@....com>, <naveen.rao@....com>, <pgonda@...gle.com>,
<linux-kselftest@...r.kernel.org>, <shuah@...nel.org>, <tiala@...rosoft.com>
Subject: [RFC PATCH v2 20/35] KVM: selftests: Add instruction decoding for movabs instructions
Compilers can generate movabs instructions for MMIO accesses,
when accessing fixed addresses like the local APIC base. The movabs
instruction is unique in that it moves data between the accumulator (RAX)
and a memory location specified by an absolute 64-bit address encoded
directly in the instruction stream.
The existing MMIO #VC handler in the SEV-ES selftest was unable to
process these instructions because its decoding logic relied on ModR/M
and SIB bytes, which movabs does not use. This would cause MMIO
emulation to fail for such instructions.
Extend insn_decode_mmio() to recognize the movabs opcodes (0xa1,
0xa3). This allows the SEV-ES #VC handler to correctly emulate movabs
instructions, improving the robustness of MMIO testing for
features like the xAPIC.
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
---
.../selftests/kvm/include/x86/insn-eval.h | 2 ++
.../testing/selftests/kvm/lib/x86/insn-eval.c | 8 +++++
tools/testing/selftests/kvm/lib/x86/sev.c | 35 ++++++++++++++-----
3 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/x86/insn-eval.h b/tools/testing/selftests/kvm/include/x86/insn-eval.h
index 0547b622295a..911b7f4e5473 100644
--- a/tools/testing/selftests/kvm/include/x86/insn-eval.h
+++ b/tools/testing/selftests/kvm/include/x86/insn-eval.h
@@ -35,10 +35,12 @@ enum insn_mmio_type {
INSN_MMIO_DECODE_FAILED,
INSN_MMIO_WRITE,
INSN_MMIO_WRITE_IMM,
+ INSN_MMIO_WRITE_MOV_ABS,
INSN_MMIO_READ,
INSN_MMIO_READ_ZERO_EXTEND,
INSN_MMIO_READ_SIGN_EXTEND,
INSN_MMIO_MOVS,
+ INSN_MMIO_READ_MOV_ABS,
};
enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes);
diff --git a/tools/testing/selftests/kvm/lib/x86/insn-eval.c b/tools/testing/selftests/kvm/lib/x86/insn-eval.c
index 369530badba9..9d370b1cef84 100644
--- a/tools/testing/selftests/kvm/lib/x86/insn-eval.c
+++ b/tools/testing/selftests/kvm/lib/x86/insn-eval.c
@@ -1224,6 +1224,14 @@ enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes)
break;
}
break;
+ case 0xa1:
+ type = INSN_MMIO_READ_MOV_ABS;
+ *bytes = insn->opnd_bytes;
+ break;
+ case 0xa3:
+ type = INSN_MMIO_WRITE_MOV_ABS;
+ *bytes = insn->opnd_bytes;
+ break;
}
return type;
diff --git a/tools/testing/selftests/kvm/lib/x86/sev.c b/tools/testing/selftests/kvm/lib/x86/sev.c
index 610342b8e479..1e0719dfd6b0 100644
--- a/tools/testing/selftests/kvm/lib/x86/sev.c
+++ b/tools/testing/selftests/kvm/lib/x86/sev.c
@@ -469,9 +469,11 @@ void sev_es_pv_mmio_rw(uint32_t *reg_gpa, uint32_t *data, bool write)
}
static void do_mmio(struct ghcb_entry *entry, struct ex_regs *regs,
- struct insn *insn, unsigned int bytes, bool read)
+ struct insn *insn, unsigned int bytes, bool read,
+ void *ref)
{
- void *ref = insn_get_addr_ref(insn, regs);
+ if (!ref)
+ ref = insn_get_addr_ref(insn, regs);
register_ghcb_page(entry->gpa);
__sev_es_hv_mmio_rw(entry, ref, bytes, !read);
@@ -600,11 +602,12 @@ static void sev_es_vc_mmio_handler(struct ex_regs *regs)
char buffer[MAX_INSN_SIZE];
struct ghcb_entry *entry;
enum insn_mmio_type mmio;
- unsigned long *reg_data;
+ unsigned long *reg_data = NULL;
unsigned int bytes;
struct ghcb *ghcb;
uint8_t sign_byte;
struct insn insn;
+ void *abs_ref;
int ret;
memcpy(buffer, (uint8_t *)regs->rip, MAX_INSN_SIZE);
@@ -616,7 +619,9 @@ static void sev_es_vc_mmio_handler(struct ex_regs *regs)
mmio = insn_decode_mmio(&insn, (int *)&bytes);
__GUEST_ASSERT(!(mmio == INSN_MMIO_DECODE_FAILED), " MMIO decode failed\n");
- if (mmio != INSN_MMIO_WRITE_IMM && mmio != INSN_MMIO_MOVS) {
+ if (mmio == INSN_MMIO_WRITE_MOV_ABS || mmio == INSN_MMIO_READ_MOV_ABS) {
+ reg_data = ®s->rax;
+ } else if (mmio != INSN_MMIO_WRITE_IMM && mmio != INSN_MMIO_MOVS) {
reg_data = insn_get_modrm_reg_ptr(&insn, regs);
__GUEST_ASSERT(reg_data, "insn_get_modrm_reg_ptr failed\n");
}
@@ -627,25 +632,37 @@ static void sev_es_vc_mmio_handler(struct ex_regs *regs)
switch (mmio) {
case INSN_MMIO_WRITE:
memcpy(ghcb->shared_buffer, reg_data, bytes);
- do_mmio(entry, regs, &insn, bytes, false);
+ do_mmio(entry, regs, &insn, bytes, false, NULL);
break;
case INSN_MMIO_WRITE_IMM:
memcpy(ghcb->shared_buffer, insn.immediate1.bytes, bytes);
- do_mmio(entry, regs, &insn, bytes, false);
+ do_mmio(entry, regs, &insn, bytes, false, NULL);
+ break;
+ case INSN_MMIO_WRITE_MOV_ABS:
+ abs_ref = (void *)*(uint64_t *)((uint8_t *)regs->rip + 1);
+ memcpy(ghcb->shared_buffer, reg_data, bytes);
+ do_mmio(entry, regs, &insn, bytes, false, abs_ref);
break;
case INSN_MMIO_READ:
- do_mmio(entry, regs, &insn, bytes, true);
+ do_mmio(entry, regs, &insn, bytes, true, NULL);
+ if (bytes == 4)
+ *reg_data = 0;
+ memcpy(reg_data, ghcb->shared_buffer, bytes);
+ break;
+ case INSN_MMIO_READ_MOV_ABS:
+ abs_ref = (void *)*(uint64_t *)((char *)regs->rip + 1);
+ do_mmio(entry, regs, &insn, bytes, true, abs_ref);
if (bytes == 4)
*reg_data = 0;
memcpy(reg_data, ghcb->shared_buffer, bytes);
break;
case INSN_MMIO_READ_ZERO_EXTEND:
- do_mmio(entry, regs, &insn, bytes, true);
+ do_mmio(entry, regs, &insn, bytes, true, NULL);
memset(reg_data, 0, insn.opnd_bytes);
memcpy(reg_data, ghcb->shared_buffer, bytes);
break;
case INSN_MMIO_READ_SIGN_EXTEND:
- do_mmio(entry, regs, &insn, bytes, true);
+ do_mmio(entry, regs, &insn, bytes, true, NULL);
if (bytes == 1) {
uint8_t *val = (uint8_t *)ghcb->shared_buffer;
--
2.34.1
Powered by blists - more mailing lists