/** Print the CPU 'revision', if available. */ static RTEXITCODE handlerCpuRevision(int argc, char **argv) { NOREF(argc); NOREF(argv); #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) uint32_t uEax, uEbx, uEcx, uEdx; ASMCpuId(0, &uEax, &uEbx, &uEcx, &uEdx); if (ASMIsValidStdRange(uEax) && uEax >= 1) { uint32_t uEax1 = ASMCpuId_EAX(1); uint32_t uVersion = (ASMGetCpuFamily(uEax1) << 24) | (ASMGetCpuModel(uEax1, ASMIsIntelCpuEx(uEbx, uEcx, uEdx)) << 8) | ASMGetCpuStepping(uEax1); int cch = RTPrintf("%#x\n", uVersion); return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } #endif return RTEXITCODE_FAILURE; }
int cpumR3DbGetCpuInfo(const char *pszName, PCPUMINFO pInfo) { CPUMDBENTRY const *pEntry = NULL; int rc; if (!strcmp(pszName, "host")) { /* * Create a CPU database entry for the host CPU. This means getting * the CPUID bits from the real CPU and grabbing the closest matching * database entry for MSRs. */ rc = CPUMR3CpuIdDetectUnknownLeafMethod(&pInfo->enmUnknownCpuIdMethod, &pInfo->DefCpuId); if (RT_FAILURE(rc)) return rc; rc = CPUMR3CpuIdCollectLeaves(&pInfo->paCpuIdLeavesR3, &pInfo->cCpuIdLeaves); if (RT_FAILURE(rc)) return rc; /* Lookup database entry for MSRs. */ CPUMCPUVENDOR const enmVendor = CPUMR3CpuIdDetectVendorEx(pInfo->paCpuIdLeavesR3[0].uEax, pInfo->paCpuIdLeavesR3[0].uEbx, pInfo->paCpuIdLeavesR3[0].uEcx, pInfo->paCpuIdLeavesR3[0].uEdx); uint32_t const uStd1Eax = pInfo->paCpuIdLeavesR3[1].uEax; uint8_t const uFamily = ASMGetCpuFamily(uStd1Eax); uint8_t const uModel = ASMGetCpuModel(uStd1Eax, enmVendor == CPUMCPUVENDOR_INTEL); uint8_t const uStepping = ASMGetCpuStepping(uStd1Eax); CPUMMICROARCH const enmMicroarch = CPUMR3CpuIdDetermineMicroarchEx(enmVendor, uFamily, uModel, uStepping); for (unsigned i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++) { CPUMDBENTRY const *pCur = g_apCpumDbEntries[i]; if ((CPUMCPUVENDOR)pCur->enmVendor == enmVendor) { /* Match against Family, Microarch, model and stepping. Except for family, always match the closer with preference given to the later/older ones. */ if (pCur->uFamily == uFamily) { if (pCur->enmMicroarch == enmMicroarch) { if (pCur->uModel == uModel) { if (pCur->uStepping == uStepping) { /* Perfect match. */ pEntry = pCur; break; } if ( !pEntry || pEntry->uModel != uModel || pEntry->enmMicroarch != enmMicroarch || pEntry->uFamily != uFamily) pEntry = pCur; else if ( pCur->uStepping >= uStepping ? pCur->uStepping < pEntry->uStepping || pEntry->uStepping < uStepping : pCur->uStepping > pEntry->uStepping) pEntry = pCur; } else if ( !pEntry || pEntry->enmMicroarch != enmMicroarch || pEntry->uFamily != uFamily) pEntry = pCur; else if ( pCur->uModel >= uModel ? pCur->uModel < pEntry->uModel || pEntry->uModel < uModel : pCur->uModel > pEntry->uModel) pEntry = pCur; } else if ( !pEntry || pEntry->uFamily != uFamily) pEntry = pCur; /* Special march matching rules applies to intel family 06h. */ else if ( enmVendor == CPUMCPUVENDOR_INTEL && uFamily == 6 ? cpumR3DbIsBetterIntelFam06Match(pCur->enmMicroarch, enmMicroarch, pEntry->enmMicroarch) : cpumR3DbIsBetterMarchMatch(pCur->enmMicroarch, enmMicroarch, pEntry->enmMicroarch)) pEntry = pCur; } /* We don't do closeness matching on family, we use the first entry for the CPU vendor instead. (P4 workaround.) */ else if (!pEntry) pEntry = pCur; } } if (pEntry) LogRel(("CPUM: Matched host CPU %s %#x/%#x/%#x %s with CPU DB entry '%s' (%s %#x/%#x/%#x %s)\n", CPUMR3CpuVendorName(enmVendor), uFamily, uModel, uStepping, CPUMR3MicroarchName(enmMicroarch), pEntry->pszName, CPUMR3CpuVendorName((CPUMCPUVENDOR)pEntry->enmVendor), pEntry->uFamily, pEntry->uModel, pEntry->uStepping, CPUMR3MicroarchName(pEntry->enmMicroarch) )); else { pEntry = g_apCpumDbEntries[0]; LogRel(("CPUM: No matching processor database entry %s %#x/%#x/%#x %s, falling back on '%s'\n", CPUMR3CpuVendorName(enmVendor), uFamily, uModel, uStepping, CPUMR3MicroarchName(enmMicroarch), pEntry->pszName)); } } else { /* * We're supposed to be emulating a specific CPU that is included in * our CPU database. The CPUID tables needs to be copied onto the * heap so the caller can modify them and so they can be freed like * in the host case above. */ for (unsigned i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++) if (!strcmp(pszName, g_apCpumDbEntries[i]->pszName)) { pEntry = g_apCpumDbEntries[i]; break; } if (!pEntry) { LogRel(("CPUM: Cannot locate any CPU by the name '%s'\n", pszName)); return VERR_CPUM_DB_CPU_NOT_FOUND; } pInfo->cCpuIdLeaves = pEntry->cCpuIdLeaves; if (pEntry->cCpuIdLeaves) { pInfo->paCpuIdLeavesR3 = (PCPUMCPUIDLEAF)RTMemDup(pEntry->paCpuIdLeaves, sizeof(pEntry->paCpuIdLeaves[0]) * pEntry->cCpuIdLeaves); if (!pInfo->paCpuIdLeavesR3) return VERR_NO_MEMORY; } else pInfo->paCpuIdLeavesR3 = NULL; pInfo->enmUnknownCpuIdMethod = pEntry->enmUnknownCpuId; pInfo->DefCpuId = pEntry->DefUnknownCpuId; LogRel(("CPUM: Using CPU DB entry '%s' (%s %#x/%#x/%#x %s)\n", pEntry->pszName, CPUMR3CpuVendorName((CPUMCPUVENDOR)pEntry->enmVendor), pEntry->uFamily, pEntry->uModel, pEntry->uStepping, CPUMR3MicroarchName(pEntry->enmMicroarch) )); } pInfo->fMsrMask = pEntry->fMsrMask; pInfo->iFirstExtCpuIdLeaf = 0; /* Set by caller. */ pInfo->uPadding = 0; pInfo->uScalableBusFreq = pEntry->uScalableBusFreq; pInfo->paCpuIdLeavesR0 = NIL_RTR0PTR; pInfo->paMsrRangesR0 = NIL_RTR0PTR; pInfo->paCpuIdLeavesRC = NIL_RTRCPTR; pInfo->paMsrRangesRC = NIL_RTRCPTR; /* * Copy the MSR range. */ uint32_t cMsrs = 0; PCPUMMSRRANGE paMsrs = NULL; PCCPUMMSRRANGE pCurMsr = pEntry->paMsrRanges; uint32_t cLeft = pEntry->cMsrRanges; while (cLeft-- > 0) { rc = cpumR3MsrRangesInsert(NULL /* pVM */, &paMsrs, &cMsrs, pCurMsr); if (RT_FAILURE(rc)) { Assert(!paMsrs); /* The above function frees this. */ RTMemFree(pInfo->paCpuIdLeavesR3); pInfo->paCpuIdLeavesR3 = NULL; return rc; } pCurMsr++; } pInfo->paMsrRangesR3 = paMsrs; pInfo->cMsrRanges = cMsrs; return VINF_SUCCESS; }