VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMTests.cpp@ 7802

Last change on this file since 7802 was 7735, checked in by vboxsync, 17 years ago

Include EFER msr in all PGMChangeMode calls.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.7 KB
Line 
1/* $Id: VMMTests.cpp 7735 2008-04-04 09:14:57Z vboxsync $ */
2/** @file
3 * VMM - The Virtual Machine Monitor Core, Tests.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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//#define NO_SUPCALLR0VMM
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#define LOG_GROUP LOG_GROUP_VMM
24#include <VBox/vmm.h>
25#include <VBox/pdm.h>
26#include <VBox/cpum.h>
27#include <VBox/mm.h>
28#include <VBox/trpm.h>
29#include <VBox/selm.h>
30#include "VMMInternal.h"
31#include <VBox/vm.h>
32#include <VBox/err.h>
33#include <VBox/param.h>
34#include <VBox/x86.h>
35#include <VBox/hwaccm.h>
36
37#include <iprt/assert.h>
38#include <iprt/asm.h>
39#include <iprt/time.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42
43
44/**
45 * Performs a testcase.
46 *
47 * @returns return value from the test.
48 * @param pVM The VM handle.
49 * @param enmTestcase The testcase operation to perform.
50 * @param uVariation The testcase variation id.
51 */
52static int vmmR3DoGCTest(PVM pVM, VMMGCOPERATION enmTestcase, unsigned uVariation)
53{
54 RTGCPTR GCPtrEP;
55 int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
56 if (VBOX_FAILURE(rc))
57 return rc;
58
59 CPUMHyperSetCtxCore(pVM, NULL);
60 memset(pVM->vmm.s.pbHCStack, 0xaa, VMM_STACK_SIZE);
61 CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
62 CPUMPushHyper(pVM, uVariation);
63 CPUMPushHyper(pVM, enmTestcase);
64 CPUMPushHyper(pVM, pVM->pVMGC);
65 CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR)); /* stack frame size */
66 CPUMPushHyper(pVM, GCPtrEP); /* what to call */
67 CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
68 return SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
69}
70
71
72/**
73 * Performs a trap test.
74 *
75 * @returns Return value from the trap test.
76 * @param pVM The VM handle.
77 * @param u8Trap The trap number to test.
78 * @param uVariation The testcase variation.
79 * @param rcExpect The expected result.
80 * @param u32Eax The expected eax value.
81 * @param pszFaultEIP The fault address. Pass NULL if this isn't available or doesn't apply.
82 * @param pszDesc The test description.
83 */
84static int vmmR3DoTrapTest(PVM pVM, uint8_t u8Trap, unsigned uVariation, int rcExpect, uint32_t u32Eax, const char *pszFaultEIP, const char *pszDesc)
85{
86 RTPrintf("VMM: testing 0%x / %d - %s\n", u8Trap, uVariation, pszDesc);
87
88 RTGCPTR GCPtrEP;
89 int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
90 if (VBOX_FAILURE(rc))
91 return rc;
92
93 CPUMHyperSetCtxCore(pVM, NULL);
94 memset(pVM->vmm.s.pbHCStack, 0xaa, VMM_STACK_SIZE);
95 CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
96 CPUMPushHyper(pVM, uVariation);
97 CPUMPushHyper(pVM, u8Trap + VMMGC_DO_TESTCASE_TRAP_FIRST);
98 CPUMPushHyper(pVM, pVM->pVMGC);
99 CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR)); /* stack frame size */
100 CPUMPushHyper(pVM, GCPtrEP); /* what to call */
101 CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
102 rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
103 bool fDump = false;
104 if (rc != rcExpect)
105 {
106 RTPrintf("VMM: FAILURE - rc=%Vrc expected %Vrc\n", rc, rcExpect);
107 if (rc != VERR_NOT_IMPLEMENTED)
108 fDump = true;
109 }
110 else if ( rcExpect != VINF_SUCCESS
111 && u8Trap != 8 /* double fault doesn't dare set TrapNo. */
112 && u8Trap != 3 /* guest only, we're not in guest. */
113 && u8Trap != 1 /* guest only, we're not in guest. */
114 && u8Trap != TRPMGetTrapNo(pVM))
115 {
116 RTPrintf("VMM: FAILURE - Trap %#x expected %#x\n", TRPMGetTrapNo(pVM), u8Trap);
117 fDump = true;
118 }
119 else if (pszFaultEIP)
120 {
121 RTGCPTR GCPtrFault;
122 int rc2 = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, pszFaultEIP, &GCPtrFault);
123 if (VBOX_FAILURE(rc2))
124 RTPrintf("VMM: FAILURE - Failed to resolve symbol '%s', %Vrc!\n", pszFaultEIP, rc);
125 else if (GCPtrFault != CPUMGetHyperEIP(pVM))
126 {
127 RTPrintf("VMM: FAILURE - EIP=%VGv expected %VGv (%s)\n", CPUMGetHyperEIP(pVM), GCPtrFault, pszFaultEIP);
128 fDump = true;
129 }
130 }
131 else if (rcExpect != VINF_SUCCESS)
132 {
133 if (CPUMGetHyperSS(pVM) == SELMGetHyperDS(pVM))
134 RTPrintf("VMM: FAILURE - ss=%x expected %x\n", CPUMGetHyperSS(pVM), SELMGetHyperDS(pVM));
135 if (CPUMGetHyperES(pVM) == SELMGetHyperDS(pVM))
136 RTPrintf("VMM: FAILURE - es=%x expected %x\n", CPUMGetHyperES(pVM), SELMGetHyperDS(pVM));
137 if (CPUMGetHyperDS(pVM) == SELMGetHyperDS(pVM))
138 RTPrintf("VMM: FAILURE - ds=%x expected %x\n", CPUMGetHyperDS(pVM), SELMGetHyperDS(pVM));
139 if (CPUMGetHyperFS(pVM) == SELMGetHyperDS(pVM))
140 RTPrintf("VMM: FAILURE - fs=%x expected %x\n", CPUMGetHyperFS(pVM), SELMGetHyperDS(pVM));
141 if (CPUMGetHyperGS(pVM) == SELMGetHyperDS(pVM))
142 RTPrintf("VMM: FAILURE - gs=%x expected %x\n", CPUMGetHyperGS(pVM), SELMGetHyperDS(pVM));
143 if (CPUMGetHyperEDI(pVM) == 0x01234567)
144 RTPrintf("VMM: FAILURE - edi=%x expected %x\n", CPUMGetHyperEDI(pVM), 0x01234567);
145 if (CPUMGetHyperESI(pVM) == 0x42000042)
146 RTPrintf("VMM: FAILURE - esi=%x expected %x\n", CPUMGetHyperESI(pVM), 0x42000042);
147 if (CPUMGetHyperEBP(pVM) == 0xffeeddcc)
148 RTPrintf("VMM: FAILURE - ebp=%x expected %x\n", CPUMGetHyperEBP(pVM), 0xffeeddcc);
149 if (CPUMGetHyperEBX(pVM) == 0x89abcdef)
150 RTPrintf("VMM: FAILURE - ebx=%x expected %x\n", CPUMGetHyperEBX(pVM), 0x89abcdef);
151 if (CPUMGetHyperECX(pVM) == 0xffffaaaa)
152 RTPrintf("VMM: FAILURE - ecx=%x expected %x\n", CPUMGetHyperECX(pVM), 0xffffaaaa);
153 if (CPUMGetHyperEDX(pVM) == 0x77778888)
154 RTPrintf("VMM: FAILURE - edx=%x expected %x\n", CPUMGetHyperEDX(pVM), 0x77778888);
155 if (CPUMGetHyperEAX(pVM) == u32Eax)
156 RTPrintf("VMM: FAILURE - eax=%x expected %x\n", CPUMGetHyperEAX(pVM), u32Eax);
157 }
158 if (fDump)
159 VMMR3FatalDump(pVM, rc);
160 return rc;
161}
162
163
164/* execute the switch. */
165VMMR3DECL(int) VMMDoTest(PVM pVM)
166{
167#if 1
168#ifdef NO_SUPCALLR0VMM
169 RTPrintf("NO_SUPCALLR0VMM\n");
170 return VINF_SUCCESS;
171#endif
172
173 /*
174 * Setup stack for calling VMMGCEntry().
175 */
176 RTGCPTR GCPtrEP;
177 int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
178 if (VBOX_SUCCESS(rc))
179 {
180 RTPrintf("VMM: VMMGCEntry=%VGv\n", GCPtrEP);
181
182 /*
183 * Test various crashes which we must be able to recover from.
184 */
185 vmmR3DoTrapTest(pVM, 0x3, 0, VINF_EM_DBG_HYPER_ASSERTION, 0xf0f0f0f0, "vmmGCTestTrap3_FaultEIP", "int3");
186 vmmR3DoTrapTest(pVM, 0x3, 1, VINF_EM_DBG_HYPER_ASSERTION, 0xf0f0f0f0, "vmmGCTestTrap3_FaultEIP", "int3 WP");
187
188#if defined(DEBUG_bird) /* guess most people would like to skip these since they write to com1. */
189 vmmR3DoTrapTest(pVM, 0x8, 0, VERR_TRPM_PANIC, 0x00000000, "vmmGCTestTrap8_FaultEIP", "#DF [#PG]");
190 SELMR3Relocate(pVM); /* this resets the busy flag of the Trap 08 TSS */
191 bool f;
192 rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "DoubleFault", &f);
193#if !defined(DEBUG_bird)
194 if (VBOX_SUCCESS(rc) && f)
195#endif
196 {
197 /* see tripple fault warnings in SELM and VMMGC.cpp. */
198 vmmR3DoTrapTest(pVM, 0x8, 1, VERR_TRPM_PANIC, 0x00000000, "vmmGCTestTrap8_FaultEIP", "#DF [#PG] WP");
199 SELMR3Relocate(pVM); /* this resets the busy flag of the Trap 08 TSS */
200 }
201#endif
202
203 vmmR3DoTrapTest(pVM, 0xd, 0, VERR_TRPM_DONT_PANIC, 0xf0f0f0f0, "vmmGCTestTrap0d_FaultEIP", "ltr #GP");
204 ///@todo find a better \#GP case, on intel ltr will \#PF (busy update?) and not \#GP.
205 //vmmR3DoTrapTest(pVM, 0xd, 1, VERR_TRPM_DONT_PANIC, 0xf0f0f0f0, "vmmGCTestTrap0d_FaultEIP", "ltr #GP WP");
206
207 vmmR3DoTrapTest(pVM, 0xe, 0, VERR_TRPM_DONT_PANIC, 0x00000000, "vmmGCTestTrap0e_FaultEIP", "#PF (NULL)");
208 vmmR3DoTrapTest(pVM, 0xe, 1, VERR_TRPM_DONT_PANIC, 0x00000000, "vmmGCTestTrap0e_FaultEIP", "#PF (NULL) WP");
209 vmmR3DoTrapTest(pVM, 0xe, 2, VINF_SUCCESS, 0x00000000, NULL, "#PF w/Tmp Handler");
210 vmmR3DoTrapTest(pVM, 0xe, 4, VINF_SUCCESS, 0x00000000, NULL, "#PF w/Tmp Handler and bad fs");
211
212 /*
213 * Set a debug register and perform a context switch.
214 */
215 rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
216 if (rc != VINF_SUCCESS)
217 {
218 RTPrintf("VMM: Nop test failed, rc=%Vrc not VINF_SUCCESS\n", rc);
219 return rc;
220 }
221
222 /* a harmless breakpoint */
223 RTPrintf("VMM: testing hardware bp at 0x10000 (not hit)\n");
224 DBGFADDRESS Addr;
225 DBGFR3AddrFromFlat(pVM, &Addr, 0x10000);
226 RTUINT iBp0;
227 rc = DBGFR3BpSetReg(pVM, &Addr, 0, ~(uint64_t)0, X86_DR7_RW_EO, 1, &iBp0);
228 AssertReleaseRC(rc);
229 rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
230 if (rc != VINF_SUCCESS)
231 {
232 RTPrintf("VMM: DR0=0x10000 test failed with rc=%Vrc!\n", rc);
233 return rc;
234 }
235
236 /* a bad one at VMMGCEntry */
237 RTPrintf("VMM: testing hardware bp at VMMGCEntry (hit)\n");
238 DBGFR3AddrFromFlat(pVM, &Addr, GCPtrEP);
239 RTUINT iBp1;
240 rc = DBGFR3BpSetReg(pVM, &Addr, 0, ~(uint64_t)0, X86_DR7_RW_EO, 1, &iBp1);
241 AssertReleaseRC(rc);
242 rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
243 if (rc != VINF_EM_DBG_HYPER_BREAKPOINT)
244 {
245 RTPrintf("VMM: DR1=VMMGCEntry test failed with rc=%Vrc! expected VINF_EM_RAW_BREAKPOINT_HYPER\n", rc);
246 return rc;
247 }
248
249 /* resume the breakpoint */
250 RTPrintf("VMM: resuming hyper after breakpoint\n");
251 CPUMSetHyperEFlags(pVM, CPUMGetHyperEFlags(pVM) | X86_EFL_RF);
252 rc = VMMR3ResumeHyper(pVM);
253 if (rc != VINF_SUCCESS)
254 {
255 RTPrintf("VMM: failed to resume on hyper breakpoint, rc=%Vrc\n", rc);
256 return rc;
257 }
258
259 /* engage the breakpoint again and try single stepping. */
260 RTPrintf("VMM: testing hardware bp at VMMGCEntry + stepping\n");
261 rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
262 if (rc != VINF_EM_DBG_HYPER_BREAKPOINT)
263 {
264 RTPrintf("VMM: DR1=VMMGCEntry test failed with rc=%Vrc! expected VINF_EM_RAW_BREAKPOINT_HYPER\n", rc);
265 return rc;
266 }
267
268 RTGCUINTREG OldPc = CPUMGetHyperEIP(pVM);
269 RTPrintf("%RGr=>", OldPc);
270 unsigned i;
271 for (i = 0; i < 8; i++)
272 {
273 CPUMSetHyperEFlags(pVM, CPUMGetHyperEFlags(pVM) | X86_EFL_TF | X86_EFL_RF);
274 rc = VMMR3ResumeHyper(pVM);
275 if (rc != VINF_EM_DBG_HYPER_STEPPED)
276 {
277 RTPrintf("\nVMM: failed to step on hyper breakpoint, rc=%Vrc\n", rc);
278 return rc;
279 }
280 RTGCUINTREG Pc = CPUMGetHyperEIP(pVM);
281 RTPrintf("%RGr=>", Pc);
282 if (Pc == OldPc)
283 {
284 RTPrintf("\nVMM: step failed, PC: %RGr -> %RGr\n", OldPc, Pc);
285 return VERR_GENERAL_FAILURE;
286 }
287 OldPc = Pc;
288 }
289 RTPrintf("ok\n");
290
291 /* done, clear it */
292 if ( VBOX_FAILURE(DBGFR3BpClear(pVM, iBp0))
293 || VBOX_FAILURE(DBGFR3BpClear(pVM, iBp1)))
294 {
295 RTPrintf("VMM: Failed to clear breakpoints!\n");
296 return VERR_GENERAL_FAILURE;
297 }
298 rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
299 if (rc != VINF_SUCCESS)
300 {
301 RTPrintf("VMM: NOP failed, rc=%Vrc\n", rc);
302 return rc;
303 }
304
305 /*
306 * Interrupt masking.
307 */
308 RTPrintf("VMM: interrupt masking...\n"); RTStrmFlush(g_pStdOut); RTThreadSleep(250);
309 for (i = 0; i < 10000; i++)
310 {
311 uint64_t StartTick = ASMReadTSC();
312 rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_INTERRUPT_MASKING, 0);
313 if (rc != VINF_SUCCESS)
314 {
315 RTPrintf("VMM: Interrupt masking failed: rc=%Vrc\n", rc);
316 return rc;
317 }
318 uint64_t Ticks = ASMReadTSC() - StartTick;
319 if (Ticks < (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000))
320 RTPrintf("Warning: Ticks=%RU64 (< %RU64)\n", Ticks, SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000);
321 }
322
323 /*
324 * Interrupt forwarding.
325 */
326 CPUMHyperSetCtxCore(pVM, NULL);
327 CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
328 CPUMPushHyper(pVM, 0);
329 CPUMPushHyper(pVM, VMMGC_DO_TESTCASE_HYPER_INTERRUPT);
330 CPUMPushHyper(pVM, pVM->pVMGC);
331 CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR)); /* stack frame size */
332 CPUMPushHyper(pVM, GCPtrEP); /* what to call */
333 CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
334 Log(("trampoline=%x\n", pVM->vmm.s.pfnGCCallTrampoline));
335
336 /*
337 * Switch and do da thing.
338 */
339 RTPrintf("VMM: interrupt forwarding...\n"); RTStrmFlush(g_pStdOut); RTThreadSleep(250);
340 i = 0;
341 uint64_t tsBegin = RTTimeNanoTS();
342 uint64_t TickStart = ASMReadTSC();
343 do
344 {
345 rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
346 if (VBOX_FAILURE(rc))
347 {
348 Log(("VMM: GC returned fatal %Vra in iteration %d\n", rc, i));
349 VMMR3FatalDump(pVM, rc);
350 return rc;
351 }
352 i++;
353 if (!(i % 32))
354 Log(("VMM: iteration %d, esi=%08x edi=%08x ebx=%08x\n",
355 i, CPUMGetHyperESI(pVM), CPUMGetHyperEDI(pVM), CPUMGetHyperEBX(pVM)));
356 } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
357 uint64_t TickEnd = ASMReadTSC();
358 uint64_t tsEnd = RTTimeNanoTS();
359
360 uint64_t Elapsed = tsEnd - tsBegin;
361 uint64_t PerIteration = Elapsed / (uint64_t)i;
362 uint64_t cTicksElapsed = TickEnd - TickStart;
363 uint64_t cTicksPerIteration = cTicksElapsed / (uint64_t)i;
364
365 RTPrintf("VMM: %8d interrupts in %11llu ns (%11llu ticks), %10llu ns/iteration (%11llu ticks)\n",
366 i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration);
367 Log(("VMM: %8d interrupts in %11llu ns (%11llu ticks), %10llu ns/iteration (%11llu ticks)\n",
368 i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration));
369
370 /*
371 * These forced actions are not necessary for the test and trigger breakpoints too.
372 */
373 VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
374 VM_FF_CLEAR(pVM, VM_FF_SELM_SYNC_TSS);
375
376 /*
377 * Profile switching.
378 */
379 RTPrintf("VMM: profiling switcher...\n");
380 Log(("VMM: profiling switcher...\n"));
381 uint64_t TickMin = ~0;
382 tsBegin = RTTimeNanoTS();
383 TickStart = ASMReadTSC();
384 for (i = 0; i < 1000000; i++)
385 {
386 CPUMHyperSetCtxCore(pVM, NULL);
387 CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
388 CPUMPushHyper(pVM, 0);
389 CPUMPushHyper(pVM, VMMGC_DO_TESTCASE_NOP);
390 CPUMPushHyper(pVM, pVM->pVMGC);
391 CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR)); /* stack frame size */
392 CPUMPushHyper(pVM, GCPtrEP); /* what to call */
393 CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
394
395 uint64_t TickThisStart = ASMReadTSC();
396 rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
397 uint64_t TickThisElapsed = ASMReadTSC() - TickThisStart;
398 if (VBOX_FAILURE(rc))
399 {
400 Log(("VMM: GC returned fatal %Vra in iteration %d\n", rc, i));
401 VMMR3FatalDump(pVM, rc);
402 return rc;
403 }
404 if (TickThisElapsed < TickMin)
405 TickMin = TickThisElapsed;
406 }
407 TickEnd = ASMReadTSC();
408 tsEnd = RTTimeNanoTS();
409
410 Elapsed = tsEnd - tsBegin;
411 PerIteration = Elapsed / (uint64_t)i;
412 cTicksElapsed = TickEnd - TickStart;
413 cTicksPerIteration = cTicksElapsed / (uint64_t)i;
414
415 RTPrintf("VMM: %8d cycles in %11llu ns (%11lld ticks), %10llu ns/iteration (%11lld ticks) Min %11lld ticks\n",
416 i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin);
417 Log(("VMM: %8d cycles in %11llu ns (%11lld ticks), %10llu ns/iteration (%11lld ticks) Min %11lld ticks\n",
418 i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin));
419
420 rc = VINF_SUCCESS;
421 }
422 else
423 AssertMsgFailed(("Failed to resolved VMMGC.gc::VMMGCEntry(), rc=%Vrc\n", rc));
424#endif
425 return rc;
426}
427
428#define SYNC_SEL(pHyperCtx, reg) \
429 if (pHyperCtx->reg) \
430 { \
431 SELMSELINFO selInfo; \
432 int rc = SELMR3GetShadowSelectorInfo(pVM, pHyperCtx->reg, &selInfo); \
433 AssertRC(rc); \
434 \
435 pHyperCtx->reg##Hid.u32Base = selInfo.GCPtrBase; \
436 pHyperCtx->reg##Hid.u32Limit = selInfo.cbLimit; \
437 pHyperCtx->reg##Hid.Attr.n.u1Present = selInfo.Raw.Gen.u1Present; \
438 pHyperCtx->reg##Hid.Attr.n.u1DefBig = selInfo.Raw.Gen.u1DefBig; \
439 pHyperCtx->reg##Hid.Attr.n.u1Granularity = selInfo.Raw.Gen.u1Granularity; \
440 pHyperCtx->reg##Hid.Attr.n.u4Type = selInfo.Raw.Gen.u4Type; \
441 pHyperCtx->reg##Hid.Attr.n.u2Dpl = selInfo.Raw.Gen.u2Dpl; \
442 pHyperCtx->reg##Hid.Attr.n.u1DescType = selInfo.Raw.Gen.u1DescType; \
443 pHyperCtx->reg##Hid.Attr.n.u1Reserved = selInfo.Raw.Gen.u1Reserved; \
444 }
445
446/* execute the switch. */
447VMMR3DECL(int) VMMDoHwAccmTest(PVM pVM)
448{
449 uint32_t i;
450 int rc;
451 PCPUMCTX pHyperCtx, pGuestCtx;
452 RTGCPHYS CR3Phys = 0x0; /* fake address */
453
454 if (!HWACCMR3IsAllowed(pVM))
455 {
456 RTPrintf("VMM: Hardware accelerated test not available!\n");
457 return VERR_ACCESS_DENIED;
458 }
459
460 /*
461 * These forced actions are not necessary for the test and trigger breakpoints too.
462 */
463 VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
464 VM_FF_CLEAR(pVM, VM_FF_SELM_SYNC_TSS);
465
466 /* Enable mapping of the hypervisor into the shadow page table. */
467 PGMR3ChangeShwPDMappings(pVM, true);
468
469 CPUMQueryHyperCtxPtr(pVM, &pHyperCtx);
470
471 pHyperCtx->cr0 = X86_CR0_PE | X86_CR0_WP | X86_CR0_PG | X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP;
472 pHyperCtx->cr4 = X86_CR4_PGE | X86_CR4_OSFSXR | X86_CR4_OSXMMEEXCPT;
473 PGMChangeMode(pVM, pHyperCtx->cr0, pHyperCtx->cr4, pHyperCtx->msrEFER);
474 PGMSyncCR3(pVM, pHyperCtx->cr0, CR3Phys, pHyperCtx->cr4, true);
475
476 VM_FF_CLEAR(pVM, VM_FF_TO_R3);
477 VM_FF_CLEAR(pVM, VM_FF_TIMER);
478 VM_FF_CLEAR(pVM, VM_FF_REQUEST);
479
480 /*
481 * Setup stack for calling VMMGCEntry().
482 */
483 RTGCPTR GCPtrEP;
484 rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
485 if (VBOX_SUCCESS(rc))
486 {
487 RTPrintf("VMM: VMMGCEntry=%VGv\n", GCPtrEP);
488
489 CPUMQueryHyperCtxPtr(pVM, &pHyperCtx);
490
491 /* Fill in hidden selector registers for the hypervisor state. */
492 SYNC_SEL(pHyperCtx, cs);
493 SYNC_SEL(pHyperCtx, ds);
494 SYNC_SEL(pHyperCtx, es);
495 SYNC_SEL(pHyperCtx, fs);
496 SYNC_SEL(pHyperCtx, gs);
497 SYNC_SEL(pHyperCtx, ss);
498 SYNC_SEL(pHyperCtx, tr);
499
500 /*
501 * Profile switching.
502 */
503 RTPrintf("VMM: profiling switcher...\n");
504 Log(("VMM: profiling switcher...\n"));
505 uint64_t TickMin = ~0;
506 uint64_t tsBegin = RTTimeNanoTS();
507 uint64_t TickStart = ASMReadTSC();
508 for (i = 0; i < 1000000; i++)
509 {
510 CPUMHyperSetCtxCore(pVM, NULL);
511
512 CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
513 CPUMPushHyper(pVM, 0);
514 CPUMPushHyper(pVM, VMMGC_DO_TESTCASE_HWACCM_NOP);
515 CPUMPushHyper(pVM, pVM->pVMGC);
516 CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR)); /* stack frame size */
517 CPUMPushHyper(pVM, GCPtrEP); /* what to call */
518 CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
519
520 CPUMQueryHyperCtxPtr(pVM, &pHyperCtx);
521 CPUMQueryGuestCtxPtr(pVM, &pGuestCtx);
522
523 /* Copy the hypervisor context to make sure we have a valid guest context. */
524 *pGuestCtx = *pHyperCtx;
525 pGuestCtx->cr3 = CR3Phys;
526
527 VM_FF_CLEAR(pVM, VM_FF_TO_R3);
528 VM_FF_CLEAR(pVM, VM_FF_TIMER);
529
530 uint64_t TickThisStart = ASMReadTSC();
531 rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_HWACC_RUN, NULL);
532 uint64_t TickThisElapsed = ASMReadTSC() - TickThisStart;
533 if (VBOX_FAILURE(rc))
534 {
535 Log(("VMM: R0 returned fatal %Vrc in iteration %d\n", rc, i));
536 VMMR3FatalDump(pVM, rc);
537 return rc;
538 }
539 if (TickThisElapsed < TickMin)
540 TickMin = TickThisElapsed;
541 }
542 uint64_t TickEnd = ASMReadTSC();
543 uint64_t tsEnd = RTTimeNanoTS();
544
545 uint64_t Elapsed = tsEnd - tsBegin;
546 uint64_t PerIteration = Elapsed / (uint64_t)i;
547 uint64_t cTicksElapsed = TickEnd - TickStart;
548 uint64_t cTicksPerIteration = cTicksElapsed / (uint64_t)i;
549
550 RTPrintf("VMM: %8d cycles in %11llu ns (%11lld ticks), %10llu ns/iteration (%11lld ticks) Min %11lld ticks\n",
551 i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin);
552 Log(("VMM: %8d cycles in %11llu ns (%11lld ticks), %10llu ns/iteration (%11lld ticks) Min %11lld ticks\n",
553 i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin));
554
555 rc = VINF_SUCCESS;
556 }
557 else
558 AssertMsgFailed(("Failed to resolved VMMGC.gc::VMMGCEntry(), rc=%Vrc\n", rc));
559
560 return rc;
561}
562
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