Index: trunk/src/VBox/VMM/VMMAll/CPUMAllCpuId.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/CPUMAllCpuId.cpp	(revision 107702)
+++ trunk/src/VBox/VMM/VMMAll/CPUMAllCpuId.cpp	(revision 107703)
@@ -1644,4 +1644,101 @@
 }
 
+
+/**
+ * Helper for extracting feature bits from IA32_ARCH_CAPABILITIES.
+ */
+static void cpumCpuIdExplodeArchCapabilities(CPUMFEATURESX86 *pFeatures, bool fHasArchCap, uint64_t fArchVal)
+{
+    Assert(fHasArchCap || fArchVal == 0);
+    pFeatures->fArchCap                = fHasArchCap;
+    pFeatures->fArchRdclNo             = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RDCL_NO);
+    pFeatures->fArchIbrsAll            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IBRS_ALL);
+    pFeatures->fArchRsbOverride        = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RSBO);
+    pFeatures->fArchVmmNeedNotFlushL1d = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D);
+#if 0
+    pFeatures->fArchSsbNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_SSB_NO);
+#endif
+    pFeatures->fArchMdsNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MDS_NO);
+#if 0
+    pFeatures->fArchIfPschangeMscNo    = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IF_PSCHANGE_MC_NO);
+    pFeatures->fArchTsxCtrl            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_TSX_CTRL);
+    pFeatures->fArchTaaNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_TAA_NO);
+    pFeatures->fArchMiscPackageCtrls   = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MISC_PACKAGE_CTRLS);
+    pFeatures->fArchEnergyFilteringCtl = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_ENERGY_FILTERING_CTL);
+    pFeatures->fArchDoitm              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_DOITM);
+    pFeatures->fArchSbdrSsdpNo         = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_SBDR_SSDP_NO);
+    pFeatures->fArchFbsdpNo            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_FBSDP_NO);
+    pFeatures->fArchPsdpNo             = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_PSDP_NO);
+    pFeatures->fArchFbClear            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_FB_CLEAR);
+    pFeatures->fArchFbClearCtrl        = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_FB_CLEAR_CTRL);
+    pFeatures->fArchRrsba              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RRSBA);
+    pFeatures->fArchBhiNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_BHI_NO);
+    pFeatures->fArchXapicDisableStatus = RT_BOOL(fArchVal & XAPIC_DISABLE_STATUS);
+    pFeatures->fArchOverclockingStatus = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_OVERCLOCKING_STATUS);
+    pFeatures->fArchPbrsbNo            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_PBRSB_NO);
+    pFeatures->fArchGdsCtrl            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_GDS_CTRL);
+    pFeatures->fArchGdsNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_GDS_NO);
+    pFeatures->fArchRfdsNo             = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RFDS_NO);
+    pFeatures->fArchRfdsClear          = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RFDS_CLEAR);
+    pFeatures->fArchIgnUmonitorSupport = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IGN_UMONITOR_SUPPORT);
+    pFeatures->fArchMonUmonMitigSupport= RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MON_UMON_MITIG_SUPPORT);
+#endif
+}
+
+
+# if defined(VBOX_VMM_TARGET_X86) || defined(VBOX_VMM_TARGET_AGNOSTIC)
+/**
+ * Sets the guest IA32_ARCH_CAPABILITIES value and associated feature bits.
+ */
+void cpumCpuIdSetGuestArchCapabilities(PVMCC pVM, bool fHasArchCap, uint64_t fArchVal, bool fHasIbrs)
+{
+    if (!fHasArchCap)
+        fArchVal = 0;
+    else if (!fHasIbrs)
+        fArchVal &= ~MSR_IA32_ARCH_CAP_F_IBRS_ALL;
+    fArchVal &= ~(  RT_BIT_64(9)
+                  | MSR_IA32_ARCH_CAP_F_MISC_PACKAGE_CTRLS
+                  | MSR_IA32_ARCH_CAP_F_ENERGY_FILTERING_CTL
+                  | MSR_IA32_ARCH_CAP_F_DOITM
+                  | RT_BIT_64(16)
+                  | RT_BIT_64(22)
+                  | MSR_IA32_ARCH_CAP_F_FB_CLEAR_CTRL
+                    /** @todo mask off MSR_IA32_ARCH_CAP_F_RRSBA ? */
+                  | MSR_IA32_ARCH_CAP_F_XAPIC_DISABLE_STATUS
+                  | MSR_IA32_ARCH_CAP_F_OVERCLOCKING_STATUS /** @todo expose IA32_OVERCLOCKING_STATUS */
+                  | MSR_IA32_ARCH_CAP_F_GDS_CTRL
+                  | MSR_IA32_ARCH_CAP_F_IGN_UMONITOR_SUPPORT
+                  | MSR_IA32_ARCH_CAP_F_MON_UMON_MITIG_SUPPORT
+                  | ~(RT_BIT_64(31) - 1U)
+                  );
+    VMCC_FOR_EACH_VMCPU_STMT(pVM, pVCpu->cpum.s.GuestMsrs.msr.ArchCaps = fArchVal);
+
+    cpumCpuIdExplodeArchCapabilities(&pVM->cpum.s.GuestFeatures, fHasArchCap, fArchVal);
+    LogRel(("CPUM: Guest IA32_ARCH_CAPABILITIES = %#RX64\n", fArchVal));
+}
+# endif
+
+
+# if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
+/**
+ * Sets host & guest feature bits & MSRs related to IA32_ARCH_CAPABILITIES.
+ *
+ * ASSUMES this is called after the basic guest features has been exploded.
+ */
+VMM_INT_DECL(void) CPUMCpuIdApplyX86HostArchCapabilities(PVMCC pVM, bool fHasArchCap, uint64_t fHostArchVal)
+{
+    cpumCpuIdExplodeArchCapabilities(const_cast<CPUMFEATURESX86 *>(&pVM->cpum.s.HostFeatures.s), fHasArchCap, fHostArchVal);
+    LogRel(("CPUM: Host IA32_ARCH_CAPABILITIES  = %#RX64\n", fHostArchVal));
+
+# if defined(VBOX_VMM_TARGET_X86) || defined(VBOX_VMM_TARGET_AGNOSTIC)
+#  ifdef VBOX_VMM_TARGET_AGNOSTIC
+    /** @todo arm on x86: check VM target. */
+#  endif
+    cpumCpuIdSetGuestArchCapabilities(pVM, fHasArchCap && pVM->cpum.s.GuestFeatures.fArchCap,
+                                      fHostArchVal, pVM->cpum.s.GuestFeatures.fIbrs);
+#  endif
+}
+# endif /* defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) */
+
 #endif /* defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) || defined(VBOX_VMM_TARGET_X86) */
 
Index: trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp	(revision 107702)
+++ trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp	(revision 107703)
@@ -361,12 +361,9 @@
          * Copy MSR_IA32_ARCH_CAPABILITIES bits over into the host and guest feature
          * structure and as well as the guest MSR.
-         * Note! we assume this happens after the CPUMR3Init is done, so CPUID bits are settled.
+         * Note! We assume this happens after the CPUMR3Init is done, so CPUID bits are settled.
          */
-        pVM->cpum.s.HostFeatures.s.fArchRdclNo             = 0;
-        pVM->cpum.s.HostFeatures.s.fArchIbrsAll            = 0;
-        pVM->cpum.s.HostFeatures.s.fArchRsbOverride        = 0;
-        pVM->cpum.s.HostFeatures.s.fArchVmmNeedNotFlushL1d = 0;
-        pVM->cpum.s.HostFeatures.s.fArchMdsNo              = 0;
-        uint32_t const cStdRange = ASMCpuId_EAX(0);
+        uint64_t       fHostArchVal = 0;
+        bool           fHasArchCap  = false;
+        uint32_t const cStdRange    = ASMCpuId_EAX(0);
         if (   RTX86IsValidStdRange(cStdRange)
             && cStdRange >= 7)
@@ -377,32 +374,9 @@
                 && (fFeatures & X86_CPUID_FEATURE_EDX_MSR))
             {
-                /* Host: */
-                uint64_t const fHostArchVal = ASMRdMsr(MSR_IA32_ARCH_CAPABILITIES);
-                uint64_t fArchVal = fHostArchVal;
-                pVM->cpum.s.HostFeatures.s.fArchRdclNo             = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RDCL_NO);
-                pVM->cpum.s.HostFeatures.s.fArchIbrsAll            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IBRS_ALL);
-                pVM->cpum.s.HostFeatures.s.fArchRsbOverride        = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RSBO);
-                pVM->cpum.s.HostFeatures.s.fArchVmmNeedNotFlushL1d = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D);
-                pVM->cpum.s.HostFeatures.s.fArchMdsNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MDS_NO);
-
-                /* guest: */
-                if (!pVM->cpum.s.GuestFeatures.fArchCap)
-                    fArchVal = 0;
-                else if (!pVM->cpum.s.GuestFeatures.fIbrs)
-                    fArchVal &= ~MSR_IA32_ARCH_CAP_F_IBRS_ALL;
-                VMCC_FOR_EACH_VMCPU_STMT(pVM, pVCpu->cpum.s.GuestMsrs.msr.ArchCaps = fArchVal);
-                pVM->cpum.s.GuestFeatures.fArchRdclNo             = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RDCL_NO);
-                pVM->cpum.s.GuestFeatures.fArchIbrsAll            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IBRS_ALL);
-                pVM->cpum.s.GuestFeatures.fArchRsbOverride        = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RSBO);
-                pVM->cpum.s.GuestFeatures.fArchVmmNeedNotFlushL1d = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D);
-                pVM->cpum.s.GuestFeatures.fArchMdsNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MDS_NO);
-                LogRel(("CPUM: IA32_ARCH_CAPABILITIES (Host=%#RX64 Guest=%#RX64)\n", fHostArchVal, fArchVal));
+                fHostArchVal = ASMRdMsr(MSR_IA32_ARCH_CAPABILITIES);
+                fHasArchCap  = true;
             }
-            else
-            {
-                pVM->cpum.s.HostFeatures.s.fArchCap = 0;
-                LogRel(("CPUM: IA32_ARCH_CAPABILITIES unsupported\n"));
-            }
-        }
+        }
+        CPUMCpuIdApplyX86HostArchCapabilities(pVM, fHasArchCap, fHostArchVal);
 
         /*
Index: trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp	(revision 107702)
+++ trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp	(revision 107703)
@@ -2203,17 +2203,17 @@
     /*
      * Get MSR_IA32_ARCH_CAPABILITIES and expand it into the host feature structure.
+     *
      * This is only available with 11.0+ (BigSur) as the required API is only available there,
      * we could in theory initialize this when creating the EMTs using hv_vcpu_read_msr() but
      * the required vCPU handle is created after CPUM was initialized which is too late.
      * Given that the majority of users is on 11.0 and later we don't care for now.
+     *
+     * (Yes, this is done after CPUM init.)
      */
+    uint64_t fHostArchVal = 0;
+    bool     fHasArchCap  = false;
     if (   hrc == HV_SUCCESS
         && hv_vmx_get_msr_info)
     {
-        g_CpumHostFeatures.s.fArchRdclNo             = 0;
-        g_CpumHostFeatures.s.fArchIbrsAll            = 0;
-        g_CpumHostFeatures.s.fArchRsbOverride        = 0;
-        g_CpumHostFeatures.s.fArchVmmNeedNotFlushL1d = 0;
-        g_CpumHostFeatures.s.fArchMdsNo              = 0;
         uint32_t const cStdRange = ASMCpuId_EAX(0);
         if (   RTX86IsValidStdRange(cStdRange)
@@ -2226,19 +2226,12 @@
                 && (fStdFeaturesEdx    & X86_CPUID_FEATURE_EDX_MSR))
             {
-                uint64_t fArchVal;
-                hrc = hv_vmx_get_msr_info(HV_VMX_INFO_MSR_IA32_ARCH_CAPABILITIES, &fArchVal);
-                if (hrc == HV_SUCCESS)
-                {
-                    g_CpumHostFeatures.s.fArchRdclNo             = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RDCL_NO);
-                    g_CpumHostFeatures.s.fArchIbrsAll            = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_IBRS_ALL);
-                    g_CpumHostFeatures.s.fArchRsbOverride        = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_RSBO);
-                    g_CpumHostFeatures.s.fArchVmmNeedNotFlushL1d = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_VMM_NEED_NOT_FLUSH_L1D);
-                    g_CpumHostFeatures.s.fArchMdsNo              = RT_BOOL(fArchVal & MSR_IA32_ARCH_CAP_F_MDS_NO);
-                }
+                fHasArchCap = true;
+                hrc = hv_vmx_get_msr_info(HV_VMX_INFO_MSR_IA32_ARCH_CAPABILITIES, &fHostArchVal);
+                if (hrc != HV_SUCCESS)
+                    fHostArchVal = 0;
             }
-            else
-                g_CpumHostFeatures.s.fArchCap = 0;
-        }
-    }
+        }
+    }
+    CPUMCpuIdApplyX86HostArchCapabilities(pVM, fHasArchCap, fHostArchVal);
 
     return nemR3DarwinHvSts2Rc(hrc);
