VirtualBox

source: vbox/trunk/src/VBox/VMM/testcase/tstMicro.cpp@ 56985

Last change on this file since 56985 was 56287, checked in by vboxsync, 9 years ago

VMM: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.0 KB
Line 
1/* $Id: tstMicro.cpp 56287 2015-06-09 11:15:22Z vboxsync $ */
2/** @file
3 * Micro Testcase, profiling special CPU operations.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <VBox/vmm/vm.h>
22#include <VBox/vmm/vmm.h>
23#include <VBox/vmm/mm.h>
24#include <VBox/vmm/cpum.h>
25#include <VBox/vmm/pdmapi.h>
26#include <VBox/vmm/dbgf.h>
27#include <VBox/vmm/pgm.h>
28#include <VBox/err.h>
29#include <VBox/param.h>
30
31#include <VBox/log.h>
32#include <iprt/assert.h>
33#include <iprt/initterm.h>
34#include <iprt/stream.h>
35#include <iprt/string.h>
36#include <iprt/semaphore.h>
37
38#include "tstMicro.h"
39
40
41/*******************************************************************************
42* Defined Constants And Macros *
43*******************************************************************************/
44#define TESTCASE "tstVMM"
45
46static const char *GetDescription(TSTMICROTEST enmTest)
47{
48 switch (enmTest)
49 {
50 case TSTMICROTEST_OVERHEAD: return "Overhead";
51 case TSTMICROTEST_INVLPG_0: return "invlpg [0]";
52 case TSTMICROTEST_INVLPG_EIP: return "invlpg [EIP]";
53 case TSTMICROTEST_INVLPG_ESP: return "invlpg [ESP]";
54 case TSTMICROTEST_CR3_RELOAD: return "cr3 reload";
55 case TSTMICROTEST_WP_DISABLE: return "CR0.WP <- 0";
56 case TSTMICROTEST_WP_ENABLE: return "CR0.WP <- 1";
57
58 case TSTMICROTEST_PF_R0: return "R0 #PG (NULL)";
59 case TSTMICROTEST_PF_R1: return "R1 #PG (NULL)";
60 case TSTMICROTEST_PF_R2: return "R2 #PG (NULL)";
61 case TSTMICROTEST_PF_R3: return "R3 #PG (NULL)";
62
63 default:
64 {
65 static char sz[64];
66 RTStrPrintf(sz, sizeof(sz), "%d?", enmTest);
67 return sz;
68 }
69 }
70}
71
72
73static void PrintHeaderInstr(void)
74{
75 RTPrintf(TESTCASE ": %-25s %10s %10s %10s\n",
76 "Test name",
77 "Min",
78 "Avg",
79 "Max");
80}
81
82static void PrintResultInstr(PTSTMICRO pTst, TSTMICROTEST enmTest, int rc, uint64_t cMinTicks, uint64_t cAvgTicks, uint64_t cMaxTicks)
83{
84 if (RT_FAILURE(rc))
85 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu - %Rrc cr2=%x err=%x eip=%x!\n",
86 GetDescription(enmTest),
87 cMinTicks,
88 cAvgTicks,
89 cMaxTicks,
90 rc,
91 pTst->u32CR2,
92 pTst->u32ErrCd,
93 pTst->u32EIP);
94 else
95 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu\n",
96 GetDescription(enmTest),
97 cMinTicks,
98 cAvgTicks,
99 cMaxTicks);
100}
101
102static void PrintHeaderTraps(void)
103{
104 RTPrintf(TESTCASE ": %-25s %10s %10s %10s %10s %10s\n",
105 "Test name",
106 "Total",
107 "ToRx",
108 "Trap",
109 "ToRxTrap",
110 "int42-done");
111}
112
113static void PrintResultTrap(PTSTMICRO pTst, TSTMICROTEST enmTest, int rc)
114{
115 if (RT_FAILURE(rc))
116 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu %10llu %10llu - %Rrc cr2=%x err=%x eip=%x!\n",
117 GetDescription(enmTest),
118 pTst->aResults[enmTest].cTotalTicks,
119 pTst->aResults[enmTest].cToRxFirstTicks,
120 pTst->aResults[enmTest].cTrapTicks,
121 pTst->aResults[enmTest].cToRxTrapTicks,
122 pTst->aResults[enmTest].cToR0Ticks,
123 rc,
124 pTst->u32CR2,
125 pTst->u32ErrCd,
126 pTst->u32EIP);
127 else
128 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu %10llu %10llu\n",
129 GetDescription(enmTest),
130 pTst->aResults[enmTest].cTotalTicks,
131 pTst->aResults[enmTest].cToRxFirstTicks,
132 pTst->aResults[enmTest].cTrapTicks,
133 pTst->aResults[enmTest].cToRxTrapTicks,
134 pTst->aResults[enmTest].cToR0Ticks);
135}
136
137
138/**
139 * 'Allocate' selectors for 32-bit code/data in rings 0-3.
140 *
141 * 0060 - r0 code
142 * 0068 - r0 data
143 *
144 * 1060 - r1 code
145 * 1068 - r1 data
146 *
147 * 2060 - r2 code
148 * 2068 - r2 data
149 *
150 * 3060 - r3 code
151 * 3068 - r3 data
152 *
153 */
154static void SetupSelectors(PVM pVM)
155{
156 /*
157 * Find the GDT - This is a HACK :-)
158 */
159 RTRCPTR RCPtr = CPUMGetHyperGDTR(VMMGetCpu0(pVM), NULL);
160 PX86DESC paGDTEs = (PX86DESC)MMHyperRCToR3(pVM, RCPtr);
161
162 for (unsigned i = 0; i <= 3; i++)
163 {
164 RTSEL Sel = (i << 12) + 0x60;
165
166 /* 32-bit code selector. */
167 PX86DESC pGDTE = &paGDTEs[Sel >> X86_SEL_SHIFT];
168 pGDTE->au32[0] = pGDTE->au32[1] = 0;
169 pGDTE->Gen.u16LimitLow = 0xffff;
170 pGDTE->Gen.u4LimitHigh = 0xf;
171 pGDTE->Gen.u1Granularity= 1;
172 pGDTE->Gen.u1Present = 1;
173 pGDTE->Gen.u2Dpl = i;
174 pGDTE->Gen.u1DefBig = 1;
175 pGDTE->Gen.u1DescType = 1; /* !system */
176 pGDTE->Gen.u4Type = X86_SEL_TYPE_ER_ACC;
177
178 /* 32-bit data selector. */
179 pGDTE++;
180 pGDTE->au32[0] = pGDTE->au32[1] = 0;
181 pGDTE->Gen.u16LimitLow = 0xffff;
182 pGDTE->Gen.u4LimitHigh = 0xf;
183 pGDTE->Gen.u1Granularity= 1;
184 pGDTE->Gen.u1Present = 1;
185 pGDTE->Gen.u2Dpl = i;
186 pGDTE->Gen.u1DefBig = 1;
187 pGDTE->Gen.u1DescType = 1; /* !system */
188 pGDTE->Gen.u4Type = X86_SEL_TYPE_RW_ACC;
189 }
190}
191
192
193static DECLCALLBACK(int) doit(PVM pVM)
194{
195 RTPrintf(TESTCASE ": testing...\n");
196 SetupSelectors(pVM);
197
198 /*
199 * Loading the module and resolve the entry point.
200 */
201 int rc = PDMR3LdrLoadRC(pVM, NULL, "tstMicroRC.gc");
202 if (RT_FAILURE(rc))
203 {
204 RTPrintf(TESTCASE ": Failed to load tstMicroRC.gc, rc=%Rra\n", rc);
205 return rc;
206 }
207 RTRCPTR RCPtrEntry;
208 rc = PDMR3LdrGetSymbolRC(pVM, "tstMicroRC.gc", "tstMicroRC", &RCPtrEntry);
209 if (RT_FAILURE(rc))
210 {
211 RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroRC' entry point in tstMicroRC.gc, rc=%Rra\n", rc);
212 return rc;
213 }
214 RTRCPTR RCPtrStart;
215 rc = PDMR3LdrGetSymbolRC(pVM, "tstMicroRC.gc", "tstMicroRCAsmStart", &RCPtrStart);
216 if (RT_FAILURE(rc))
217 {
218 RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroRCAsmStart' entry point in tstMicroRC.gc, rc=%Rra\n", rc);
219 return rc;
220 }
221 RTRCPTR RCPtrEnd;
222 rc = PDMR3LdrGetSymbolRC(pVM, "tstMicroRC.gc", "tstMicroRCAsmEnd", &RCPtrEnd);
223 if (RT_FAILURE(rc))
224 {
225 RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroRCAsmEnd' entry point in tstMicroRC.gc, rc=%Rra\n", rc);
226 return rc;
227 }
228
229 /*
230 * Allocate and initialize the instance data.
231 */
232 PTSTMICRO pTst;
233 rc = MMHyperAlloc(pVM, RT_ALIGN_Z(sizeof(*pTst), PAGE_SIZE), PAGE_SIZE, MM_TAG_VM, (void **)&pTst);
234 if (RT_FAILURE(rc))
235 {
236 RTPrintf(TESTCASE ": Failed to resolve allocate instance memory (%d bytes), rc=%Rra\n", sizeof(*pTst), rc);
237 return rc;
238 }
239 pTst->RCPtr = MMHyperR3ToRC(pVM, pTst);
240 pTst->RCPtrStack = MMHyperR3ToRC(pVM, &pTst->au8Stack[sizeof(pTst->au8Stack) - 32]);
241
242 /* the page must be writable from user mode */
243 rc = PGMMapModifyPage(pVM, pTst->RCPtr, sizeof(*pTst), X86_PTE_US | X86_PTE_RW, ~(uint64_t)(X86_PTE_US | X86_PTE_RW));
244 if (RT_FAILURE(rc))
245 {
246 RTPrintf(TESTCASE ": PGMMapModifyPage -> rc=%Rra\n", rc);
247 return rc;
248 }
249
250 /* all the code must be executable from R3. */
251 rc = PGMMapModifyPage(pVM, RCPtrStart, RCPtrEnd - RCPtrStart + PAGE_SIZE, X86_PTE_US, ~(uint64_t)X86_PTE_US);
252 if (RT_FAILURE(rc))
253 {
254 RTPrintf(TESTCASE ": PGMMapModifyPage -> rc=%Rra\n", rc);
255 return rc;
256 }
257 DBGFR3PagingDumpEx(pVM->pUVM, 0 /*idCpu*/, DBGFPGDMP_FLAGS_CURRENT_CR3 | DBGFPGDMP_FLAGS_CURRENT_MODE
258 | DBGFPGDMP_FLAGS_SHADOW | DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3,
259 0 /*cr3*/, 0 /*u64FirstAddr*/, UINT64_MAX /*u64LastAddr*/, 99 /*cMaxDepth*/, NULL);
260
261#if 0
262 /*
263 * Disassemble the assembly...
264 */
265 RTGCPTR GCPtr = RCPtrStart;
266 while (GCPtr < RCPtrEnd)
267 {
268 size_t cb = 0;
269 char sz[256];
270 int rc = DBGFR3DisasInstrEx(pVM, CPUMGetHyperCS(pVM), GCPtr, 0, sz, sizeof(sz), &cb);
271 if (RT_SUCCESS(rc))
272 RTLogPrintf("%s\n", sz);
273 else
274 {
275 RTLogPrintf("%RGv rc=%Rrc\n", GCPtr, rc);
276 cb = 1;
277 }
278 GCPtr += cb;
279 }
280#endif
281
282#ifdef VBOX_WITH_RAW_MODE
283 /*
284 * Do the profiling.
285 */
286 /* execute the instruction profiling tests */
287 PrintHeaderInstr();
288 int i;
289 for (i = TSTMICROTEST_OVERHEAD; i < TSTMICROTEST_TRAP_FIRST; i++)
290 {
291 TSTMICROTEST enmTest = (TSTMICROTEST)i;
292 uint64_t cMin = ~0;
293 uint64_t cMax = 0;
294 uint64_t cTotal = 0;
295 unsigned cSamples = 0;
296 rc = VINF_SUCCESS;
297 for (int c = 0; c < 100; c++)
298 {
299 int rc2 = VMMR3CallRC(pVM, RCPtrEntry, 2, pTst->RCPtr, enmTest);
300 if (RT_SUCCESS(rc2))
301 {
302 uint64_t u64 = pTst->aResults[enmTest].cTotalTicks;
303 if (cMin > u64)
304 cMin = u64;
305 if (cMax < u64)
306 cMax = u64;
307 cTotal += u64;
308 cSamples++;
309 }
310 else if (RT_SUCCESS(rc))
311 rc = rc2;
312 }
313 uint64_t cAvg = cTotal / (cSamples ? cSamples : 1);
314 pTst->aResults[enmTest].cTotalTicks = cAvg;
315 PrintResultInstr(pTst, enmTest, rc, cMin, cAvg, cMax);
316 /* store the overhead */
317 if (enmTest == TSTMICROTEST_OVERHEAD)
318 pTst->u64Overhead = cMin;
319 }
320#endif
321
322
323#ifdef VBOX_WITH_RAW_MODE
324 /* execute the trap/cycle profiling tests. */
325 RTPrintf("\n");
326 PrintHeaderTraps();
327 /* don't disable rdtsc in R1/R2/R3! */
328 CPUMR3SetCR4Feature(pVM, 0, ~X86_CR4_TSD);
329 for (i = TSTMICROTEST_TRAP_FIRST; i < TSTMICROTEST_MAX; i++)
330 {
331 TSTMICROTEST enmTest = (TSTMICROTEST)i;
332 rc = VMMR3CallRC(pVM, RCPtrEntry, 2, pTst->RCPtr, enmTest);
333 PrintResultTrap(pTst, enmTest, rc);
334 }
335#endif
336
337 RTPrintf(TESTCASE ": done!\n");
338 return VINF_SUCCESS;
339}
340
341
342/**
343 * Entry point.
344 */
345extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
346{
347 int rcRet = 0; /* error count. */
348
349 RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
350
351 /*
352 * Create empty VM.
353 */
354 PVM pVM;
355 PUVM pUVM;
356 int rc = VMR3Create(1, NULL, NULL, NULL, NULL, NULL, &pVM, &pUVM);
357 if (RT_SUCCESS(rc))
358 {
359 /*
360 * Do testing.
361 */
362 rc = VMR3ReqCallVoidWaitU(pUVM, VMCPUID_ANY, (PFNRT)doit, 1, pVM);
363 AssertRC(rc);
364 STAMR3Dump(pUVM, "*");
365
366 /*
367 * Cleanup.
368 */
369 rc = VMR3PowerOff(pUVM);
370 if (!RT_SUCCESS(rc))
371 {
372 RTPrintf(TESTCASE ": error: failed to power off vm! rc=%Rrc\n", rc);
373 rcRet++;
374 }
375 rc = VMR3Destroy(pUVM);
376 if (!RT_SUCCESS(rc))
377 {
378 RTPrintf(TESTCASE ": error: failed to destroy vm! rc=%Rrc\n", rc);
379 rcRet++;
380 }
381 VMR3ReleaseUVM(pUVM);
382 }
383 else
384 {
385 RTPrintf(TESTCASE ": fatal error: failed to create vm! rc=%Rrc\n", rc);
386 rcRet++;
387 }
388
389 return rcRet;
390}
391
392
393#if !defined(VBOX_WITH_HARDENING) || !defined(RT_OS_WINDOWS)
394/**
395 * Main entry point.
396 */
397int main(int argc, char **argv, char **envp)
398{
399 return TrustedMain(argc, argv, envp);
400}
401#endif
402
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