git: 20d3d425900d - stable/15 - vmm: Synchronize long-mode state when emulating CR0 writes
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 22 Oct 2026 17:31:53 UTC
The branch stable/15 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=20d3d425900d6fe6de92158158346dfc3bd0e581
commit 20d3d425900d6fe6de92158158346dfc3bd0e581
Author: Hayzam Sherif <hayzam@gmail.com>
AuthorDate: 2026-09-21 16:33:55 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-10-22 15:45:40 +0000
vmm: Synchronize long-mode state when emulating CR0 writes
vmx_emulate_cr0_access() sets EFER.LMA and the IA-32e guest VM-entry
control when enabling paging with EFER.LME set, but does not clear them
when disabling paging. This can leave an inconsistent guest state that
fails VM entry.
Update both fields in either direction based on EFER.LME and the CR0
value written to the VMCS. Use the mask-adjusted CR0 value so the
resulting state remains consistent with the VMX fixed-bit requirements.
Reviewed by: markj
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D59756
(cherry picked from commit d400b1ca31fd9b12655c83f9a7b3e8cdb68646dd)
---
sys/amd64/vmm/intel/vmx.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index 65a6d9603caf..29aadb5881f3 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -1879,7 +1879,7 @@ vmx_set_guest_reg(struct vmx_vcpu *vcpu, int ident, uint64_t regval)
static int
vmx_emulate_cr0_access(struct vmx_vcpu *vcpu, uint64_t exitqual)
{
- uint64_t crval, regval;
+ uint64_t crval, efer, entry_ctls, regval;
/* We only handle mov to %cr0 at this time */
if ((exitqual & 0xf0) != 0x00)
@@ -1893,23 +1893,21 @@ vmx_emulate_cr0_access(struct vmx_vcpu *vcpu, uint64_t exitqual)
crval &= ~cr0_zeros_mask;
vmcs_write(VMCS_GUEST_CR0, crval);
- if (regval & CR0_PG) {
- uint64_t efer, entry_ctls;
-
- /*
- * If CR0.PG is 1 and EFER.LME is 1 then EFER.LMA and
- * the "IA-32e mode guest" bit in VM-entry control must be
- * equal.
- */
- efer = vmcs_read(VMCS_GUEST_IA32_EFER);
- if (efer & EFER_LME) {
- efer |= EFER_LMA;
- vmcs_write(VMCS_GUEST_IA32_EFER, efer);
- entry_ctls = vmcs_read(VMCS_ENTRY_CTLS);
- entry_ctls |= VM_ENTRY_GUEST_LMA;
- vmcs_write(VMCS_ENTRY_CTLS, entry_ctls);
- }
+ /*
+ * Keep EFER.LMA and the IA-32e guest VM-entry control in sync
+ * with CR0.PG, using the value written to the VMCS (crval).
+ */
+ efer = vmcs_read(VMCS_GUEST_IA32_EFER);
+ entry_ctls = vmcs_read(VMCS_ENTRY_CTLS);
+ if ((crval & CR0_PG) != 0 && (efer & EFER_LME) != 0) {
+ efer |= EFER_LMA;
+ entry_ctls |= VM_ENTRY_GUEST_LMA;
+ } else {
+ efer &= ~EFER_LMA;
+ entry_ctls &= ~VM_ENTRY_GUEST_LMA;
}
+ vmcs_write(VMCS_GUEST_IA32_EFER, efer);
+ vmcs_write(VMCS_ENTRY_CTLS, entry_ctls);
return (HANDLED);
}