VirtualBox

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

Last change on this file since 109020 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: 11.6 KB
Line 
1/* $Id: VBoxCpuReport.cpp 109020 2025-04-17 23:37:08Z 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
169const char *vbCpuVendorToString(CPUMCPUVENDOR enmCpuVendor)
170{
171 switch (enmCpuVendor)
172 {
173 case CPUMCPUVENDOR_INTEL: return "Intel";
174 case CPUMCPUVENDOR_AMD: return "AMD";
175 case CPUMCPUVENDOR_VIA: return "VIA";
176 case CPUMCPUVENDOR_CYRIX: return "Cyrix";
177 case CPUMCPUVENDOR_SHANGHAI: return "Shanghai";
178 case CPUMCPUVENDOR_HYGON: return "Hygon";
179
180 case CPUMCPUVENDOR_ARM: return "ARM";
181 case CPUMCPUVENDOR_BROADCOM: return "Broadcom";
182 case CPUMCPUVENDOR_QUALCOMM: return "Qualecomm";
183 case CPUMCPUVENDOR_APPLE: return "Apple";
184 case CPUMCPUVENDOR_AMPERE: return "Ampere";
185
186 case CPUMCPUVENDOR_INVALID:
187 case CPUMCPUVENDOR_UNKNOWN:
188 case CPUMCPUVENDOR_32BIT_HACK:
189 break;
190 }
191 return "invalid-cpu-vendor";
192}
193
194
195int main(int argc, char **argv)
196{
197 int rc = RTR3InitExe(argc, &argv, 0 /*fFlags*/);
198 if (RT_FAILURE(rc))
199 return RTMsgInitFailure(rc);
200
201 /*
202 * Argument parsing?
203 */
204 static const RTGETOPTDEF s_aOptions[] =
205 {
206 { "--cpu-name", 'c', RTGETOPT_REQ_STRING },
207#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
208 { "--msrs-only", 'm', RTGETOPT_REQ_NOTHING },
209 { "--msrs-dev", 'd', RTGETOPT_REQ_NOTHING },
210 { "--no-msrs", 'n', RTGETOPT_REQ_NOTHING },
211#endif
212 { "--output", 'o', RTGETOPT_REQ_STRING },
213 { "--log", 'l', RTGETOPT_REQ_STRING },
214 };
215 RTGETOPTSTATE State;
216 RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
217
218 enum
219 {
220 kCpuReportOp_Normal,
221#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
222 kCpuReportOp_MsrsOnly,
223 kCpuReportOp_MsrsHacking
224#else
225 kCpuReportOp_Dummy
226#endif
227 } enmOp = kCpuReportOp_Normal;
228 g_pReportOut = NULL;
229 g_pDebugOut = NULL;
230 const char *pszOutput = NULL;
231 const char *pszDebugOut = NULL;
232
233 int iOpt;
234 RTGETOPTUNION ValueUnion;
235 while ((iOpt = RTGetOpt(&State, &ValueUnion)) != 0)
236 {
237 switch (iOpt)
238 {
239 case 'c':
240 g_pszCpuNameOverride = *ValueUnion.psz ? ValueUnion.psz : NULL;
241 break;
242
243#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
244 case 'm':
245 enmOp = kCpuReportOp_MsrsOnly;
246 break;
247
248 case 'd':
249 enmOp = kCpuReportOp_MsrsHacking;
250 break;
251
252 case 'n':
253 g_fNoMsrs = true;
254 break;
255#endif
256
257 case 'o':
258 pszOutput = ValueUnion.psz;
259 break;
260
261 case 'l':
262 pszDebugOut = ValueUnion.psz;
263 break;
264
265 case 'h':
266 {
267#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
268 const char * const pszArchOps = "[-m|--msrs-only] [-d|--msrs-dev] [-n|--no-msrs] ";
269#else
270 const char * const pszArchOps = "";
271#endif
272 RTPrintf("Usage: VBoxCpuReport %s[-c|--cpu-name <name>] [-h|--help] [-V|--version] [-o filename.h] [-l debug.log]\n",
273 pszArchOps);
274 RTPrintf("Internal tool for gathering information to the VMM CPU database.\n");
275 return RTEXITCODE_SUCCESS;
276 }
277 case 'V':
278 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
279 return RTEXITCODE_SUCCESS;
280 default:
281 return RTGetOptPrintError(iOpt, &ValueUnion);
282 }
283 }
284
285 /*
286 * Open the alternative debug log stream.
287 */
288 if (pszDebugOut)
289 {
290 if (RTFileExists(pszDebugOut) && !RTSymlinkExists(pszDebugOut))
291 {
292 char szOld[RTPATH_MAX];
293 rc = RTStrCopy(szOld, sizeof(szOld), pszDebugOut);
294 if (RT_SUCCESS(rc))
295 rc = RTStrCat(szOld, sizeof(szOld), ".old");
296 if (RT_SUCCESS(rc))
297 RTFileRename(pszDebugOut, szOld, RTFILEMOVE_FLAGS_REPLACE);
298 }
299 rc = RTStrmOpen(pszDebugOut, "w", &g_pDebugOut);
300 if (RT_FAILURE(rc))
301 {
302 RTMsgError("Error opening '%s': %Rrc", pszDebugOut, rc);
303 g_pDebugOut = NULL;
304 }
305 }
306
307 /*
308 * Do the requested job.
309 */
310 rc = VERR_INTERNAL_ERROR;
311 switch (enmOp)
312 {
313 case kCpuReportOp_Normal:
314 /* switch output file. */
315 if (pszOutput)
316 {
317 if (RTFileExists(pszOutput) && !RTSymlinkExists(pszOutput))
318 {
319 char szOld[RTPATH_MAX];
320 rc = RTStrCopy(szOld, sizeof(szOld), pszOutput);
321 if (RT_SUCCESS(rc))
322 rc = RTStrCat(szOld, sizeof(szOld), ".old");
323 if (RT_SUCCESS(rc))
324 RTFileRename(pszOutput, szOld, RTFILEMOVE_FLAGS_REPLACE);
325 }
326 rc = RTStrmOpen(pszOutput, "w", &g_pReportOut);
327 if (RT_FAILURE(rc))
328 {
329 RTMsgError("Error opening '%s': %Rrc", pszOutput, rc);
330 break;
331 }
332 }
333 rc = produceCpuReport();
334 break;
335#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
336 case kCpuReportOp_MsrsOnly:
337 case kCpuReportOp_MsrsHacking:
338 rc = probeMsrs(enmOp == kCpuReportOp_MsrsHacking, NULL, NULL, NULL, 0);
339 break;
340#else
341 case kCpuReportOp_Dummy:
342 break;
343#endif
344 }
345
346 /*
347 * Close the output files.
348 */
349 if (g_pReportOut)
350 {
351 RTStrmClose(g_pReportOut);
352 g_pReportOut = NULL;
353 }
354
355 if (g_pDebugOut)
356 {
357 RTStrmClose(g_pDebugOut);
358 g_pDebugOut = NULL;
359 }
360
361 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
362}
363
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