On 2025/6/26 16:09, Yicong Yang wrote:
From: Yicong Yang yangyicong@hisilicon.com
The unsupported exclusive/atomic DABT exception is hand to the userspace. Provide a way for the userspace to inject this DABT to the guest if they want to imitate how this is handled on the host.
Tested LS64 fault in VM using kvmtool with below patch, debug information added. The LS64 DABT injection works as expected.
# Perform LS64 on emulated MMIO root@localhost:/mnt# lspci -tv -[0000:00]-+-00.0 Device 1af4:1049 -01.0 Device 1af4:1041 root@localhost:/mnt# ./ls64.o -d 0000:00:00.0 -b 2 Start address of 0000:00:00.0 BAR2 is 0x0 mappded va is 0xffff82d20000 addr is 0x4120e8 Info: esr_iss 93c09000 fault_ipa 50000000 // kvmtool debug information Info: correct mapping but emulated MMIO // kvmtool debug information test FEAT_LS64 Bus error # Perform LS64 on normal memory root@localhost:/mnt# ./ls64.o -a mappded va is 0xffffa5400000 addr is 0x4120e8 test FEAT_LS64 Info: esr_iss 35 fault_ipa 83971000 // kvmtool debug information Info: Injecting DABT since incorrect Guest memory attribute // kvmtool debug information Bus error
diff --git a/arm/aarch64/include/asm/kvm.h b/arm/aarch64/include/asm/kvm.h index 66736ff..d3cd866 100644 --- a/arm/aarch64/include/asm/kvm.h +++ b/arm/aarch64/include/asm/kvm.h @@ -186,8 +186,9 @@ struct kvm_vcpu_events { __u8 serror_pending; __u8 serror_has_esr; __u8 ext_dabt_pending; + __u8 ext_dabt_excl_atom_pending; /* Align it to 8 bytes */ - __u8 pad[5]; + __u8 pad[4]; __u64 serror_esr; } exception; __u32 reserved[12]; diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h index eb23e2f..56b985d 100644 --- a/include/kvm/kvm.h +++ b/include/kvm/kvm.h @@ -129,6 +129,8 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr); int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr, enum kvm_mem_type type); +bool kvm__valid_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u32 len); + static inline int kvm__register_ram(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr) { diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 502ea63..fa01051 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -178,6 +178,7 @@ struct kvm_xen_exit { #define KVM_EXIT_NOTIFY 37 #define KVM_EXIT_LOONGARCH_IOCSR 38 #define KVM_EXIT_MEMORY_FAULT 39 +#define KVM_EXIT_ARM_LDST64B 41
/* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ diff --git a/kvm-cpu.c b/kvm-cpu.c index 7362f2e..f544cf4 100644 --- a/kvm-cpu.c +++ b/kvm-cpu.c @@ -238,6 +238,42 @@ int kvm_cpu__start(struct kvm_cpu *cpu) goto exit_kvm; }; break; + case KVM_EXIT_ARM_LDST64B: { + struct kvm_run *kvm_run = cpu->kvm_run; + __u64 ipa = kvm_run->arm_nisv.fault_ipa; + int ret; + + pr_info("esr_iss %llx fault_ipa %llx", + kvm_run->arm_nisv.esr_iss, ipa); + + if (!kvm__valid_mmio(cpu, ipa, 64)) { + struct kvm_vcpu_events events = { + .exception.ext_dabt_excl_atom_pending = 1, + }; + + pr_info("Injecting DABT since incorrect Guest memory attribute"); + + ret = ioctl(cpu->vcpu_fd, KVM_SET_VCPU_EVENTS, &events); + if (ret) { + pr_err("err inject DABT"); + goto panic_kvm; + } + } else { + struct kvm_vcpu_events events = { + .exception.ext_dabt_excl_atom_pending = 1, + }; + + pr_info("correct mapping but emulated MMIO"); + + ret = ioctl(cpu->vcpu_fd, KVM_SET_VCPU_EVENTS, &events); + if (ret) { + pr_err("err inject DABT"); + goto panic_kvm; + } + } + + break; + } default: { bool ret;
diff --git a/mmio.c b/mmio.c index 231ce91..7071d3a 100644 --- a/mmio.c +++ b/mmio.c @@ -195,6 +195,11 @@ bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags) return true; }
+bool kvm__valid_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u32 len) +{ + return !!mmio_get(&mmio_tree, phys_addr, len); +} + bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write) {
Signed-off-by: Yicong Yang yangyicong@hisilicon.com
arch/arm64/include/asm/kvm_emulate.h | 1 + arch/arm64/include/uapi/asm/kvm.h | 3 ++- arch/arm64/kvm/guest.c | 4 ++++ arch/arm64/kvm/inject_fault.c | 29 ++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 0720898f563e..df141ae77019 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -47,6 +47,7 @@ void kvm_skip_instr32(struct kvm_vcpu *vcpu); void kvm_inject_undefined(struct kvm_vcpu *vcpu); void kvm_inject_vabt(struct kvm_vcpu *vcpu); void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); +void kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_size_fault(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index ed5f3892674c..69985acda668 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -184,8 +184,9 @@ struct kvm_vcpu_events { __u8 serror_pending; __u8 serror_has_esr; __u8 ext_dabt_pending;
/* Align it to 8 bytes */__u8 ext_dabt_excl_atom_pending;
__u8 pad[5];
__u64 serror_esr; } exception; __u32 reserved[12];__u8 pad[4];
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 2196979a24a3..47bc09ea50c3 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -839,6 +839,7 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, bool serror_pending = events->exception.serror_pending; bool has_esr = events->exception.serror_has_esr; bool ext_dabt_pending = events->exception.ext_dabt_pending;
- bool ext_dabt_excl_atom_pending = events->exception.ext_dabt_excl_atom_pending;
if (serror_pending && has_esr) { if (!cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) @@ -855,6 +856,9 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, if (ext_dabt_pending) kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
- if (ext_dabt_excl_atom_pending)
kvm_inject_dabt_excl_atomic(vcpu, kvm_vcpu_get_hfar(vcpu));
- return 0;
} diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index a640e839848e..d64650a1aefe 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -171,6 +171,35 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr) inject_abt64(vcpu, false, addr); } +/**
- kvm_inject_dabt_excl_atomic - inject a data abort for unsupported exclusive
or atomic access
- @vcpu: The VCPU to receive the data abort
- @addr: The address to report in the DFAR
- It is assumed that this code is called from the VCPU thread and that the
- VCPU therefore is not currently executing guest code.
- */
+void kvm_inject_dabt_excl_atomic(struct kvm_vcpu *vcpu, unsigned long addr) +{
- u64 esr = 0;
- /* Reuse the general DABT injection routine and modify the DFSC */
- kvm_inject_dabt(vcpu, addr);
- if (match_target_el(vcpu, unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC))) {
esr = vcpu_read_sys_reg(vcpu, ESR_EL1);
esr &= ~ESR_ELx_FSC;
esr |= ESR_ELx_FSC_EXCL_ATOMIC;
vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
- } else {
esr = vcpu_read_sys_reg(vcpu, ESR_EL2);
esr &= ~ESR_ELx_FSC;
esr |= ESR_ELx_FSC_EXCL_ATOMIC;
vcpu_write_sys_reg(vcpu, esr, ESR_EL2);
- }
+}
/**
- kvm_inject_pabt - inject a prefetch abort into the guest
- @vcpu: The VCPU to receive the prefetch abort