VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/VMMRC.cpp@ 50653

Last change on this file since 50653 was 49893, checked in by vboxsync, 10 years ago

MSR rewrite: initial hacking - half disabled.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.3 KB
Line 
1/* $Id: VMMRC.cpp 49893 2013-12-13 00:40:20Z vboxsync $ */
2/** @file
3 * VMM - Raw-mode Context.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_VMM
23#include <iprt/asm-amd64-x86.h> /* for SUPGetCpuHzFromGIP */
24#include <VBox/vmm/vmm.h>
25#include <VBox/vmm/trpm.h>
26#include <VBox/vmm/pgm.h>
27#include "VMMInternal.h"
28#include <VBox/vmm/vm.h>
29#include <VBox/sup.h>
30#include <VBox/err.h>
31#include <VBox/log.h>
32#include <iprt/assert.h>
33#include <iprt/initterm.h>
34
35
36/*******************************************************************************
37* Global Variables *
38*******************************************************************************/
39/** Default logger instance. */
40extern "C" DECLIMPORT(RTLOGGERRC) g_Logger;
41extern "C" DECLIMPORT(RTLOGGERRC) g_RelLogger;
42
43
44/*******************************************************************************
45* Internal Functions *
46*******************************************************************************/
47static int vmmGCTest(PVM pVM, unsigned uOperation, unsigned uArg);
48static DECLCALLBACK(int) vmmGCTestTmpPFHandler(PVM pVM, PCPUMCTXCORE pRegFrame);
49static DECLCALLBACK(int) vmmGCTestTmpPFHandlerCorruptFS(PVM pVM, PCPUMCTXCORE pRegFrame);
50DECLASM(bool) vmmRCSafeMsrRead(uint32_t uMsr, uint64_t *pu64Value);
51DECLASM(bool) vmmRCSafeMsrWrite(uint32_t uMsr, uint64_t u64Value);
52
53
54
55/**
56 * The GC entry point.
57 *
58 * @returns VBox status code.
59 * @param pVM Pointer to the VM.
60 * @param uOperation Which operation to execute (VMMGCOPERATION).
61 * @param uArg Argument to that operation.
62 */
63VMMRCDECL(int) VMMGCEntry(PVM pVM, unsigned uOperation, unsigned uArg, ...)
64{
65 /* todo */
66 switch (uOperation)
67 {
68 /*
69 * Init RC modules.
70 */
71 case VMMGC_DO_VMMGC_INIT:
72 {
73 /*
74 * Validate the svn revision (uArg) and build type (ellipsis).
75 */
76 if (uArg != VMMGetSvnRev())
77 return VERR_VMM_RC_VERSION_MISMATCH;
78
79 va_list va;
80 va_start(va, uArg);
81
82 uint32_t uBuildType = va_arg(va, uint32_t);
83 if (uBuildType != vmmGetBuildType())
84 return VERR_VMM_RC_VERSION_MISMATCH;
85
86 /*
87 * Initialize the runtime.
88 */
89 uint64_t u64TS = va_arg(va, uint64_t);
90
91 va_end(va);
92
93 int rc = RTRCInit(u64TS);
94 Log(("VMMGCEntry: VMMGC_DO_VMMGC_INIT - uArg=%u (svn revision) u64TS=%RX64; rc=%Rrc\n", uArg, u64TS, rc));
95 AssertRCReturn(rc, rc);
96
97 rc = PGMRegisterStringFormatTypes();
98 AssertRCReturn(rc, rc);
99
100 rc = PGMRCDynMapInit(pVM);
101 AssertRCReturn(rc, rc);
102 return VINF_SUCCESS;
103 }
104
105 /*
106 * Testcase which is used to test interrupt forwarding.
107 * It spins for a while with interrupts enabled.
108 */
109 case VMMGC_DO_TESTCASE_HYPER_INTERRUPT:
110 {
111 uint32_t volatile i = 0;
112 ASMIntEnable();
113 while (i < _2G32)
114 i++;
115 ASMIntDisable();
116 return 0;
117 }
118
119 /*
120 * Testcase which simply returns, this is used for
121 * profiling of the switcher.
122 */
123 case VMMGC_DO_TESTCASE_NOP:
124 return 0;
125
126 /*
127 * Testcase executes a privileged instruction to force a world switch. (in both SVM & VMX)
128 */
129 case VMMGC_DO_TESTCASE_HM_NOP:
130 ASMRdMsr_Low(MSR_IA32_SYSENTER_CS);
131 return 0;
132
133 /*
134 * Delay for ~100us.
135 */
136 case VMMGC_DO_TESTCASE_INTERRUPT_MASKING:
137 {
138 uint64_t u64MaxTicks = (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) != ~(uint64_t)0
139 ? SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage)
140 : _2G)
141 / 10000;
142 uint64_t u64StartTSC = ASMReadTSC();
143 uint64_t u64TicksNow;
144 uint32_t volatile i = 0;
145
146 do
147 {
148 /* waste some time and protect against getting stuck. */
149 for (uint32_t volatile j = 0; j < 1000; j++, i++)
150 if (i > _2G32)
151 return VERR_GENERAL_FAILURE;
152
153 /* check if we're done.*/
154 u64TicksNow = ASMReadTSC() - u64StartTSC;
155 } while (u64TicksNow < u64MaxTicks);
156
157 return VINF_SUCCESS;
158 }
159
160 /*
161 * Trap testcases and unknown operations.
162 */
163 default:
164 if ( uOperation >= VMMGC_DO_TESTCASE_TRAP_FIRST
165 && uOperation < VMMGC_DO_TESTCASE_TRAP_LAST)
166 return vmmGCTest(pVM, uOperation, uArg);
167 return VERR_INVALID_PARAMETER;
168 }
169}
170
171
172/**
173 * Internal RC logger worker: Flush logger.
174 *
175 * @returns VINF_SUCCESS.
176 * @param pLogger The logger instance to flush.
177 * @remark This function must be exported!
178 */
179VMMRCDECL(int) vmmGCLoggerFlush(PRTLOGGERRC pLogger)
180{
181 PVM pVM = &g_VM;
182 NOREF(pLogger);
183 if (pVM->vmm.s.fRCLoggerFlushingDisabled)
184 return VINF_SUCCESS; /* fail quietly. */
185 return VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_VMM_LOGGER_FLUSH, 0);
186}
187
188
189/**
190 * Flush logger if almost full.
191 *
192 * @param pVM Pointer to the VM.
193 */
194VMMRCDECL(void) VMMGCLogFlushIfFull(PVM pVM)
195{
196 if ( pVM->vmm.s.pRCLoggerRC
197 && pVM->vmm.s.pRCLoggerRC->offScratch >= (sizeof(pVM->vmm.s.pRCLoggerRC->achScratch)*3/4))
198 {
199 if (pVM->vmm.s.fRCLoggerFlushingDisabled)
200 return; /* fail quietly. */
201 VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_VMM_LOGGER_FLUSH, 0);
202 }
203}
204
205
206/**
207 * Switches from guest context to host context.
208 *
209 * @param pVM Pointer to the VM.
210 * @param rc The status code.
211 */
212VMMRCDECL(void) VMMGCGuestToHost(PVM pVM, int rc)
213{
214 pVM->vmm.s.pfnRCToHost(rc);
215}
216
217
218/**
219 * Calls the ring-0 host code.
220 *
221 * @param pVM Pointer to the VM.
222 */
223DECLASM(void) vmmRCProbeFireHelper(PVM pVM)
224{
225 pVM->vmm.s.pfnRCToHost(VINF_VMM_CALL_TRACER);
226}
227
228
229
230/**
231 * Execute the trap testcase.
232 *
233 * There is some common code here, that's why we're collecting them
234 * like this. Odd numbered variation (uArg) are executed with write
235 * protection (WP) enabled.
236 *
237 * @returns VINF_SUCCESS if it was a testcase setup up to continue and did so successfully.
238 * @returns VERR_NOT_IMPLEMENTED if the testcase wasn't implemented.
239 * @returns VERR_GENERAL_FAILURE if the testcase continued when it shouldn't.
240 *
241 * @param pVM Pointer to the VM.
242 * @param uOperation The testcase.
243 * @param uArg The variation. See function description for odd / even details.
244 *
245 * @remark Careful with the trap 08 testcase and WP, it will triple
246 * fault the box if the TSS, the Trap8 TSS and the fault TSS
247 * GDTE are in pages which are read-only.
248 * See bottom of SELMR3Init().
249 */
250static int vmmGCTest(PVM pVM, unsigned uOperation, unsigned uArg)
251{
252 /*
253 * Set up the testcase.
254 */
255#if 0
256 switch (uOperation)
257 {
258 default:
259 break;
260 }
261#endif
262
263 /*
264 * Enable WP if odd variation.
265 */
266 if (uArg & 1)
267 vmmGCEnableWP();
268
269 /*
270 * Execute the testcase.
271 */
272 int rc = VERR_NOT_IMPLEMENTED;
273 switch (uOperation)
274 {
275 //case VMMGC_DO_TESTCASE_TRAP_0:
276 //case VMMGC_DO_TESTCASE_TRAP_1:
277 //case VMMGC_DO_TESTCASE_TRAP_2:
278
279 case VMMGC_DO_TESTCASE_TRAP_3:
280 {
281 if (uArg <= 1)
282 rc = vmmGCTestTrap3();
283 break;
284 }
285
286 //case VMMGC_DO_TESTCASE_TRAP_4:
287 //case VMMGC_DO_TESTCASE_TRAP_5:
288 //case VMMGC_DO_TESTCASE_TRAP_6:
289 //case VMMGC_DO_TESTCASE_TRAP_7:
290
291 case VMMGC_DO_TESTCASE_TRAP_8:
292 {
293#ifndef DEBUG_bird /** @todo dynamic check that this won't triple fault... */
294 if (uArg & 1)
295 break;
296#endif
297 if (uArg <= 1)
298 rc = vmmGCTestTrap8();
299 break;
300 }
301
302 //VMMGC_DO_TESTCASE_TRAP_9,
303 //VMMGC_DO_TESTCASE_TRAP_0A,
304 //VMMGC_DO_TESTCASE_TRAP_0B,
305 //VMMGC_DO_TESTCASE_TRAP_0C,
306
307 case VMMGC_DO_TESTCASE_TRAP_0D:
308 {
309 if (uArg <= 1)
310 rc = vmmGCTestTrap0d();
311 break;
312 }
313
314 case VMMGC_DO_TESTCASE_TRAP_0E:
315 {
316 if (uArg <= 1)
317 rc = vmmGCTestTrap0e();
318 else if (uArg == 2 || uArg == 4)
319 {
320 /*
321 * Test the use of a temporary #PF handler.
322 */
323 rc = TRPMGCSetTempHandler(pVM, X86_XCPT_PF, uArg != 4 ? vmmGCTestTmpPFHandler : vmmGCTestTmpPFHandlerCorruptFS);
324 if (RT_SUCCESS(rc))
325 {
326 rc = vmmGCTestTrap0e();
327
328 /* in case it didn't fire. */
329 int rc2 = TRPMGCSetTempHandler(pVM, X86_XCPT_PF, NULL);
330 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
331 rc = rc2;
332 }
333 }
334 break;
335 }
336 }
337
338 /*
339 * Re-enable WP.
340 */
341 if (uArg & 1)
342 vmmGCDisableWP();
343
344 return rc;
345}
346
347
348
349/**
350 * Reads a range of MSRs.
351 *
352 * This is called directly via VMMR3CallRC.
353 *
354 * @returns VBox status code.
355 * @param pVM The VM handle.
356 * @param uMsr The MSR to start at.
357 * @param cMsrs The number of MSRs to read.
358 * @param paResults Where to store the results. This must be large
359 * enough to hold at least @a cMsrs result values.
360 */
361extern "C" VMMRCDECL(int)
362VMMRCTestReadMsrs(PVM pVM, uint32_t uMsr, uint32_t cMsrs, PVMMTESTMSRENTRY paResults)
363{
364 AssertReturn(cMsrs <= 16384, VERR_INVALID_PARAMETER);
365 AssertPtrReturn(paResults, VERR_INVALID_POINTER);
366 ASMIntEnable(); /* Run with interrupts enabled, so we can query more MSRs in one block. */
367
368 for (uint32_t i = 0; i < cMsrs; i++, uMsr++)
369 {
370 if (vmmRCSafeMsrRead(uMsr, &paResults[i].uValue))
371 paResults[i].uMsr = uMsr;
372 else
373 paResults[i].uMsr = UINT64_MAX;
374 }
375
376 ASMIntDisable();
377 return VINF_SUCCESS;
378}
379
380
381/**
382 * Tries to write the given value to an MSR, returns the effect and restors the
383 * original value.
384 *
385 * This is called directly via VMMR3CallRC.
386 *
387 * @returns VBox status code.
388 * @param pVM The VM handle.
389 * @param uMsr The MSR to start at.
390 * @param u32ValueLow The low part of the value to write.
391 * @param u32ValueHi The high part of the value to write.
392 * @param puValueBefore The value before writing.
393 * @param puValueAfter The value read back after writing.
394 */
395extern "C" VMMRCDECL(int)
396VMMRCTestTestWriteMsr(PVM pVM, uint32_t uMsr, uint32_t u32ValueLow, uint32_t u32ValueHi,
397 uint64_t *puValueBefore, uint64_t *puValueAfter)
398{
399 AssertPtrReturn(puValueBefore, VERR_INVALID_POINTER);
400 AssertPtrReturn(puValueAfter, VERR_INVALID_POINTER);
401 ASMIntDisable();
402
403 int rc = VINF_SUCCESS;
404 uint64_t uValueBefore = UINT64_MAX;
405 uint64_t uValueAfter = UINT64_MAX;
406 if (vmmRCSafeMsrRead(uMsr, &uValueBefore))
407 {
408 if (!vmmRCSafeMsrWrite(uMsr, RT_MAKE_U64(u32ValueLow, u32ValueHi)))
409 rc = VERR_WRITE_PROTECT;
410 if (!vmmRCSafeMsrRead(uMsr, &uValueAfter) && RT_SUCCESS(rc))
411 rc = VERR_READ_ERROR;
412 vmmRCSafeMsrWrite(uMsr, uValueBefore);
413 }
414 else
415 rc = VERR_ACCESS_DENIED;
416
417 *puValueBefore = uValueBefore;
418 *puValueAfter = uValueAfter;
419 return rc;
420}
421
422
423
424/**
425 * Temporary \#PF trap handler for the \#PF test case.
426 *
427 * @returns VBox status code (appropriate for GC return).
428 * In this context RT_SUCCESS means to restart the instruction.
429 * @param pVM Pointer to the VM.
430 * @param pRegFrame Trap register frame.
431 */
432static DECLCALLBACK(int) vmmGCTestTmpPFHandler(PVM pVM, PCPUMCTXCORE pRegFrame)
433{
434 if (pRegFrame->eip == (uintptr_t)vmmGCTestTrap0e_FaultEIP)
435 {
436 pRegFrame->eip = (uintptr_t)vmmGCTestTrap0e_ResumeEIP;
437 return VINF_SUCCESS;
438 }
439 NOREF(pVM);
440 return VERR_INTERNAL_ERROR;
441}
442
443
444/**
445 * Temporary \#PF trap handler for the \#PF test case, this one messes up the fs
446 * selector.
447 *
448 * @returns VBox status code (appropriate for GC return).
449 * In this context RT_SUCCESS means to restart the instruction.
450 * @param pVM Pointer to the VM.
451 * @param pRegFrame Trap register frame.
452 */
453static DECLCALLBACK(int) vmmGCTestTmpPFHandlerCorruptFS(PVM pVM, PCPUMCTXCORE pRegFrame)
454{
455 int rc = vmmGCTestTmpPFHandler(pVM, pRegFrame);
456 pRegFrame->fs.Sel = 0x30;
457 return rc;
458}
459
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use