Index: /trunk/include/VBox/vmm/hm.h
===================================================================
--- /trunk/include/VBox/vmm/hm.h	(revision 71528)
+++ /trunk/include/VBox/vmm/hm.h	(revision 71529)
@@ -161,5 +161,5 @@
  * @{ */
 VMM_INT_DECL(TRPMEVENT)         HMSvmEventToTrpmEventType(PCSVMEVENT pSvmEvent);
-VMM_INT_DECL(int)               HMSvmGetMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint32_t *puMsrpmBit);
+VMM_INT_DECL(int)               HMSvmGetMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit);
 VMM_INT_DECL(bool)              HMSvmIsIOInterceptActive(void *pvIoBitmap, uint16_t u16Port, SVMIOIOTYPE enmIoType, uint8_t cbReg,
                                                          uint8_t cAddrSizeBits, uint8_t iEffSeg, bool fRep, bool fStrIo,
Index: /trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp	(revision 71528)
+++ /trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp	(revision 71529)
@@ -317,5 +317,5 @@
  *                      returned in @a pbOffMsrpm.
  */
-VMM_INT_DECL(int) HMSvmGetMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint32_t *puMsrpmBit)
+VMM_INT_DECL(int) HMSvmGetMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit)
 {
     Assert(pbOffMsrpm);
@@ -335,6 +335,7 @@
     {
         /* Pentium-compatible MSRs. */
-        *pbOffMsrpm = 0;
-        *puMsrpmBit = idMsr << 1;
+        uint32_t const bitoffMsr = idMsr << 1;
+        *pbOffMsrpm = bitoffMsr >> 3;
+        *puMsrpmBit = bitoffMsr & 7;
         return VINF_SUCCESS;
     }
@@ -344,6 +345,7 @@
     {
         /* AMD Sixth Generation x86 Processor MSRs. */
-        *pbOffMsrpm = 0x800;
-        *puMsrpmBit = (idMsr - 0xc0000000) << 1;
+        uint32_t const bitoffMsr = (idMsr - 0xc0000000) << 1;
+        *pbOffMsrpm = 0x800 + (bitoffMsr >> 3);
+        *puMsrpmBit = bitoffMsr & 7;
         return VINF_SUCCESS;
     }
@@ -353,6 +355,7 @@
     {
         /* AMD Seventh and Eighth Generation Processor MSRs. */
-        *pbOffMsrpm = 0x1000;
-        *puMsrpmBit = (idMsr - 0xc0010000) << 1;
+        uint32_t const bitoffMsr = (idMsr - 0xc0010000) << 1;
+        *pbOffMsrpm = 0x1000 + (bitoffMsr >> 3);
+        *puMsrpmBit = bitoffMsr & 7;
         return VINF_SUCCESS;
     }
Index: /trunk/src/VBox/VMM/VMMR0/HMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 71528)
+++ /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 71529)
@@ -632,4 +632,9 @@
         g_HmR0.aCpuInfo[i].HCPhysMemObj = NIL_RTHCPHYS;
         g_HmR0.aCpuInfo[i].pvMemObj     = NULL;
+#ifdef VBOX_WITH_NESTED_HWVIRT
+        g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm      = NIL_RTR0MEMOBJ;
+        g_HmR0.aCpuInfo[i].n.svm.HCPhysNstGstMsrpm = NIL_RTHCPHYS;
+        g_HmR0.aCpuInfo[i].n.svm.pvNstGstMsrpm     = NULL;
+#endif
     }
 
@@ -785,4 +790,13 @@
                 g_HmR0.aCpuInfo[i].pvMemObj     = NULL;
             }
+#ifdef VBOX_WITH_NESTED_HWVIRT
+            if (g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm != NIL_RTR0MEMOBJ)
+            {
+                RTR0MemObjFree(g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm, false);
+                g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm      = NIL_RTR0MEMOBJ;
+                g_HmR0.aCpuInfo[i].n.svm.HCPhysNstGstMsrpm = NIL_RTHCPHYS;
+                g_HmR0.aCpuInfo[i].n.svm.pvNstGstMsrpm     = NULL;
+            }
+#endif
         }
     }
@@ -924,10 +938,15 @@
     for (unsigned i = 0; i < RT_ELEMENTS(g_HmR0.aCpuInfo); i++)
     {
-        Assert(g_HmR0.aCpuInfo[i].hMemObj == NIL_RTR0MEMOBJ);
+        Assert(g_HmR0.aCpuInfo[i].hMemObj      == NIL_RTR0MEMOBJ);
         Assert(g_HmR0.aCpuInfo[i].HCPhysMemObj == NIL_RTHCPHYS);
-        Assert(g_HmR0.aCpuInfo[i].pvMemObj == NULL);
+        Assert(g_HmR0.aCpuInfo[i].pvMemObj     == NULL);
         Assert(!g_HmR0.aCpuInfo[i].fConfigured);
         Assert(!g_HmR0.aCpuInfo[i].cTlbFlushes);
         Assert(!g_HmR0.aCpuInfo[i].uCurrentAsid);
+# ifdef VBOX_WITH_NESTED_HWVIRT
+        Assert(g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm      == NIL_RTR0MEMOBJ);
+        Assert(g_HmR0.aCpuInfo[i].n.svm.HCPhysNstGstMsrpm == NIL_RTHCPHYS);
+        Assert(g_HmR0.aCpuInfo[i].n.svm.pvNstGstMsrpm     == NULL);
+# endif
     }
 #endif
@@ -959,5 +978,7 @@
         {
             Assert(g_HmR0.aCpuInfo[i].hMemObj == NIL_RTR0MEMOBJ);
-
+#ifdef VBOX_WITH_NESTED_HWVIRT
+            Assert(g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm == NIL_RTR0MEMOBJ);
+#endif
             if (RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(i)))
             {
@@ -973,4 +994,18 @@
                 AssertPtr(g_HmR0.aCpuInfo[i].pvMemObj);
                 ASMMemZeroPage(g_HmR0.aCpuInfo[i].pvMemObj);
+
+#ifdef VBOX_WITH_NESTED_HWVIRT
+                rc = RTR0MemObjAllocCont(&g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT,
+                                         false /* executable R0 mapping */);
+                AssertLogRelRCReturn(rc, rc);
+
+                g_HmR0.aCpuInfo[i].n.svm.HCPhysNstGstMsrpm = RTR0MemObjGetPagePhysAddr(g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm, 0);
+                Assert(g_HmR0.aCpuInfo[i].n.svm.HCPhysNstGstMsrpm != NIL_RTHCPHYS);
+                Assert(!(g_HmR0.aCpuInfo[i].n.svm.HCPhysNstGstMsrpm & PAGE_OFFSET_MASK));
+
+                g_HmR0.aCpuInfo[i].n.svm.pvNstGstMsrpm    = RTR0MemObjAddress(g_HmR0.aCpuInfo[i].n.svm.hNstGstMsrpm);
+                AssertPtr(g_HmR0.aCpuInfo[i].n.svm.pvNstGstMsrpm);
+                ASMMemFill32(g_HmR0.aCpuInfo[i].n.svm.pvNstGstMsrpm, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT, UINT32_C(0xffffffff));
+#endif
             }
         }
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 71528)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 71529)
@@ -326,5 +326,5 @@
 *   Internal Functions                                                                                                           *
 *********************************************************************************************************************************/
-static void hmR0SvmSetMsrPermission(PSVMVMCB pVmcb, uint8_t *pbMsrBitmap, unsigned uMsr, SVMMSREXITREAD enmRead,
+static void hmR0SvmSetMsrPermission(PCPUMCTX pCtx, uint8_t *pbMsrBitmap, unsigned uMsr, SVMMSREXITREAD enmRead,
                                     SVMMSREXITWRITE enmWrite);
 static void hmR0SvmPendingEventToTrpmTrap(PVMCPU pVCpu);
@@ -393,34 +393,24 @@
 *********************************************************************************************************************************/
 /** Ring-0 memory object for the IO bitmap. */
-RTR0MEMOBJ                  g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
+static RTR0MEMOBJ           g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
 /** Physical address of the IO bitmap. */
-RTHCPHYS                    g_HCPhysIOBitmap  = 0;
+static RTHCPHYS             g_HCPhysIOBitmap;
 /** Pointer to the IO bitmap. */
-R0PTRTYPE(void *)           g_pvIOBitmap      = NULL;
-
-#ifdef VBOX_WITH_NESTED_HWVIRT
-/** Ring-0 memory object for the nested-guest MSRPM bitmap. */
-RTR0MEMOBJ                  g_hMemObjNstGstMsrBitmap = NIL_RTR0MEMOBJ;
-/** Physical address of the nested-guest MSRPM bitmap. */
-RTHCPHYS                    g_HCPhysNstGstMsrBitmap  = 0;
-/** Pointer to the  nested-guest MSRPM bitmap. */
-R0PTRTYPE(void *)           g_pvNstGstMsrBitmap      = NULL;
-#endif
-
+static R0PTRTYPE(void *)        g_pvIOBitmap;
 
 #ifdef VBOX_STRICT
-# define HMSVM_LOG_CS          RT_BIT_32(0)
-# define HMSVM_LOG_SS          RT_BIT_32(1)
-# define HMSVM_LOG_FS          RT_BIT_32(2)
-# define HMSVM_LOG_GS          RT_BIT_32(3)
-# define HMSVM_LOG_LBR         RT_BIT_32(4)
-# define HMSVM_LOG_ALL         (  HMSVM_LOG_CS \
-                                | HMSVM_LOG_SS \
-                                | HMSVM_LOG_FS \
-                                | HMSVM_LOG_GS \
-                                | HMSVM_LOG_LBR)
-
-/**
- * Dumps CPU state and additional info. to the logger for diagnostics.
+# define HMSVM_LOG_CS           RT_BIT_32(0)
+# define HMSVM_LOG_SS           RT_BIT_32(1)
+# define HMSVM_LOG_FS           RT_BIT_32(2)
+# define HMSVM_LOG_GS           RT_BIT_32(3)
+# define HMSVM_LOG_LBR          RT_BIT_32(4)
+# define HMSVM_LOG_ALL          (  HMSVM_LOG_CS \
+                                 | HMSVM_LOG_SS \
+                                 | HMSVM_LOG_FS \
+                                 | HMSVM_LOG_GS \
+                                 | HMSVM_LOG_LBR)
+
+/**
+ * Dumps virtual CPU state and additional info. to the logger for diagnostics.
  *
  * @param   pVCpu       The cross context virtual CPU structure.
@@ -468,5 +458,5 @@
     NOREF(pVmcbGuest);
 }
-#endif
+#endif  /* VBOX_STRICT */
 
 
@@ -585,6 +575,6 @@
 {
     /*
-     * Allocate 12 KB for the IO bitmap. Since this is non-optional and we always intercept all IO accesses, it's done
-     * once globally here instead of per-VM.
+     * Allocate 12 KB (3 pages) for the IO bitmap. Since this is non-optional and we always
+     * intercept all IO accesses, it's done once globally here instead of per-VM.
      */
     Assert(g_hMemObjIOBitmap == NIL_RTR0MEMOBJ);
@@ -599,20 +589,4 @@
     ASMMemFill32(g_pvIOBitmap, SVM_IOPM_PAGES << X86_PAGE_4K_SHIFT, UINT32_C(0xffffffff));
 
-#ifdef VBOX_WITH_NESTED_HWVIRT
-    /*
-     * Allocate 8 KB for the MSR permission bitmap for the nested-guest.
-     */
-    Assert(g_hMemObjNstGstMsrBitmap == NIL_RTR0MEMOBJ);
-    rc = RTR0MemObjAllocCont(&g_hMemObjNstGstMsrBitmap, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT, false /* fExecutable */);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    g_pvNstGstMsrBitmap     = RTR0MemObjAddress(g_hMemObjNstGstMsrBitmap);
-    g_HCPhysNstGstMsrBitmap = RTR0MemObjGetPagePhysAddr(g_hMemObjNstGstMsrBitmap, 0 /* iPage */);
-
-    /* Set all bits to intercept all MSR accesses. */
-    ASMMemFill32(g_pvNstGstMsrBitmap, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT, UINT32_C(0xffffffff));
-#endif
-
     return VINF_SUCCESS;
 }
@@ -631,14 +605,4 @@
         g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
     }
-
-#ifdef VBOX_WITH_NESTED_HWVIRT
-    if (g_hMemObjNstGstMsrBitmap != NIL_RTR0MEMOBJ)
-    {
-        RTR0MemObjFree(g_hMemObjNstGstMsrBitmap, true /* fFreeMappings */);
-        g_pvNstGstMsrBitmap      = NULL;
-        g_HCPhysNstGstMsrBitmap  = 0;
-        g_hMemObjNstGstMsrBitmap = NIL_RTR0MEMOBJ;
-    }
-#endif
 }
 
@@ -850,21 +814,25 @@
 
 /**
- * Sets the permission bits for the specified MSR in the MSRPM.
- *
- * @param   pVmcb           Pointer to the VM control block.
+ * Sets the permission bits for the specified MSR in the MSRPM bitmap.
+ *
+ * @param   pCtx            Pointer to the guest-CPU or nested-guest-CPU context.
  * @param   pbMsrBitmap     Pointer to the MSR bitmap.
- * @param   uMsr            The MSR for which the access permissions are being set.
+ * @param   idMsr           The MSR for which the permissions are being set.
  * @param   enmRead         MSR read permissions.
  * @param   enmWrite        MSR write permissions.
- */
-static void hmR0SvmSetMsrPermission(PSVMVMCB pVmcb, uint8_t *pbMsrBitmap, unsigned uMsr, SVMMSREXITREAD enmRead,
+ *
+ * @remarks This function does -not- clear the VMCB clean bits for MSRPM. The
+ *          caller needs to take care of this.
+ */
+static void hmR0SvmSetMsrPermission(PCPUMCTX pCtx, uint8_t *pbMsrBitmap, uint32_t idMsr, SVMMSREXITREAD enmRead,
                                     SVMMSREXITWRITE enmWrite)
 {
-    uint16_t offMsrpm;
-    uint32_t uMsrpmBit;
-    int rc = HMSvmGetMsrpmOffsetAndBit(uMsr, &offMsrpm, &uMsrpmBit);
+    bool const  fInNestedGuestMode = CPUMIsGuestInSvmNestedHwVirtMode(pCtx);
+    uint16_t    offMsrpm;
+    uint8_t     uMsrpmBit;
+    int rc = HMSvmGetMsrpmOffsetAndBit(idMsr, &offMsrpm, &uMsrpmBit);
     AssertRC(rc);
 
-    Assert(uMsrpmBit < 0x3fff);
+    Assert(uMsrpmBit == 0 || uMsrpmBit == 2 || uMsrpmBit == 4 || uMsrpmBit == 6);
     Assert(offMsrpm < SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT);
 
@@ -873,12 +841,40 @@
         ASMBitSet(pbMsrBitmap, uMsrpmBit);
     else
-        ASMBitClear(pbMsrBitmap, uMsrpmBit);
+    {
+        if (!fInNestedGuestMode)
+            ASMBitClear(pbMsrBitmap, uMsrpmBit);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+        else
+        {
+            /* Only clear the bit if the nested-guest is also not intercepting the MSR read.*/
+            uint8_t const *pbNstGstMsrBitmap = (uint8_t *)pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
+            pbNstGstMsrBitmap += offMsrpm;
+            if (!ASMBitTest(pbNstGstMsrBitmap, uMsrpmBit))
+                ASMBitClear(pbMsrBitmap, uMsrpmBit);
+            else
+                Assert(ASMBitTest(pbMsrBitmap, uMsrpmBit));
+        }
+#endif
+    }
 
     if (enmWrite == SVMMSREXIT_INTERCEPT_WRITE)
         ASMBitSet(pbMsrBitmap, uMsrpmBit + 1);
     else
-        ASMBitClear(pbMsrBitmap, uMsrpmBit + 1);
-
-    pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
+    {
+        if (!fInNestedGuestMode)
+            ASMBitClear(pbMsrBitmap, uMsrpmBit + 1);
+#ifdef VBOX_WITH_NESTED_HWVIRT
+        else
+        {
+            /* Only clear the bit if the nested-guest is also not intercepting the MSR write.*/
+            uint8_t const *pbNstGstMsrBitmap = (uint8_t *)pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
+            pbNstGstMsrBitmap += offMsrpm;
+            if (!ASMBitTest(pbNstGstMsrBitmap, uMsrpmBit + 1))
+                ASMBitClear(pbMsrBitmap, uMsrpmBit + 1);
+            else
+                Assert(ASMBitTest(pbMsrBitmap, uMsrpmBit + 1));
+        }
+#endif
+    }
 }
 
@@ -1049,14 +1045,16 @@
          */
         uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.svm.pvMsrBitmap;
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_LSTAR,          SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_CSTAR,          SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K6_STAR,           SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_SF_MASK,        SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_FS_BASE,        SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_GS_BASE,        SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_KERNEL_GS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_IA32_SYSENTER_CS,  SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_IA32_SYSENTER_ESP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_IA32_SYSENTER_EIP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        PCPUMCTX pCtx        = CPUMQueryGuestCtxPtr(pVCpu);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_LSTAR,          SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_CSTAR,          SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K6_STAR,           SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_SF_MASK,        SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_FS_BASE,        SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_GS_BASE,        SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_KERNEL_GS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_IA32_SYSENTER_CS,  SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_IA32_SYSENTER_ESP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_IA32_SYSENTER_EIP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
     }
 
@@ -1969,10 +1967,11 @@
             /* If there are interrupts pending, intercept LSTAR writes, otherwise don't intercept reads or writes. */
             if (fPendingIntr)
-                hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_INTERCEPT_WRITE);
+                hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_INTERCEPT_WRITE);
             else
             {
-                hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+                hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
                 pVCpu->hm.s.svm.fSyncVTpr = true;
             }
+            pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
         }
         else
@@ -2358,4 +2357,27 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT
+/**
+ * Merges the guest and nested-guest MSR permission bitmap.
+ *
+ * If the guest is intercepting an MSR we need to intercept it regardless of
+ * whether the nested-guest is intercepting it or not.
+ *
+ * @param   pHostCpu    Pointer to the physical CPU HM info. struct.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pCtx        Pointer to the nested-guest-CPU context.
+ */
+static void hmR0SvmMergeMsrpm(PHMGLOBALCPUINFO pHostCpu, PVMCPU pVCpu, PCPUMCTX pCtx)
+{
+    uint64_t const *pu64GstMsrpm    = (uint64_t const *)pVCpu->hm.s.svm.pvMsrBitmap;
+    uint64_t const *pu64NstGstMsrpm = (uint64_t const *)pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
+    uint64_t       *pu64DstMsrpm    = (uint64_t *)pHostCpu->n.svm.pvNstGstMsrpm;
+
+    /* MSRPM bytes from offset 0x1800 are reserved, so we stop merging there. */
+    uint32_t const offRsvdQwords = 0x1800 >> 3;
+    for (uint32_t i = 0; i < offRsvdQwords; i++)
+        pu64DstMsrpm[i] = pu64NstGstMsrpm[i] | pu64GstMsrpm[i];
+}
+
+
 /**
  * Caches the nested-guest VMCB fields before we modify them for execution using
@@ -2431,18 +2453,12 @@
          * The IOPM of the nested-guest can be ignored because the the guest always
          * intercepts all IO port accesses. Thus, we'll swap to the guest IOPM rather
-         * into the nested-guest one and swap it back on the #VMEXIT.
+         * than the nested-guest IOPM and swap the field back on the #VMEXIT.
          */
         pVmcbNstGstCtrl->u64IOPMPhysAddr = g_HCPhysIOBitmap;
-
-        /*
-         * Load the host-physical address into the MSRPM rather than the nested-guest
-         * physical address (currently we trap all MSRs in the nested-guest).
-         */
-        pVmcbNstGstCtrl->u64MSRPMPhysAddr = g_HCPhysNstGstMsrBitmap;
 
         /*
          * Use the same nested-paging as the "outer" guest. We can't dynamically
          * switch off nested-paging suddenly while executing a VM (see assertion at the
-         * end of Trap0eHandler in PGMAllBth.h).
+         * end of Trap0eHandler() in PGMAllBth.h).
          */
         pVmcbNstGstCtrl->NestedPaging.n.u1NestedPaging = pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging;
@@ -2457,5 +2473,4 @@
     {
         Assert(pVmcbNstGstCtrl->u64IOPMPhysAddr == g_HCPhysIOBitmap);
-        Assert(pVmcbNstGstCtrl->u64MSRPMPhysAddr = g_HCPhysNstGstMsrBitmap);
         Assert(RT_BOOL(pVmcbNstGstCtrl->NestedPaging.n.u1NestedPaging) == pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
     }
@@ -2532,5 +2547,5 @@
     return rc;
 }
-#endif
+#endif /* VBOX_WITH_NESTED_HWVIRT */
 
 
@@ -4290,4 +4305,5 @@
     hmR0SvmInjectPendingEvent(pVCpu, pCtx, pVmcbNstGst);
 
+    /* Pre-load the guest FPU state. */
     if (!CPUMIsGuestFPUStateActive(pVCpu))
     {
@@ -4306,9 +4322,11 @@
     AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
 
+    PHMGLOBALCPUINFO pHostCpu  = hmR0GetCurrentCpu();
+    RTCPUID const idCurrentCpu = pHostCpu->idCpu;
+    bool const    fMigratedCpu = idCurrentCpu != pVCpu->hm.s.idLastCpu;
+
     /* Setup TSC offsetting. */
-    RTCPUID idCurrentCpu = hmR0GetCurrentCpu()->idCpu;
     if (   pSvmTransient->fUpdateTscOffsetting
-        || idCurrentCpu != pVCpu->hm.s.idLastCpu)   /** @todo is this correct for nested-guests where
-                                                              nested-VCPU<->physical-CPU mapping doesn't exist. */
+        || fMigratedCpu)
     {
         hmR0SvmUpdateTscOffsettingNested(pVM, pVCpu, pCtx, pVmcbNstGst);
@@ -4317,5 +4335,5 @@
 
     /* If we've migrating CPUs, mark the VMCB Clean bits as dirty. */
-    if (idCurrentCpu != pVCpu->hm.s.idLastCpu)
+    if (fMigratedCpu)
         pVmcbNstGst->ctrl.u32VmcbCleanBits = 0;
 
@@ -4334,4 +4352,10 @@
     }
     pSvmTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
+
+    /* Merge the guest and nested-guest MSRPM. */
+    hmR0SvmMergeMsrpm(pHostCpu, pVCpu, pCtx);
+
+    /* Update the nested-guest VMCB to use the newly merged MSRPM. */
+    pVmcbNstGst->ctrl.u64MSRPMPhysAddr = pHostCpu->n.svm.HCPhysNstGstMsrpm;
 
     /* The TLB flushing would've already been setup by the nested-hypervisor. */
@@ -4355,5 +4379,7 @@
         && !(pVmcbNstGst->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSCP))
     {
-        hmR0SvmSetMsrPermission(pVmcbNstGst, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        pVmcbNstGst->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
+
         pVCpu->hm.s.u64HostTscAux = ASMRdMsr(MSR_K8_TSC_AUX);
         uint64_t u64GuestTscAux = CPUMR0GetGuestTscAux(pVCpu);
@@ -4364,5 +4390,6 @@
     else
     {
-        hmR0SvmSetMsrPermission(pVmcbNstGst, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_INTERCEPT_READ, SVMMSREXIT_INTERCEPT_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_INTERCEPT_READ, SVMMSREXIT_INTERCEPT_WRITE);
+        pVmcbNstGst->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
         pSvmTransient->fRestoreTscAuxMsr = false;
     }
@@ -4469,5 +4496,7 @@
         && !(pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSCP))
     {
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
+        pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
+
         pVCpu->hm.s.u64HostTscAux = ASMRdMsr(MSR_K8_TSC_AUX);
         uint64_t u64GuestTscAux = CPUMR0GetGuestTscAux(pVCpu);
@@ -4478,5 +4507,6 @@
     else
     {
-        hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_INTERCEPT_READ, SVMMSREXIT_INTERCEPT_WRITE);
+        hmR0SvmSetMsrPermission(pCtx, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_INTERCEPT_READ, SVMMSREXIT_INTERCEPT_WRITE);
+        pVmcb->ctrl.u32VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
         pSvmTransient->fRestoreTscAuxMsr = false;
     }
@@ -5031,5 +5061,5 @@
     const uint16_t    u16Port       = pIoExitInfo->n.u16Port;
     const SVMIOIOTYPE enmIoType     = (SVMIOIOTYPE)pIoExitInfo->n.u1Type;
-    const uint8_t     cbReg         = (pIoExitInfo->u >> SVM_IOIO_OP_SIZE_SHIFT) & 7;
+    const uint8_t     cbReg         = (pIoExitInfo->u  >> SVM_IOIO_OP_SIZE_SHIFT)   & 7;
     const uint8_t     cAddrSizeBits = ((pIoExitInfo->u >> SVM_IOIO_ADDR_SIZE_SHIFT) & 7) << 4;
     const uint8_t     iEffSeg       = pIoExitInfo->n.u3SEG;
@@ -5122,11 +5152,15 @@
                 uint32_t const idMsr = pCtx->ecx;
                 uint16_t offMsrpm;
-                uint32_t uMsrpmBit;
+                uint8_t  uMsrpmBit;
                 int rc = HMSvmGetMsrpmOffsetAndBit(idMsr, &offMsrpm, &uMsrpmBit);
                 if (RT_SUCCESS(rc))
                 {
-                    void const *pvMsrBitmap    = pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
-                    bool const fInterceptRead  = ASMBitTest(pvMsrBitmap, (offMsrpm << 3) + uMsrpmBit);
-                    bool const fInterceptWrite = ASMBitTest(pvMsrBitmap, (offMsrpm << 3) + uMsrpmBit + 1);
+                    Assert(uMsrpmBit == 0 || uMsrpmBit == 2 || uMsrpmBit == 4 || uMsrpmBit == 6);
+                    Assert(offMsrpm < SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT);
+
+                    uint8_t const *pbMsrBitmap = (uint8_t const *)pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
+                    pbMsrBitmap               += offMsrpm;
+                    bool const fInterceptRead  = ASMBitTest(pbMsrBitmap, uMsrpmBit);
+                    bool const fInterceptWrite = ASMBitTest(pbMsrBitmap, uMsrpmBit + 1);
 
                     if (   (fInterceptWrite && pVmcbNstGstCtrl->u64ExitInfo1 == SVM_EXIT1_MSR_WRITE)
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 71528)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 71529)
@@ -289,4 +289,22 @@
     /** In use by our code. (for power suspend) */
     volatile bool       fInUse;
+#ifdef VBOX_WITH_NESTED_HWVIRT
+    /** Nested-guest union (put data common to SVM/VMX outside the union). */
+    union
+    {
+        /** Nested-guest SVM data. */
+        struct
+        {
+            /** The active nested-guest MSR permission bitmap memory backing. */
+            RTR0MEMOBJ          hNstGstMsrpm;
+            /** The physical address of the first page in hNstGstMsrpm (physcially
+             *  contigous allocation). */
+            RTHCPHYS            HCPhysNstGstMsrpm;
+            /** The address of the active nested-guest MSRPM. */
+            void               *pvNstGstMsrpm;
+        } svm;
+        /** @todo Nested-VMX. */
+    } n;
+#endif
 } HMGLOBALCPUINFO;
 /** Pointer to the per-cpu global information. */
