Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 79572)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 79573)
@@ -2561,4 +2561,18 @@
             return iemVmxAbort(pVCpu, VMXABORT_SAVE_GUEST_MSRS);
 
+        /*
+         * Write the contents of the virtual-APIC page back into guest memory (shouldn't really fail).
+         */
+        if (pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty)
+        {
+            Assert(pVmcs->u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW);
+            int rc2 = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), pVmcs->u64AddrVirtApic.u,
+                                               pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage), VMX_V_VIRT_APIC_SIZE);
+            AssertRCReturn(rc2, rc2);
+
+            /* Clear the virtual-APIC page dirty bit now that it's written back to guest memory. */
+            pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty = false;
+        }
+
         /* Clear any saved NMI-blocking state so we don't assert on next VM-entry (if it was in effect on the previous one). */
         pVCpu->cpum.GstCtx.hwvirt.fLocalForcedActions &= ~VMCPU_FF_BLOCK_NMIS;
@@ -3912,15 +3926,8 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     Assert(pVmcs);
-
-    uint32_t uReg;
-    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uReg));
-    RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
-    int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg, sizeof(uReg));
-    if (RT_FAILURE(rc))
-    {
-        AssertMsgFailed(("Failed to read %u bytes at offset %#x of the virtual-APIC page at %#RGp\n", sizeof(uReg), offReg,
-                         GCPhysVirtApic));
-        uReg = 0;
-    }
+    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint32_t));
+    uint32_t const *pbVirtApicPage = (uint32_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
+    pbVirtApicPage += offReg;
+    uint32_t const uReg = *pbVirtApicPage;
     return uReg;
 }
@@ -3938,15 +3945,8 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     Assert(pVmcs);
-
-    uint64_t uReg;
-    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uReg));
-    RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
-    int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg, sizeof(uReg));
-    if (RT_FAILURE(rc))
-    {
-        AssertMsgFailed(("Failed to read %u bytes at offset %#x of the virtual-APIC page at %#RGp\n", sizeof(uReg), offReg,
-                         GCPhysVirtApic));
-        uReg = 0;
-    }
+    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint64_t));
+    uint64_t const *pbVirtApicPage = (uint64_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
+    pbVirtApicPage += offReg;
+    uint64_t const uReg = *pbVirtApicPage;
     return uReg;
 }
@@ -3964,12 +3964,9 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     Assert(pVmcs);
-    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uReg));
-    RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
-    int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg, &uReg, sizeof(uReg));
-    if (RT_FAILURE(rc))
-    {
-        AssertMsgFailed(("Failed to write %u bytes at offset %#x of the virtual-APIC page at %#RGp\n", sizeof(uReg), offReg,
-                         GCPhysVirtApic));
-    }
+    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint32_t));
+    uint32_t *pbVirtApicPage = (uint32_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
+    pbVirtApicPage += offReg;
+    *pbVirtApicPage = uReg;
+    pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty = true;
 }
 
@@ -3986,12 +3983,9 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     Assert(pVmcs);
-    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uReg));
-    RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
-    int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg, &uReg, sizeof(uReg));
-    if (RT_FAILURE(rc))
-    {
-        AssertMsgFailed(("Failed to write %u bytes at offset %#x of the virtual-APIC page at %#RGp\n", sizeof(uReg), offReg,
-                         GCPhysVirtApic));
-    }
+    Assert(offReg <= VMX_V_VIRT_APIC_SIZE - sizeof(uint64_t));
+    uint64_t *pbVirtApicPage = (uint64_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
+    pbVirtApicPage += offReg;
+    *pbVirtApicPage = uReg;
+    pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty = true;
 }
 
@@ -4010,24 +4004,24 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     Assert(pVmcs);
-    uint32_t uReg;
-    uint16_t const offVector      = (uVector & UINT32_C(0xe0)) >> 1;
-    RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
-    int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg + offVector, sizeof(uReg));
-    if (RT_SUCCESS(rc))
-    {
-        uint16_t const idxVectorBit = uVector & UINT32_C(0x1f);
-        uReg |= RT_BIT(idxVectorBit);
-        rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg + offVector, &uReg, sizeof(uReg));
-        if (RT_FAILURE(rc))
-        {
-            AssertMsgFailed(("Failed to set vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp\n",
-                             uVector, offReg, GCPhysVirtApic));
-        }
-    }
-    else
-    {
-        AssertMsgFailed(("Failed to get vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp\n",
-                         uVector, offReg, GCPhysVirtApic));
-    }
+
+    /* Determine the vector offset within the chunk. */
+    uint32_t       uReg;
+    uint32_t       *pbVirtApicPage = (uint32_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
+    uint16_t const offVector       = (uVector & UINT32_C(0xe0)) >> 1;
+
+    /* Read the chunk at the offset. */
+    pbVirtApicPage += offReg + offVector;
+    uReg = *pbVirtApicPage;
+
+    /* Set the vector bit in the chunk. */
+    uint16_t const idxVectorBit = uVector & UINT32_C(0x1f);
+    uReg |= RT_BIT(idxVectorBit);
+
+    /* Write back the chunk at the offset. */
+    pbVirtApicPage += offReg + offVector;
+    *pbVirtApicPage = uReg;
+
+    /* Mark the page dirty. */
+    pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty = true;
 }
 
@@ -4046,24 +4040,24 @@
     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     Assert(pVmcs);
-    uint32_t uReg;
+
+    /* Determine the vector offset within the chunk. */
+    uint32_t       uReg;
+    uint32_t      *pbVirtApicPage = (uint32_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
     uint16_t const offVector      = (uVector & UINT32_C(0xe0)) >> 1;
-    RTGCPHYS const GCPhysVirtApic = pVmcs->u64AddrVirtApic.u;
-    int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &uReg, GCPhysVirtApic + offReg + offVector, sizeof(uReg));
-    if (RT_SUCCESS(rc))
-    {
-        uint16_t const idxVectorBit = uVector & UINT32_C(0x1f);
-        uReg &= ~RT_BIT(idxVectorBit);
-        rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVirtApic + offReg + offVector, &uReg, sizeof(uReg));
-        if (RT_FAILURE(rc))
-        {
-            AssertMsgFailed(("Failed to clear vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp\n",
-                             uVector, offReg, GCPhysVirtApic));
-        }
-    }
-    else
-    {
-        AssertMsgFailed(("Failed to get vector %#x in 256-bit register at %#x of the virtual-APIC page at %#RGp\n",
-                         uVector, offReg, GCPhysVirtApic));
-    }
+
+    /* Read the chunk at the offset. */
+    pbVirtApicPage += offReg + offVector;
+    uReg = *pbVirtApicPage;
+
+    /* Clear the vector bit in the chunk. */
+    uint16_t const idxVectorBit = uVector & UINT32_C(0x1f);
+    uReg &= ~RT_BIT(idxVectorBit);
+
+    /* Write back the chunk at the offset. */
+    pbVirtApicPage += offReg + offVector;
+    *pbVirtApicPage = uReg;
+
+    /* Mark the page dirty. */
+    pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty = true;
 }
 
@@ -6315,20 +6309,27 @@
             IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_AddrVirtApicPage);
 
-        /* TPR threshold without virtual-interrupt delivery. */
-        if (   !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
-            &&  (pVmcs->u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK))
+        /* Read the virtual-APIC page. */
+        int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage),
+                                         GCPhysVirtApic, VMX_V_VIRT_APIC_SIZE);
+        if (RT_SUCCESS(rc))
+        { /* likely */ }
+        else
+            IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys);
+
+        /* TPR threshold bits 31:4 MBZ without virtual-interrupt delivery. */
+        if (   !(pVmcs->u32TprThreshold & ~VMX_TPR_THRESHOLD_MASK)
+            ||  (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
+        { /* likely */ }
+        else
             IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_TprThresholdRsvd);
 
-        /* TPR threshold and VTPR. */
+        /* Verify TPR threshold and VTPR when both virtualize-APIC accesses and virtual-interrupt delivery aren't used. */
         if (   !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS)
             && !(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY))
         {
             /* Read the VTPR from the virtual-APIC page. */
-            uint8_t u8VTpr;
-            int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), &u8VTpr, GCPhysVirtApic + XAPIC_OFF_TPR, sizeof(u8VTpr));
-            if (RT_SUCCESS(rc))
-            { /* likely */ }
-            else
-                IEM_VMX_VMENTRY_FAILED_RET(pVCpu, pszInstr, pszFailure, kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys);
+            uint8_t const *pbVirtApicPage = (uint8_t const *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pvVirtApicPage);
+            pbVirtApicPage += XAPIC_OFF_TPR;
+            uint8_t const u8VTpr = *pbVirtApicPage;
 
             /* Bits 3:0 of the TPR-threshold must not be greater than bits 7:4 of VTPR. */
@@ -7386,4 +7387,7 @@
                                     return rcStrict;
                                 }
+
+                                /* Clear virtual-APIC page dirty bit to ensure it's not stale due to prior, failed VM-exits. */
+                                pVCpu->cpum.GstCtx.hwvirt.vmx.fVirtApicPageDirty = false;
 
                                 /* We've now entered nested-guest execution. */
