Re: [PATCH v7 26/26] KVM: selftest: Add a selftest for VMRUN/#VMEXIT with unmappable vmcb12

From: Yosry Ahmed

Date: Fri Mar 06 2026 - 12:54:37 EST


On Fri, Mar 6, 2026 at 7:52 AM Yosry Ahmed <yosry@xxxxxxxxxx> wrote:
>
> > > > It also does the same thing for VMSAVE/VMLOAD, which seems to also not
> > > > be architectural. This would be more annoying to handle correctly
> > > > because we'll need to copy all 1's to the relevant fields in vmcb12 or
> > > > vmcb01.
> > >
> > > Or just exit to userspace with
> > > KVM_EXIT_INTERNAL_ERROR/KVM_INTERNAL_ERROR_EMULATION. I think on the
> > > VMX side, this sort of thing goes through kvm_handle_memory_failure().
> >
> > Yep, I think this is the correct fixup:
>
> Looks good, I was going to say ignore the series @
> https://lore.kernel.org/kvm/20260305203005.1021335-1-yosry@xxxxxxxxxx/,
> because I will incorporate the fix in it after patch 1 (the cleanup),
> and patch 2 will need to be redone such that the test checks for
> KVM_EXIT_INTERNAL_ERROR/KVM_INTERNAL_ERROR_EMULATION. But then I
> stumbled upon the VMSAVE/VMLOAD behavior and the #GP I was observing
> with vls=1 (see cover letter).
>
> So I dug a bit deeper. Turns out with vls=1, if the GPA is supported
> but not mapped, VMLOAD will generate a #NPF, and because there is no
> slot KVM will install an MMIO SPTE and emulate the instruction. The
> emulator will end up calling check_svme_pa() -> emulate_gp(). I didn't
> catch this initially because I was tracing kvm_queue_exception_e() and
> didn't get any hits, but I can see the call to
> inject_emulated_exception() with #GP so probably the compiler just
> inlines it.
>
> Anyway, we'll also need to update the emulator. Perhaps just return
> X86EMUL_UNHANDLEABLE from check_svme_pa() instead of injecting #GP,

Actually, not quite. check_svme_pa() should keep injecting #GP, but
based on checking rax against kvm_host.maxphyaddr instead of the
hardcoded 0xffff000000000000ULL value. The address my test is using is
0xffffffffff000, which is a legal address on Turin (52 bit phyaddr),
but check_svme_pa() thinks it isn't and injects #GP. I think if that
is fixed, check_svme_pa() will succeed, and then emulation will fail
anyway because it's not implemented. So that seems like a separate
bug.

But then if the address is below maxphyaddr and the EFER.SVME check
succeeds, I think we should return X86EMUL_UNHANDLEABLE? I cannot
immediately tell if this will organically happen in x86_emulate_insn()
after check_svme_pa() returns.

The rest of what I said stands.

> although I don't think this will always end up returning to userspace
> with
> KVM_EXIT_INTERNAL_ERROR/KVM_INTERNAL_ERROR_EMULATION. Looking at
> handle_emulation_failure(), we'll only immediately exit to userspace
> if KVM_CAP_EXIT_ON_EMULATION_FAILURE is set (because EMULTYPE_SKIP
> won't be set). Otherwise we'll inject a #UD, and only exit to
> userspace if the VMSAVE/VMLOAD came from L1.
>
> Not sure if that's good enough or if we need to augment the emulator
> somehow (e.g. new return value that always exits to userspace? Or
> allow EMULTYPE_SKIP x86_emulate_insn() -> check_perm() to change the
> emulation type to add EMULTYPE_SKIP?

On Fri, Mar 6, 2026 at 7:52 AM Yosry Ahmed <yosry@xxxxxxxxxx> wrote:
>
> > > > It also does the same thing for VMSAVE/VMLOAD, which seems to also not
> > > > be architectural. This would be more annoying to handle correctly
> > > > because we'll need to copy all 1's to the relevant fields in vmcb12 or
> > > > vmcb01.
> > >
> > > Or just exit to userspace with
> > > KVM_EXIT_INTERNAL_ERROR/KVM_INTERNAL_ERROR_EMULATION. I think on the
> > > VMX side, this sort of thing goes through kvm_handle_memory_failure().
> >
> > Yep, I think this is the correct fixup:
>
> Looks good, I was going to say ignore the series @
> https://lore.kernel.org/kvm/20260305203005.1021335-1-yosry@xxxxxxxxxx/,
> because I will incorporate the fix in it after patch 1 (the cleanup),
> and patch 2 will need to be redone such that the test checks for
> KVM_EXIT_INTERNAL_ERROR/KVM_INTERNAL_ERROR_EMULATION. But then I
> stumbled upon the VMSAVE/VMLOAD behavior and the #GP I was observing
> with vls=1 (see cover letter).
>
> So I dug a bit deeper. Turns out with vls=1, if the GPA is supported
> but not mapped, VMLOAD will generate a #NPF, and because there is no
> slot KVM will install an MMIO SPTE and emulate the instruction. The
> emulator will end up calling check_svme_pa() -> emulate_gp(). I didn't
> catch this initially because I was tracing kvm_queue_exception_e() and
> didn't get any hits, but I can see the call to
> inject_emulated_exception() with #GP so probably the compiler just
> inlines it.
>
> Anyway, we'll also need to update the emulator. Perhaps just return
> X86EMUL_UNHANDLEABLE from check_svme_pa() instead of injecting #GP,
> although I don't think this will always end up returning to userspace
> with
> KVM_EXIT_INTERNAL_ERROR/KVM_INTERNAL_ERROR_EMULATION. Looking at
> handle_emulation_failure(), we'll only immediately exit to userspace
> if KVM_CAP_EXIT_ON_EMULATION_FAILURE is set (because EMULTYPE_SKIP
> won't be set). Otherwise we'll inject a #UD, and only exit to
> userspace if the VMSAVE/VMLOAD came from L1.
>
> Not sure if that's good enough or if we need to augment the emulator
> somehow (e.g. new return value that always exits to userspace? Or
> allow EMULTYPE_SKIP x86_emulate_insn() -> check_perm() to change the
> emulation type to add EMULTYPE_SKIP?