VirtualBox

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

Last change on this file since 19420 was 19334, checked in by vboxsync, 16 years ago

DBGF,SELM,DBGC,++: Refactored the selector info querying and usage, mainly for fixing VM_ASSERT_EMT issues cropping up after from #3170, but also for moving the external interface to DBGF.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 24.2 KB
Line 
1/* $Id: VMMTests.cpp 19334 2009-05-04 16:03:57Z 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 DBGFSELINFO 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