VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testboxscript/TestBoxHelper.cpp@ 64226

Last change on this file since 64226 was 62484, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.5 KB
Line 
1/* $Id: TestBoxHelper.cpp 62484 2016-07-22 18:35:33Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Testbox C Helper Utility.
4 */
5
6/*
7 * Copyright (C) 2012-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/buildconfig.h>
32#include <iprt/env.h>
33#include <iprt/initterm.h>
34#include <iprt/message.h>
35#include <iprt/mp.h>
36#include <iprt/string.h>
37#include <iprt/stream.h>
38#include <iprt/system.h>
39
40#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
41# include <iprt/x86.h>
42# include <iprt/asm-amd64-x86.h>
43#endif
44
45#ifdef RT_OS_DARWIN
46# include <sys/types.h>
47# include <sys/sysctl.h>
48#endif
49
50
51/**
52 * Generates a kind of report of the hardware, software and whatever else we
53 * think might be useful to know about the testbox.
54 */
55static RTEXITCODE handlerReport(int argc, char **argv)
56{
57 NOREF(argc); NOREF(argv);
58
59#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
60 /*
61 * For now, a simple CPUID dump. Need to figure out how to share code
62 * like this with other bits, putting it in IPRT.
63 */
64 RTPrintf("CPUID Dump\n"
65 "Leaf eax ebx ecx edx\n"
66 "---------------------------------------------\n");
67 static uint32_t const s_auRanges[] =
68 {
69 UINT32_C(0x00000000),
70 UINT32_C(0x80000000),
71 UINT32_C(0x80860000),
72 UINT32_C(0xc0000000),
73 UINT32_C(0x40000000),
74 };
75 for (uint32_t iRange = 0; iRange < RT_ELEMENTS(s_auRanges); iRange++)
76 {
77 uint32_t const uFirst = s_auRanges[iRange];
78
79 uint32_t uEax, uEbx, uEcx, uEdx;
80 ASMCpuIdExSlow(uFirst, 0, 0, 0, &uEax, &uEbx, &uEcx, &uEdx);
81 if (uEax >= uFirst && uEax < uFirst + 100)
82 {
83 uint32_t const cLeafs = RT_MIN(uEax - uFirst + 1, 32);
84 for (uint32_t iLeaf = 0; iLeaf < cLeafs; iLeaf++)
85 {
86 uint32_t uLeaf = uFirst + iLeaf;
87 ASMCpuIdExSlow(uLeaf, 0, 0, 0, &uEax, &uEbx, &uEcx, &uEdx);
88
89 /* Clear APIC IDs to avoid submitting new reports all the time. */
90 if (uLeaf == 1)
91 uEbx &= UINT32_C(0x00ffffff);
92 if (uLeaf == 0xb)
93 uEdx = 0;
94 if (uLeaf == 0x8000001e)
95 uEax = 0;
96
97 /* Clear some other node/cpu/core/thread ids. */
98 if (uLeaf == 0x8000001e)
99 {
100 uEbx &= UINT32_C(0xffffff00);
101 uEcx &= UINT32_C(0xffffff00);
102 }
103
104 RTPrintf("%08x: %08x %08x %08x %08x\n", uLeaf, uEax, uEbx, uEcx, uEdx);
105 }
106 }
107 }
108 RTPrintf("\n");
109
110 /*
111 * DMI info.
112 */
113 RTPrintf("DMI Info\n"
114 "--------\n");
115 static const struct { const char *pszName; RTSYSDMISTR enmDmiStr; } s_aDmiStrings[] =
116 {
117 { "Product Name", RTSYSDMISTR_PRODUCT_NAME },
118 { "Product version", RTSYSDMISTR_PRODUCT_VERSION },
119 { "Product UUID", RTSYSDMISTR_PRODUCT_UUID },
120 { "Product Serial", RTSYSDMISTR_PRODUCT_SERIAL },
121 { "System Manufacturer", RTSYSDMISTR_MANUFACTURER },
122 };
123 for (uint32_t iDmiString = 0; iDmiString < RT_ELEMENTS(s_aDmiStrings); iDmiString++)
124 {
125 char szTmp[4096];
126 RT_ZERO(szTmp);
127 int rc = RTSystemQueryDmiString(s_aDmiStrings[iDmiString].enmDmiStr, szTmp, sizeof(szTmp) - 1);
128 if (RT_SUCCESS(rc))
129 RTPrintf("%25s: %s\n", s_aDmiStrings[iDmiString].pszName, RTStrStrip(szTmp));
130 else
131 RTPrintf("%25s: %s [rc=%Rrc]\n", s_aDmiStrings[iDmiString].pszName, RTStrStrip(szTmp), rc);
132 }
133 RTPrintf("\n");
134
135#else
136#endif
137
138 /*
139 * Dump the environment.
140 */
141 RTPrintf("Environment\n"
142 "-----------\n");
143 RTENV hEnv;
144 int rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
145 if (RT_SUCCESS(rc))
146 {
147 uint32_t cVars = RTEnvCountEx(hEnv);
148 for (uint32_t iVar = 0; iVar < cVars; iVar++)
149 {
150 char szVar[1024];
151 char szValue[16384];
152 rc = RTEnvGetByIndexEx(hEnv, iVar, szVar, sizeof(szVar), szValue, sizeof(szValue));
153
154 /* zap the value of variables that are subject to change. */
155 if ( (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
156 && ( !strcmp(szVar, "TESTBOX_SCRIPT_REV")
157 || !strcmp(szVar, "TESTBOX_ID")
158 || !strcmp(szVar, "TESTBOX_SCRATCH_SIZE")
159 || !strcmp(szVar, "TESTBOX_TIMEOUT")
160 || !strcmp(szVar, "TESTBOX_TIMEOUT_ABS")
161 || !strcmp(szVar, "TESTBOX_TEST_SET_ID")
162 )
163 )
164 strcpy(szValue, "<volatile>");
165
166 if (RT_SUCCESS(rc))
167 RTPrintf("%25s=%s\n", szVar, szValue);
168 else if (rc == VERR_BUFFER_OVERFLOW)
169 RTPrintf("%25s=%s [VERR_BUFFER_OVERFLOW]\n", szVar, szValue);
170 else
171 RTPrintf("rc=%Rrc\n", rc);
172 }
173 RTEnvDestroy(hEnv);
174 }
175
176 /** @todo enumerate volumes and whatnot. */
177
178 int cch = RTPrintf("\n");
179 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
180}
181
182
183/** Print the total memory size in bytes. */
184static RTEXITCODE handlerMemSize(int argc, char **argv)
185{
186 NOREF(argc); NOREF(argv);
187
188 uint64_t cb;
189 int rc = RTSystemQueryTotalRam(&cb);
190 if (RT_SUCCESS(rc))
191 {
192 int cch = RTPrintf("%llu\n", cb);
193 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
194 }
195 RTPrintf("%Rrc\n", rc);
196 return RTEXITCODE_FAILURE;
197}
198
199typedef enum { HWVIRTTYPE_NONE, HWVIRTTYPE_VTX, HWVIRTTYPE_AMDV } HWVIRTTYPE;
200static HWVIRTTYPE isHwVirtSupported(void)
201{
202#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
203 uint32_t uEax, uEbx, uEcx, uEdx;
204
205 /* VT-x */
206 ASMCpuId(0x00000000, &uEax, &uEbx, &uEcx, &uEdx);
207 if (ASMIsValidStdRange(uEax))
208 {
209 ASMCpuId(0x00000001, &uEax, &uEbx, &uEcx, &uEdx);
210 if (uEcx & X86_CPUID_FEATURE_ECX_VMX)
211 return HWVIRTTYPE_VTX;
212 }
213
214 /* AMD-V */
215 ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
216 if (ASMIsValidExtRange(uEax))
217 {
218 ASMCpuId(0x80000001, &uEax, &uEbx, &uEcx, &uEdx);
219 if (uEcx & X86_CPUID_AMD_FEATURE_ECX_SVM)
220 return HWVIRTTYPE_AMDV;
221 }
222#endif
223
224 return HWVIRTTYPE_NONE;
225}
226
227/** Print the 'true' if VT-x or AMD-v is supported, 'false' it not. */
228static RTEXITCODE handlerCpuHwVirt(int argc, char **argv)
229{
230 NOREF(argc); NOREF(argv);
231 int cch = RTPrintf(isHwVirtSupported() != HWVIRTTYPE_NONE ? "true\n" : "false\n");
232 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
233}
234
235
236/** Print the 'true' if nested paging is supported, 'false' if not and
237 * 'dunno' if we cannot tell. */
238static RTEXITCODE handlerCpuNestedPaging(int argc, char **argv)
239{
240 NOREF(argc); NOREF(argv);
241 HWVIRTTYPE enmHwVirt = isHwVirtSupported();
242 int fSupported = -1;
243
244#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
245 if (enmHwVirt == HWVIRTTYPE_AMDV)
246 {
247 uint32_t uEax, uEbx, uEcx, uEdx;
248 ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
249 if (ASMIsValidExtRange(uEax) && uEax >= 0x8000000a)
250 {
251 ASMCpuId(0x8000000a, &uEax, &uEbx, &uEcx, &uEdx);
252 if (uEdx & RT_BIT(0) /* AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING */)
253 fSupported = 1;
254 else
255 fSupported = 0;
256 }
257 }
258#endif
259
260 int cch = RTPrintf(fSupported == 1 ? "true\n" : fSupported == 0 ? "false\n" : "dunno\n");
261 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
262}
263
264
265/** Print the 'true' if long mode guests are supported, 'false' if not and
266 * 'dunno' if we cannot tell. */
267static RTEXITCODE handlerCpuLongMode(int argc, char **argv)
268{
269 NOREF(argc); NOREF(argv);
270 HWVIRTTYPE enmHwVirt = isHwVirtSupported();
271 int fSupported = 0;
272
273 if (enmHwVirt != HWVIRTTYPE_NONE)
274 {
275#if defined(RT_ARCH_AMD64)
276 fSupported = 1; /* We're running long mode, so it must be supported. */
277
278#elif defined(RT_ARCH_X86)
279# ifdef RT_OS_DARWIN
280 /* On darwin, we just ask the kernel via sysctl. Rules are a bit different here. */
281 int f64bitCapable = 0;
282 size_t cbParameter = sizeof(f64bitCapable);
283 int rc = sysctlbyname("hw.cpu64bit_capable", &f64bitCapable, &cbParameter, NULL, NULL);
284 if (rc != -1)
285 fSupported = f64bitCapable != 0;
286 else
287# endif
288 {
289 /* PAE and HwVirt are required */
290 uint32_t uEax, uEbx, uEcx, uEdx;
291 ASMCpuId(0x00000000, &uEax, &uEbx, &uEcx, &uEdx);
292 if (ASMIsValidStdRange(uEax))
293 {
294 ASMCpuId(0x00000001, &uEax, &uEbx, &uEcx, &uEdx);
295 if (uEdx & X86_CPUID_FEATURE_EDX_PAE)
296 {
297 /* AMD will usually advertise long mode in 32-bit mode. Intel OTOH,
298 won't necessarily do so. */
299 ASMCpuId(0x80000000, &uEax, &uEbx, &uEcx, &uEdx);
300 if (ASMIsValidExtRange(uEax))
301 {
302 ASMCpuId(0x80000001, &uEax, &uEbx, &uEcx, &uEdx);
303 if (uEdx & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE)
304 fSupported = 1;
305 else if (enmHwVirt != HWVIRTTYPE_AMDV)
306 fSupported = -1;
307 }
308 }
309 }
310 }
311#endif
312 }
313
314 int cch = RTPrintf(fSupported == 1 ? "true\n" : fSupported == 0 ? "false\n" : "dunno\n");
315 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
316}
317
318
319/** Print the CPU 'revision', if available. */
320static RTEXITCODE handlerCpuRevision(int argc, char **argv)
321{
322 NOREF(argc); NOREF(argv);
323
324#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
325 uint32_t uEax, uEbx, uEcx, uEdx;
326 ASMCpuId(0, &uEax, &uEbx, &uEcx, &uEdx);
327 if (ASMIsValidStdRange(uEax) && uEax >= 1)
328 {
329 uint32_t uEax1 = ASMCpuId_EAX(1);
330 uint32_t uVersion = (ASMGetCpuFamily(uEax1) << 24)
331 | (ASMGetCpuModel(uEax1, ASMIsIntelCpuEx(uEbx, uEcx, uEdx)) << 8)
332 | ASMGetCpuStepping(uEax1);
333 int cch = RTPrintf("%#x\n", uVersion);
334 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
335 }
336#endif
337 return RTEXITCODE_FAILURE;
338}
339
340
341/** Print the CPU name, if available. */
342static RTEXITCODE handlerCpuName(int argc, char **argv)
343{
344 NOREF(argc); NOREF(argv);
345
346 char szTmp[1024];
347 int rc = RTMpGetDescription(NIL_RTCPUID, szTmp, sizeof(szTmp));
348 if (RT_SUCCESS(rc))
349 {
350 int cch = RTPrintf("%s\n", RTStrStrip(szTmp));
351 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
352 }
353 return RTEXITCODE_FAILURE;
354}
355
356
357/** Print the CPU vendor name, 'GenuineIntel' and such. */
358static RTEXITCODE handlerCpuVendor(int argc, char **argv)
359{
360 NOREF(argc); NOREF(argv);
361
362#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
363 uint32_t uEax, uEbx, uEcx, uEdx;
364 ASMCpuId(0, &uEax, &uEbx, &uEcx, &uEdx);
365 int cch = RTPrintf("%.04s%.04s%.04s\n", &uEbx, &uEdx, &uEcx);
366#else
367 int cch = RTPrintf("%s\n", RTBldCfgTargetArch());
368#endif
369 return cch > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
370}
371
372
373
374int main(int argc, char **argv)
375{
376 int rc = RTR3InitExe(argc, &argv, 0);
377 if (RT_FAILURE(rc))
378 return RTMsgInitFailure(rc);
379
380 /*
381 * The first argument is a command. Figure out which and call its handler.
382 */
383 static const struct
384 {
385 const char *pszCommand;
386 RTEXITCODE (*pfnHandler)(int argc, char **argv);
387 bool fNoArgs;
388 } s_aHandlers[] =
389 {
390 { "cpuvendor", handlerCpuVendor, true },
391 { "cpuname", handlerCpuName, true },
392 { "cpurevision", handlerCpuRevision, true },
393 { "cpuhwvirt", handlerCpuHwVirt, true },
394 { "nestedpaging", handlerCpuNestedPaging, true },
395 { "longmode", handlerCpuLongMode, true },
396 { "memsize", handlerMemSize, true },
397 { "report", handlerReport, true }
398 };
399
400 if (argc < 2)
401 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "expected command as the first argument");
402
403 for (unsigned i = 0; i < RT_ELEMENTS(s_aHandlers); i++)
404 {
405 if (!strcmp(argv[1], s_aHandlers[i].pszCommand))
406 {
407 if ( s_aHandlers[i].fNoArgs
408 && argc != 2)
409 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "the command '%s' does not take any arguments", argv[1]);
410 return s_aHandlers[i].pfnHandler(argc - 1, argv + 1);
411 }
412 }
413
414 /*
415 * Help or version query?
416 */
417 for (int i = 1; i < argc; i++)
418 if ( !strcmp(argv[i], "--help")
419 || !strcmp(argv[i], "-h")
420 || !strcmp(argv[i], "-?")
421 || !strcmp(argv[i], "help") )
422 {
423 RTPrintf("usage: %s <cmd> [cmd specific args]\n"
424 "\n"
425 "commands:\n", argv[0]);
426 for (unsigned j = 0; j < RT_ELEMENTS(s_aHandlers); j++)
427 RTPrintf(" %s\n", s_aHandlers[j].pszCommand);
428 return RTEXITCODE_FAILURE;
429 }
430 else if ( !strcmp(argv[i], "--version")
431 || !strcmp(argv[i], "-V") )
432 {
433 RTPrintf("%sr%u", RTBldCfgVersion(), RTBldCfgRevision());
434 return argc == 2 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
435 }
436
437 /*
438 * Syntax error.
439 */
440 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "unknown command '%s'", argv[1]);
441}
442
Note: See TracBrowser for help on using the repository browser.

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