CSAM.cpp revision fe95fa9fc2a364e3d678307971cc900b89f5c94a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* $Id$ */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** @file
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * CSAM - Guest OS Code Scanning and Analysis Manager
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Copyright (C) 2006-2007 Oracle Corporation
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * available from http://www.virtualbox.org. This file is free software;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * General Public License (GPL) as published by the Free Software
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync* Header Files *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync*******************************************************************************/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define LOG_GROUP LOG_GROUP_CSAM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/cpum.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/stam.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/patm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/csam.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/cpumdis.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/pgm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/iom.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/sup.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/mm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/em.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_REM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# include <VBox/vmm/rem.h>
384478d3896257fbce9ceb8c01e74040b969e6d7vboxsync#endif
384478d3896257fbce9ceb8c01e74040b969e6d7vboxsync#include <VBox/vmm/selm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/trpm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/cfgm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/param.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/avl.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/asm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/thread.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include "CSAMInternal.h"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/vm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/dbg.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/err.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/vmm/ssm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/log.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/assert.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/string.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/dis.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/disopcode.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include "internal/pgm.h"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/* Enabled by default */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync#define CSAM_ENABLE
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/* Enable to monitor code pages for self-modifying code. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync#define CSAM_MONITOR_CODE_PAGES
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/* Enable to monitor all scanned pages
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync#define CSAM_MONITOR_CSAM_CODE_PAGES */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/* Enable to scan beyond ret instructions.
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync#define CSAM_ANALYSE_BEYOND_RET */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/*******************************************************************************
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync* Internal Functions *
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync*******************************************************************************/
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic DECLCALLBACK(int) csamr3Save(PVM pVM, PSSMHANDLE pSSM);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic DECLCALLBACK(int) csamr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic DECLCALLBACK(int) CSAMCodePageWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic DECLCALLBACK(int) CSAMCodePageInvalidate(PVM pVM, RTGCPTR GCPtr);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncbool csamIsCodeScanned(PVM pVM, RTRCPTR pInstr, PCSAMPAGE *pPage);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncint csamR3CheckPageRecord(PVM pVM, RTRCPTR pInstr);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic PCSAMPAGE csamCreatePageRecord(PVM pVM, RTRCPTR GCPtr, CSAMTAG enmTag, bool fCode32, bool fMonitorInvalidation = false);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic int csamRemovePageRecord(PVM pVM, RTRCPTR GCPtr);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic int csamReinit(PVM pVM);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic void csamMarkCode(PVM pVM, PCSAMPAGE pPage, RTRCPTR pInstr, uint32_t opsize, bool fScanned);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic int csamAnalyseCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** @todo Temporary for debugging. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic bool fInCSAMCodePageInvalidate = false;
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/*******************************************************************************
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync* Global Variables *
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync*******************************************************************************/
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync#ifdef VBOX_WITH_DEBUGGER
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic DECLCALLBACK(int) csamr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic DECLCALLBACK(int) csamr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** Command descriptors. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsyncstatic const DBGCCMD g_aCmds[] =
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync{
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, fFlags, pfnHandler pszSyntax, ....pszDescription */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync { "csamon", 0, 0, NULL, 0, 0, csamr3CmdOn, "", "Enable CSAM code scanning." },
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync { "csamoff", 0, 0, NULL, 0, 0, csamr3CmdOff, "", "Disable CSAM code scanning." },
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync};
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * SSM descriptor table for the CSAM structure.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic const SSMFIELD g_aCsamFields[] =
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo there are more fields that can be ignored here. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, offVM),
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync SSMFIELD_ENTRY_PAD_HC64( CSAM, Alignment0, sizeof(uint32_t)),
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAM, pPageTree),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, aDangerousInstr),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, cDangerousInstr),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, iDangerousInstr),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_RCPTR( CSAM, pPDBitmapGC), /// @todo ignore this?
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_RCPTR( CSAM, pPDHCBitmapGC), /// @todo ignore this?
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAM, pPDBitmapHC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAM, pPDGCBitmapHC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAM, savedstate.pSSM),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, savedstate.cPageRecords),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, savedstate.cPatchPageRecords),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, cDirtyPages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_RCPTR_ARRAY( CSAM, pvDirtyBasePage),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_RCPTR_ARRAY( CSAM, pvDirtyFaultPage),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, cPossibleCodePages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_RCPTR_ARRAY( CSAM, pvPossibleCodePage),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_RCPTR_ARRAY( CSAM, pvCallInstruction),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, iCallInstruction),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, fScanningStarted),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY( CSAM, fGatesChecked),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_PAD_HC( CSAM, Alignment1, 6, 2),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrTraps),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrPages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrPagesInv),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrRemovedPages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrPatchPages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrPageNPHC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrPageNPGC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrFlushes),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrFlushesSkipped),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrKnownPagesHC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrKnownPagesGC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrInstr),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrBytesRead),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrOpcodeRead),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatTime),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatTimeCheckAddr),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatTimeAddrConv),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatTimeFlushPage),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatTimeDisasm),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatFlushDirtyPages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatCheckGates),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatCodePageModified),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatDangerousWrite),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatInstrCacheHit),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatInstrCacheMiss),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatPagePATM),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatPageCSAM),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatPageREM),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatNrUserPages),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatPageMonitor),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatPageRemoveREMFlush),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatBitmapAlloc),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatScanNextFunction),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAM, StatScanNextFunctionFailed),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_TERM()
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync};
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** Fake type to simplify g_aCsamPDBitmapArray construction. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *a[CSAM_PGDIRBMP_CHUNKS];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync} CSAMPDBITMAPARRAY;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * SSM descriptor table for the CSAM::pPDBitmapHC array.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic SSMFIELD const g_aCsamPDBitmapArray[] =
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_HCPTR_NI_ARRAY(CSAMPDBITMAPARRAY, a),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_TERM()
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync};
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * SSM descriptor table for the CSAMPAGEREC structure.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic const SSMFIELD g_aCsamPageRecFields[] =
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAMPAGEREC, Core.Key),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAMPAGEREC, Core.pLeft),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGN_HCPTR( CSAMPAGEREC, Core.pRight),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_IGNORE( CSAMPAGEREC, Core.uchHeight),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_PAD_HC_AUTO( 3, 7),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY_RCPTR( CSAMPAGEREC, page.pPageGC),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_PAD_HC_AUTO( 0, 4),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMFIELD_ENTRY_PAD_MSC32_AUTO( 4),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY_GCPHYS( CSAMPAGEREC, page.GCPhys),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.fFlags),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.uSize),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY_PAD_HC_AUTO( 0, 4),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY_HCPTR_NI( CSAMPAGEREC, page.pBitmap),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.fCode32),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.fMonitorActive),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.fMonitorInvalidation),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY_PAD_HC_AUTO( 1, 1),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.enmTag),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY( CSAMPAGEREC, page.u64Hash),
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync SSMFIELD_ENTRY_TERM()
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync};
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Initializes the CSAM.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3Init(PVM pVM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogFlow(("CSAMR3Init\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Allocate bitmap for the page directory. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = MMR3HyperAllocOnceNoRel(pVM, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR), 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDBitmapHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRCReturn(rc, rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = MMR3HyperAllocOnceNoRel(pVM, CSAM_PGDIRBMP_CHUNKS*sizeof(RTRCPTR), 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDGCBitmapHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRCReturn(rc, rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pVM->csam.s.pPDBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDGCBitmapHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pVM->csam.s.pPDHCBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamReinit(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRCReturn(rc, rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Register save and load state notifiers.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = SSMR3RegisterInternal(pVM, "CSAM", 0, CSAM_SSM_VERSION, sizeof(pVM->csam.s) + PAGE_SIZE*16,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync NULL, NULL, NULL,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync NULL, csamr3Save, NULL,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync NULL, csamr3Load, NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRCReturn(rc, rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrTraps, STAMTYPE_COUNTER, "/CSAM/PageTraps", STAMUNIT_OCCURENCES, "The number of CSAM page traps.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatDangerousWrite, STAMTYPE_COUNTER, "/CSAM/DangerousWrites", STAMUNIT_OCCURENCES, "The number of dangerous writes that cause a context switch.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPageNPHC, STAMTYPE_COUNTER, "/CSAM/HC/PageNotPresent", STAMUNIT_OCCURENCES, "The number of CSAM pages marked not present.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPageNPGC, STAMTYPE_COUNTER, "/CSAM/GC/PageNotPresent", STAMUNIT_OCCURENCES, "The number of CSAM pages marked not present.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPages, STAMTYPE_COUNTER, "/CSAM/PageRec/AddedRW", STAMUNIT_OCCURENCES, "The number of CSAM page records (RW monitoring).");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPagesInv, STAMTYPE_COUNTER, "/CSAM/PageRec/AddedRWI", STAMUNIT_OCCURENCES, "The number of CSAM page records (RW & invalidation monitoring).");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrRemovedPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Removed", STAMUNIT_OCCURENCES, "The number of removed CSAM page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageRemoveREMFlush,STAMTYPE_COUNTER, "/CSAM/PageRec/Removed/REMFlush", STAMUNIT_OCCURENCES, "The number of removed CSAM page records that caused a REM flush.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPatchPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Patch", STAMUNIT_OCCURENCES, "The number of CSAM patch page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrUserPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Ignore/User", STAMUNIT_OCCURENCES, "The number of CSAM user page records (ignored).");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPagePATM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/PATM", STAMUNIT_OCCURENCES, "The number of PATM page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageCSAM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/CSAM", STAMUNIT_OCCURENCES, "The number of CSAM page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageREM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/REM", STAMUNIT_OCCURENCES, "The number of REM page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageMonitor, STAMTYPE_COUNTER, "/CSAM/PageRec/Monitored", STAMUNIT_OCCURENCES, "The number of monitored pages.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatCodePageModified, STAMTYPE_COUNTER, "/CSAM/Monitor/DirtyPage", STAMUNIT_OCCURENCES, "The number of code page modifications.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrFlushes, STAMTYPE_COUNTER, "/CSAM/PageFlushes", STAMUNIT_OCCURENCES, "The number of CSAM page flushes.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrFlushesSkipped, STAMTYPE_COUNTER, "/CSAM/PageFlushesSkipped", STAMUNIT_OCCURENCES, "The number of CSAM page flushes that were skipped.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrKnownPagesHC, STAMTYPE_COUNTER, "/CSAM/HC/KnownPageRecords", STAMUNIT_OCCURENCES, "The number of known CSAM page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrKnownPagesGC, STAMTYPE_COUNTER, "/CSAM/GC/KnownPageRecords", STAMUNIT_OCCURENCES, "The number of known CSAM page records.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrInstr, STAMTYPE_COUNTER, "/CSAM/ScannedInstr", STAMUNIT_OCCURENCES, "The number of scanned instructions.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrBytesRead, STAMTYPE_COUNTER, "/CSAM/BytesRead", STAMUNIT_OCCURENCES, "The number of bytes read for scanning.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrOpcodeRead, STAMTYPE_COUNTER, "/CSAM/OpcodeBytesRead", STAMUNIT_OCCURENCES, "The number of opcode bytes read by the recompiler.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatBitmapAlloc, STAMTYPE_COUNTER, "/CSAM/Alloc/PageBitmap", STAMUNIT_OCCURENCES, "The number of page bitmap allocations.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatInstrCacheHit, STAMTYPE_COUNTER, "/CSAM/Cache/Hit", STAMUNIT_OCCURENCES, "The number of dangerous instruction cache hits.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatInstrCacheMiss, STAMTYPE_COUNTER, "/CSAM/Cache/Miss", STAMUNIT_OCCURENCES, "The number of dangerous instruction cache misses.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatScanNextFunction, STAMTYPE_COUNTER, "/CSAM/Function/Scan/Success", STAMUNIT_OCCURENCES, "The number of found functions beyond the ret border.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatScanNextFunctionFailed, STAMTYPE_COUNTER, "/CSAM/Function/Scan/Failed", STAMUNIT_OCCURENCES, "The number of refused functions beyond the ret border.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTime, STAMTYPE_PROFILE, "/PROF/CSAM/Scan", STAMUNIT_TICKS_PER_CALL, "Scanning overhead.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeCheckAddr, STAMTYPE_PROFILE, "/PROF/CSAM/CheckAddr", STAMUNIT_TICKS_PER_CALL, "Address check overhead.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeAddrConv, STAMTYPE_PROFILE, "/PROF/CSAM/AddrConv", STAMUNIT_TICKS_PER_CALL, "Address conversion overhead.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeFlushPage, STAMTYPE_PROFILE, "/PROF/CSAM/FlushPage", STAMUNIT_TICKS_PER_CALL, "Page flushing overhead.");
09f4b412099acda62997fd82c8608075c453b3ebvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeDisasm, STAMTYPE_PROFILE, "/PROF/CSAM/Disasm", STAMUNIT_TICKS_PER_CALL, "Disassembly overhead.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatFlushDirtyPages, STAMTYPE_PROFILE, "/PROF/CSAM/FlushDirtyPage", STAMUNIT_TICKS_PER_CALL, "Dirty page flushing overhead.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REG(pVM, &pVM->csam.s.StatCheckGates, STAMTYPE_PROFILE, "/PROF/CSAM/CheckGates", STAMUNIT_TICKS_PER_CALL, "CSAMR3CheckGates overhead.");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Check CFGM option and enable/disable CSAM.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fEnabled;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "CSAMEnabled", &fEnabled);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_ENABLE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fEnabled = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fEnabled = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fEnabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CSAMEnableScanning(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_DEBUGGER
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Debugger commands.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static bool fRegisteredCmds = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!fRegisteredCmds)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = DBGCRegisterCommands(&g_aCmds[0], RT_ELEMENTS(g_aCmds));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRegisteredCmds = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * (Re)initializes CSAM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int csamReinit(PVM pVM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /*
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Assert alignment and sizes.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync AssertRelease(!(RT_OFFSETOF(VM, csam.s) & 31));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync AssertRelease(sizeof(pVM->csam.s) <= sizeof(pVM->csam.padding));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /*
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Setup any fixed pointers and offsets.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.offVM = RT_OFFSETOF(VM, patm);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.fGatesChecked = false;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.fScanningStarted = false;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies 1 VPCU */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_CSAM_PENDING_ACTION);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.cDirtyPages = 0;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* not necessary */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync memset(pVM->csam.s.pvDirtyBasePage, 0, sizeof(pVM->csam.s.pvDirtyBasePage));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync memset(pVM->csam.s.pvDirtyFaultPage, 0, sizeof(pVM->csam.s.pvDirtyFaultPage));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync memset(&pVM->csam.s.aDangerousInstr, 0, sizeof(pVM->csam.s.aDangerousInstr));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.cDangerousInstr = 0;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.iDangerousInstr = 0;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync memset(pVM->csam.s.pvCallInstruction, 0, sizeof(pVM->csam.s.pvCallInstruction));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.iCallInstruction = 0;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** @note never mess with the pgdir bitmap here! */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync return VINF_SUCCESS;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync}
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync/**
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Applies relocations to data and code managed by this
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * component. This function will be called at init and
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * whenever the VMM need to relocate itself inside the GC.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * The csam will update the addresses used by the switcher.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @param pVM The VM.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @param offDelta Relocation delta.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync */
09f4b412099acda62997fd82c8608075c453b3ebvboxsyncVMMR3DECL(void) CSAMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
09f4b412099acda62997fd82c8608075c453b3ebvboxsync if (offDelta)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* Adjust pgdir and page bitmap pointers. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.pPDBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDGCBitmapHC);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.pPDHCBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync for(int i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
09f4b412099acda62997fd82c8608075c453b3ebvboxsync if (pVM->csam.s.pPDGCBitmapHC[i])
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
09f4b412099acda62997fd82c8608075c453b3ebvboxsync pVM->csam.s.pPDGCBitmapHC[i] += offDelta;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync }
09f4b412099acda62997fd82c8608075c453b3ebvboxsync }
09f4b412099acda62997fd82c8608075c453b3ebvboxsync }
09f4b412099acda62997fd82c8608075c453b3ebvboxsync return;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync}
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync/**
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Terminates the csam.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Termination means cleaning up and freeing all resources,
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * the VM it self is at this point powered off or suspended.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @returns VBox status code.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @param pVM The VM to operate on.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync */
09f4b412099acda62997fd82c8608075c453b3ebvboxsyncVMMR3DECL(int) CSAMR3Term(PVM pVM)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
09f4b412099acda62997fd82c8608075c453b3ebvboxsync int rc;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync rc = CSAMR3Reset(pVM);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync AssertRC(rc);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* @todo triggers assertion in MMHyperFree */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync#if 0
09f4b412099acda62997fd82c8608075c453b3ebvboxsync for(int i=0;i<CSAM_PAGEBMP_CHUNKS;i++)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
09f4b412099acda62997fd82c8608075c453b3ebvboxsync if (pVM->csam.s.pPDBitmapHC[i])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMHyperFree(pVM, pVM->csam.s.pPDBitmapHC[i]);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * CSAM reset callback.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @returns VBox status code.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @param pVM The VM which is reset.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3Reset(PVM pVM)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Clear page bitmaps. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for(int i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pVM->csam.s.pPDBitmapHC[i])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert((CSAM_PAGE_BITMAP_SIZE& 3) == 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ASMMemZero32(pVM->csam.s.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Remove all CSAM page records. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while(true)
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec = (PCSAMPAGEREC)RTAvlPVGetBestFit(&pVM->csam.s.pPageTree, 0, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec)
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamRemovePageRecord(pVM, pPageRec->page.pPageGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!pVM->csam.s.pPageTree);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamReinit(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Callback function for RTAvlPVDoWithAll
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync * Counts the number of records in the tree
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync * @param pNode Current node
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcPatches Pointer to patch counter
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) CountRecord(PAVLPVNODECORE pNode, void *pcPatches)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync NOREF(pNode);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return VINF_SUCCESS;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Callback function for RTAvlPVDoWithAll
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Saves the state of the page record
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @returns VBox status code.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pNode Current node
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pVM1 VM Handle
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic DECLCALLBACK(int) SavePageState(PAVLPVNODECORE pNode, void *pVM1)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PVM pVM = (PVM)pVM1;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PCSAMPAGEREC pPage = (PCSAMPAGEREC)pNode;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync CSAMPAGEREC page = *pPage;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PSSMHANDLE pSSM = pVM->csam.s.savedstate.pSSM;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Save the page record itself */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3PutMem(pSSM, &page, sizeof(page));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (page.page.pBitmap)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3PutMem(pSSM, page.page.pBitmap, CSAM_PAGE_BITMAP_SIZE);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return VINF_SUCCESS;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Execute state save operation.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @returns VBox status code.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pVM VM Handle.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pSSM SSM operation handle.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic DECLCALLBACK(int) csamr3Save(PVM pVM, PSSMHANDLE pSSM)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync CSAM csamInfo = pVM->csam.s;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Count the number of page records in the tree (feeling lazy)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync csamInfo.savedstate.cPageRecords = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync RTAvlPVDoWithAll(&pVM->csam.s.pPageTree, true, CountRecord, &csamInfo.savedstate.cPageRecords);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Save CSAM structure
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.savedstate.pSSM = pSSM;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3PutMem(pSSM, &csamInfo, sizeof(csamInfo));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Save pgdir bitmap */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3PutMem(pSSM, csamInfo.pPDBitmapHC, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync for (unsigned i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if(csamInfo.pPDBitmapHC[i])
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Save the page bitmap. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3PutMem(pSSM, csamInfo.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Save page records
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTAvlPVDoWithAll(&pVM->csam.s.pPageTree, true, SavePageState, pVM);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /** @note we don't restore aDangerousInstr; it will be recreated automatically. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return VINF_SUCCESS;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Execute state load operation.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @returns VBox status code.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pVM VM Handle.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pSSM SSM operation handle.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param uVersion Data layout version.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param uPass The data pass.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic DECLCALLBACK(int) csamr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync CSAM csamInfo;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (uVersion != CSAM_SSM_VERSION)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertMsgFailed(("csamR3Load: Invalid version uVersion=%d!\n", uVersion));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.savedstate.pSSM = pSSM;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Restore CSAM structure
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#if 0
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetMem(pSSM, &csamInfo, sizeof(csamInfo));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync RT_ZERO(csamInfo);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetStructEx(pSSM, &csamInfo, sizeof(csamInfo), SSMSTRUCT_FLAGS_MEM_BAND_AID, &g_aCsamFields[0], NULL);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#endif
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.fGatesChecked = csamInfo.fGatesChecked;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.fScanningStarted = csamInfo.fScanningStarted;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Restore dirty code page info. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.cDirtyPages = csamInfo.cDirtyPages;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync memcpy(pVM->csam.s.pvDirtyBasePage, csamInfo.pvDirtyBasePage, sizeof(pVM->csam.s.pvDirtyBasePage));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync memcpy(pVM->csam.s.pvDirtyFaultPage, csamInfo.pvDirtyFaultPage, sizeof(pVM->csam.s.pvDirtyFaultPage));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Restore possible code page */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.cPossibleCodePages = csamInfo.cPossibleCodePages;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync memcpy(pVM->csam.s.pvPossibleCodePage, csamInfo.pvPossibleCodePage, sizeof(pVM->csam.s.pvPossibleCodePage));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Restore pgdir bitmap (we'll change the pointers next). */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#if 0
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetMem(pSSM, pVM->csam.s.pPDBitmapHC, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetStructEx(pSSM, pVM->csam.s.pPDBitmapHC, sizeof(uint8_t *) * CSAM_PGDIRBMP_CHUNKS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync SSMSTRUCT_FLAGS_MEM_BAND_AID, &g_aCsamPDBitmapArray[0], NULL);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#endif
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Restore page bitmaps
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync for (unsigned i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if(pVM->csam.s.pPDBitmapHC[i])
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = MMHyperAlloc(pVM, CSAM_PAGE_BITMAP_SIZE, 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDBitmapHC[i]);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (RT_FAILURE(rc))
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log(("MMHyperAlloc failed with %Rrc\n", rc));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Convert to GC pointer. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.pPDGCBitmapHC[i] = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC[i]);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(pVM->csam.s.pPDGCBitmapHC[i]);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Restore the bitmap. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetMem(pSSM, pVM->csam.s.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(!pVM->csam.s.pPDGCBitmapHC[i]);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.pPDGCBitmapHC[i] = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Restore page records
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync for (uint32_t i=0;i<csamInfo.savedstate.cPageRecords + csamInfo.savedstate.cPatchPageRecords;i++)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync CSAMPAGEREC page;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PCSAMPAGE pPage;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#if 0
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetMem(pSSM, &page, sizeof(page));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync RT_ZERO(page);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetStructEx(pSSM, &page, sizeof(page), SSMSTRUCT_FLAGS_MEM_BAND_AID, &g_aCsamPageRecFields[0], NULL);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#endif
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /*
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Recreate the page record
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pPage = csamCreatePageRecord(pVM, page.page.pPageGC, page.page.enmTag, page.page.fCode32, page.page.fMonitorInvalidation);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertReturn(pPage, VERR_NO_MEMORY);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pPage->GCPhys = page.page.GCPhys;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pPage->fFlags = page.page.fFlags;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pPage->u64Hash = page.page.u64Hash;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (page.page.pBitmap)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = SSMR3GetMem(pSSM, pPage->pBitmap, CSAM_PAGE_BITMAP_SIZE);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRCReturn(rc, rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
bf7ab711aa3580b3a587dcbc4653fe78c99fff37vboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync MMR3HeapFree(pPage->pBitmap);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pPage->pBitmap = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Note: we don't restore aDangerousInstr; it will be recreated automatically. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync memset(&pVM->csam.s.aDangerousInstr, 0, sizeof(pVM->csam.s.aDangerousInstr));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.cDangerousInstr = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pVM->csam.s.iDangerousInstr = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return VINF_SUCCESS;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Convert guest context address to host context pointer
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @returns VBox status code.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pVM The VM to operate on.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pCacheRec Address conversion cache record
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pGCPtr Guest context pointer
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @returns Host context pointer or NULL in case of an error
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic R3PTRTYPE(void *) CSAMGCVirtToHCVirt(PVM pVM, PCSAMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync R3PTRTYPE(void *) pHCPtr;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(pVM->cCpus == 1);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeAddrConv, a);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pHCPtr = PATMR3GCPtrToHCPtr(pVM, pGCPtr);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pHCPtr)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return pHCPtr;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCacheRec->pPageLocStartHC)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync uint32_t offset = pGCPtr & PAGE_OFFSET_MASK;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCacheRec->pGuestLoc == (pGCPtr & PAGE_BASE_GC_MASK))
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeAddrConv, a);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return pCacheRec->pPageLocStartHC + offset;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Release previous lock if any. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCacheRec->Lock.pvMap)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PGMPhysReleasePageMappingLock(pVM, &pCacheRec->Lock);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCacheRec->Lock.pvMap = NULL;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pGCPtr, (const void **)&pHCPtr, &pCacheRec->Lock);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (rc != VINF_SUCCESS)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync//// AssertMsgRC(rc, ("MMR3PhysGCVirt2HCVirtEx failed for %RRv\n", pGCPtr));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeAddrConv, a);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return NULL;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCacheRec->pPageLocStartHC = (R3PTRTYPE(uint8_t*))((RTHCUINTPTR)pHCPtr & PAGE_BASE_HC_MASK);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCacheRec->pGuestLoc = pGCPtr & PAGE_BASE_GC_MASK;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeAddrConv, a);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return pHCPtr;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @callback_method_impl{FNDISREADBYTES}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic DECLCALLBACK(int) CSAMR3ReadBytes(PDISCPUSTATE pDisState, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PVM pVM = (PVM)pDisState->pvUser;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync RTHCUINTPTR pInstrHC = (RTHCUINTPTR)pDisState->pvUser2;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync RTGCUINTPTR32 pInstrGC = pDisState->uInstrAddr;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int orgsize = cbToRead;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* We are not interested in patched instructions, so read the original opcode bytes.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Note! single instruction patches (int3) are checked in CSAMR3AnalyseCallback */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync for (int i = 0; i < orgsize; i++)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc = PATMR3QueryOpcode(pVM, (RTRCPTR)uSrcAddr, pbDst);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (RT_FAILURE(rc))
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync uSrcAddr++;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pbDst++;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync cbToRead--;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (cbToRead == 0)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return VINF_SUCCESS;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync if (PAGE_ADDRESS(pInstrGC) != PAGE_ADDRESS(uSrcAddr + cbToRead - 1) && !PATMIsPatchGCAddr(pVM, uSrcAddr))
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync return PGMPhysSimpleReadGCPtr(pVCpu, pbDst, uSrcAddr, cbToRead);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync Assert(pInstrHC);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync /* pInstrHC is the base address; adjust according to the GC pointer. */
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync pInstrHC = pInstrHC + (uSrcAddr - pInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(pbDst, (void *)pInstrHC, cbToRead);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync return VINF_SUCCESS;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(int) CSAMR3DISInstr(PVM pVM, RTRCPTR InstrGC, uint8_t *InstrHC, DISCPUMODE enmCpuMode,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDISCPUSTATE pCpu, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCpu->pvUser2 = InstrHC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DISInstrToStrEx(InstrGC, enmCpuMode, CSAMR3ReadBytes, pVM, DISOPTYPE_ALL,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCpu, pcbInstr, pszOutput, cbOutput);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We are interested in everything except harmless stuff */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pszOutput)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DISInstrToStrEx(InstrGC, enmCpuMode, CSAMR3ReadBytes, pVM, ~(DISOPTYPE_INVALID | DISOPTYPE_HARMLESS | DISOPTYPE_RRM_MASK),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCpu, pcbInstr, pszOutput, cbOutput);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DISInstEx(InstrGC, enmCpuMode, ~(DISOPTYPE_INVALID | DISOPTYPE_HARMLESS | DISOPTYPE_RRM_MASK), CSAMR3ReadBytes, pVM,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCpu, pcbInstr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Analyses the instructions following the cli for compliance with our heuristics for cli
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCpu CPU disassembly state
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstrGC Guest context pointer to privileged instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCurInstrGC Guest context pointer to the current instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCacheRec GC to HC cache record
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pUserData User pointer (callback specific)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int CSAMR3AnalyseCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMP2GLOOKUPREC pCacheRec, void *pUserData)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = (PCSAMPAGE)pUserData;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync int rc;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync NOREF(pInstrGC);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync switch (pCpu->pCurInstr->uOpcode)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync case OP_INT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pCpu->param1.fUse & DISUSE_IMMEDIATE8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCpu->param1.parval == 3)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync //two byte int 3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_ILLUD2:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This appears to be some kind of kernel panic in Linux 2.4; no point to continue. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_RETN:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_INT3:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_INVALID:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if 1
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* removing breaks win2k guests? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_IRET:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // Check for exit points
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (pCpu->pCurInstr->uOpcode)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* It's not a good idea to patch pushf instructions:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - increases the chance of conflicts (code jumping to the next instruction)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - better to patch the cli
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - code that branches before the cli will likely hit an int 3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - in general doesn't offer any benefits as we don't allow nested patch blocks (IF is always 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_PUSHF:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_POPF:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_CLI:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbInstrs = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbCurInstr = pCpu->cbInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fCode32 = pPage->fCode32;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(fCode32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATMR3AddHint(pVM, pCurInstrGC, (fCode32) ? PATMFL_CODE32 : 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Make sure the instructions that follow the cli have not been encountered before. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (true)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DISCPUSTATE cpu;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbInstrs + cbCurInstr >= SIZEOF_NEARJUMP32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC + cbCurInstr, &pPage) == true)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We've scanned the next instruction(s) already. This means we've followed a branch that ended up there before -> dangerous!! */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATMR3DetectConflict(pVM, pCurInstrGC, pCurInstrGC + cbCurInstr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCurInstrGC += cbCurInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbInstrs += cbCurInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync { /* Force pCurInstrHC out of scope after we stop using it (page lock!) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pCurInstrHC = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCurInstrHC == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMGCVirtToHCVirt failed for %RRv\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(VALID_PTR(pCurInstrHC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, (fCode32) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync &cpu, &cbCurInstr, NULL, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync case OP_PUSH:
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (pCpu->pCurInstr->param1 != OP_PARM_REG_CS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* no break */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_STR:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_LSL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_LAR:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SGDT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SLDT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SIDT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SMSW:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_VERW:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_VERR:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_CPUID:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_IRET:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch(pCpu->pCurInstr->uOpcode)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_STR:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: str!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_LSL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: lsl!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_LAR:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: lar!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SGDT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: sgdt!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SLDT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: sldt!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SIDT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: sidt!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SMSW:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: smsw!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_VERW:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: verw!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_VERR:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: verr!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_CPUID:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: cpuid!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_PUSH:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: push cs!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_IRET:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Privileged instruction at %RRv: iret!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (PATMR3HasBeenPatched(pVM, pCurInstrGC) == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PATMR3InstallPatch(pVM, pCurInstrGC, (pPage->fCode32) ? PATMFL_CODE32 : 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("PATMR3InstallPatch failed with %d\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCpu->pCurInstr->uOpcode == OP_IRET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS; /* Look no further in this branch. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_JMP:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_CALL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // return or jump/call through a jump table
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (OP_PARM_VTYPE(pCpu->pCurInstr->param1) != OP_PARM_J)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch(pCpu->pCurInstr->uOpcode)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_JMP:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Control Flow instruction at %RRv: jmp!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_CALL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Control Flow instruction at %RRv: call!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_ANALYSE_BEYOND_RET
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wrapper for csamAnalyseCodeStream for call instructions.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * @param pInstrGC Guest context pointer to privileged instruction
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * @param pCurInstrGC Guest context pointer to the current instruction
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * @param fCode32 16 or 32 bits code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pfnCSAMR3Analyse Callback for testing the disassembled instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pUserData User pointer (callback specific)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int csamAnalyseCallCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec)
2721dfb0e330d57ba888311520f5a343c64e7cefvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CSAMCALLEXITREC CallExitRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMCALLEXITREC pOldCallRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CallExitRec.cInstrAfterRet = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pOldCallRec = pCacheRec->pCallExitRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->pCallExitRec = &CallExitRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamAnalyseCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (i=0;i<CallExitRec.cInstrAfterRet;i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCurInstrGC = CallExitRec.pInstrAfterRetGC[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Check if we've previously encountered the instruction after the ret. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DISCPUSTATE cpu;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char szOutput[256];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* New address; let's take a look at it. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage = csamCreatePageRecord(pVM, pCurInstrGC, CSAM_TAG_CSAM, fCode32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VERR_NO_MEMORY;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Some generic requirements for recognizing an adjacent function:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - alignment fillers that consist of:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - nop
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - lea genregX, [genregX (+ 0)]
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * - push ebp after the filler (can extend this later); aligned at at least a 4 byte boundary
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (int j = 0; j < 16; j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCurInstrHC == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMGCVirtToHCVirt failed for %RRv\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(VALID_PTR(pCurInstrHC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeDisasm, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, (fCode32) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync &cpu, &cbInstr, szOutput, sizeof(szOutput));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc2)) Log(("CSAM Call Analysis: %s", szOutput));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, (fCode32) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync &cpu, &cbInstr, NULL, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeDisasm, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc2))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Disassembly failed at %RRv with %Rrc (probably page not present) -> return to caller\n", pCurInstrGC, rc2));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrBytesRead, cbInstr);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RCPTRTYPE(uint8_t *) addr = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pJmpPage = NULL;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (PAGE_ADDRESS(pCurInstrGC) != PAGE_ADDRESS(pCurInstrGC + cbInstr - 1))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!PGMGstIsPagePresent(pVM, pCurInstrGC + cbInstr - 1))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync /// @todo fault in the page
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Page for current instruction %RRv is not present!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync //all is fine, let's continue
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamR3CheckPageRecord(pVM, pCurInstrGC + cbInstr - 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (cpu.pCurInstr->uOpcode)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_NOP:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync case OP_INT3:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync break; /* acceptable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync case OP_LEA:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Must be similar to:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync *
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * lea esi, [esi]
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * lea esi, [esi+0]
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Any register is allowed as long as source and destination are identical.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( cpu.param1.fUse != DISUSE_REG_GEN32
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || ( cpu.param2.flags != DISUSE_REG_GEN32
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync && ( !(cpu.param2.flags & DISUSE_REG_GEN32)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync || !(cpu.param2.flags & (DISUSE_DISPLACEMENT8|DISUSE_DISPLACEMENT16|DISUSE_DISPLACEMENT32))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || cpu.param2.parval != 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync )
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync || cpu.param1.base.reg_gen32 != cpu.param2.base.reg_gen32
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync )
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
09f4b412099acda62997fd82c8608075c453b3ebvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto next_function;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync case OP_PUSH:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if ( (pCurInstrGC & 0x3) != 0
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync || cpu.param1.fUse != DISUSE_REG_GEN32
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync || cpu.param1.base.reg_gen32 != USE_REG_EBP
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_function;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync CSAMCALLEXITREC CallExitRec2;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync CallExitRec2.cInstrAfterRet = 0;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->pCallExitRec = &CallExitRec2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Analyse the function. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Found new function at %RRv\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunction);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamAnalyseCallCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_function;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case OP_SUB:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( (pCurInstrGC & 0x3) != 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || cpu.param1.fUse != DISUSE_REG_GEN32
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || cpu.param1.base.reg_gen32 != USE_REG_ESP
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_function;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CSAMCALLEXITREC CallExitRec2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CallExitRec2.cInstrAfterRet = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->pCallExitRec = &CallExitRec2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Analyse the function. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Found new function at %RRv\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunction);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamAnalyseCallCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_function;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_function;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Mark it as scanned. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamMarkCode(pVM, pPage, pCurInstrGC, cbInstr, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCurInstrGC += cbInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync } /* for at most 16 instructions */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncnext_function:
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync ; /* MSVC complains otherwise */
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncdone:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->pCallExitRec = pOldCallRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync#define csamAnalyseCallCodeStream csamAnalyseCodeStream
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync#endif
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Disassembles the code stream until the callback function detects a failure or decides everything is acceptable
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstrGC Guest context pointer to privileged instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCurInstrGC Guest context pointer to the current instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fCode32 16 or 32 bits code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pfnCSAMR3Analyse Callback for testing the disassembled instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pUserData User pointer (callback specific)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int csamAnalyseCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DISCPUSTATE cpu;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = (PCSAMPAGE)pUserData;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char szOutput[256];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogFlow(("csamAnalyseCodeStream: code at %RRv depth=%d\n", pCurInstrGC, pCacheRec->depth));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pVM->csam.s.fScanningStarted = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->depth++;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Limit the call depth. (rather arbitrary upper limit; too low and we won't detect certain
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * cpuid instructions in Linux kernels; too high and we waste too much time scanning code)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * (512 is necessary to detect cpuid instructions in Red Hat EL4; see defect 1355)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @note we are using a lot of stack here. couple of 100k when we go to the full depth (!)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCacheRec->depth > 512)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogFlow(("CSAM: maximum calldepth reached for %RRv\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->depth--;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS; //let's not go on forever
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!PATMIsPatchGCAddr(pVM, pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamR3CheckPageRecord(pVM, pCurInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while(rc == VWRN_CONTINUE_ANALYSIS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* New address; let's take a look at it. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage = csamCreatePageRecord(pVM, pCurInstrGC, CSAM_TAG_CSAM, fCode32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VERR_NO_MEMORY;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogFlow(("Code at %RRv has been scanned before\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync { /* Force pCurInstrHC out of scope after we stop using it (page lock!) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCurInstrHC == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMGCVirtToHCVirt failed for %RRv\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VERR_PATCHING_REFUSED;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(VALID_PTR(pCurInstrHC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeDisasm, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, fCode32 ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync &cpu, &cbInstr, szOutput, sizeof(szOutput));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc2)) Log(("CSAM Analysis: %s", szOutput));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, fCode32 ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync &cpu, &cbInstr, NULL, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeDisasm, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc2))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Disassembly failed at %RRv with %Rrc (probably page not present) -> return to caller\n", pCurInstrGC, rc2));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrBytesRead, cbInstr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamMarkCode(pVM, pPage, pCurInstrGC, cbInstr, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RCPTRTYPE(uint8_t *) addr = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pJmpPage = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (PAGE_ADDRESS(pCurInstrGC) != PAGE_ADDRESS(pCurInstrGC + cbInstr - 1))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!PGMGstIsPagePresent(pVCpu, pCurInstrGC + cbInstr - 1))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /// @todo fault in the page
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Page for current instruction %RRv is not present!!\n", pCurInstrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_please;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync //all is fine, let's continue
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamR3CheckPageRecord(pVM, pCurInstrGC + cbInstr - 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * If it's harmless, then don't bother checking it (the disasm tables had better be accurate!)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((cpu.pCurInstr->optype & ~DISOPTYPE_RRM_MASK) == DISOPTYPE_HARMLESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(pfnCSAMR3Analyse(pVM, &cpu, pInstrGC, pCurInstrGC, pCacheRec, (void *)pPage) == VWRN_CONTINUE_ANALYSIS, ("Instruction incorrectly marked harmless?!?!?\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync goto next_please;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
e6ad2e18e663b076aeabfec994947514566a7accvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_ANALYSE_BEYOND_RET
e6ad2e18e663b076aeabfec994947514566a7accvboxsync /* Remember the address of the instruction following the ret in case the parent instruction was a call. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( pCacheRec->pCallExitRec
e6ad2e18e663b076aeabfec994947514566a7accvboxsync && cpu.pCurInstr->uOpcode == OP_RETN
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && pCacheRec->pCallExitRec->cInstrAfterRet < CSAM_MAX_CALLEXIT_RET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->pCallExitRec->pInstrAfterRetGC[pCacheRec->pCallExitRec->cInstrAfterRet] = pCurInstrGC + cbInstr;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pCacheRec->pCallExitRec->cInstrAfterRet++;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pfnCSAMR3Analyse(pVM, &cpu, pInstrGC, pCurInstrGC, pCacheRec, (void *)pPage);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // For our first attempt, we'll handle only simple relative jumps and calls (immediate offset coded in instruction)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( ((cpu.pCurInstr->optype & DISOPTYPE_CONTROLFLOW) && (OP_PARM_VTYPE(cpu.pCurInstr->param1) == OP_PARM_J))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || (cpu.pCurInstr->uOpcode == OP_CALL && cpu.param1.fUse == DISUSE_DISPLACEMENT32)) /* simple indirect call (call dword ptr [address]) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We need to parse 'call dword ptr [address]' type of calls to catch cpuid instructions in some recent Linux distributions (e.g. OpenSuse 10.3) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( cpu.pCurInstr->uOpcode == OP_CALL
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && cpu.param1.fUse == DISUSE_DISPLACEMENT32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
e6ad2e18e663b076aeabfec994947514566a7accvboxsync addr = 0;
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync PGMPhysSimpleReadGCPtr(pVCpu, &addr, (RTRCUINTPTR)cpu.param1.uDisp.i32, sizeof(addr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync addr = CSAMResolveBranch(&cpu, pCurInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (addr == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("We don't support far jumps here!! (%08X)\n", cpu.param1.fUse));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!PATMIsPatchGCAddr(pVM, addr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* If the target address lies in a patch generated jump, then special action needs to be taken. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATMR3DetectConflict(pVM, pCurInstrGC, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Same page? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (PAGE_ADDRESS(addr) != PAGE_ADDRESS(pCurInstrGC ))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!PGMGstIsPagePresent(pVCpu, addr))
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Page for current instruction %RRv is not present!!\n", addr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto next_please;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* All is fine, let's continue. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamR3CheckPageRecord(pVM, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pJmpPage = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (csamIsCodeScanned(pVM, addr, &pJmpPage) == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pJmpPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* New branch target; let's take a look at it. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pJmpPage = csamCreatePageRecord(pVM, addr, CSAM_TAG_CSAM, fCode32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pJmpPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VERR_NO_MEMORY;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPage);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cpu.pCurInstr->uOpcode == OP_CALL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamAnalyseCallCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamAnalyseCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS) {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cpu.pCurInstr->uOpcode == OP_JMP)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {//unconditional jump; return to caller
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync } //if ((cpu.pCurInstr->optype & DISOPTYPE_CONTROLFLOW) && (OP_PARM_VTYPE(cpu.pCurInstr->param1) == OP_PARM_J))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_SCAN_JUMP_TABLE
e6ad2e18e663b076aeabfec994947514566a7accvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( cpu.pCurInstr->uOpcode == OP_JMP
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (cpu.param1.fUse & (DISUSE_DISPLACEMENT32|DISUSE_INDEX|DISUSE_SCALE)) == (DISUSE_DISPLACEMENT32|DISUSE_INDEX|DISUSE_SCALE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
e6ad2e18e663b076aeabfec994947514566a7accvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTRCPTR pJumpTableGC = (RTRCPTR)cpu.param1.disp32;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync uint8_t *pJumpTableHC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Jump through jump table\n"));
e6ad2e18e663b076aeabfec994947514566a7accvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pJumpTableGC, (PRTHCPTR)&pJumpTableHC, missing page lock);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync if (rc2 == VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i=0;i<2;i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync uint64_t fFlags;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync addr = pJumpTableGC + cpu.param1.scale * i;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Same page? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (PAGE_ADDRESS(addr) != PAGE_ADDRESS(pJumpTableGC))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync addr = *(RTRCPTR *)(pJumpTableHC + cpu.param1.scale * i);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync rc2 = PGMGstGetPage(pVCpu, addr, &fFlags, NULL);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if ( rc2 != VINF_SUCCESS
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync || (fFlags & X86_PTE_US)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync || !(fFlags & X86_PTE_P)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync )
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync break;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync Log(("Jump to %RRv\n", addr));
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync pJmpPage = NULL;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (csamIsCodeScanned(pVM, addr, &pJmpPage) == false)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (pJmpPage == NULL)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync /* New branch target; let's take a look at it. */
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync pJmpPage = csamCreatePageRecord(pVM, addr, CSAM_TAG_CSAM, fCode32);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (pJmpPage == NULL)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync rc = VERR_NO_MEMORY;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync goto done;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync Assert(pPage);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync rc = csamAnalyseCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (rc != VINF_SUCCESS) {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync goto done;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync#endif
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (rc != VWRN_CONTINUE_ANALYSIS) {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break; //done!
c58dc77ef4af214d7ae06910fa5ab18587d2ae08vboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncnext_please:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cpu.pCurInstr->uOpcode == OP_JMP)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto done;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCurInstrGC += cbInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncdone:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCacheRec->depth--;
c58dc77ef4af214d7ae06910fa5ab18587d2ae08vboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Calculates the 64 bits hash value for the current page
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns hash value
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstr Page address
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncuint64_t csamR3CalcPageHash(PVM pVM, RTRCPTR pInstr)
e6ad2e18e663b076aeabfec994947514566a7accvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t hash = 0;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync uint32_t val[5];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert((pInstr & PAGE_OFFSET_MASK) == 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysSimpleReadGCPtr(pVCpu, &val[0], pInstr, sizeof(val[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("csamR3CalcPageHash: page %RRv not present!!\n", pInstr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return ~0ULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysSimpleReadGCPtr(pVCpu, &val[1], pInstr+1024, sizeof(val[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
e6ad2e18e663b076aeabfec994947514566a7accvboxsync Log(("csamR3CalcPageHash: page %RRv not present!!\n", pInstr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return ~0ULL;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysSimpleReadGCPtr(pVCpu, &val[2], pInstr+2048, sizeof(val[0]));
e6ad2e18e663b076aeabfec994947514566a7accvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("csamR3CalcPageHash: page %RRv not present!!\n", pInstr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return ~0ULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysSimpleReadGCPtr(pVCpu, &val[3], pInstr+3072, sizeof(val[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("csamR3CalcPageHash: page %RRv not present!!\n", pInstr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return ~0ULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysSimpleReadGCPtr(pVCpu, &val[4], pInstr+4092, sizeof(val[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("csamR3CalcPageHash: page %RRv not present!!\n", pInstr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return ~0ULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // don't want to get division by zero traps
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val[2] |= 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val[4] |= 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync hash = (uint64_t)val[0] * (uint64_t)val[1] / (uint64_t)val[2] + (val[3]%val[4]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (hash == ~0ULL) ? hash - 1 : hash;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * Notify CSAM of a page flush
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code
e6ad2e18e663b076aeabfec994947514566a7accvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param addr GC address of the page to flush
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fRemovePage Page removal flag
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int csamFlushPage(PVM pVM, RTRCPTR addr, bool fRemovePage)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
e6ad2e18e663b076aeabfec994947514566a7accvboxsync PCSAMPAGEREC pPageRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPHYS GCPhys = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t fFlags = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1 || !CSAMIsEnabled(pVM));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!CSAMIsEnabled(pVM))
e6ad2e18e663b076aeabfec994947514566a7accvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync addr = addr & PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Note: searching for the page in our tree first is more expensive (skipped flushes are two orders of magnitude more common)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pVM->csam.s.pPageTree == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMGstGetPage(pVCpu, addr, &fFlags, &GCPhys);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Returned at a very early stage (no paging yet presumably). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_NOT_SUPPORTED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( (fFlags & X86_PTE_US)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || rc == VERR_PGM_PHYS_PAGE_RESERVED
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* User page -> not relevant for us. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrFlushesSkipped, 1);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VERR_PAGE_NOT_PRESENT && rc != VERR_PAGE_TABLE_NOT_PRESENT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("PGMR3GetPage %RRv failed with %Rrc\n", addr, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( GCPhys == pPageRec->page.GCPhys
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (fFlags & X86_PTE_P))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrFlushesSkipped, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3FlushPage: page %RRv has changed -> FLUSH (rc=%Rrc) (Phys: %RGp vs %RGp)\n", addr, rc, GCPhys, pPageRec->page.GCPhys));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrFlushes, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fRemovePage)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamRemovePageRecord(pVM, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CSAMMarkPage(pVM, addr, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.GCPhys = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.fFlags = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMGstGetPage(pVCpu, addr, &pPageRec->page.fFlags, &pPageRec->page.GCPhys);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.u64Hash = csamR3CalcPageHash(pVM, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec->page.pBitmap == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.pBitmap = (uint8_t *)MMR3HeapAllocZ(pVM, MM_TAG_CSAM_PATCH, CSAM_PAGE_BITMAP_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPageRec->page.pBitmap);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec->page.pBitmap == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_NO_MEMORY;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(pPageRec->page.pBitmap, 0, CSAM_PAGE_BITMAP_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Inform patch manager about the flush; no need to repeat the above check twice.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATMR3FlushPage(pVM, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Notify CSAM of a page flush
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param addr GC address of the page to flush
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3FlushPage(PVM pVM, RTRCPTR addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return csamFlushPage(pVM, addr, true /* remove page record */);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
eb2d4958f7faf812c3bdb2d7587d815022f0bd55vboxsync * Remove a CSAM monitored page. Use with care!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param addr GC address of the page to flush
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3RemovePage(PVM pVM, RTRCPTR addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync addr = addr & PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamRemovePageRecord(pVM, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATMR3FlushPage(pVM, addr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Check a page record in case a page has been changed
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code. (trap handled or not)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstrGC GC instruction pointer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncint csamR3CheckPageRecord(PVM pVM, RTRCPTR pInstrGC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t u64hash;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pInstrGC = pInstrGC & PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync u64hash = csamR3CalcPageHash(pVM, pInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (u64hash != pPageRec->page.u64Hash)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync csamFlushPage(pVM, pInstrGC, false /* don't remove page record */);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
2721dfb0e330d57ba888311520f5a343c64e7cefvboxsync
2721dfb0e330d57ba888311520f5a343c64e7cefvboxsync return VINF_SUCCESS;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync}
e6ad2e18e663b076aeabfec994947514566a7accvboxsync
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync/**
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync * Returns monitor description based on CSAM tag
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync *
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync * @return description string
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync * @param enmTag Owner tag
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync */
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsyncconst char *csamGetMonitorDescription(CSAMTAG enmTag)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync{
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync if (enmTag == CSAM_TAG_PATM)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync return "CSAM-PATM self-modifying code monitor handler";
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (enmTag == CSAM_TAG_REM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return "CSAM-REM self-modifying code monitor handler";
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(enmTag == CSAM_TAG_CSAM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return "CSAM self-modifying code monitor handler";
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Adds page record to our lookup tree
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns CSAMPAGE ptr or NULL if failure
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param GCPtr Page address
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param enmTag Owner tag
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fCode32 16 or 32 bits code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fMonitorInvalidation Monitor page invalidation flag
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic PCSAMPAGE csamCreatePageRecord(PVM pVM, RTRCPTR GCPtr, CSAMTAG enmTag, bool fCode32, bool fMonitorInvalidation)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPage;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool ret;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("New page record for %RRv\n", GCPtr & PAGE_BASE_GC_MASK));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage = (PCSAMPAGEREC)MMR3HeapAllocZ(pVM, MM_TAG_CSAM_PATCH, sizeof(CSAMPAGEREC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("csamCreatePageRecord: Out of memory!!!!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Round down to page boundary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync GCPtr = (GCPtr & PAGE_BASE_GC_MASK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->Core.Key = (AVLPVKEY)(uintptr_t)GCPtr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.pPageGC = GCPtr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.fCode32 = fCode32;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.fMonitorInvalidation = fMonitorInvalidation;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.enmTag = enmTag;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.fMonitorActive = false;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync pPage->page.pBitmap = (uint8_t *)MMR3HeapAllocZ(pVM, MM_TAG_CSAM_PATCH, PAGE_SIZE/sizeof(uint8_t));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMGstGetPage(pVCpu, GCPtr, &pPage->page.fFlags, &pPage->page.GCPhys);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.u64Hash = csamR3CalcPageHash(pVM, GCPtr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ret = RTAvlPVInsert(&pVM->csam.s.pPageTree, &pPage->Core);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(ret);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_MONITOR_CODE_PAGES
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(!fInCSAMCodePageInvalidate);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (enmTag)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case CSAM_TAG_PATM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case CSAM_TAG_REM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case CSAM_TAG_CSAM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtr, GCPtr + (PAGE_SIZE - 1) /* inclusive! */,
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync (fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamGetMonitorDescription(enmTag));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %RRv failed with %Rrc\n", GCPtr, rc));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("PGMR3HandlerVirtualRegisterEx for %RRv failed with %Rrc\n", GCPtr, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Could fail, because it's already monitored. Don't treat that condition as fatal. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Prefetch it in case it's not there yet. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPrefetchPage(pVCpu, GCPtr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMShwMakePageReadonly(pVCpu, GCPtr, 0 /*fFlags*/);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->page.fMonitorActive = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageMonitor);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break; /* to shut up GCC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log(("csamCreatePageRecord %RRv GCPhys=%RGp\n", GCPtr, pPage->page.GCPhys));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_STATISTICS
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (enmTag)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case CSAM_TAG_CSAM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageCSAM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case CSAM_TAG_PATM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPagePATM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case CSAM_TAG_REM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageREM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break; /* to shut up GCC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrPages);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fMonitorInvalidation)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrPagesInv);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return &pPage->page;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * Monitors a code page (if not already monitored)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * @param pPageAddrGC The page to monitor
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param enmTag Monitor tag
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3MonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fMonitorInvalidation;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Dirty pages must be handled before calling this function!. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!pVM->csam.s.cDirtyPages);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pVM->csam.s.fScanningStarted == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS; /* too early */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageAddrGC &= PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3MonitorPage %RRv %d\n", pPageAddrGC, enmTag));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implicit assumption */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fMonitorInvalidation = (enmTag == CSAM_TAG_PATM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pPageAddrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t fFlags;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMGstGetPage(pVCpu, pPageAddrGC, &fFlags, NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( rc == VINF_SUCCESS
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (fFlags & X86_PTE_US))
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We don't care about user pages. */
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrUserPages);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamCreatePageRecord(pVM, pPageAddrGC, enmTag, true /* 32 bits code */, fMonitorInvalidation);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pPageAddrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPageRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo reference count */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPageRec->page.fMonitorActive);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_MONITOR_CODE_PAGES
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pPageRec->page.fMonitorActive)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3MonitorPage: activate monitoring for %RRv\n", pPageAddrGC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, pPageAddrGC, pPageAddrGC + (PAGE_SIZE - 1) /* inclusive! */,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamGetMonitorDescription(enmTag));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %RRv failed with %Rrc\n", pPageAddrGC, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("PGMR3HandlerVirtualRegisterEx for %RRv failed with %Rrc\n", pPageAddrGC, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Could fail, because it's already monitored. Don't treat that condition as fatal. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Prefetch it in case it's not there yet. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPrefetchPage(pVCpu, pPageAddrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMShwMakePageReadonly(pVCpu, pPageAddrGC, 0 /*fFlags*/);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageMonitor);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.fMonitorActive = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.fMonitorInvalidation = fMonitorInvalidation;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( !pPageRec->page.fMonitorInvalidation
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync && fMonitorInvalidation)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPageRec->page.fMonitorActive);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PGMHandlerVirtualChangeInvalidateCallback(pVM, pPageRec->page.pPageGC, CSAMCodePageInvalidate);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec->page.fMonitorInvalidation = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrPagesInv);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Prefetch it in case it's not there yet. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPrefetchPage(pVCpu, pPageAddrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Make sure it's readonly. Page invalidation may have modified the attributes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMShwMakePageReadonly(pVCpu, pPageAddrGC, 0 /*fFlags*/);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync#if 0 /* def VBOX_STRICT -> very annoying) */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if (pPageRec->page.fMonitorActive)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync uint64_t fPageShw;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync RTHCPHYS GCPhys;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync rc = PGMShwGetPage(pVCpu, pPageAddrGC, &fPageShw, &GCPhys);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync// AssertMsg( (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync// || !(fPageShw & X86_PTE_RW)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync// || (pPageRec->page.GCPhys == 0), ("Shadow page flags for %RRv (%RHp) aren't readonly (%RX64)!!\n", pPageAddrGC, GCPhys, fPageShw));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync#endif
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if (pPageRec->page.GCPhys == 0)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Prefetch it in case it's not there yet. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync rc = PGMPrefetchPage(pVCpu, pPageAddrGC);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync AssertRC(rc);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* The page was changed behind our back. It won't be made read-only until the next SyncCR3, so force it here. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync rc = PGMShwMakePageReadonly(pVCpu, pPageAddrGC, 0 /*fFlags*/);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync#endif /* CSAM_MONITOR_CODE_PAGES */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return VINF_SUCCESS;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync}
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync/**
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Unmonitors a code page
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @returns VBox status code
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pPageAddrGC The page to monitor
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param enmTag Monitor tag
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3UnmonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageAddrGC &= PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3UnmonitorPage %RRv %d\n", pPageAddrGC, enmTag));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(enmTag == CSAM_TAG_REM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync#ifdef VBOX_STRICT
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pPageAddrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPageRec && pPageRec->page.enmTag == enmTag);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return CSAMR3RemovePage(pVM, pPageAddrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Removes a page record from our lookup tree
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param GCPtr Page address
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int csamRemovePageRecord(PVM pVM, RTRCPTR GCPtr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("csamRemovePageRecord %RRv\n", GCPtr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVRemove(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)GCPtr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrRemovedPages);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef CSAM_MONITOR_CODE_PAGES
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec->page.fMonitorActive)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* @todo -> this is expensive (cr3 reload)!!!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * if this happens often, then reuse it instead!!!
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync */
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync Assert(!fInCSAMCodePageInvalidate);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPageMonitor);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync PGMHandlerVirtualDeregister(pVM, GCPtr);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (pPageRec->page.enmTag == CSAM_TAG_PATM)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync /* Make sure the recompiler flushes its cache as this page is no longer monitored. */
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageRemoveREMFlush);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync }
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync#endif
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync#ifdef VBOX_WITH_STATISTICS
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync switch (pPageRec->page.enmTag)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync {
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync case CSAM_TAG_CSAM:
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPageCSAM);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync break;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync case CSAM_TAG_PATM:
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPagePATM);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync break;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync case CSAM_TAG_REM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPageREM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break; /* to shut up GCC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec->page.pBitmap) MMR3HeapFree(pPageRec->page.pBitmap);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMR3HeapFree(pPageRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertFailed();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync/**
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Callback for delayed writes from non-EMT threads
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param pVM VM Handle.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cbBuf How much it's reading/writing.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsyncstatic DECLCALLBACK(void) CSAMDelayedWriteHandler(PVM pVM, RTRCPTR GCPtr, size_t cbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync int rc = PATMR3PatchWrite(pVM, GCPtr, (uint32_t)cbBuf);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync AssertRC(rc);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync}
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync/**
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * \#PF Handler callback for virtual access handler ranges.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Important to realize that a physical page in a range can have aliases, and
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * for ALL and WRITE handlers these will also trigger.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @returns VINF_SUCCESS if the handler have carried out the operation.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param pVM VM Handle.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param pvPtr The HC mapping of that address.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param pvBuf What the guest is reading/writing.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param cbBuf How much it's reading/writing.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param enmAccessType The access type.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * @param pvUser User argument.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsyncstatic DECLCALLBACK(int) CSAMCodePageWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync int rc;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(enmAccessType == PGMACCESSTYPE_WRITE); NOREF(enmAccessType);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log(("CSAMCodePageWriteHandler: write to %RGv size=%zu\n", GCPtr, cbBuf));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync NOREF(pvUser);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if ( PAGE_ADDRESS(pvPtr) == PAGE_ADDRESS((uintptr_t)pvPtr + cbBuf - 1)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync && !memcmp(pvPtr, pvBuf, cbBuf))
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log(("CSAMCodePageWriteHandler: dummy write -> ignore\n"));
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return VINF_PGM_HANDLER_DO_DEFAULT;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VM_IS_EMT(pVM))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PATMR3PatchWrite(pVM, GCPtr, (uint32_t)cbBuf);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Queue the write instead otherwise we'll get concurrency issues. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @note in theory not correct to let it write the data first before disabling a patch!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * (if it writes the same data as the patch jump and we replace it with obsolete opcodes)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCodePageWriteHandler: delayed write!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertCompileSize(RTRCPTR, 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMR3ReqCallVoidNoWait(pVM, VMCPUID_ANY, (PFNRT)CSAMDelayedWriteHandler, 3, pVM, (RTRCPTR)GCPtr, cbBuf);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_PGM_HANDLER_DO_DEFAULT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * \#PF Handler callback for invalidation of virtual access handler ranges.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM VM Handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param GCPtr The virtual address the guest has changed.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) CSAMCodePageInvalidate(PVM pVM, RTGCPTR GCPtr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fInCSAMCodePageInvalidate = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogFlow(("CSAMCodePageInvalidate %RGv\n", GCPtr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo We can't remove the page (which unregisters the virtual handler) as we are called from a DoWithAll on the virtual handler tree. Argh. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamFlushPage(pVM, GCPtr, false /* don't remove page! */);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fInCSAMCodePageInvalidate = false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/**
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Check if the current instruction has already been checked before
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code. (trap handled or not)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstr Instruction pointer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pPage CSAM patch structure pointer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncbool csamIsCodeScanned(PVM pVM, RTRCPTR pInstr, PCSAMPAGE *pPage)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t offset;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeCheckAddr, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync offset = pInstr & PAGE_OFFSET_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pInstr = pInstr & PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pPage);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (*pPage && (*pPage)->pPageGC == pInstr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((*pPage)->pBitmap == NULL || ASMBitTest((*pPage)->pBitmap, offset))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrKnownPagesHC, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pInstr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage) *pPage= &pPageRec->page;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec->page.pBitmap == NULL || ASMBitTest(pPageRec->page.pBitmap, offset))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrKnownPagesHC, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage) *pPage = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Mark an instruction in a page as scanned/not scanned
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pPage Patch structure pointer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstr Instruction pointer
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param cbInstr Instruction size
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param fScanned Mark as scanned or not
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncstatic void csamMarkCode(PVM pVM, PCSAMPAGE pPage, RTRCPTR pInstr, uint32_t cbInstr, bool fScanned)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync{
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync LogFlow(("csamMarkCodeAsScanned %RRv cbInstr=%d\n", pInstr, cbInstr));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync CSAMMarkPage(pVM, pInstr, fScanned);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync /** @todo should recreate empty bitmap if !fScanned */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (pPage->pBitmap == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fScanned)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // retn instructions can be scanned more than once
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (ASMBitTest(pPage->pBitmap, pInstr & PAGE_OFFSET_MASK) == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->uSize += cbInstr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrInstr, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPage->uSize >= PAGE_SIZE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Scanned full page (%RRv) -> free bitmap\n", pInstr & PAGE_BASE_GC_MASK));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMR3HeapFree(pPage->pBitmap);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPage->pBitmap = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ASMBitSet(pPage->pBitmap, pInstr & PAGE_OFFSET_MASK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ASMBitClear(pPage->pBitmap, pInstr & PAGE_OFFSET_MASK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Mark an instruction in a page as scanned/not scanned
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstr Instruction pointer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cbInstr Instruction size
521d8df5a1a304406b911c2e2c7bf9214d6d9200vboxsync * @param fScanned Mark as scanned or not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3MarkCode(PVM pVM, RTRCPTR pInstr, uint32_t cbInstr, bool fScanned)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = 0;
521d8df5a1a304406b911c2e2c7bf9214d6d9200vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!fScanned); /* other case not implemented. */
521d8df5a1a304406b911c2e2c7bf9214d6d9200vboxsync Assert(!PATMIsPatchGCAddr(pVM, pInstr));
521d8df5a1a304406b911c2e2c7bf9214d6d9200vboxsync
521d8df5a1a304406b911c2e2c7bf9214d6d9200vboxsync if (csamIsCodeScanned(pVM, pInstr, &pPage) == false)
521d8df5a1a304406b911c2e2c7bf9214d6d9200vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(fScanned == true); /* other case should not be possible */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3MarkCode: %RRv size=%d fScanned=%d\n", pInstr, cbInstr, fScanned));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamMarkCode(pVM, pPage, pInstr, cbInstr, fScanned);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Scan and analyse code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCtxCore CPU context
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstrGC Instruction pointer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3CheckCodeEx(PVM pVM, PCPUMCTXCORE pCtxCore, RTRCPTR pInstrGC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (EMIsRawRing0Enabled(pVM) == false || PATMIsPatchGCAddr(pVM, pInstrGC) == true)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // No use
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (CSAMIsEnabled(pVM))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Assuming 32 bits code for now. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(SELMGetCpuModeFromSelector(VMMGetCpu0(pVM), pCtxCore->eflags, pCtxCore->cs, &pCtxCore->csHid) == DISCPUMODE_32BIT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pInstrGC = SELMToFlat(pVM, DISSELREG_CS, pCtxCore, pInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return CSAMR3CheckCode(pVM, pInstrGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Scan and analyse code
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInstrGC Instruction pointer (0:32 virtual address)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3CheckCode(PVM pVM, RTRCPTR pInstrGC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( EMIsRawRing0Enabled(pVM) == false
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync || PATMIsPatchGCAddr(pVM, pInstrGC) == true)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync /* Not active. */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return VINF_SUCCESS;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync }
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync if (CSAMIsEnabled(pVM))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync /* Cache record for CSAMGCVirtToHCVirt */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync CSAMP2GLOOKUPREC cacheRec;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync RT_ZERO(cacheRec);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTime, a);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync rc = csamAnalyseCallCodeStream(pVM, pInstrGC, pInstrGC, true /* 32 bits code */, CSAMR3AnalyseCallback, pPage, &cacheRec);
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTime, a);
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync if (cacheRec.Lock.pvMap)
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync PGMPhysReleasePageMappingLock(pVM, &cacheRec.Lock);
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync if (rc != VINF_SUCCESS)
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync {
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync Log(("csamAnalyseCodeStream failed with %d\n", rc));
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return rc;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync }
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync }
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return VINF_SUCCESS;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync}
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync/**
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync * Flush dirty code pages
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync *
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync * @returns VBox status code.
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int csamR3FlushDirtyPages(PVM pVM)
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync{
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync Assert(pVM->cCpus == 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync STAM_PROFILE_START(&pVM->csam.s.StatFlushDirtyPages, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync for (uint32_t i=0;i<pVM->csam.s.cDirtyPages;i++)
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync {
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGEREC pPageRec;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync RTRCPTR GCPtr = pVM->csam.s.pvDirtyBasePage[i];
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync GCPtr = GCPtr & PAGE_BASE_GC_MASK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_REM
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync /* Notify the recompiler that this page has been changed. */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync REMR3NotifyCodePageChanged(pVM, pVCpu, GCPtr);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync#endif
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync /* Enable write protection again. (use the fault address as it might be an alias) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMShwMakePageReadonly(pVCpu, pVM->csam.s.pvDirtyFaultPage[i], 0 /*fFlags*/);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3FlushDirtyPages: flush %RRv (modifypage rc=%Rrc)\n", pVM->csam.s.pvDirtyBasePage[i], rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)GCPtr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pPageRec && pPageRec->page.enmTag == CSAM_TAG_REM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t fFlags;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMGstGetPage(pVCpu, GCPtr, &fFlags, NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( rc == VINF_SUCCESS
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (fFlags & X86_PTE_US))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We don't care about user pages. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamRemovePageRecord(pVM, GCPtr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrUserPages);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pVM->csam.s.cDirtyPages = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatFlushDirtyPages, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Flush potential new code pages
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
105b1a31b6037dbe14acb8d09e60da540885202bvboxsyncstatic int csamR3FlushCodePages(PVM pVM)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(pVM->cCpus == 1);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i=0;i<pVM->csam.s.cPossibleCodePages;i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTRCPTR GCPtr = pVM->csam.s.pvPossibleCodePage[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync GCPtr = GCPtr & PAGE_BASE_GC_MASK;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log(("csamR3FlushCodePages: %RRv\n", GCPtr));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PGMShwMakePageNotPresent(pVCpu, GCPtr, 0 /*fFlags*/);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Resync the page to make sure instruction fetch will fault */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CSAMMarkPage(pVM, GCPtr, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pVM->csam.s.cPossibleCodePages = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Perform any pending actions
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVCpu The VMCPU to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3DoPendingAction(PVM pVM, PVMCPU pVCpu)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamR3FlushDirtyPages(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync csamR3FlushCodePages(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_CSAM_PENDING_ACTION);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Analyse interrupt and trap gates
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iGate Start gate
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cGates Number of gates to check
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3CheckGates(PVM pVM, uint32_t iGate, uint32_t cGates)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pVM->cCpus == 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMCPU pVCpu = VMMGetCpu0(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint16_t cbIDT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTRCPTR GCPtrIDT = CPUMGetGuestIDTR(pVCpu, &cbIDT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iGateEnd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t maxGates;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync VBOXIDTE aIDT[256];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVBOXIDTE pGuestIdte;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (EMIsRawRing0Enabled(pVM) == false)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Enabling interrupt gates only works when raw ring 0 is enabled. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync //AssertFailed();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We only check all gates once during a session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( !pVM->csam.s.fGatesChecked
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && cGates != 256)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS; /* too early */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* We only check all gates once during a session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( pVM->csam.s.fGatesChecked
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && cGates != 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS; /* ignored */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cGates <= 256);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!GCPtrIDT || cGates > 256)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_INVALID_PARAMETER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cGates != 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync pVM->csam.s.fGatesChecked = true;
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync for (unsigned i=0;i<RT_ELEMENTS(pVM->csam.s.pvCallInstruction);i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTRCPTR pHandler = pVM->csam.s.pvCallInstruction[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pHandler)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync CSAMP2GLOOKUPREC cacheRec; /* Cache record for CSAMGCVirtToHCVirt. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RT_ZERO(cacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCheckGates: checking previous call instruction %RRv\n", pHandler));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTime, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamAnalyseCodeStream(pVM, pHandler, pHandler, true, CSAMR3AnalyseCallback, pPage, &cacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTime, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cacheRec.Lock.pvMap)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PGMPhysReleasePageMappingLock(pVM, &cacheRec.Lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCheckGates: csamAnalyseCodeStream failed with %d\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync continue;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Determine valid upper boundary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync maxGates = (cbIDT+1) / sizeof(VBOXIDTE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(iGate < maxGates);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (iGate > maxGates)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_INVALID_PARAMETER;
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync if (iGate + cGates > maxGates)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cGates = maxGates - iGate;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync GCPtrIDT = GCPtrIDT + iGate * sizeof(VBOXIDTE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iGateEnd = iGate + cGates;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatCheckGates, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Get IDT entries.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysSimpleReadGCPtr(pVCpu, aIDT, GCPtrIDT, cGates*sizeof(VBOXIDTE));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgRC(rc, ("Failed to read IDTE! rc=%Rrc\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatCheckGates, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pGuestIdte = &aIDT[0];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (/*iGate*/; iGate<iGateEnd; iGate++, pGuestIdte++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(TRPMR3GetGuestTrapHandler(pVM, iGate) == TRPM_INVALID_HANDLER);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( pGuestIdte->Gen.u1Present
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32 || pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (pGuestIdte->Gen.u2DPL == 3 || pGuestIdte->Gen.u2DPL == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTRCPTR pHandler;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCSAMPAGE pPage = NULL;
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync DBGFSELINFO selInfo;
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync CSAMP2GLOOKUPREC cacheRec; /* Cache record for CSAMGCVirtToHCVirt. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RT_ZERO(cacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pHandler = VBOXIDTE_OFFSET(*pGuestIdte);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pHandler = SELMToFlatBySel(pVM, pGuestIdte->Gen.u16SegSel, pHandler);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = SELMR3GetSelectorInfo(pVM, pVCpu, pGuestIdte->Gen.u16SegSel, &selInfo);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( RT_FAILURE(rc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || (selInfo.fFlags & (DBGFSELINFO_FLAGS_NOT_PRESENT | DBGFSELINFO_FLAGS_INVALID))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || selInfo.GCPtrBase != 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || selInfo.cbLimit != ~0U
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Refuse to patch a handler whose idt cs selector isn't wide open. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCheckGates: check gate %d failed due to rc %Rrc GCPtrBase=%RRv limit=%x\n", iGate, rc, selInfo.GCPtrBase, selInfo.cbLimit));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync continue;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCheckGates: check trap gate %d at %04X:%08X (flat %RRv)\n", iGate, pGuestIdte->Gen.u16SegSel, VBOXIDTE_OFFSET(*pGuestIdte), pHandler));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCheckGates: check interrupt gate %d at %04X:%08X (flat %RRv)\n", iGate, pGuestIdte->Gen.u16SegSel, VBOXIDTE_OFFSET(*pGuestIdte), pHandler));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTime, b);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = csamAnalyseCodeStream(pVM, pHandler, pHandler, true, CSAMR3AnalyseCallback, pPage, &cacheRec);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTime, b);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cacheRec.Lock.pvMap)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PGMPhysReleasePageMappingLock(pVM, &cacheRec.Lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMCheckGates: csamAnalyseCodeStream failed with %d\n", rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync continue;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* OpenBSD guest specific patch test. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (iGate >= 0x20)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCPUMCTX pCtx;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DISCPUSTATE cpu;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCUINTPTR32 aOpenBsdPushCSOffset[3] = {0x03, /* OpenBSD 3.7 & 3.8 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 0x2B, /* OpenBSD 4.0 installation ISO */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 0x2F}; /* OpenBSD 4.0 after install */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtx = CPUMQueryGuestCtxPtr(pVCpu);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (unsigned i=0;i<RT_ELEMENTS(aOpenBsdPushCSOffset);i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CPUMR3DisasmInstrCPU(pVM, pVCpu, pCtx, pHandler - aOpenBsdPushCSOffset[i], &cpu, NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( rc == VINF_SUCCESS
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && cpu.pCurInstr->uOpcode == OP_PUSH
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && cpu.pCurInstr->param1 == OP_PARM_REG_CS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PATMR3InstallPatch(pVM, pHandler - aOpenBsdPushCSOffset[i], PATMFL_CODE32 | PATMFL_GUEST_SPECIFIC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Installed OpenBSD interrupt handler prefix instruction (push cs) patch\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Trap gates and certain interrupt gates. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t fPatchFlags = PATMFL_CODE32 | PATMFL_IDTHANDLER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fPatchFlags |= PATMFL_TRAPHANDLER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fPatchFlags |= PATMFL_INTHANDLER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (iGate) {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 8:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 11:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 13:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 14:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 17:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fPatchFlags |= PATMFL_TRAPHANDLER_WITH_ERRORCODE;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* No error code. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Installing %s gate handler for 0x%X at %RRv\n", (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32) ? "trap" : "intr", iGate, pHandler));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PATMR3InstallPatch(pVM, pHandler, fPatchFlags);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_SUCCESS(rc) || rc == VERR_PATM_ALREADY_PATCHED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("Gate handler 0x%X is SAFE!\n", iGate));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTRCPTR pNewHandlerGC = PATMR3QueryPatchGCPtr(pVM, pHandler);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pNewHandlerGC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = TRPMR3SetGuestTrapHandler(pVM, iGate, pNewHandlerGC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("TRPMR3SetGuestTrapHandler %d failed with %Rrc\n", iGate, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync } /* for */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatCheckGates, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Record previous call instruction addresses
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param GCPtrCall Call address
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3RecordCallAddress(PVM pVM, RTRCPTR GCPtrCall)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (unsigned i=0;i<RT_ELEMENTS(pVM->csam.s.pvCallInstruction);i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pVM->csam.s.pvCallInstruction[i] == GCPtrCall)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("CSAMR3RecordCallAddress %RRv\n", GCPtrCall));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pVM->csam.s.pvCallInstruction[pVM->csam.s.iCallInstruction++] = GCPtrCall;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pVM->csam.s.iCallInstruction >= RT_ELEMENTS(pVM->csam.s.pvCallInstruction))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pVM->csam.s.iCallInstruction = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Query CSAM state (enabled/disabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns 0 - disabled, 1 - enabled
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM The VM to operate on.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncVMMR3DECL(int) CSAMR3IsEnabled(PVM pVM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return pVM->fCSAMEnabled;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_DEBUGGER
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The '.csamoff' command.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCmd Pointer to the command descriptor (as registered).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCmdHlp Pointer to command helper functions.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM Pointer to the current VM (if any).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param paArgs Pointer to (readonly) array of arguments.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cArgs Number of arguments in the array.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) csamr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DBGC_CMDHLP_REQ_VM_RET(pCmdHlp, pCmd, pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync NOREF(cArgs); NOREF(paArgs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = CSAMDisableScanning(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "CSAMDisableScanning");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DBGCCmdHlpPrintf(pCmdHlp, "CSAM Scanning disabled\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The '.csamon' command.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCmd Pointer to the command descriptor (as registered).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCmdHlp Pointer to command helper functions.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pVM Pointer to the current VM (if any).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param paArgs Pointer to (readonly) array of arguments.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cArgs Number of arguments in the array.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) csamr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DBGC_CMDHLP_REQ_VM_RET(pCmdHlp, pCmd, pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync NOREF(cArgs); NOREF(paArgs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = CSAMEnableScanning(pVM);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "CSAMEnableScanning");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return DBGCCmdHlpPrintf(pCmdHlp, "CSAM Scanning enabled\n");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* VBOX_WITH_DEBUGGER */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync