> On 16. Mar 2026, at 10:40, Alex Bennée <[email protected]> wrote: > > Zenghui Yu <[email protected]> writes: > >> It seems that hvf doesn't deal with the abort generated when guest tries to >> execute instructions outside of the valid physical memory range, for >> unknown reason. The abort is forwarded to userspace and QEMU doesn't handle >> it either, which ends up with faulting on the same instruction infinitely. >> Hello,
This one is a bit complicated. We don’t fully implement the whole vmapple device model for example - and I have hacks locally around that to run new macOS releases... I think at this point that a lot of the exception story would be better off in a common library between backends, like the upcoming target/arm/emulate for isv=0…. Interestingly, behaviour on x86 also has expectations around accessing an unmapped memory region, and _that_ is actually leveraged by the Linux kernel with https://github.com/torvalds/linux/commit/ab8131028710d009ab93d6bffd2a2749ade909b0 only checking CPUID… >> This was noticed by the kvm-unit-tests/selftest-vectors-kernel failure: >> >> timeout -k 1s --foreground 90s /opt/homebrew/bin/qemu-system-aarch64 \ >> -nodefaults -machine virt -accel hvf -cpu host \ >> -device virtio-serial-device -device virtconsole,chardev=ctd \ >> -chardev testdev,id=ctd -device pci-testdev -display none \ >> -serial stdio -kernel arm/selftest.flat -smp 1 -append >> vectors-kernel > > Have you got patches for teaching kvm-unit-tests about hvf or are you > running these all manually? I tried building on the Mac we have but it > failed the build and the docs only mention x86. It builds fine from aarch64-elf cross toolchain and runs as usual with accel=hvf. > >> >> PASS: selftest: vectors-kernel: und >> PASS: selftest: vectors-kernel: svc >> qemu-system-aarch64: 0xffffc000: unhandled exception ec=0x20 >> qemu-system-aarch64: 0xffffc000: unhandled exception ec=0x20 >> qemu-system-aarch64: 0xffffc000: unhandled exception ec=0x20 > > I think this is running: > > static bool check_pabt(void) > { > enum vector v = check_vector_prep(); > > install_exception_handler(v, ESR_EL1_EC_IABT_EL1, pabt_handler); > > test_exception("adrp x9, check_pabt_invalid_paddr\n" > "add x9, x9, :lo12:check_pabt_invalid_paddr\n" > "ldr x9, [x9]\n", > "blr x9\n", > "", "x9", "x30"); > > install_exception_handler(v, ESR_EL1_EC_IABT_EL1, NULL); > > return pabt_works; > } > > which is expecting 0x21 - instruction abort at the same exception level. > I wonder why there is the difference. > > >> [...] >> >> It's apparent that the guest is braindead and it's unsure what prevents hvf >> from injecting an abort directly in that case. Try to deal with the insane >> guest in QEMU by injecting an SEA back into it in the EC_INSNABORT >> emulation path. >> >> Signed-off-by: Zenghui Yu <[email protected]> >> --- >> target/arm/hvf/hvf.c | 23 +++++++++++++++++++++++ >> 1 file changed, 23 insertions(+) >> >> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c >> index aabc7d32c1..54d6ea469c 100644 >> --- a/target/arm/hvf/hvf.c >> +++ b/target/arm/hvf/hvf.c >> @@ -2332,9 +2332,32 @@ static int hvf_handle_exception(CPUState *cpu, >> hv_vcpu_exit_exception_t *excp) >> bool ea = (syndrome >> 9) & 1; >> bool s1ptw = (syndrome >> 7) & 1; >> uint32_t ifsc = (syndrome >> 0) & 0x3f; >> + uint64_t ipa = excp->physical_address; >> + AddressSpace *as = cpu_get_address_space(cpu, ARMASIdx_NS); >> + hwaddr xlat; >> + MemoryRegion *mr; >> + >> + cpu_synchronize_state(cpu); >> >> trace_hvf_insn_abort(env->pc, set, fnv, ea, s1ptw, ifsc); >> >> + /* >> + * TODO: If s1ptw, this is an error in the guest os page tables. >> + * Inject the exception into the guest. >> + */ >> + assert(!s1ptw); >> + >> + mr = address_space_translate(as, ipa, &xlat, NULL, false, >> + MEMTXATTRS_UNSPECIFIED); >> + if (unlikely(!memory_region_is_ram(mr))) { >> + uint32_t syn; >> + >> + /* inject an SEA back into the guest */ >> + syn = syn_insn_abort(arm_current_el(env) == 1, ea, false, 0x10); >> + hvf_raise_exception(cpu, EXCP_PREFETCH_ABORT, syn, 1); >> + break; >> + } >> + >> /* fall through */ >> } >> default: > > I need the check the exception paths for KVM and TCG. I guess for the > KVM case it is all in the kernel? KVM does a whole lot in the kernel that other backends don’t. Perhaps it’d be a good idea to introduce a reduced capability KVM cap that shrinks the number of things KVM does. > -- > Alex Bennée > Virtualisation Tech Lead @ Linaro >
