From: Sean Christopherson <seanjc@google.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Kiryl Shutsemau <kas@kernel.org>
Cc: kvm@vger.kernel.org, x86@kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org,
Yashu Zhang <zhangjiaji1@huawei.com>,
Rick Edgecombe <rick.p.edgecombe@intel.com>,
Binbin Wu <binbin.wu@linux.intel.com>,
Xiaoyao Li <xiaoyao.li@intel.com>,
Tom Lendacky <thomas.lendacky@amd.com>,
Michael Roth <michael.roth@amd.com>
Subject: [PATCH 02/14] KVM: x86: Open code handling of completed MMIO reads in emulator_read_write()
Date: Tue, 24 Feb 2026 17:20:37 -0800 [thread overview]
Message-ID: <20260225012049.920665-3-seanjc@google.com> (raw)
In-Reply-To: <20260225012049.920665-1-seanjc@google.com>
Open code the handling of completed MMIO reads instead of using an ops
hook, as burying the logic behind a (likely RETPOLINE'd) indirect call,
and with an unintuitive name, makes relatively straightforward code hard
to comprehend.
Opportunistically add comments to explain the dependencies between the
emulator's mem_read cache and the MMIO read completion logic, as it's very
easy to overlook the cache's role in getting the read data into the
correct destination.
No functional change intended.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/emulate.c | 13 +++++++++++++
arch/x86/kvm/x86.c | 33 ++++++++++++++++-----------------
2 files changed, 29 insertions(+), 17 deletions(-)
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c8e292e9a24d..70850e591350 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1297,12 +1297,25 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt,
int rc;
struct read_cache *mc = &ctxt->mem_read;
+ /*
+ * If the read gets a cache hit, simply copy the value from the cache.
+ * A "hit" here means that there is unused data in the cache, i.e. when
+ * re-emulating an instruction to complete a userspace exit, KVM relies
+ * on "no decode" to ensure the instruction is re-emulated in the same
+ * sequence, so that multiple reads are fulfilled in the correct order.
+ */
if (mc->pos < mc->end)
goto read_cached;
if (KVM_EMULATOR_BUG_ON((mc->end + size) >= sizeof(mc->data), ctxt))
return X86EMUL_UNHANDLEABLE;
+ /*
+ * Route all reads to the cache. This allows @dest to be an on-stack
+ * variable without triggering use-after-free if KVM needs to exit to
+ * userspace to handle an MMIO read (the MMIO fragment will point at
+ * the current location in the cache).
+ */
rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size,
&ctxt->exception);
if (rc != X86EMUL_CONTINUE)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ff3a6f86973f..8b1f02cc8196 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8109,8 +8109,6 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
}
struct read_write_emulator_ops {
- int (*read_write_prepare)(struct kvm_vcpu *vcpu, void *val,
- int bytes);
int (*read_write_emulate)(struct kvm_vcpu *vcpu, gpa_t gpa,
void *val, int bytes);
int (*read_write_mmio)(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -8120,18 +8118,6 @@ struct read_write_emulator_ops {
bool write;
};
-static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes)
-{
- if (vcpu->mmio_read_completed) {
- trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
- vcpu->mmio_fragments[0].gpa, val);
- vcpu->mmio_read_completed = 0;
- return 1;
- }
-
- return 0;
-}
-
static int read_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
void *val, int bytes)
{
@@ -8167,7 +8153,6 @@ static int write_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
}
static const struct read_write_emulator_ops read_emultor = {
- .read_write_prepare = read_prepare,
.read_write_emulate = read_emulate,
.read_write_mmio = vcpu_mmio_read,
.read_write_exit_mmio = read_exit_mmio,
@@ -8250,9 +8235,23 @@ static int emulator_read_write(struct x86_emulate_ctxt *ctxt,
if (WARN_ON_ONCE((bytes > 8u || !ops->write) && object_is_on_stack(val)))
return X86EMUL_UNHANDLEABLE;
- if (ops->read_write_prepare &&
- ops->read_write_prepare(vcpu, val, bytes))
+ /*
+ * If the read was already completed via a userspace MMIO exit, there's
+ * nothing left to do except trace the MMIO read. When completing MMIO
+ * reads, KVM re-emulates the instruction to propagate the value into
+ * the correct destination, e.g. into the correct register, but the
+ * value itself has already been copied to the read cache.
+ *
+ * Note! This is *tightly* coupled to read_emulated() satisfying reads
+ * from the emulator's mem_read cache, so that the MMIO fragment data
+ * is copied to the correct chunk of the correct operand.
+ */
+ if (!ops->write && vcpu->mmio_read_completed) {
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
+ vcpu->mmio_fragments[0].gpa, val);
+ vcpu->mmio_read_completed = 0;
return X86EMUL_CONTINUE;
+ }
vcpu->mmio_nr_fragments = 0;
--
2.53.0.414.gf7e9f6c205-goog
next prev parent reply other threads:[~2026-02-25 1:20 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-25 1:20 [PATCH 00/14] KVM: x86: Emulator MMIO fix and cleanups Sean Christopherson
2026-02-25 1:20 ` [PATCH 01/14] KVM: x86: Use scratch field in MMIO fragment to hold small write values Sean Christopherson
2026-02-25 1:20 ` Sean Christopherson [this message]
2026-02-25 1:20 ` [PATCH 03/14] KVM: x86: Trace unsatisfied MMIO reads on a per-page basis Sean Christopherson
2026-02-25 1:20 ` [PATCH 04/14] KVM: x86: Use local MMIO fragment variable to clean up emulator_read_write() Sean Christopherson
2026-02-25 1:20 ` [PATCH 05/14] KVM: x86: Open code read vs. write userspace MMIO exits in emulator_read_write() Sean Christopherson
2026-02-25 1:20 ` [PATCH 06/14] KVM: x86: Move MMIO write tracing into vcpu_mmio_write() Sean Christopherson
2026-02-25 1:20 ` [PATCH 07/14] KVM: x86: Harden SEV-ES MMIO against on-stack use-after-free Sean Christopherson
2026-02-25 1:20 ` [PATCH 08/14] KVM: x86: Dedup kvm_sev_es_mmio_{read,write}() Sean Christopherson
2026-02-25 1:20 ` [PATCH 09/14] KVM: x86: Consolidate SEV-ES MMIO emulation into a single public API Sean Christopherson
2026-02-25 1:20 ` [PATCH 10/14] KVM: x86: Bury emulator read/write ops in emulator_{read,write}_emulated() Sean Christopherson
2026-02-25 1:20 ` [PATCH 11/14] KVM: x86: Fold emulator_write_phys() into write_emulate() Sean Christopherson
2026-02-25 1:20 ` [PATCH 12/14] KVM: x86: Rename .read_write_emulate() to .read_write_guest() Sean Christopherson
2026-02-25 1:20 ` [PATCH 13/14] KVM: x86: Don't panic the kernel if completing userspace I/O / MMIO goes sideways Sean Christopherson
2026-02-25 1:20 ` [PATCH 14/14] KVM: x86: Add helpers to prepare kvm_run for userspace MMIO exit Sean Christopherson
2026-02-25 17:32 ` Edgecombe, Rick P
2026-02-25 19:22 ` Sean Christopherson
2026-03-03 2:24 ` Sean Christopherson
2026-03-03 19:21 ` Edgecombe, Rick P
2026-03-03 19:44 ` Sean Christopherson
2026-03-03 19:51 ` Edgecombe, Rick P
2026-02-25 17:32 ` [PATCH 00/14] KVM: x86: Emulator MMIO fix and cleanups Edgecombe, Rick P
2026-02-25 20:19 ` Tom Lendacky
2026-02-27 20:19 ` Tom Lendacky
2026-03-05 17:07 ` Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260225012049.920665-3-seanjc@google.com \
--to=seanjc@google.com \
--cc=binbin.wu@linux.intel.com \
--cc=kas@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.roth@amd.com \
--cc=pbonzini@redhat.com \
--cc=rick.p.edgecombe@intel.com \
--cc=thomas.lendacky@amd.com \
--cc=x86@kernel.org \
--cc=xiaoyao.li@intel.com \
--cc=zhangjiaji1@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox