VMMRC.cpp revision 24f999b2de96dbbd04541167293a869ea9851ad1
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/* $Id$ */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/** @file
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * VMM - Raw-mode Context.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Copyright (C) 2006-2012 Oracle Corporation
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * This file is part of VirtualBox Open Source Edition (OSE), as
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * available from http://www.virtualbox.org. This file is free software;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * you can redistribute it and/or modify it under the terms of the GNU
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * General Public License (GPL) as published by the Free Software
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Foundation, in version 2 as it comes in the "COPYING" file of the
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/*******************************************************************************
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest* Header Files *
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest*******************************************************************************/
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#define LOG_GROUP LOG_GROUP_VMM
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#include <iprt/asm-amd64-x86.h> /* for SUPGetCpuHzFromGIP */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#include <VBox/vmm/vmm.h>
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#include <VBox/vmm/trpm.h>
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest#include <VBox/vmm/pgm.h>
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest#include "VMMInternal.h"
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#include <VBox/vmm/vm.h>
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#include <VBox/sup.h>
89c76a8c99f25ef6d24c3642f95dde19c5fd4d05Phill Cunnington#include <VBox/err.h>
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest#include <VBox/log.h>
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest#include <iprt/assert.h>
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest#include <iprt/initterm.h>
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest/*******************************************************************************
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest* Global Variables *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest*******************************************************************************/
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/** Default logger instance. */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrestextern "C" DECLIMPORT(RTLOGGERRC) g_Logger;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrestextern "C" DECLIMPORT(RTLOGGERRC) g_RelLogger;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/*******************************************************************************
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest* Internal Functions *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest*******************************************************************************/
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forreststatic int vmmGCTest(PVM pVM, unsigned uOperation, unsigned uArg);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forreststatic DECLCALLBACK(int) vmmGCTestTmpPFHandler(PVM pVM, PCPUMCTXCORE pRegFrame);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forreststatic DECLCALLBACK(int) vmmGCTestTmpPFHandlerCorruptFS(PVM pVM, PCPUMCTXCORE pRegFrame);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew ForrestDECLASM(bool) vmmRCSafeMsrRead(uint32_t uMsr, uint64_t *pu64Value);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/**
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * The GC entry point.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @returns VBox status code.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param pVM Pointer to the VM.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param uOperation Which operation to execute (VMMGCOPERATION).
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param uArg Argument to that operation.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew ForrestVMMRCDECL(int) VMMGCEntry(PVM pVM, unsigned uOperation, unsigned uArg, ...)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest{
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /* todo */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest switch (uOperation)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest {
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Init RC modules.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest case VMMGC_DO_VMMGC_INIT:
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest {
6197cac1b7f675588382db0a6f279614032b5568David Luna /*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Validate the svn revision (uArg) and build type (ellipsis).
6197cac1b7f675588382db0a6f279614032b5568David Luna */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if (uArg != VMMGetSvnRev())
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return VERR_VMM_RC_VERSION_MISMATCH;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest va_list va;
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest va_start(va, uArg);
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest uint32_t uBuildType = va_arg(va, uint32_t);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if (uBuildType != vmmGetBuildType())
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return VERR_VMM_RC_VERSION_MISMATCH;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Initialize the runtime.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest uint64_t u64TS = va_arg(va, uint64_t);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest va_end(va);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest int rc = RTRCInit(u64TS);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest Log(("VMMGCEntry: VMMGC_DO_VMMGC_INIT - uArg=%u (svn revision) u64TS=%RX64; rc=%Rrc\n", uArg, u64TS, rc));
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest AssertRCReturn(rc, rc);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest rc = PGMRegisterStringFormatTypes();
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest AssertRCReturn(rc, rc);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest rc = PGMRCDynMapInit(pVM);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest AssertRCReturn(rc, rc);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return VINF_SUCCESS;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest }
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
6197cac1b7f675588382db0a6f279614032b5568David Luna /*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Testcase which is used to test interrupt forwarding.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * It spins for a while with interrupts enabled.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest case VMMGC_DO_TESTCASE_HYPER_INTERRUPT:
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest {
ece5a262d20a50d0abf584d0f7ec73929ede9cfdJaco Jooste uint32_t volatile i = 0;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest ASMIntEnable();
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest while (i < _2G32)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest i++;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest ASMIntDisable();
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return 0;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest }
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest /*
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest * Testcase which simply returns, this is used for
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest * profiling of the switcher.
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest case VMMGC_DO_TESTCASE_NOP:
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return 0;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Testcase executes a privileged instruction to force a world switch. (in both SVM & VMX)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest case VMMGC_DO_TESTCASE_HM_NOP:
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest ASMRdMsr_Low(MSR_IA32_SYSENTER_CS);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return 0;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /*
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Delay for ~100us.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest case VMMGC_DO_TESTCASE_INTERRUPT_MASKING:
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest {
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest uint64_t u64MaxTicks = (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) != ~(uint64_t)0
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest ? SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest : _2G)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest / 10000;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest uint64_t u64StartTSC = ASMReadTSC();
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest uint64_t u64TicksNow;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest uint32_t volatile i = 0;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest do
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest {
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /* waste some time and protect against getting stuck. */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest for (uint32_t volatile j = 0; j < 1000; j++, i++)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if (i > _2G32)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return VERR_GENERAL_FAILURE;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /* check if we're done.*/
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest u64TicksNow = ASMReadTSC() - u64StartTSC;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest } while (u64TicksNow < u64MaxTicks);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest return VINF_SUCCESS;
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest }
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest /*
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest * Trap testcases and unknown operations.
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest default:
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if ( uOperation >= VMMGC_DO_TESTCASE_TRAP_FIRST
f52ca8f9ce43f7765e8c5959e45a667b496526eeAndrew Forrest && uOperation < VMMGC_DO_TESTCASE_TRAP_LAST)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return vmmGCTest(pVM, uOperation, uArg);
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste return VERR_INVALID_PARAMETER;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest }
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest}
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
ece5a262d20a50d0abf584d0f7ec73929ede9cfdJaco Jooste
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/**
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Internal RC logger worker: Flush logger.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest *
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste * @returns VINF_SUCCESS.
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste * @param pLogger The logger instance to flush.
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste * @remark This function must be exported!
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste */
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco JoosteVMMRCDECL(int) vmmGCLoggerFlush(PRTLOGGERRC pLogger)
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste{
919ca0cd7bf1dee3c8021e1c80bd699c7a386001Andrew Forrest PVM pVM = &g_VM;
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest NOREF(pLogger);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if (pVM->vmm.s.fRCLoggerFlushingDisabled)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return VINF_SUCCESS; /* fail quietly. */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_VMM_LOGGER_FLUSH, 0);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest}
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/**
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Flush logger if almost full.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param pVM Pointer to the VM.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew ForrestVMMRCDECL(void) VMMGCLogFlushIfFull(PVM pVM)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest{
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if ( pVM->vmm.s.pRCLoggerRC
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest && pVM->vmm.s.pRCLoggerRC->offScratch >= (sizeof(pVM->vmm.s.pRCLoggerRC->achScratch)*3/4))
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest {
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest if (pVM->vmm.s.fRCLoggerFlushingDisabled)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest return; /* fail quietly. */
f52ca8f9ce43f7765e8c5959e45a667b496526eeAndrew Forrest VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_VMM_LOGGER_FLUSH, 0);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest }
f52ca8f9ce43f7765e8c5959e45a667b496526eeAndrew Forrest}
f52ca8f9ce43f7765e8c5959e45a667b496526eeAndrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest/**
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * Switches from guest context to host context.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param pVM Pointer to the VM.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param rc The status code.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew ForrestVMMRCDECL(void) VMMGCGuestToHost(PVM pVM, int rc)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest{
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest pVM->vmm.s.pfnRCToHost(rc);
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste}
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste/**
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste * Calls the ring-0 host code.
60d290d5a2f0643d86ef3f8eb5d4381022cdfa68Jaco Jooste *
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest * @param pVM Pointer to the VM.
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest */
864e2a74d7dc5e572cd895466611cc57e3523083Andrew ForrestDECLASM(void) vmmRCProbeFireHelper(PVM pVM)
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest{
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest pVM->vmm.s.pfnRCToHost(VINF_VMM_CALL_TRACER);
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest}
864e2a74d7dc5e572cd895466611cc57e3523083Andrew Forrest
/**
* Execute the trap testcase.
*
* There is some common code here, that's why we're collecting them
* like this. Odd numbered variation (uArg) are executed with write
* protection (WP) enabled.
*
* @returns VINF_SUCCESS if it was a testcase setup up to continue and did so successfully.
* @returns VERR_NOT_IMPLEMENTED if the testcase wasn't implemented.
* @returns VERR_GENERAL_FAILURE if the testcase continued when it shouldn't.
*
* @param pVM Pointer to the VM.
* @param uOperation The testcase.
* @param uArg The variation. See function description for odd / even details.
*
* @remark Careful with the trap 08 testcase and WP, it will triple
* fault the box if the TSS, the Trap8 TSS and the fault TSS
* GDTE are in pages which are read-only.
* See bottom of SELMR3Init().
*/
static int vmmGCTest(PVM pVM, unsigned uOperation, unsigned uArg)
{
/*
* Set up the testcase.
*/
#if 0
switch (uOperation)
{
default:
break;
}
#endif
/*
* Enable WP if odd variation.
*/
if (uArg & 1)
vmmGCEnableWP();
/*
* Execute the testcase.
*/
int rc = VERR_NOT_IMPLEMENTED;
switch (uOperation)
{
//case VMMGC_DO_TESTCASE_TRAP_0:
//case VMMGC_DO_TESTCASE_TRAP_1:
//case VMMGC_DO_TESTCASE_TRAP_2:
case VMMGC_DO_TESTCASE_TRAP_3:
{
if (uArg <= 1)
rc = vmmGCTestTrap3();
break;
}
//case VMMGC_DO_TESTCASE_TRAP_4:
//case VMMGC_DO_TESTCASE_TRAP_5:
//case VMMGC_DO_TESTCASE_TRAP_6:
//case VMMGC_DO_TESTCASE_TRAP_7:
case VMMGC_DO_TESTCASE_TRAP_8:
{
#ifndef DEBUG_bird /** @todo dynamic check that this won't triple fault... */
if (uArg & 1)
break;
#endif
if (uArg <= 1)
rc = vmmGCTestTrap8();
break;
}
//VMMGC_DO_TESTCASE_TRAP_9,
//VMMGC_DO_TESTCASE_TRAP_0A,
//VMMGC_DO_TESTCASE_TRAP_0B,
//VMMGC_DO_TESTCASE_TRAP_0C,
case VMMGC_DO_TESTCASE_TRAP_0D:
{
if (uArg <= 1)
rc = vmmGCTestTrap0d();
break;
}
case VMMGC_DO_TESTCASE_TRAP_0E:
{
if (uArg <= 1)
rc = vmmGCTestTrap0e();
else if (uArg == 2 || uArg == 4)
{
/*
* Test the use of a temporary #PF handler.
*/
rc = TRPMGCSetTempHandler(pVM, X86_XCPT_PF, uArg != 4 ? vmmGCTestTmpPFHandler : vmmGCTestTmpPFHandlerCorruptFS);
if (RT_SUCCESS(rc))
{
rc = vmmGCTestTrap0e();
/* in case it didn't fire. */
int rc2 = TRPMGCSetTempHandler(pVM, X86_XCPT_PF, NULL);
if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
rc = rc2;
}
}
break;
}
}
/*
* Re-enable WP.
*/
if (uArg & 1)
vmmGCDisableWP();
return rc;
}
/**
* Reads a range of MSRs.
*
* This is called directly via VMMR3CallRC.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param uMsr The MSR to start at.
* @param cMsrs The number of MSRs to read.
* @param paResults Where to store the results. This must be large
* enough to hold at least @a cMsrs result values.
*/
extern "C" VMMRCDECL(int)
VMMRCTestReadMsrs(PVM pVM, uint32_t uMsr, uint32_t cMsrs, PVMMTESTMSRENTRY paResults)
{
AssertReturn(cMsrs <= 4096, VERR_INVALID_PARAMETER);
AssertPtrReturn(paResults, VERR_INVALID_POINTER);
for (uint32_t i = 0; i < cMsrs; i++, uMsr++)
{
if (vmmRCSafeMsrRead(uMsr, &paResults[i].uValue))
paResults[i].uMsr = uMsr;
else
paResults[i].uMsr = UINT64_MAX;
}
return VINF_SUCCESS;
}
/**
* Temporary \#PF trap handler for the \#PF test case.
*
* @returns VBox status code (appropriate for GC return).
* In this context RT_SUCCESS means to restart the instruction.
* @param pVM Pointer to the VM.
* @param pRegFrame Trap register frame.
*/
static DECLCALLBACK(int) vmmGCTestTmpPFHandler(PVM pVM, PCPUMCTXCORE pRegFrame)
{
if (pRegFrame->eip == (uintptr_t)vmmGCTestTrap0e_FaultEIP)
{
pRegFrame->eip = (uintptr_t)vmmGCTestTrap0e_ResumeEIP;
return VINF_SUCCESS;
}
NOREF(pVM);
return VERR_INTERNAL_ERROR;
}
/**
* Temporary \#PF trap handler for the \#PF test case, this one messes up the fs
* selector.
*
* @returns VBox status code (appropriate for GC return).
* In this context RT_SUCCESS means to restart the instruction.
* @param pVM Pointer to the VM.
* @param pRegFrame Trap register frame.
*/
static DECLCALLBACK(int) vmmGCTestTmpPFHandlerCorruptFS(PVM pVM, PCPUMCTXCORE pRegFrame)
{
int rc = vmmGCTestTmpPFHandler(pVM, pRegFrame);
pRegFrame->fs.Sel = 0x30;
return rc;
}