VirtualBox

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

Last change on this file since 41932 was 41931, checked in by vboxsync, 13 years ago

TRPM: Save state directly to the CPUMCPU context member instead of putting on the stack. this avoid copying the state around before returning to host context to service an IRQ, or before using IEM.

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

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