Re: [RFC] Expose L1 guest register state for nested VMX via KVM_GET_NESTED_STATE

Sean Christopherson <[email protected]>
Newsgroups org.kernel.vger.kvm
Message-ID <[email protected]>
On Fri, Aug 14, 2026, Zhengrong Li wrote:
> [RFC] Expose L1 guest register state for nested VMX via KVM_GET_NESTED_STATE
> 
> Problem
> =======
> 
> KVM_GET_REGS and KVM_GET_SREGS always return the register state of the
> currently active guest context.  When a vCPU is in VMX non-root
> operation running an L2 nested guest, these ioctls return L2 state.
> There is no way for userspace to retrieve L1 guest state while L2 is
> active.
> 
> This affects any tool that inspects vCPU register state.  For example,
> QEMU's "info registers" monitor command and GDB stub both show L2
> registers when L2 is running, making nested VM debugging difficult.
> Users have no way to determine where L1 was executing, 

vmcs12.HOST_RIP will provide a solid clue given that software convention is to
put the exit handler close to the entry point.

> what page tables it was using,

vmcs12.HOST_{CR3,CR4} and vmcs12.HOST_EFER

> or which privilege level it was in.

Given that VMLAUNCH and VMRESUME are CPL0-only, this one's easy. :-D

> SVM Comparison
> ==============
> 
> For AMD/SVM, KVM_GET_NESTED_STATE already returns the vmcb01 save area,
> which provides comprehensive L1 state (see svm_get_nested_state() in
> arch/x86/kvm/svm/nested.c, line 1943):
> 
>     copy_to_user(&user_vmcb->save, &svm->vmcb01.ptr->save,
>                  sizeof(user_vmcb->save));
> 
> The SVM vmcb_save_area includes:
> 
>   Registers:  RIP, RSP, RAX, RFLAGS
>   Control:    CR0, CR2, CR3, CR4, EFER
>   Debug:      DR6, DR7
>   Segments:   ES/CS/SS/DS/FS/GS (selector, base, limit, attr)
>   Tables:     GDTR, IDTR, LDTR, TR
>   Syscall MSRs: STAR, LSTAR, CSTAR, SFMASK, KERNEL_GS_BASE,
>                 SYSENTER_CS/ESP/EIP
>   Other:      PAT, SPEC_CTRL, CPL
> 
> This gives userspace a near-complete snapshot of L1 state.
> 
> VMX has no equivalent.  KVM_GET_NESTED_STATE for VMX returns vmcs12
> (which contains L2 guest state + L1 host-state area for VM-exit) but
> never exposes L1's running guest state from vmcs01.

Because there is no L1 "running" state.  The majority of the data that's listed
above is explicitly loaded from vmcs12 on VM-Exit from L2 => L1.  CR2 isn't
loaded because it's software's responsibility to context switch CR2.

In other words, what you want is already available via KVM_GET_NESTED_STATE, it
simply requires reading vmcs12.HOST_xxx.

> Proposed: L1 Guest State Snapshot for VMX
> =========================================
> 
> Add a new section to the VMX nested state data that provides a
> comprehensive L1 register snapshot, assembled from all sources KVM has
> access to.
> 
> The data should be returned as a VMCS12-sized blob (same format as the
> existing vmcs12 and shadow_vmcs12 sections).  This reuses existing
> infrastructure and lets userspace parse fields using the well-known
> vmcs12 layout.
> 
> Fields to include (from vmcs01 hardware VMCS):
>   GUEST_RSP, GUEST_RIP, GUEST_RFLAGS
>   GUEST_CR0, GUEST_CR3, GUEST_CR4
>   GUEST_IA32_EFER, GUEST_IA32_PAT
>   GUEST_DR7
>   GUEST_ES/CS/SS/DS/FS/GS (selector, base, limit, ar_bytes)
>   GUEST_GDTR, GUEST_IDTR (base, limit)
>   GUEST_LDTR, GUEST_TR (selector, base, limit, ar_bytes)
>   GUEST_SYSENTER_CS, GUEST_SYSENTER_ESP, GUEST_SYSENTER_EIP
>   GUEST_PDPTR0-3
>   GUEST_INTERRUPTIBILITY_INFO, GUEST_ACTIVITY_STATE
> 
> Additional fields from KVM's vcpu software model (vcpu->arch.*):
>   CR2      -- vcpu->arch.cr2 (cached from last #PF)
>   DR6      -- vcpu->arch.dr6 (cached from last debug event)
>   MSR_IA32_SPEC_CTRL  -- vcpu->arch.spec_ctrl
>   MSR_KERNEL_GS_BASE  -- via kvm_get_msr() or uret array
>   MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SF_MASK
>     -- via uret/uret_msrs array (populated on VM-exit)
> 
> Note: the MSR-derived fields (KERNEL_GS_BASE, STAR, LSTAR, CSTAR,
> SFMASK, SPEC_CTRL) are not VMCS guest-state fields in Intel VMX.  They
> are saved/restored by the VM-entry MSR-load mechanism or KVM's MSR
> save/restore path.  

No.  Like GPRs, KVM can't distinguish between L1 and L2 values because how L1
manages L2's values is defined by L1 software, not by the architecture.

> Hardware Limitation (GPRs)
> ==========================
> 
> Neither Intel VMX nor AMD SVM saves general-purpose registers (beyond
> RAX/RSP/RIP) into the VMCS/VMCB on VM-entry.  RBX, RCX, RDX, RSI, RDI,
> R8-R15 remain in physical registers and are overwritten when L2 starts.
> 
> For SVM, hardware saves RAX to the VMCB save area; for VMX, RAX is not
> in the VMCS guest-state area at all.  This is a hardware constraint,
> not something KVM can work around.
> 
> The L1 hypervisor is responsible for saving its own GPRs (typically on
> its stack), which KVM cannot locate.

Well, KVM could locate that, but so could QEMU.  The host RSP will provide a
very good starting point for guessing L1's GPR state.

> Questions for Maintainers
> =========================
> 
> 1. Is exposing L1 guest state via KVM_GET_NESTED_STATE acceptable?

No, because architecturally it has no meaning, and in practice the vmcs12 host
state should give you pretty much everything you need.  If you want more debug
information than what is avaiable via KVM ioctls, then there's always BPF.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.