Index: /trunk/include/VBox/vmm/iem.h
===================================================================
--- /trunk/include/VBox/vmm/iem.h	(revision 79342)
+++ /trunk/include/VBox/vmm/iem.h	(revision 79343)
@@ -353,4 +353,6 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+VMM_INT_DECL(void)          IEMReadVmxVmcsField(PCVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t *pu64Dst);
+VMM_INT_DECL(void)          IEMWriteVmxVmcsField(PVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t u64Val);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVirtApicAccessMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *pu64Val, bool fWrite);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitApicWrite(PVMCPU pVCpu);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 79342)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 79343)
@@ -15785,4 +15785,45 @@
 
 /**
+ * Interface for HM and EM to read a VMCS field from the nested-guest VMCS.
+ *
+ * It is ASSUMED the caller knows what they're doing. No VMREAD instruction checks
+ * are performed. Bounds checks are strict builds only.
+ *
+ * @param   pVmcs           Pointer to the virtual VMCS.
+ * @param   u64VmcsField    The VMCS field.
+ * @param   pu64Dst         Where to store the VMCS value.
+ *
+ * @remarks May be called with interrupts disabled.
+ * @todo    This should probably be moved to CPUM someday.
+ */
+VMM_INT_DECL(void) IEMReadVmxVmcsField(PCVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t *pu64Dst)
+{
+    AssertPtr(pVmcs);
+    AssertPtr(pu64Dst);
+    iemVmxVmreadNoCheck(pVmcs, pu64Dst, u64VmcsField);
+}
+
+
+/**
+ * Interface for HM and EM to write a VMCS field in the nested-guest VMCS.
+ *
+ * It is ASSUMED the caller knows what they're doing. No VMWRITE instruction checks
+ * are performed. Bounds checks are strict builds only.
+ *
+ * @param   pVmcs           Pointer to the virtual VMCS.
+ * @param   u64VmcsField    The VMCS field.
+ * @param   u64Val          The value to write.
+ *
+ * @remarks May be called with interrupts disabled.
+ * @todo    This should probably be moved to CPUM someday.
+ */
+VMM_INT_DECL(void) IEMWriteVmxVmcsField(PVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t u64Val)
+{
+    AssertPtr(pVmcs);
+    iemVmxVmwriteNoCheck(pVmcs, u64Val, u64VmcsField);
+}
+
+
+/**
  * Interface for HM and EM to virtualize x2APIC MSR accesses.
  *
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 79342)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 79343)
@@ -2609,6 +2609,9 @@
         Log3(("vmexit: Loading host-state failed. uExitReason=%u rc=%Rrc\n", uExitReason, VBOXSTRICTRC_VAL(rcStrict)));
 
+    /* Notify HM that the current VMCS fields have been modified. */
+    HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
+
     /* Notify HM that we've completed the VM-exit. */
-    HMNotifyVmxNstGstVmexit(pVCpu, &pVCpu->cpum.GstCtx);
+    HMNotifyVmxNstGstVmexit(pVCpu);
 
     /* We're no longer in nested-guest execution mode. */
@@ -4573,5 +4576,5 @@
         if ((uRvi >> 4) > (uPpr >> 4))
         {
-            Log2(("eval_virt_intrs: uRvi=%#x uPpr=%#x - Signaling pending interrupt\n", uRvi, uPpr));
+            Log2(("eval_virt_intrs: uRvi=%#x uPpr=%#x - Signalling pending interrupt\n", uRvi, uPpr));
             VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
         }
@@ -5709,5 +5712,5 @@
         Assert(pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pShadowVmcs));
         int rc = PGMPhysSimpleReadGCPhys(pVCpu->CTX_SUFF(pVM), pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pShadowVmcs),
-                                         GCPhysShadowVmcs, VMX_V_VMCS_SIZE);
+                                         GCPhysShadowVmcs, VMX_V_SHADOW_VMCS_SIZE);
         if (RT_SUCCESS(rc))
         { /* likely */ }
@@ -7531,5 +7534,53 @@
 
 /**
- * VMREAD common (memory/register) instruction execution worker
+ * VMREAD instruction execution worker that does not perform any validation checks.
+ *
+ * Callers are expected to have performed the necessary checks and to ensure the
+ * VMREAD will succeed.
+ *
+ * @param   pVmcs           Pointer to the virtual VMCS.
+ * @param   pu64Dst         Where to write the VMCS value.
+ * @param   u64VmcsField    The VMCS field.
+ *
+ * @remarks May be called with interrupts disabled.
+ */
+IEM_STATIC void iemVmxVmreadNoCheck(PCVMXVVMCS pVmcs, uint64_t *pu64Dst, uint64_t u64VmcsField)
+{
+    VMXVMCSFIELD VmcsField;
+    VmcsField.u = u64VmcsField;
+    uint8_t  const uWidth     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
+    uint8_t  const uType      = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
+    uint8_t  const uWidthType = (uWidth << 2) | uType;
+    uint8_t  const uIndex     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
+    Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
+    uint16_t const offField   = g_aoffVmcsMap[uWidthType][uIndex];
+    Assert(offField < VMX_V_VMCS_SIZE);
+    AssertCompile(VMX_V_SHADOW_VMCS_SIZE == VMX_V_VMCS_SIZE);
+
+    /*
+     * Read the VMCS component based on the field's effective width.
+     *
+     * The effective width is 64-bit fields adjusted to 32-bits if the access-type
+     * indicates high bits (little endian).
+     *
+     * Note! The caller is responsible to trim the result and update registers
+     * or memory locations are required. Here we just zero-extend to the largest
+     * type (i.e. 64-bits).
+     */
+    uint8_t const *pbVmcs    = (uint8_t const *)pVmcs;
+    uint8_t const *pbField   = pbVmcs + offField;
+    uint8_t const  uEffWidth = HMVmxGetVmcsFieldWidthEff(VmcsField.u);
+    switch (uEffWidth)
+    {
+        case VMX_VMCSFIELD_WIDTH_64BIT:
+        case VMX_VMCSFIELD_WIDTH_NATURAL: *pu64Dst = *(uint64_t const *)pbField; break;
+        case VMX_VMCSFIELD_WIDTH_32BIT:   *pu64Dst = *(uint32_t const *)pbField; break;
+        case VMX_VMCSFIELD_WIDTH_16BIT:   *pu64Dst = *(uint16_t const *)pbField; break;
+    }
+}
+
+
+/**
+ * VMREAD common (memory/register) instruction execution worker.
  *
  * @returns Strict VBox status code.
@@ -7603,42 +7654,11 @@
 
     /*
-     * Setup reading from the current or shadow VMCS.
-     */
-    uint8_t *pbVmcs;
-    if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
-        pbVmcs = (uint8_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
-    else
-        pbVmcs = (uint8_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pShadowVmcs);
-    Assert(pbVmcs);
-
-    VMXVMCSFIELD VmcsField;
-    VmcsField.u = u64VmcsField;
-    uint8_t  const uWidth     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
-    uint8_t  const uType      = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
-    uint8_t  const uWidthType = (uWidth << 2) | uType;
-    uint8_t  const uIndex     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
-    AssertReturn(uIndex <= VMX_V_VMCS_MAX_INDEX, VERR_IEM_IPE_2);
-    uint16_t const offField   = g_aoffVmcsMap[uWidthType][uIndex];
-    Assert(offField < VMX_V_VMCS_SIZE);
-
-    /*
-     * Read the VMCS component based on the field's effective width.
-     *
-     * The effective width is 64-bit fields adjusted to 32-bits if the access-type
-     * indicates high bits (little endian).
-     *
-     * Note! The caller is responsible to trim the result and update registers
-     * or memory locations are required. Here we just zero-extend to the largest
-     * type (i.e. 64-bits).
-     */
-    uint8_t      *pbField   = pbVmcs + offField;
-    uint8_t const uEffWidth = HMVmxGetVmcsFieldWidthEff(VmcsField.u);
-    switch (uEffWidth)
-    {
-        case VMX_VMCSFIELD_WIDTH_64BIT:
-        case VMX_VMCSFIELD_WIDTH_NATURAL: *pu64Dst = *(uint64_t *)pbField; break;
-        case VMX_VMCSFIELD_WIDTH_32BIT:   *pu64Dst = *(uint32_t *)pbField; break;
-        case VMX_VMCSFIELD_WIDTH_16BIT:   *pu64Dst = *(uint16_t *)pbField; break;
-    }
+     * Reading from the current or shadow VMCS.
+     */
+    PCVMXVVMCS pVmcs = !IEM_VMX_IS_NON_ROOT_MODE(pVCpu)
+                     ? pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs)
+                     : pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pShadowVmcs);
+    Assert(pVmcs);
+    iemVmxVmreadNoCheck(pVmcs, pu64Dst, u64VmcsField);
     return VINF_SUCCESS;
 }
@@ -7740,4 +7760,49 @@
     Log(("vmread/mem: iemVmxVmreadCommon failed rc=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     return rcStrict;
+}
+
+
+/**
+ * VMWRITE instruction execution worker that does not perform any validation
+ * checks.
+ *
+ * Callers are expected to have performed the necessary checks and to ensure the
+ * VMWRITE will succeed.
+ *
+ * @param   pVmcs           Pointer to the virtual VMCS.
+ * @param   u64Val          The value to write.
+ * @param   u64VmcsField    The VMCS field.
+ *
+ * @remarks May be called with interrupts disabled.
+ */
+IEM_STATIC void iemVmxVmwriteNoCheck(PVMXVVMCS pVmcs, uint64_t u64Val, uint64_t u64VmcsField)
+{
+    VMXVMCSFIELD VmcsField;
+    VmcsField.u = u64VmcsField;
+    uint8_t  const uWidth     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
+    uint8_t  const uType      = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
+    uint8_t  const uWidthType = (uWidth << 2) | uType;
+    uint8_t  const uIndex     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
+    Assert(uIndex <= VMX_V_VMCS_MAX_INDEX);
+    uint16_t const offField   = g_aoffVmcsMap[uWidthType][uIndex];
+    Assert(offField < VMX_V_VMCS_SIZE);
+    AssertCompile(VMX_V_SHADOW_VMCS_SIZE == VMX_V_VMCS_SIZE);
+
+    /*
+     * Write the VMCS component based on the field's effective width.
+     *
+     * The effective width is 64-bit fields adjusted to 32-bits if the access-type
+     * indicates high bits (little endian).
+     */
+    uint8_t      *pbVmcs    = (uint8_t *)pVmcs;
+    uint8_t      *pbField   = pbVmcs + offField;
+    uint8_t const uEffWidth = HMVmxGetVmcsFieldWidthEff(VmcsField.u);
+    switch (uEffWidth)
+    {
+        case VMX_VMCSFIELD_WIDTH_64BIT:
+        case VMX_VMCSFIELD_WIDTH_NATURAL: *(uint64_t *)pbField = u64Val; break;
+        case VMX_VMCSFIELD_WIDTH_32BIT:   *(uint32_t *)pbField = u64Val; break;
+        case VMX_VMCSFIELD_WIDTH_16BIT:   *(uint16_t *)pbField = u64Val; break;
+    }
 }
 
@@ -7858,38 +7923,16 @@
 
     /*
-     * Setup writing to the current or shadow VMCS.
-     */
-    uint8_t *pbVmcs;
-    if (!IEM_VMX_IS_NON_ROOT_MODE(pVCpu))
-        pbVmcs = (uint8_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
-    else
-        pbVmcs = (uint8_t *)pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pShadowVmcs);
-    Assert(pbVmcs);
-
-    VMXVMCSFIELD VmcsField;
-    VmcsField.u = u64VmcsField;
-    uint8_t  const uWidth     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_WIDTH);
-    uint8_t  const uType      = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_TYPE);
-    uint8_t  const uWidthType = (uWidth << 2) | uType;
-    uint8_t  const uIndex     = RT_BF_GET(VmcsField.u, VMX_BF_VMCSFIELD_INDEX);
-    AssertReturn(uIndex <= VMX_V_VMCS_MAX_INDEX, VERR_IEM_IPE_2);
-    uint16_t const offField   = g_aoffVmcsMap[uWidthType][uIndex];
-    Assert(offField < VMX_V_VMCS_SIZE);
-
-    /*
-     * Write the VMCS component based on the field's effective width.
-     *
-     * The effective width is 64-bit fields adjusted to 32-bits if the access-type
-     * indicates high bits (little endian).
-     */
-    uint8_t      *pbField   = pbVmcs + offField;
-    uint8_t const uEffWidth = HMVmxGetVmcsFieldWidthEff(VmcsField.u);
-    switch (uEffWidth)
-    {
-        case VMX_VMCSFIELD_WIDTH_64BIT:
-        case VMX_VMCSFIELD_WIDTH_NATURAL: *(uint64_t *)pbField = u64Val; break;
-        case VMX_VMCSFIELD_WIDTH_32BIT:   *(uint32_t *)pbField = u64Val; break;
-        case VMX_VMCSFIELD_WIDTH_16BIT:   *(uint16_t *)pbField = u64Val; break;
-    }
+     * Write to the current or shadow VMCS.
+     */
+    bool const fInVmxNonRootMode = IEM_VMX_IS_NON_ROOT_MODE(pVCpu);
+    PVMXVVMCS pVmcs = !fInVmxNonRootMode
+                    ? pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs)
+                    : pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pShadowVmcs);
+    Assert(pVmcs);
+    iemVmxVmwriteNoCheck(pVmcs, u64Val, u64VmcsField);
+
+    /* Notify HM that the VMCS content might have changed. */
+    if (!fInVmxNonRootMode)
+        HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
 
     iemVmxVmSucceed(pVCpu);
@@ -8231,5 +8274,8 @@
         rc = iemVmxReadCurrentVmcsFromGstMem(pVCpu);
         if (RT_SUCCESS(rc))
-        { /* likely */ }
+        {
+            /* Notify HM that a new, current VMCS is loaded. */
+            HMNotifyVmxNstGstCurrentVmcsChanged(pVCpu);
+        }
         else
         {
