Changeset 94934 in vbox for trunk/src/VBox/VMM/VMMR0
- Timestamp:
- May 9, 2022 8:41:13 AM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 151342
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp
r94933 r94934 33 33 #include <iprt/asm-amd64-x86.h> 34 34 #include <iprt/mem.h> 35 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI36 # include <iprt/memobj.h>37 # include <VBox/apic.h>38 #endif39 35 #include <iprt/x86.h> 40 41 42 /*********************************************************************************************************************************43 * Structures and Typedefs *44 *********************************************************************************************************************************/45 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI46 /**47 * Local APIC mappings.48 */49 typedef struct CPUMHOSTLAPIC50 {51 /** Indicates that the entry is in use and have valid data. */52 bool fEnabled;53 /** Whether it's operating in X2APIC mode (EXTD). */54 bool fX2Apic;55 /** The APIC version number. */56 uint32_t uVersion;57 /** The physical address of the APIC registers. */58 RTHCPHYS PhysBase;59 /** The memory object entering the physical address. */60 RTR0MEMOBJ hMemObj;61 /** The mapping object for hMemObj. */62 RTR0MEMOBJ hMapObj;63 /** The mapping address APIC registers.64 * @remarks Different CPUs may use the same physical address to map their65 * APICs, so this pointer is only valid when on the CPU owning the66 * APIC. */67 void *pv;68 } CPUMHOSTLAPIC;69 #endif70 36 71 37 … … 78 44 static CPUMMSRS g_CpumHostMsrs; 79 45 80 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI81 static CPUMHOSTLAPIC g_aLApics[RTCPUSET_MAX_CPUS];82 #endif83 84 46 /** 85 47 * CPUID bits to unify among all cores. … … 105 67 * Internal Functions * 106 68 *********************************************************************************************************************************/ 107 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI108 static int cpumR0MapLocalApics(void);109 static void cpumR0UnmapLocalApics(void);110 #endif111 69 static int cpumR0SaveHostDebugState(PVMCPUCC pVCpu); 112 70 … … 155 113 AssertLogRelRCReturn(rc, rc); 156 114 157 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI158 return cpumR0MapLocalApics();159 #else160 115 return VINF_SUCCESS; 161 #endif162 116 } 163 117 … … 168 122 VMMR0_INT_DECL(int) CPUMR0ModuleTerm(void) 169 123 { 170 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI171 cpumR0UnmapLocalApics();172 #endif173 124 return VINF_SUCCESS; 174 125 } … … 752 703 } 753 704 754 #ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI755 756 /**757 * Per-CPU callback that probes the CPU for APIC support.758 *759 * @param idCpu The identifier for the CPU the function is called on.760 * @param pvUser1 Ignored.761 * @param pvUser2 Ignored.762 */763 static DECLCALLBACK(void) cpumR0MapLocalApicCpuProber(RTCPUID idCpu, void *pvUser1, void *pvUser2)764 {765 NOREF(pvUser1); NOREF(pvUser2);766 int iCpu = RTMpCpuIdToSetIndex(idCpu);767 AssertReturnVoid(iCpu >= 0 && (unsigned)iCpu < RT_ELEMENTS(g_aLApics));768 769 /*770 * Check for APIC support.771 */772 uint32_t uMaxLeaf, u32EBX, u32ECX, u32EDX;773 ASMCpuId(0, &uMaxLeaf, &u32EBX, &u32ECX, &u32EDX);774 if ( ( RTX86IsIntelCpu(u32EBX, u32ECX, u32EDX)775 || RTX86IsAmdCpu(u32EBX, u32ECX, u32EDX)776 || RTX86IsViaCentaurCpu(u32EBX, u32ECX, u32EDX)777 || RTX86IsShanghaiCpu(u32EBX, u32ECX, u32EDX)778 || RTX86IsHygonCpu(u32EBX, u32ECX, u32EDX))779 && RTX86IsValidStdRange(uMaxLeaf))780 {781 uint32_t uDummy;782 ASMCpuId(1, &uDummy, &u32EBX, &u32ECX, &u32EDX);783 if ( (u32EDX & X86_CPUID_FEATURE_EDX_APIC)784 && (u32EDX & X86_CPUID_FEATURE_EDX_MSR))785 {786 /*787 * Safe to access the MSR. Read it and calc the BASE (a little complicated).788 */789 uint64_t u64ApicBase = ASMRdMsr(MSR_IA32_APICBASE);790 uint64_t u64Mask = MSR_IA32_APICBASE_BASE_MIN;791 792 /* see Intel Manual: Local APIC Status and Location: MAXPHYADDR default is bit 36 */793 uint32_t uMaxExtLeaf;794 ASMCpuId(0x80000000, &uMaxExtLeaf, &u32EBX, &u32ECX, &u32EDX);795 if ( uMaxExtLeaf >= UINT32_C(0x80000008)796 && RTX86IsValidExtRange(uMaxExtLeaf))797 {798 uint32_t u32PhysBits;799 ASMCpuId(0x80000008, &u32PhysBits, &u32EBX, &u32ECX, &u32EDX);800 u32PhysBits &= 0xff;801 u64Mask = ((UINT64_C(1) << u32PhysBits) - 1) & UINT64_C(0xfffffffffffff000);802 }803 804 AssertCompile(sizeof(g_aLApics[iCpu].PhysBase) == sizeof(u64ApicBase));805 g_aLApics[iCpu].PhysBase = u64ApicBase & u64Mask;806 g_aLApics[iCpu].fEnabled = RT_BOOL(u64ApicBase & MSR_IA32_APICBASE_EN);807 g_aLApics[iCpu].fX2Apic = (u64ApicBase & (MSR_IA32_APICBASE_EXTD | MSR_IA32_APICBASE_EN))808 == (MSR_IA32_APICBASE_EXTD | MSR_IA32_APICBASE_EN);809 }810 }811 }812 813 814 815 /**816 * Per-CPU callback that verifies our APIC expectations.817 *818 * @param idCpu The identifier for the CPU the function is called on.819 * @param pvUser1 Ignored.820 * @param pvUser2 Ignored.821 */822 static DECLCALLBACK(void) cpumR0MapLocalApicCpuChecker(RTCPUID idCpu, void *pvUser1, void *pvUser2)823 {824 NOREF(pvUser1); NOREF(pvUser2);825 826 int iCpu = RTMpCpuIdToSetIndex(idCpu);827 AssertReturnVoid(iCpu >= 0 && (unsigned)iCpu < RT_ELEMENTS(g_aLApics));828 if (!g_aLApics[iCpu].fEnabled)829 return;830 831 /*832 * 0x0X 82489 external APIC833 * 0x1X Local APIC834 * 0x2X..0xFF reserved835 */836 uint32_t uApicVersion;837 if (g_aLApics[iCpu].fX2Apic)838 uApicVersion = ApicX2RegRead32(APIC_REG_VERSION);839 else840 uApicVersion = ApicRegRead(g_aLApics[iCpu].pv, APIC_REG_VERSION);841 if ((APIC_REG_VERSION_GET_VER(uApicVersion) & 0xF0) == 0x10)842 {843 g_aLApics[iCpu].uVersion = uApicVersion;844 845 # if 0 /* enable if you need it. */846 if (g_aLApics[iCpu].fX2Apic)847 SUPR0Printf("CPUM: X2APIC %02u - ver %#010x, lint0=%#07x lint1=%#07x pc=%#07x thmr=%#07x cmci=%#07x\n",848 iCpu, uApicVersion,849 ApicX2RegRead32(APIC_REG_LVT_LINT0), ApicX2RegRead32(APIC_REG_LVT_LINT1),850 ApicX2RegRead32(APIC_REG_LVT_PC), ApicX2RegRead32(APIC_REG_LVT_THMR),851 ApicX2RegRead32(APIC_REG_LVT_CMCI));852 else853 {854 SUPR0Printf("CPUM: APIC %02u at %RGp (mapped at %p) - ver %#010x, lint0=%#07x lint1=%#07x pc=%#07x thmr=%#07x cmci=%#07x\n",855 iCpu, g_aLApics[iCpu].PhysBase, g_aLApics[iCpu].pv, uApicVersion,856 ApicRegRead(g_aLApics[iCpu].pv, APIC_REG_LVT_LINT0), ApicRegRead(g_aLApics[iCpu].pv, APIC_REG_LVT_LINT1),857 ApicRegRead(g_aLApics[iCpu].pv, APIC_REG_LVT_PC), ApicRegRead(g_aLApics[iCpu].pv, APIC_REG_LVT_THMR),858 ApicRegRead(g_aLApics[iCpu].pv, APIC_REG_LVT_CMCI));859 if (uApicVersion & 0x80000000)860 {861 uint32_t uExtFeatures = ApicRegRead(g_aLApics[iCpu].pv, 0x400);862 uint32_t cEiLvt = (uExtFeatures >> 16) & 0xff;863 SUPR0Printf("CPUM: APIC %02u: ExtSpace available. extfeat=%08x eilvt[0..3]=%08x %08x %08x %08x\n",864 iCpu,865 ApicRegRead(g_aLApics[iCpu].pv, 0x400),866 cEiLvt >= 1 ? ApicRegRead(g_aLApics[iCpu].pv, 0x500) : 0,867 cEiLvt >= 2 ? ApicRegRead(g_aLApics[iCpu].pv, 0x510) : 0,868 cEiLvt >= 3 ? ApicRegRead(g_aLApics[iCpu].pv, 0x520) : 0,869 cEiLvt >= 4 ? ApicRegRead(g_aLApics[iCpu].pv, 0x530) : 0);870 }871 }872 # endif873 }874 else875 {876 g_aLApics[iCpu].fEnabled = false;877 g_aLApics[iCpu].fX2Apic = false;878 SUPR0Printf("VBox/CPUM: Unsupported APIC version %#x (iCpu=%d)\n", uApicVersion, iCpu);879 }880 }881 882 883 /**884 * Map the MMIO page of each local APIC in the system.885 */886 static int cpumR0MapLocalApics(void)887 {888 /*889 * Check that we'll always stay within the array bounds.890 */891 if (RTMpGetArraySize() > RT_ELEMENTS(g_aLApics))892 {893 LogRel(("CPUM: Too many real CPUs/cores/threads - %u, max %u\n", RTMpGetArraySize(), RT_ELEMENTS(g_aLApics)));894 return VERR_TOO_MANY_CPUS;895 }896 897 /*898 * Create mappings for all online CPUs we think have legacy APICs.899 */900 int rc = RTMpOnAll(cpumR0MapLocalApicCpuProber, NULL, NULL);901 902 for (unsigned iCpu = 0; RT_SUCCESS(rc) && iCpu < RT_ELEMENTS(g_aLApics); iCpu++)903 {904 if (g_aLApics[iCpu].fEnabled && !g_aLApics[iCpu].fX2Apic)905 {906 rc = RTR0MemObjEnterPhys(&g_aLApics[iCpu].hMemObj, g_aLApics[iCpu].PhysBase,907 HOST_PAGE_SIZE, RTMEM_CACHE_POLICY_MMIO);908 if (RT_SUCCESS(rc))909 {910 rc = RTR0MemObjMapKernel(&g_aLApics[iCpu].hMapObj, g_aLApics[iCpu].hMemObj, (void *)-1,911 HOST_PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);912 if (RT_SUCCESS(rc))913 {914 g_aLApics[iCpu].pv = RTR0MemObjAddress(g_aLApics[iCpu].hMapObj);915 continue;916 }917 RTR0MemObjFree(g_aLApics[iCpu].hMemObj, true /* fFreeMappings */);918 }919 g_aLApics[iCpu].fEnabled = false;920 }921 g_aLApics[iCpu].pv = NULL;922 }923 924 /*925 * Check the APICs.926 */927 if (RT_SUCCESS(rc))928 rc = RTMpOnAll(cpumR0MapLocalApicCpuChecker, NULL, NULL);929 930 if (RT_FAILURE(rc))931 {932 cpumR0UnmapLocalApics();933 return rc;934 }935 936 # ifdef LOG_ENABLED937 /*938 * Log the result (pretty useless, requires enabling CPUM in VBoxDrv939 * and !VBOX_WITH_R0_LOGGING).940 */941 if (LogIsEnabled())942 {943 uint32_t cEnabled = 0;944 uint32_t cX2Apics = 0;945 for (unsigned iCpu = 0; iCpu < RT_ELEMENTS(g_aLApics); iCpu++)946 if (g_aLApics[iCpu].fEnabled)947 {948 cEnabled++;949 cX2Apics += g_aLApics[iCpu].fX2Apic;950 }951 Log(("CPUM: %u APICs, %u X2APICs\n", cEnabled, cX2Apics));952 }953 # endif954 955 return VINF_SUCCESS;956 }957 958 959 /**960 * Unmap the Local APIC of all host CPUs.961 */962 static void cpumR0UnmapLocalApics(void)963 {964 for (unsigned iCpu = RT_ELEMENTS(g_aLApics); iCpu-- > 0;)965 {966 if (g_aLApics[iCpu].pv)967 {968 RTR0MemObjFree(g_aLApics[iCpu].hMapObj, true /* fFreeMappings */);969 RTR0MemObjFree(g_aLApics[iCpu].hMemObj, true /* fFreeMappings */);970 g_aLApics[iCpu].hMapObj = NIL_RTR0MEMOBJ;971 g_aLApics[iCpu].hMemObj = NIL_RTR0MEMOBJ;972 g_aLApics[iCpu].fEnabled = false;973 g_aLApics[iCpu].fX2Apic = false;974 g_aLApics[iCpu].pv = NULL;975 }976 }977 }978 979 980 /**981 * Updates CPUMCPU::pvApicBase and CPUMCPU::fX2Apic prior to world switch.982 *983 * Writes the Local APIC mapping address of the current host CPU to CPUMCPU so984 * the world switchers can access the APIC registers for the purpose of985 * disabling and re-enabling the NMIs. Must be called with disabled preemption986 * or disabled interrupts!987 *988 * @param pVCpu The cross context virtual CPU structure of the calling EMT.989 * @param iHostCpuSet The CPU set index of the current host CPU.990 */991 VMMR0_INT_DECL(void) CPUMR0SetLApic(PVMCPUCC pVCpu, uint32_t iHostCpuSet)992 {993 Assert(iHostCpuSet <= RT_ELEMENTS(g_aLApics));994 pVCpu->cpum.s.pvApicBase = g_aLApics[iHostCpuSet].pv;995 pVCpu->cpum.s.fX2Apic = g_aLApics[iHostCpuSet].fX2Apic;996 // Log6(("CPUMR0SetLApic: pvApicBase=%p fX2Apic=%d\n", g_aLApics[idxCpu].pv, g_aLApics[idxCpu].fX2Apic));997 }998 999 #endif /* VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI */1000
Note:
See TracChangeset
for help on using the changeset viewer.