VirtualBox

source: vbox/trunk/src/VBox/VMM/tools/VBoxCpuReport.cpp@ 109139

Last change on this file since 109139 was 109030, checked in by vboxsync, 3 weeks ago

VBoxCpuReport,VMM/CPUM,iprt/armv8.h: Deal with core variations on arm CPUs when generating reports for them. Fixes. jiraref:VBP-1598

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1/* $Id: VBoxCpuReport.cpp 109030 2025-04-20 22:07:17Z vboxsync $ */
2/** @file
3 * VBoxCpuReport - Produces the basis for a CPU DB entry.
4 */
5
6/*
7 * Copyright (C) 2013-2024 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#include <iprt/asm.h>
33#include <iprt/buildconfig.h>
34#include <iprt/ctype.h>
35#include <iprt/errcore.h>
36#include <iprt/file.h>
37#include <iprt/getopt.h>
38#include <iprt/initterm.h>
39#include <iprt/message.h>
40#include <iprt/mem.h>
41#include <iprt/path.h>
42#include <iprt/string.h>
43#include <iprt/stream.h>
44#include <iprt/symlink.h>
45#include <iprt/thread.h>
46#include <iprt/time.h>
47
48#include <VBox/vmm/cpum.h>
49#include <VBox/sup.h>
50#include <VBox/version.h>
51
52#include "VBoxCpuReport.h"
53
54
55/*********************************************************************************************************************************
56* Global Variables *
57*********************************************************************************************************************************/
58/** The alternative report stream. */
59PRTSTREAM g_pReportOut;
60/** The alternative debug stream. */
61PRTSTREAM g_pDebugOut;
62/** The CPU vendor. Used by the MSR code. */
63CPUMCPUVENDOR g_enmVendor = CPUMCPUVENDOR_INVALID;
64/** The CPU microarchitecture. Used by the MSR code. */
65CPUMMICROARCH g_enmMicroarch = kCpumMicroarch_Invalid;
66/** Overrides the detected CPU name.
67 * This is main for non-x86 hosts where the processor name string isn't
68 * part of the silicone. */
69const char *g_pszCpuNameOverride = NULL;
70
71
72
73void vbCpuRepDebug(const char *pszMsg, ...)
74{
75 va_list va;
76
77 /* Always print a copy of the report to standard error. */
78 va_start(va, pszMsg);
79 RTStrmPrintfV(g_pStdErr, pszMsg, va);
80 va_end(va);
81 RTStrmFlush(g_pStdErr);
82
83 /* Alternatively, also print to a log file. */
84 if (g_pDebugOut)
85 {
86 va_start(va, pszMsg);
87 RTStrmPrintfV(g_pDebugOut, pszMsg, va);
88 va_end(va);
89 RTStrmFlush(g_pDebugOut);
90 }
91
92 /* Give the output device a chance to write / display it. */
93 RTThreadSleep(1);
94}
95
96
97void vbCpuRepPrintf(const char *pszMsg, ...)
98{
99 va_list va;
100
101 /* Output to report file, if requested. */
102 if (g_pReportOut)
103 {
104 va_start(va, pszMsg);
105 RTStrmPrintfV(g_pReportOut, pszMsg, va);
106 va_end(va);
107 RTStrmFlush(g_pReportOut);
108 }
109
110 /* Always print a copy of the report to standard out. */
111 va_start(va, pszMsg);
112 RTStrmPrintfV(g_pStdOut, pszMsg, va);
113 va_end(va);
114 RTStrmFlush(g_pStdOut);
115}
116
117
118/** Prints the file header. */
119void vbCpuRepFileHdr(const char *pszName, const char *pszNameC)
120{
121 RTTIMESPEC Now;
122 char szNow[64];
123 RTTimeSpecToString(RTTimeNow(&Now), szNow, sizeof(szNow));
124 char *pchDot = strchr(szNow, '.');
125 if (pchDot)
126 strcpy(pchDot, "Z");
127
128 vbCpuRepPrintf("/* $" "Id" "$ */\n"
129 "/** @file\n"
130 " * CPU database entry \"%s\".\n"
131 " * Generated at %s by VBoxCpuReport v%sr%s on %s.%s.\n"
132 " */\n"
133 "\n"
134 "/*\n"
135 " * Copyright (C) 2013-" VBOX_C_YEAR " Oracle and/or its affiliates.\n"
136 " *\n"
137 " * This file is part of VirtualBox base platform packages, as\n"
138 " * available from https://www.virtualbox.org.\n"
139 " *\n"
140 " * This program is free software; you can redistribute it and/or\n"
141 " * modify it under the terms of the GNU General Public License\n"
142 " * as published by the Free Software Foundation, in version 3 of the\n"
143 " * License.\n"
144 " *\n"
145 " * This program is distributed in the hope that it will be useful, but\n"
146 " * WITHOUT ANY WARRANTY; without even the implied warranty of\n"
147 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
148 " * General Public License for more details.\n"
149 " *\n"
150 " * You should have received a copy of the GNU General Public License\n"
151 " * along with this program; if not, see <https://www.gnu.org/licenses>.\n"
152 " *\n"
153 " * SPDX-License-Identifier: GPL-3.0-only\n"
154 " */\n"
155 "\n"
156 "#ifndef VBOX_CPUDB_%s_h\n"
157 "#define VBOX_CPUDB_%s_h\n"
158 "#ifndef RT_WITHOUT_PRAGMA_ONCE\n"
159 "# pragma once\n"
160 "#endif\n"
161 "\n",
162 pszName,
163 szNow, RTBldCfgVersion(), RTBldCfgRevisionStr(), RTBldCfgTarget(), RTBldCfgTargetArch(),
164 pszNameC, pszNameC);
165}
166
167
168/**
169 * Converts @a enmCpuVendor to the enum value name sans the typename prefix.
170 */
171const char *vbCpuVendorToString(CPUMCPUVENDOR enmCpuVendor)
172{
173 switch (enmCpuVendor)
174 {
175 case CPUMCPUVENDOR_INTEL: return "INTEL";
176 case CPUMCPUVENDOR_AMD: return "AMD";
177 case CPUMCPUVENDOR_VIA: return "VIA";
178 case CPUMCPUVENDOR_CYRIX: return "CYRIX";
179 case CPUMCPUVENDOR_SHANGHAI: return "SHANGHAI";
180 case CPUMCPUVENDOR_HYGON: return "HYGON";
181
182 case CPUMCPUVENDOR_ARM: return "ARM";
183 case CPUMCPUVENDOR_BROADCOM: return "BROADCOM";
184 case CPUMCPUVENDOR_QUALCOMM: return "QUALCOMM";
185 case CPUMCPUVENDOR_APPLE: return "APPLE";
186 case CPUMCPUVENDOR_AMPERE: return "AMPERE";
187
188 case CPUMCPUVENDOR_INVALID:
189 case CPUMCPUVENDOR_UNKNOWN:
190 case CPUMCPUVENDOR_32BIT_HACK:
191 break;
192 }
193 return "invalid-cpu-vendor";
194}
195
196
197/**
198 * Converts @a enmCoreType to the enum value name sans the typename prefix.
199 */
200const char *vbGetCoreTypeToString(CPUMCORETYPE enmCoreType)
201{
202 switch (enmCoreType)
203 {
204 case kCpumCoreType_Efficiency: return "Efficiency";
205 case kCpumCoreType_Performance: return "Performance";
206 case kCpumCoreType_Unknown: return "Unknown";
207
208 case kCpumCoreType_Invalid:
209 case kCpumCoreType_End:
210 case kCpumCoreType_32BitHack:
211 break;
212 }
213 return NULL;
214}
215
216
217int main(int argc, char **argv)
218{
219 int rc = RTR3InitExe(argc, &argv, 0 /*fFlags*/);
220 if (RT_FAILURE(rc))
221 return RTMsgInitFailure(rc);
222
223 /*
224 * Argument parsing?
225 */
226 static const RTGETOPTDEF s_aOptions[] =
227 {
228 { "--cpu-name", 'c', RTGETOPT_REQ_STRING },
229#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
230 { "--msrs-only", 'm', RTGETOPT_REQ_NOTHING },
231 { "--msrs-dev", 'd', RTGETOPT_REQ_NOTHING },
232 { "--no-msrs", 'n', RTGETOPT_REQ_NOTHING },
233#endif
234 { "--output", 'o', RTGETOPT_REQ_STRING },
235 { "--log", 'l', RTGETOPT_REQ_STRING },
236 };
237 RTGETOPTSTATE State;
238 RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
239
240 enum
241 {
242 kCpuReportOp_Normal,
243#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
244 kCpuReportOp_MsrsOnly,
245 kCpuReportOp_MsrsHacking
246#else
247 kCpuReportOp_Dummy
248#endif
249 } enmOp = kCpuReportOp_Normal;
250 g_pReportOut = NULL;
251 g_pDebugOut = NULL;
252 const char *pszOutput = NULL;
253 const char *pszDebugOut = NULL;
254
255 int iOpt;
256 RTGETOPTUNION ValueUnion;
257 while ((iOpt = RTGetOpt(&State, &ValueUnion)) != 0)
258 {
259 switch (iOpt)
260 {
261 case 'c':
262 g_pszCpuNameOverride = *ValueUnion.psz ? ValueUnion.psz : NULL;
263 break;
264
265#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
266 case 'm':
267 enmOp = kCpuReportOp_MsrsOnly;
268 break;
269
270 case 'd':
271 enmOp = kCpuReportOp_MsrsHacking;
272 break;
273
274 case 'n':
275 g_fNoMsrs = true;
276 break;
277#endif
278
279 case 'o':
280 pszOutput = ValueUnion.psz;
281 break;
282
283 case 'l':
284 pszDebugOut = ValueUnion.psz;
285 break;
286
287 case 'h':
288 {
289#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
290 const char * const pszArchOps = "[-m|--msrs-only] [-d|--msrs-dev] [-n|--no-msrs] ";
291#else
292 const char * const pszArchOps = "";
293#endif
294 RTPrintf("Usage: VBoxCpuReport %s[-c|--cpu-name <name>] [-h|--help] [-V|--version] [-o filename.h] [-l debug.log]\n",
295 pszArchOps);
296 RTPrintf("Internal tool for gathering information to the VMM CPU database.\n");
297 return RTEXITCODE_SUCCESS;
298 }
299 case 'V':
300 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
301 return RTEXITCODE_SUCCESS;
302 default:
303 return RTGetOptPrintError(iOpt, &ValueUnion);
304 }
305 }
306
307 /*
308 * Open the alternative debug log stream.
309 */
310 if (pszDebugOut)
311 {
312 if (RTFileExists(pszDebugOut) && !RTSymlinkExists(pszDebugOut))
313 {
314 char szOld[RTPATH_MAX];
315 rc = RTStrCopy(szOld, sizeof(szOld), pszDebugOut);
316 if (RT_SUCCESS(rc))
317 rc = RTStrCat(szOld, sizeof(szOld), ".old");
318 if (RT_SUCCESS(rc))
319 RTFileRename(pszDebugOut, szOld, RTFILEMOVE_FLAGS_REPLACE);
320 }
321 rc = RTStrmOpen(pszDebugOut, "w", &g_pDebugOut);
322 if (RT_FAILURE(rc))
323 {
324 RTMsgError("Error opening '%s': %Rrc", pszDebugOut, rc);
325 g_pDebugOut = NULL;
326 }
327 }
328
329 /*
330 * Do the requested job.
331 */
332 rc = VERR_INTERNAL_ERROR;
333 switch (enmOp)
334 {
335 case kCpuReportOp_Normal:
336 /* switch output file. */
337 if (pszOutput)
338 {
339 if (RTFileExists(pszOutput) && !RTSymlinkExists(pszOutput))
340 {
341 char szOld[RTPATH_MAX];
342 rc = RTStrCopy(szOld, sizeof(szOld), pszOutput);
343 if (RT_SUCCESS(rc))
344 rc = RTStrCat(szOld, sizeof(szOld), ".old");
345 if (RT_SUCCESS(rc))
346 RTFileRename(pszOutput, szOld, RTFILEMOVE_FLAGS_REPLACE);
347 }
348 rc = RTStrmOpen(pszOutput, "w", &g_pReportOut);
349 if (RT_FAILURE(rc))
350 {
351 RTMsgError("Error opening '%s': %Rrc", pszOutput, rc);
352 break;
353 }
354 }
355 rc = produceCpuReport();
356 break;
357#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
358 case kCpuReportOp_MsrsOnly:
359 case kCpuReportOp_MsrsHacking:
360 rc = probeMsrs(enmOp == kCpuReportOp_MsrsHacking, NULL, NULL, NULL, 0);
361 break;
362#else
363 case kCpuReportOp_Dummy:
364 break;
365#endif
366 }
367
368 /*
369 * Close the output files.
370 */
371 if (g_pReportOut)
372 {
373 RTStrmClose(g_pReportOut);
374 g_pReportOut = NULL;
375 }
376
377 if (g_pDebugOut)
378 {
379 RTStrmClose(g_pDebugOut);
380 g_pDebugOut = NULL;
381 }
382
383 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
384}
385
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