VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/CPUMR3Db.cpp@ 109021

Last change on this file since 109021 was 109020, checked in by vboxsync, 3 weeks ago

VMM,SUP,VBoxCpuReport: Port of VBoxCpuReport to ARM. jiraref:VBP-1598

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 KB
Line 
1/* $Id: CPUMR3Db.cpp 109020 2025-04-17 23:37:08Z vboxsync $ */
2/** @file
3 * CPUM - CPU database part.
4 */
5
6/*
7 * Copyright (C) 2013-2025 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_CPUM
33#include <VBox/vmm/cpum.h>
34#include "CPUMInternal.h"
35#include <VBox/vmm/vm.h>
36#include <VBox/vmm/mm.h>
37
38#include <VBox/err.h>
39#if defined(VBOX_VMM_TARGET_ARMV8) || defined(RT_ARCH_ARM64)
40# include <iprt/armv8.h>
41#endif
42#if !defined(RT_ARCH_ARM64)
43# include <iprt/asm-amd64-x86.h>
44#endif
45#include <iprt/mem.h>
46#include <iprt/string.h>
47
48
49/*********************************************************************************************************************************
50* Internal Functions *
51*********************************************************************************************************************************/
52static int cpumDbPopulateInfoFromEntry(PCPUMINFO pInfo, PCCPUMDBENTRY pEntryCore, bool fHost);
53
54
55/*********************************************************************************************************************************
56* Defined Constants And Macros *
57*********************************************************************************************************************************/
58/** @def NULL_ALONE
59 * For eliminating an unnecessary data dependency in standalone builds (for
60 * VBoxSVC). */
61/** @def ZERO_ALONE
62 * For eliminating an unnecessary data size dependency in standalone builds (for
63 * VBoxSVC). */
64#ifndef CPUM_DB_STANDALONE
65# define NULL_ALONE(a_aTable) a_aTable
66# define ZERO_ALONE(a_cTable) a_cTable
67#else
68# define NULL_ALONE(a_aTable) NULL
69# define ZERO_ALONE(a_cTable) 0
70#endif
71
72
73/*********************************************************************************************************************************
74* Global Variables *
75*********************************************************************************************************************************/
76/*
77 * Include the X86 profiles.
78 */
79#if defined(VBOX_VMM_TARGET_X86)
80
81# include "CPUMR3Msr-x86.h" /* MSR macros needed by the profiles. */
82
83# include "cpus/Intel_Core_i7_6700K.h"
84# include "cpus/Intel_Core_i7_5600U.h"
85# include "cpus/Intel_Core_i7_3960X.h"
86# include "cpus/Intel_Core_i5_3570.h"
87# include "cpus/Intel_Core_i7_2635QM.h"
88# include "cpus/Intel_Xeon_X5482_3_20GHz.h"
89# include "cpus/Intel_Core2_X6800_2_93GHz.h"
90# include "cpus/Intel_Core2_T7600_2_33GHz.h"
91# include "cpus/Intel_Core_Duo_T2600_2_16GHz.h"
92# include "cpus/Intel_Pentium_M_processor_2_00GHz.h"
93# include "cpus/Intel_Pentium_4_3_00GHz.h"
94# include "cpus/Intel_Pentium_N3530_2_16GHz.h"
95# include "cpus/Intel_Atom_330_1_60GHz.h"
96# include "cpus/Intel_80486.h"
97# include "cpus/Intel_80386.h"
98# include "cpus/Intel_80286.h"
99# include "cpus/Intel_80186.h"
100# include "cpus/Intel_8086.h"
101
102# include "cpus/AMD_Ryzen_7_1800X_Eight_Core.h"
103# include "cpus/AMD_FX_8150_Eight_Core.h"
104# include "cpus/AMD_Phenom_II_X6_1100T.h"
105# include "cpus/Quad_Core_AMD_Opteron_2384.h"
106# include "cpus/AMD_Athlon_64_X2_Dual_Core_4200.h"
107# include "cpus/AMD_Athlon_64_3200.h"
108
109# include "cpus/VIA_QuadCore_L4700_1_2_GHz.h"
110
111# include "cpus/ZHAOXIN_KaiXian_KX_U5581_1_8GHz.h"
112
113# include "cpus/Hygon_C86_7185_32_core.h"
114
115#endif /* VBOX_VMM_TARGET_X86 */
116
117
118/*
119 * Include the ARM profiles.
120 *
121 * Note! We include these when on ARM64 hosts regardless of the VMM target, so
122 * we can get more info about the host CPU.
123 */
124#if defined(VBOX_VMM_TARGET_ARMV8) || defined(RT_ARCH_ARM64)
125
126# include "cpus/ARM_Apple_M1.h"
127
128#endif
129
130
131/**
132 * The database entries.
133 *
134 * 1. The first entry is special. It is the fallback for unknown
135 * processors. Thus, it better be pretty representative.
136 *
137 * 2. The first entry for a CPU vendor is likewise important as it is
138 * the default entry for that vendor.
139 *
140 * Generally we put the most recent CPUs first, since these tend to have the
141 * most complicated and backwards compatible list of MSRs.
142 */
143static CPUMDBENTRY const * const g_apCpumDbEntries[] =
144{
145#if defined(VBOX_VMM_TARGET_X86)
146 /*
147 * X86 profiles:
148 */
149# ifdef VBOX_CPUDB_Intel_Core_i7_6700K_h
150 &g_Entry_Intel_Core_i7_6700K.Core,
151# endif
152# ifdef VBOX_CPUDB_Intel_Core_i7_5600U_h
153 &g_Entry_Intel_Core_i7_5600U.Core,
154# endif
155# ifdef VBOX_CPUDB_Intel_Core_i5_3570_h
156 &g_Entry_Intel_Core_i5_3570.Core,
157# endif
158# ifdef VBOX_CPUDB_Intel_Core_i7_3960X_h
159 &g_Entry_Intel_Core_i7_3960X.Core,
160# endif
161# ifdef VBOX_CPUDB_Intel_Core_i7_2635QM_h
162 &g_Entry_Intel_Core_i7_2635QM.Core,
163# endif
164# ifdef VBOX_CPUDB_Intel_Pentium_N3530_2_16GHz_h
165 &g_Entry_Intel_Pentium_N3530_2_16GHz.Core,
166# endif
167# ifdef VBOX_CPUDB_Intel_Atom_330_1_60GHz_h
168 &g_Entry_Intel_Atom_330_1_60GHz.Core,
169# endif
170# ifdef VBOX_CPUDB_Intel_Pentium_M_processor_2_00GHz_h
171 &g_Entry_Intel_Pentium_M_processor_2_00GHz.Core,
172# endif
173# ifdef VBOX_CPUDB_Intel_Xeon_X5482_3_20GHz_h
174 &g_Entry_Intel_Xeon_X5482_3_20GHz.Core,
175# endif
176# ifdef VBOX_CPUDB_Intel_Core2_X6800_2_93GHz_h
177 &g_Entry_Intel_Core2_X6800_2_93GHz.Core,
178# endif
179# ifdef VBOX_CPUDB_Intel_Core2_T7600_2_33GHz_h
180 &g_Entry_Intel_Core2_T7600_2_33GHz.Core,
181# endif
182# ifdef VBOX_CPUDB_Intel_Core_Duo_T2600_2_16GHz_h
183 &g_Entry_Intel_Core_Duo_T2600_2_16GHz.Core,
184# endif
185# ifdef VBOX_CPUDB_Intel_Pentium_4_3_00GHz_h
186 &g_Entry_Intel_Pentium_4_3_00GHz.Core,
187# endif
188/** @todo pentium, pentium mmx, pentium pro, pentium II, pentium III */
189# ifdef VBOX_CPUDB_Intel_80486_h
190 &g_Entry_Intel_80486.Core,
191# endif
192# ifdef VBOX_CPUDB_Intel_80386_h
193 &g_Entry_Intel_80386.Core,
194# endif
195# ifdef VBOX_CPUDB_Intel_80286_h
196 &g_Entry_Intel_80286.Core,
197# endif
198# ifdef VBOX_CPUDB_Intel_80186_h
199 &g_Entry_Intel_80186.Core,
200# endif
201# ifdef VBOX_CPUDB_Intel_8086_h
202 &g_Entry_Intel_8086.Core,
203# endif
204
205# ifdef VBOX_CPUDB_AMD_Ryzen_7_1800X_Eight_Core_h
206 &g_Entry_AMD_Ryzen_7_1800X_Eight_Core.Core,
207# endif
208# ifdef VBOX_CPUDB_AMD_FX_8150_Eight_Core_h
209 &g_Entry_AMD_FX_8150_Eight_Core.Core,
210# endif
211# ifdef VBOX_CPUDB_AMD_Phenom_II_X6_1100T_h
212 &g_Entry_AMD_Phenom_II_X6_1100T.Core,
213# endif
214# ifdef VBOX_CPUDB_Quad_Core_AMD_Opteron_2384_h
215 &g_Entry_Quad_Core_AMD_Opteron_2384.Core,
216# endif
217# ifdef VBOX_CPUDB_AMD_Athlon_64_X2_Dual_Core_4200_h
218 &g_Entry_AMD_Athlon_64_X2_Dual_Core_4200.Core,
219# endif
220# ifdef VBOX_CPUDB_AMD_Athlon_64_3200_h
221 &g_Entry_AMD_Athlon_64_3200.Core,
222# endif
223
224# ifdef VBOX_CPUDB_ZHAOXIN_KaiXian_KX_U5581_1_8GHz_h
225 &g_Entry_ZHAOXIN_KaiXian_KX_U5581_1_8GHz.Core,
226# endif
227
228# ifdef VBOX_CPUDB_VIA_QuadCore_L4700_1_2_GHz_h
229 &g_Entry_VIA_QuadCore_L4700_1_2_GHz.Core,
230# endif
231
232# ifdef VBOX_CPUDB_NEC_V20_h
233 &g_Entry_NEC_V20.Core,
234# endif
235
236# ifdef VBOX_CPUDB_Hygon_C86_7185_32_core_h
237 &g_Entry_Hygon_C86_7185_32_core.Core,
238# endif
239#endif /* VBOX_VMM_TARGET_X86 */
240
241#if defined(VBOX_VMM_TARGET_ARMV8) || defined(RT_ARCH_ARM64)
242 /*
243 * ARM profiles:
244 */
245 &g_Entry_ARM_Apple_M1.Core,
246#endif /* VBOX_VMM_TARGET_ARMV8 || RT_ARCH_ARM64 */
247};
248
249
250/**
251 * Returns the number of entries in the CPU database.
252 *
253 * @returns Number of entries.
254 * @sa PFNCPUMDBGETENTRIES
255 */
256VMMR3DECL(uint32_t) CPUMR3DbGetEntries(void)
257{
258 return RT_ELEMENTS(g_apCpumDbEntries);
259}
260
261
262/**
263 * Returns CPU database entry for the given index.
264 *
265 * @returns Pointer the CPU database entry, NULL if index is out of bounds.
266 * @param idxCpuDb The index (0..CPUMR3DbGetEntries).
267 * @sa PFNCPUMDBGETENTRYBYINDEX
268 */
269VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByIndex(uint32_t idxCpuDb)
270{
271 AssertReturn(idxCpuDb < RT_ELEMENTS(g_apCpumDbEntries), NULL);
272 return g_apCpumDbEntries[idxCpuDb];
273}
274
275
276/**
277 * Returns CPU database entry with the given name.
278 *
279 * @returns Pointer the CPU database entry, NULL if not found.
280 * @param pszName The name of the profile to return.
281 * @sa PFNCPUMDBGETENTRYBYNAME
282 */
283VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByName(const char *pszName)
284{
285 AssertPtrReturn(pszName, NULL);
286 AssertReturn(*pszName, NULL);
287 for (size_t i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++)
288 if (strcmp(g_apCpumDbEntries[i]->pszName, pszName) == 0)
289 return g_apCpumDbEntries[i];
290 return NULL;
291}
292
293#if defined(VBOX_VMM_TARGET_X86) && (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64))
294
295/**
296 * Do we consider @a enmConsider a better match for @a enmTarget than
297 * @a enmFound?
298 *
299 * Only called when @a enmConsider isn't exactly what we're looking for.
300 *
301 * @returns true/false.
302 * @param enmConsider The new microarch to consider.
303 * @param enmTarget The target microarch.
304 * @param enmFound The best microarch match we've found thus far.
305 */
306DECLINLINE(bool) cpumR3DbIsBetterMarchMatch(CPUMMICROARCH enmConsider, CPUMMICROARCH enmTarget, CPUMMICROARCH enmFound)
307{
308 Assert(enmConsider != enmTarget);
309
310 /*
311 * If we've got an march match, don't bother with enmConsider.
312 */
313 if (enmFound == enmTarget)
314 return false;
315
316 /*
317 * Found is below: Pick 'consider' if it's closer to the target or above it.
318 */
319 if (enmFound < enmTarget)
320 return enmConsider > enmFound;
321
322 /*
323 * Found is above: Pick 'consider' if it's also above (paranoia: or equal)
324 * and but closer to the target.
325 */
326 return enmConsider >= enmTarget && enmConsider < enmFound;
327}
328
329
330/**
331 * Do we consider @a enmConsider a better match for @a enmTarget than
332 * @a enmFound?
333 *
334 * Only called for intel family 06h CPUs.
335 *
336 * @returns true/false.
337 * @param enmConsider The new microarch to consider.
338 * @param enmTarget The target microarch.
339 * @param enmFound The best microarch match we've found thus far.
340 */
341static bool cpumR3DbIsBetterIntelFam06Match(CPUMMICROARCH enmConsider, CPUMMICROARCH enmTarget, CPUMMICROARCH enmFound)
342{
343 /* Check intel family 06h claims. */
344 AssertReturn(enmConsider >= kCpumMicroarch_Intel_P6_Core_Atom_First && enmConsider <= kCpumMicroarch_Intel_P6_Core_Atom_End,
345 false);
346 AssertReturn( (enmTarget >= kCpumMicroarch_Intel_P6_Core_Atom_First && enmTarget <= kCpumMicroarch_Intel_P6_Core_Atom_End)
347 || enmTarget == kCpumMicroarch_Intel_Unknown,
348 false);
349
350 /* Put matches out of the way. */
351 if (enmConsider == enmTarget)
352 return true;
353 if (enmFound == enmTarget)
354 return false;
355
356 /* If found isn't a family 06h march, whatever we're considering must be a better choice. */
357 if ( enmFound < kCpumMicroarch_Intel_P6_Core_Atom_First
358 || enmFound > kCpumMicroarch_Intel_P6_Core_Atom_End)
359 return true;
360
361 /*
362 * The family 06h stuff is split into three categories:
363 * - Common P6 heritage
364 * - Core
365 * - Atom
366 *
367 * Determin which of the three arguments are Atom marchs, because that's
368 * all we need to make the right choice.
369 */
370 bool const fConsiderAtom = enmConsider >= kCpumMicroarch_Intel_Atom_First;
371 bool const fTargetAtom = enmTarget >= kCpumMicroarch_Intel_Atom_First;
372 bool const fFoundAtom = enmFound >= kCpumMicroarch_Intel_Atom_First;
373
374 /*
375 * Want atom:
376 */
377 if (fTargetAtom)
378 {
379 /* Pick the atom if we've got one of each.*/
380 if (fConsiderAtom != fFoundAtom)
381 return fConsiderAtom;
382 /* If we haven't got any atoms under consideration, pick a P6 or the earlier core.
383 Note! Not entirely sure Dothan is the best choice, but it'll do for now. */
384 if (!fConsiderAtom)
385 {
386 if (enmConsider > enmFound)
387 return enmConsider <= kCpumMicroarch_Intel_P6_M_Dothan;
388 return enmFound > kCpumMicroarch_Intel_P6_M_Dothan;
389 }
390 /* else: same category, default comparison rules. */
391 Assert(fConsiderAtom && fFoundAtom);
392 }
393 /*
394 * Want non-atom:
395 */
396 /* Pick the non-atom if we've got one of each. */
397 else if (fConsiderAtom != fFoundAtom)
398 return fFoundAtom;
399 /* If we've only got atoms under consideration, pick the older one just to pick something. */
400 else if (fConsiderAtom)
401 return enmConsider < enmFound;
402 else
403 Assert(!fConsiderAtom && !fFoundAtom);
404
405 /*
406 * Same basic category. Do same compare as caller.
407 */
408 return cpumR3DbIsBetterMarchMatch(enmConsider, enmTarget, enmFound);
409}
410
411
412/**
413 * X86 version of helper that picks a DB entry for the host and merges it with
414 * available info in the @a pInfo structure.
415 */
416static int cpumR3DbCreateHostEntry(PCPUMINFO pInfo)
417{
418 /*
419 * Create a CPU database entry for the host CPU. This means getting
420 * the CPUID bits from the real CPU and grabbing the closest matching
421 * database entry for MSRs.
422 */
423 int rc = CPUMR3CpuIdDetectUnknownLeafMethod(&pInfo->enmUnknownCpuIdMethod, &pInfo->DefCpuId);
424 if (RT_FAILURE(rc))
425 return rc;
426 rc = CPUMCpuIdCollectLeavesFromX86Host(&pInfo->paCpuIdLeavesR3, &pInfo->cCpuIdLeaves);
427 if (RT_FAILURE(rc))
428 return rc;
429 pInfo->fMxCsrMask = CPUMR3DeterminHostMxCsrMask();
430
431 /* Lookup database entry for MSRs. */
432 CPUMCPUVENDOR const enmVendor = CPUMCpuIdDetectX86VendorEx(pInfo->paCpuIdLeavesR3[0].uEax,
433 pInfo->paCpuIdLeavesR3[0].uEbx,
434 pInfo->paCpuIdLeavesR3[0].uEcx,
435 pInfo->paCpuIdLeavesR3[0].uEdx);
436 uint32_t const uStd1Eax = pInfo->paCpuIdLeavesR3[1].uEax;
437 uint8_t const uFamily = RTX86GetCpuFamily(uStd1Eax);
438 uint8_t const uModel = RTX86GetCpuModel(uStd1Eax, enmVendor == CPUMCPUVENDOR_INTEL);
439 uint8_t const uStepping = RTX86GetCpuStepping(uStd1Eax);
440 CPUMMICROARCH const enmMicroarch = CPUMCpuIdDetermineX86MicroarchEx(enmVendor, uFamily, uModel, uStepping);
441
442 PCCPUMDBENTRYX86 pEntry = NULL;
443 for (unsigned i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++)
444 {
445 CPUMDBENTRY const * const pCurCore = g_apCpumDbEntries[i];
446 if ( (CPUMCPUVENDOR)pCurCore->enmVendor == enmVendor
447 && pCurCore->enmEntryType == CPUMDBENTRYTYPE_X86)
448 {
449 CPUMDBENTRYX86 const * const pCur = (CPUMDBENTRYX86 const *)pCurCore;
450
451 /* Match against Family, Microarch, model and stepping. Except
452 for family, always match the closer with preference given to
453 the later/older ones. */
454 if (pCur->uFamily == uFamily)
455 {
456 if (pCur->Core.enmMicroarch == enmMicroarch)
457 {
458 if (pCur->uModel == uModel)
459 {
460 if (pCur->uStepping == uStepping)
461 {
462 /* Perfect match. */
463 pEntry = pCur;
464 break;
465 }
466
467 if ( !pEntry
468 || pEntry->uModel != uModel
469 || pEntry->Core.enmMicroarch != enmMicroarch
470 || pEntry->uFamily != uFamily)
471 pEntry = pCur;
472 else if ( pCur->uStepping >= uStepping
473 ? pCur->uStepping < pEntry->uStepping || pEntry->uStepping < uStepping
474 : pCur->uStepping > pEntry->uStepping)
475 pEntry = pCur;
476 }
477 else if ( !pEntry
478 || pEntry->Core.enmMicroarch != enmMicroarch
479 || pEntry->uFamily != uFamily)
480 pEntry = pCur;
481 else if ( pCur->uModel >= uModel
482 ? pCur->uModel < pEntry->uModel || pEntry->uModel < uModel
483 : pCur->uModel > pEntry->uModel)
484 pEntry = pCur;
485 }
486 else if ( !pEntry
487 || pEntry->uFamily != uFamily)
488 pEntry = pCur;
489 /* Special march matching rules applies to intel family 06h. */
490 else if ( enmVendor == CPUMCPUVENDOR_INTEL
491 && uFamily == 6
492 ? cpumR3DbIsBetterIntelFam06Match(pCur->Core.enmMicroarch, enmMicroarch, pEntry->Core.enmMicroarch)
493 : cpumR3DbIsBetterMarchMatch(pCur->Core.enmMicroarch, enmMicroarch, pEntry->Core.enmMicroarch))
494 pEntry = pCur;
495 }
496 /* We don't do closeness matching on family, we use the first
497 entry for the CPU vendor instead. (P4 workaround.) */
498 else if (!pEntry)
499 pEntry = pCur;
500 }
501 }
502
503 if (pEntry)
504 LogRel(("CPUM: Matched host CPU %s %#x/%#x/%#x %s with CPU DB entry '%s' (%s %#x/%#x/%#x %s)\n",
505 CPUMCpuVendorName(enmVendor), uFamily, uModel, uStepping, CPUMMicroarchName(enmMicroarch),
506 pEntry->Core.pszName, CPUMCpuVendorName(pEntry->Core.enmVendor), pEntry->uFamily, pEntry->uModel,
507 pEntry->uStepping, CPUMMicroarchName(pEntry->Core.enmMicroarch) ));
508 else
509 {
510 pEntry = (CPUMDBENTRYX86 const *)g_apCpumDbEntries[0];
511 LogRel(("CPUM: No matching processor database entry %s %#x/%#x/%#x %s, falling back on '%s'\n",
512 CPUMCpuVendorName(enmVendor), uFamily, uModel, uStepping, CPUMMicroarchName(enmMicroarch),
513 pEntry->Core.pszName));
514 }
515
516 return cpumDbPopulateInfoFromEntry(pInfo, &pEntry->Core, true /*fHost*/);
517}
518
519#endif /* VBOX_VMM_TARGET_X86 && (RT_ARCH_AMD64 || RT_ARCH_X86) */
520
521
522/**
523 * Helper that populates the CPUMINFO structure from DB entry.
524 */
525static int cpumDbPopulateInfoFromEntry(PCPUMINFO pInfo, PCCPUMDBENTRY pEntryCore, bool fHost)
526{
527#ifdef VBOX_VMM_TARGET_X86
528 /*
529 * X86.
530 */
531 AssertReturn(pEntryCore->enmEntryType == CPUMDBENTRYTYPE_X86, VERR_INTERNAL_ERROR_3);
532 PCCPUMDBENTRYX86 const pEntry = (PCCPUMDBENTRYX86)pEntryCore;
533
534 if (!fHost)
535 {
536 /*
537 * The CPUID tables needs to be copied onto the heap so the caller can
538 * modify them and so they can be freed like in the host case.
539 */
540 pInfo->cCpuIdLeaves = pEntry->cCpuIdLeaves;
541 if (pEntry->cCpuIdLeaves)
542 {
543 /* Must allocate a multiple of 16 here, matching cpumR3CpuIdEnsureSpace. */
544 size_t cbExtra = sizeof(pEntry->paCpuIdLeaves[0]) * (RT_ALIGN(pEntry->cCpuIdLeaves, 16) - pEntry->cCpuIdLeaves);
545 pInfo->paCpuIdLeavesR3 = (PCPUMCPUIDLEAF)RTMemDupEx(pEntry->paCpuIdLeaves,
546 sizeof(pEntry->paCpuIdLeaves[0]) * pEntry->cCpuIdLeaves,
547 cbExtra);
548 if (!pInfo->paCpuIdLeavesR3)
549 return VERR_NO_MEMORY;
550 }
551 else
552 pInfo->paCpuIdLeavesR3 = NULL;
553
554 pInfo->enmUnknownCpuIdMethod = pEntry->enmUnknownCpuId;
555 pInfo->DefCpuId = pEntry->DefUnknownCpuId;
556 pInfo->fMxCsrMask = pEntry->fMxCsrMask;
557
558 LogRel(("CPUM: Using CPU DB entry '%s' (%s %#x/%#x/%#x %s)\n",
559 pEntry->Core.pszName, CPUMCpuVendorName(pEntry->Core.enmVendor),
560 pEntry->uFamily, pEntry->uModel, pEntry->uStepping, CPUMMicroarchName(pEntry->Core.enmMicroarch) ));
561 }
562
563 pInfo->fMsrMask = pEntry->fMsrMask;
564 pInfo->iFirstExtCpuIdLeaf = 0; /* Set by caller. */
565 pInfo->uScalableBusFreq = pEntry->uScalableBusFreq;
566
567 /*
568 * Copy the MSR range.
569 */
570 uint32_t cMsrs = 0;
571 PCPUMMSRRANGE paMsrs = NULL;
572
573 PCCPUMMSRRANGE pCurMsr = pEntry->paMsrRanges;
574 uint32_t cLeft = pEntry->cMsrRanges;
575 while (cLeft-- > 0)
576 {
577 int rc = cpumR3MsrRangesInsert(NULL /* pVM */, &paMsrs, &cMsrs, pCurMsr);
578 if (RT_FAILURE(rc))
579 {
580 Assert(!paMsrs); /* The above function frees this. */
581 RTMemFree(pInfo->paCpuIdLeavesR3);
582 pInfo->paCpuIdLeavesR3 = NULL;
583 return rc;
584 }
585 pCurMsr++;
586 }
587
588 pInfo->paMsrRangesR3 = paMsrs;
589 pInfo->cMsrRanges = cMsrs;
590
591#elif defined(VBOX_VMM_TARGET_ARMV8)
592 /*
593 * ARM.
594 */
595 AssertReturn(pEntryCore->enmEntryType == CPUMDBENTRYTYPE_ARM, VERR_INTERNAL_ERROR_3);
596 PCCPUMDBENTRYARM const pEntry = (PCCPUMDBENTRYARM)pEntryCore;
597 RT_NOREF(pInfo, pEntry, fHost);
598
599#else
600# error "port me"
601#endif
602 return VINF_SUCCESS;
603}
604
605
606int cpumR3DbGetCpuInfo(const char *pszName, PCPUMINFO pInfo)
607{
608#ifdef VBOX_VMM_TARGET_X86
609 CPUMDBENTRYTYPE const enmEntryType = CPUMDBENTRYTYPE_X86;
610#elif defined(VBOX_VMM_TARGET_ARMV8)
611 CPUMDBENTRYTYPE const enmEntryType = CPUMDBENTRYTYPE_ARM;
612#else
613# error "port me"
614#endif
615
616 /*
617 * Deal with the dynamic 'host' entry first.
618 *
619 * If we're not on a matchin host, we just pick the first entry in the
620 * table and proceed as if this was specified by the caller (configured).
621 */
622 if (!strcmp(pszName, "host"))
623 {
624#if (defined(VBOX_VMM_TARGET_X86) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))) \
625 || (defined(VBOX_VMM_TARGET_ARMV8) && defined(RT_ARCH_ARM64) && 0)
626 return cpumR3DbCreateHostEntry(pInfo);
627#else
628 Assert(g_apCpumDbEntries[0]->enmEntryType == enmEntryType);
629 pszName = g_apCpumDbEntries[0]->pszName; /* Just pick the first entry for non-x86 hosts. */
630#endif
631 }
632
633 /*
634 * We're supposed to be emulating a specific CPU from the database.
635 */
636 for (unsigned i = 0; i < RT_ELEMENTS(g_apCpumDbEntries); i++)
637 if ( g_apCpumDbEntries[i]->enmEntryType == enmEntryType
638 && !strcmp(pszName, g_apCpumDbEntries[i]->pszName))
639 return cpumDbPopulateInfoFromEntry(pInfo, g_apCpumDbEntries[i], false /*fHost*/);
640 LogRel(("CPUM: Cannot locate any CPU by the name '%s'\n", pszName));
641 return VERR_CPUM_DB_CPU_NOT_FOUND;
642}
643
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette