/* $Id$ */
/** @file
* Micro Testcase, profiling special CPU operations - GC Code (hacks).
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <VBox/vmm/vm.h>
#include <VBox/vmm/vmm.h>
#include <VBox/vmm/selm.h>
#include "tstMicro.h"
#include <VBox/err.h>
#include <iprt/asm-amd64-x86.h>
#include <VBox/log.h>
#include <iprt/assert.h>
#include <iprt/string.h>
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
RT_C_DECLS_BEGIN
DECLEXPORT(int) tstMicroRC(PTSTMICRO pTst, unsigned uTestcase);
RT_C_DECLS_END
/**
* Save and load our IDT.
*
* @param pTst Pointer to the instance data.
* @param iIDT The index of the IDT entry which should be hooked.
*/
void idtInstall(PTSTMICRO pTst, int iIDT)
{
RTIDTR Idtr;
ASMGetIDTR(&Idtr);
if (Idtr.pIdt == (uintptr_t)&pTst->aIDT[0])
return;
pTst->OriginalIDTR.cbIdt = Idtr.cbIdt;
pTst->OriginalIDTR.pIdt = Idtr.pIdt;
/*
* Copy the IDT.
*/
if (Idtr.cbIdt >= sizeof(pTst->aIDT))
Idtr.cbIdt = sizeof(pTst->aIDT) - 1;
memcpy(&pTst->aIDT[0], (void *)Idtr.pIdt, Idtr.cbIdt + 1);
/* Hook up IDT entry. */
if (iIDT >= 0)
{
uintptr_t uHandler = (uintptr_t)tstTrapHandlerNoErr;
if ( iIDT == 8
|| iIDT == 0xa
|| iIDT == 0xb
|| iIDT == 0xc
|| iIDT == 0xd
|| iIDT == 0xe
|| iIDT == 0x11)
uHandler = (uintptr_t)tstTrapHandler;
pTst->aIDT[iIDT].Int.u16OffsetHigh = uHandler >> 16;
pTst->aIDT[iIDT].Int.u16OffsetLow = uHandler & 0xffff;
pTst->aIDT[iIDT].Int.u16SegSel = SELMGetHyperCS(&g_VM);
pTst->aIDT[iIDT].Int.u2DPL = 3;
pTst->aIDT[iIDT].Int.u1Present = 1;
pTst->aIDT[iIDT].Int.u1Fixed0 = 0;
pTst->aIDT[iIDT].Int.u1Fixed1 = 0;
pTst->aIDT[iIDT].Int.u1Fixed2 = 0;
pTst->aIDT[iIDT].Int.u1Fixed3 = 0;
pTst->aIDT[iIDT].Int.u1Fixed4 = 1;
pTst->aIDT[iIDT].Int.u1Fixed5 = 1;
pTst->aIDT[iIDT].Int.u132BitGate = 1;
pTst->aIDT[iIDT].Int.u1Fixed6 = 0;
pTst->aIDT[iIDT].Int.u5Reserved2 = 0;
}
/* Install int 42h, R3 gate */
pTst->aIDT[0x42].Int.u16OffsetHigh = (uintptr_t)tstInterrupt42 >> 16;
pTst->aIDT[0x42].Int.u16OffsetLow = (uintptr_t)tstInterrupt42 & 0xffff;
pTst->aIDT[0x42].Int.u16SegSel = SELMGetHyperCS(&g_VM);
pTst->aIDT[0x42].Int.u2DPL = 3;
pTst->aIDT[0x42].Int.u1Present = 1;
pTst->aIDT[0x42].Int.u1Fixed0 = 0;
pTst->aIDT[0x42].Int.u1Fixed1 = 0;
pTst->aIDT[0x42].Int.u1Fixed2 = 0;
pTst->aIDT[0x42].Int.u1Fixed3 = 0;
pTst->aIDT[0x42].Int.u1Fixed4 = 1;
pTst->aIDT[0x42].Int.u1Fixed5 = 1;
pTst->aIDT[0x42].Int.u132BitGate = 1;
pTst->aIDT[0x42].Int.u1Fixed6 = 0;
pTst->aIDT[0x42].Int.u5Reserved2 = 0;
/*
* Load our IDT.
*/
Idtr.pIdt = (uintptr_t)&pTst->aIDT[0];
ASMSetIDTR(&Idtr);
RTIDTR Idtr2;
ASMGetIDTR(&Idtr2);
Assert(Idtr2.pIdt == (uintptr_t)&pTst->aIDT[0]);
}
/**
* Removes all trap overrides except for gate 42.
*/
DECLASM(void) idtOnly42(PTSTMICRO pTst)
{
if (pTst->OriginalIDTR.pIdt)
memcpy(&pTst->aIDT[0], (void *)(uintptr_t)pTst->OriginalIDTR.pIdt, sizeof(VBOXIDTE) * 32);
}
DECLEXPORT(int) tstMicroRC(PTSTMICRO pTst, unsigned uTestcase)
{
RTLogPrintf("pTst=%p uTestcase=%d\n", pTst, uTestcase);
/*
* Validate input.
*/
if (uTestcase >= TSTMICROTEST_MAX)
return VERR_INVALID_PARAMETER;
/*
* Clear the results.
*/
pTst->u64TSCR0Start = 0;
pTst->u64TSCRxStart = 0;
pTst->u64TSCR0Enter = 0;
pTst->u64TSCR0Exit = 0;
pTst->u64TSCRxEnd = 0;
pTst->u64TSCR0End = 0;
pTst->cHits = 0;
pTst->offEIPAdd = 0;
pTst->u32CR2 = 0;
pTst->u32EIP = 0;
pTst->u32ErrCd = 0;
PTSTMICRORESULT pRes = &pTst->aResults[uTestcase];
memset(&pTst->aResults[uTestcase], 0, sizeof(pTst->aResults[uTestcase]));
/*
* Do the testcase.
*/
int rc = VINF_SUCCESS;
switch (uTestcase)
{
case TSTMICROTEST_OVERHEAD:
{
tstOverhead(pTst);
break;
}
case TSTMICROTEST_INVLPG_0:
{
tstInvlpg0(pTst);
break;
}
case TSTMICROTEST_INVLPG_EIP:
{
tstInvlpgEIP(pTst);
break;
}
case TSTMICROTEST_INVLPG_ESP:
{
tstInvlpgESP(pTst);
break;
}
case TSTMICROTEST_CR3_RELOAD:
{
tstCR3Reload(pTst);
break;
}
case TSTMICROTEST_WP_DISABLE:
{
tstWPDisable(pTst);
break;
}
case TSTMICROTEST_WP_ENABLE:
{
tstWPEnable(pTst);
break;
}
case TSTMICROTEST_PF_R0:
{
idtInstall(pTst, 0xe);
pTst->offEIPAdd = 2;
rc = tstPFR0(pTst);
break;
}
case TSTMICROTEST_PF_R1:
{
idtInstall(pTst, 0xe);
pTst->offEIPAdd = 2;
rc = tstPFR1(pTst);
break;
}
case TSTMICROTEST_PF_R2:
{
idtInstall(pTst, 0xe);
pTst->offEIPAdd = 2;
rc = tstPFR2(pTst);
break;
}
case TSTMICROTEST_PF_R3:
{
idtInstall(pTst, 0xe);
pTst->offEIPAdd = 2;
rc = tstPFR3(pTst);
break;
}
}
/*
* Compute the results.
*/
if (pTst->u64TSCR0End && pTst->u64TSCR0Start)
pRes->cTotalTicks = pTst->u64TSCR0End - pTst->u64TSCR0Start - pTst->u64Overhead;
if (pTst->u64TSCRxStart && pTst->u64TSCR0Start)
pRes->cToRxFirstTicks = pTst->u64TSCRxStart - pTst->u64TSCR0Start - pTst->u64Overhead;
if (pTst->u64TSCR0Enter && pTst->u64TSCRxStart)
pRes->cTrapTicks = pTst->u64TSCR0Enter - pTst->u64TSCRxStart - pTst->u64Overhead;
if (pTst->u64TSCRxEnd && pTst->u64TSCR0Exit)
pRes->cToRxTrapTicks = pTst->u64TSCRxEnd - pTst->u64TSCR0Exit - pTst->u64Overhead;
if (pTst->u64TSCR0End && pTst->u64TSCRxEnd)
pRes->cToR0Ticks = pTst->u64TSCR0End - pTst->u64TSCRxEnd - pTst->u64Overhead;
return rc;
}