VirtualBox

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

Last change on this file since 19167 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

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