VirtualBox

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

Last change on this file since 77807 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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