Re: [PATCH v15 16/37] KVM: arm64: CCA: Handle realm MMIO emulation
Steven Price <[email protected]> Mon, 3 Aug 2026 15:57:17 +0100
| Newsgroups | dev.linux.lists.linux-coco,dev.linux.lists.kvmarm,org.infradead.lists.linux-arm-kernel,org.kernel.vger.kvm,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 03/08/2026 12:27, Marc Zyngier wrote: > On Wed, 15 Jul 2026 15:28:18 +0100, > Steven Price <[email protected]> wrote: >> >> MMIO emulation for a realm cannot be done directly with the VM's >> registers as they are protected from the host. However, for emulatable >> data aborts, the RMM uses GPRS[0] to provide the read/written value. >> We can transfer this from/to the equivalent VCPU's register entry and >> then depend on the generic MMIO handling code in KVM. >> >> For a MMIO read, the value is placed in the shared RecExit structure >> during kvm_handle_mmio_return() rather than in the VCPU's register >> entry. >> >> Signed-off-by: Steven Price <[email protected]> >> Reviewed-by: Gavin Shan <[email protected]> >> Reviewed-by: Suzuki K Poulose <[email protected]> >> --- >> Changes since v7: >> * New comment for rec_exit_sync_dabt() explaining the call to >> vcpu_set_reg(). >> Changes since v5: >> * Inject SEA to the guest is an emulatable MMIO access triggers a data >> abort. >> * kvm_handle_mmio_return() - disable kvm_incr_pc() for a REC (as the PC >> isn't under the host's control) and move the REC_ENTER_EMULATED_MMIO >> flag setting to this location (as that tells the RMM to skip the >> instruction). >> --- >> arch/arm64/kvm/inject_fault.c | 4 +++- >> arch/arm64/kvm/mmio.c | 16 ++++++++++++---- >> arch/arm64/kvm/rmi-exit.c | 15 +++++++++++++++ >> 3 files changed, 30 insertions(+), 5 deletions(-) >> >> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c >> index 89982bd3345f..6492397b73d7 100644 >> --- a/arch/arm64/kvm/inject_fault.c >> +++ b/arch/arm64/kvm/inject_fault.c >> @@ -228,7 +228,9 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr) >> >> static void __kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr) >> { >> - if (vcpu_el1_is_32bit(vcpu)) >> + if (unlikely(vcpu_is_rec(vcpu))) >> + vcpu->arch.rec.run->enter.flags |= REC_ENTER_FLAG_INJECT_SEA; >> + else if (vcpu_el1_is_32bit(vcpu)) >> inject_abt32(vcpu, iabt, addr); >> else >> inject_abt64(vcpu, iabt, addr); > > Why don't you let inject_dabt64() do its job and reconcile the REC > stuff at run time? Ok, one wrinkle is the __kvm_adjust_pc() path. But I can skip that and leave the PENDING_EXCEPTION flag set on return to user space. That way the flag is still set for the next entry and we can handle the RMM specific parts there. >> diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c >> index e2285ed8c91d..a8c125205695 100644 >> --- a/arch/arm64/kvm/mmio.c >> +++ b/arch/arm64/kvm/mmio.c >> @@ -6,6 +6,7 @@ >> >> #include <linux/kvm_host.h> >> #include <asm/kvm_emulate.h> >> +#include <linux/arm-smccc-rmi.h> >> #include <trace/events/kvm.h> >> >> #include "trace.h" >> @@ -138,14 +139,21 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu) >> trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, >> &data); >> data = vcpu_data_host_to_guest(vcpu, data, len); >> - vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data); >> + >> + if (vcpu_is_rec(vcpu)) >> + vcpu->arch.rec.run->enter.gprs[0] = data; >> + else >> + vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data); > > This is yet another example of things I do not want to see. KVM works > on the GPRs described in the vcpu structure. And that's it. > > So let the ESR information be correct for CCA, the data being written > back to x0, and once you're ready to enter the guest again, copy > whatever you need into the CCA data structure. > > But not any of this stuff. Yes this is a bit silly. A while ago the RMM wasn't populating the ESR information correctly which is where all these gprs[0] hacks came from. That's been fixed and it should be possible to do this on entry. >> } >> >> /* >> * The MMIO instruction is emulated and should not be re-executed >> * in the guest. >> */ >> - kvm_incr_pc(vcpu); >> + if (vcpu_is_rec(vcpu)) >> + vcpu->arch.rec.run->enter.flags |= REC_ENTER_FLAG_EMULATED_MMIO; >> + else >> + kvm_incr_pc(vcpu); > > Same thing. kvm_incr_pc() sets a flag. Use that to reconcile the state > with CCA. It's not an ideal flag for this use (it's set in other places). But I think it should be sufficient along with checking other state to identify this condition. Thanks, Steve