CSAM.cpp revision 8da94e4d6813b682cdb38eb9b151ada72d91b40e
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* $Id$ */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** @file
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * CSAM - Guest OS Code Scanning and Analysis Manager
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * additional information or have any questions.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Header Files *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define LOG_GROUP LOG_GROUP_CSAM
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/cpum.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/stam.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/patm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/csam.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/cpumdis.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/pgm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/iom.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/sup.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/mm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/em.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/rem.h>
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync#include <VBox/selm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/trpm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/cfgm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/param.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/avl.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/asm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/thread.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "CSAMInternal.h"
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/vm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/dbg.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/err.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/ssm.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/log.h>
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync#include <iprt/assert.h>
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync#include <iprt/string.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/dis.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <VBox/disopcode.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <stdlib.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <stdio.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
afed5ab737f4aacfae3fe73776f40e989190a7cavboxsync/* Enabled by default */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define CSAM_ENABLE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* Enable to monitor code pages for self-modifying code. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define CSAM_MONITOR_CODE_PAGES
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* Enable to monitor all scanned pages
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define CSAM_MONITOR_CSAM_CODE_PAGES */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* Enable to scan beyond ret instructions.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define CSAM_ANALYSE_BEYOND_RET */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Internal Functions *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) csamr3Save(PVM pVM, PSSMHANDLE pSSM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) csamr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) CSAMCodePageWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) CSAMCodePageInvalidate(PVM pVM, RTGCPTR GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncbool csamIsCodeScanned(PVM pVM, RTRCPTR pInstr, PCSAMPAGE *pPage);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncint csamR3CheckPageRecord(PVM pVM, RTRCPTR pInstr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PCSAMPAGE csamCreatePageRecord(PVM pVM, RTRCPTR GCPtr, CSAMTAG enmTag, bool fCode32, bool fMonitorInvalidation = false);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamRemovePageRecord(PVM pVM, RTRCPTR GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamReinit(PVM pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void csamMarkCode(PVM pVM, PCSAMPAGE pPage, RTRCPTR pInstr, uint32_t opsize, bool fScanned);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamAnalyseCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** @todo Temporary for debugging. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool fInCSAMCodePageInvalidate = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Global Variables *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_WITH_DEBUGGER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) csamr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) csamr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Command descriptors. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic const DBGCCMD g_aCmds[] =
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "csamon", 0, 0, NULL, 0, NULL, 0, csamr3CmdOn, "", "Enable CSAM code scanning." },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync { "csamoff", 0, 0, NULL, 0, NULL, 0, csamr3CmdOff, "", "Disable CSAM code scanning." },
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync};
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initializes the CSAM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3Init(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync LogFlow(("CSAMR3Init\n"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync /* Allocate bitmap for the page directory. */
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync rc = MMR3HyperAllocOnceNoRel(pVM, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR), 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDBitmapHC);
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync AssertRCReturn(rc, rc);
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync rc = MMR3HyperAllocOnceNoRel(pVM, CSAM_PGDIRBMP_CHUNKS*sizeof(RTRCPTR), 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDGCBitmapHC);
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync AssertRCReturn(rc, rc);
fdea543f71872a3ec3909536a4fce37ab7aa3a8bvboxsync pVM->csam.s.pPDBitmapGC = MMHyperHC2GC(pVM, pVM->csam.s.pPDGCBitmapHC);
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync pVM->csam.s.pPDHCBitmapGC = MMHyperHC2GC(pVM, pVM->csam.s.pPDBitmapHC);
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamReinit(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRCReturn(rc, rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Register save and load state notificators.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = SSMR3RegisterInternal(pVM, "CSAM", 0, CSAM_SSM_VERSION, sizeof(pVM->csam.s) + PAGE_SIZE*16,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync NULL, csamr3Save, NULL,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync NULL, csamr3Load, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRCReturn(rc, rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrTraps, STAMTYPE_COUNTER, "/CSAM/PageTraps", STAMUNIT_OCCURENCES, "The number of CSAM page traps.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatDangerousWrite, STAMTYPE_COUNTER, "/CSAM/DangerousWrites", STAMUNIT_OCCURENCES, "The number of dangerous writes that cause a context switch.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPageNPHC, STAMTYPE_COUNTER, "/CSAM/HC/PageNotPresent", STAMUNIT_OCCURENCES, "The number of CSAM pages marked not present.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPageNPGC, STAMTYPE_COUNTER, "/CSAM/GC/PageNotPresent", STAMUNIT_OCCURENCES, "The number of CSAM pages marked not present.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPages, STAMTYPE_COUNTER, "/CSAM/PageRec/AddedRW", STAMUNIT_OCCURENCES, "The number of CSAM page records (RW monitoring).");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPagesInv, STAMTYPE_COUNTER, "/CSAM/PageRec/AddedRWI", STAMUNIT_OCCURENCES, "The number of CSAM page records (RW & invalidation monitoring).");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrRemovedPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Removed", STAMUNIT_OCCURENCES, "The number of removed CSAM page records.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync 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.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrPatchPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Patch", STAMUNIT_OCCURENCES, "The number of CSAM patch page records.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrUserPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Ignore/User", STAMUNIT_OCCURENCES, "The number of CSAM user page records (ignored).");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPagePATM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/PATM", STAMUNIT_OCCURENCES, "The number of PATM page records.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageCSAM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/CSAM", STAMUNIT_OCCURENCES, "The number of CSAM page records.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageREM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/REM", STAMUNIT_OCCURENCES, "The number of REM page records.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatPageMonitor, STAMTYPE_COUNTER, "/CSAM/PageRec/Monitored", STAMUNIT_OCCURENCES, "The number of monitored pages.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatCodePageModified, STAMTYPE_COUNTER, "/CSAM/Monitor/DirtyPage", STAMUNIT_OCCURENCES, "The number of code page modifications.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrFlushes, STAMTYPE_COUNTER, "/CSAM/PageFlushes", STAMUNIT_OCCURENCES, "The number of CSAM page flushes.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrFlushesSkipped, STAMTYPE_COUNTER, "/CSAM/PageFlushesSkipped", STAMUNIT_OCCURENCES, "The number of CSAM page flushes that were skipped.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrKnownPagesHC, STAMTYPE_COUNTER, "/CSAM/HC/KnownPageRecords", STAMUNIT_OCCURENCES, "The number of known CSAM page records.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrKnownPagesGC, STAMTYPE_COUNTER, "/CSAM/GC/KnownPageRecords", STAMUNIT_OCCURENCES, "The number of known CSAM page records.");
a11c569636fa6838bd423f4631a9660a5a84204bvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrInstr, STAMTYPE_COUNTER, "/CSAM/ScannedInstr", STAMUNIT_OCCURENCES, "The number of scanned instructions.");
a11c569636fa6838bd423f4631a9660a5a84204bvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrBytesRead, STAMTYPE_COUNTER, "/CSAM/BytesRead", STAMUNIT_OCCURENCES, "The number of bytes read for scanning.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatNrOpcodeRead, STAMTYPE_COUNTER, "/CSAM/OpcodeBytesRead", STAMUNIT_OCCURENCES, "The number of opcode bytes read by the recompiler.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatBitmapAlloc, STAMTYPE_COUNTER, "/CSAM/Alloc/PageBitmap", STAMUNIT_OCCURENCES, "The number of page bitmap allocations.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatInstrCacheHit, STAMTYPE_COUNTER, "/CSAM/Cache/Hit", STAMUNIT_OCCURENCES, "The number of dangerous instruction cache hits.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatInstrCacheMiss, STAMTYPE_COUNTER, "/CSAM/Cache/Miss", STAMUNIT_OCCURENCES, "The number of dangerous instruction cache misses.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatScanNextFunction, STAMTYPE_COUNTER, "/CSAM/Function/Scan/Success", STAMUNIT_OCCURENCES, "The number of found functions beyond the ret border.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatScanNextFunctionFailed, STAMTYPE_COUNTER, "/CSAM/Function/Scan/Failed", STAMUNIT_OCCURENCES, "The number of refused functions beyond the ret border.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTime, STAMTYPE_PROFILE, "/PROF/CSAM/Scan", STAMUNIT_TICKS_PER_CALL, "Scanning overhead.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeCheckAddr, STAMTYPE_PROFILE, "/PROF/CSAM/CheckAddr", STAMUNIT_TICKS_PER_CALL, "Address check overhead.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeAddrConv, STAMTYPE_PROFILE, "/PROF/CSAM/AddrConv", STAMUNIT_TICKS_PER_CALL, "Address conversion overhead.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeFlushPage, STAMTYPE_PROFILE, "/PROF/CSAM/FlushPage", STAMUNIT_TICKS_PER_CALL, "Page flushing overhead.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatTimeDisasm, STAMTYPE_PROFILE, "/PROF/CSAM/Disasm", STAMUNIT_TICKS_PER_CALL, "Disassembly overhead.");
3ecf9412133496b2aeb090cfd33a286404ec59fbvboxsync STAM_REG(pVM, &pVM->csam.s.StatFlushDirtyPages, STAMTYPE_PROFILE, "/PROF/CSAM/FlushDirtyPage", STAMUNIT_TICKS_PER_CALL, "Dirty page flushing overhead.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_REG(pVM, &pVM->csam.s.StatCheckGates, STAMTYPE_PROFILE, "/PROF/CSAM/CheckGates", STAMUNIT_TICKS_PER_CALL, "CSAMR3CheckGates overhead.");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Check CFGM option and enable/disable CSAM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync bool fEnabled;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "CSAMEnabled", &fEnabled);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_ENABLE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fEnabled = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fEnabled = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (fEnabled)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMEnableScanning(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_WITH_DEBUGGER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Debugger commands.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync static bool fRegisteredCmds = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!fRegisteredCmds)
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync {
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync int rc = DBGCRegisterCommands(&g_aCmds[0], RT_ELEMENTS(g_aCmds));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fRegisteredCmds = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync * (Re)initializes CSAM
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
78a205e3fc6719d59e8c561b3d287d3a4f879852vboxsyncstatic int csamReinit(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Assert alignment and sizes.
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRelease(!(RT_OFFSETOF(VM, csam.s) & 31));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRelease(sizeof(pVM->csam.s) <= sizeof(pVM->csam.padding));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Setup any fixed pointers and offsets.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.offVM = RT_OFFSETOF(VM, patm);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.fGatesChecked = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.fScanningStarted = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync VM_FF_CLEAR(pVM, VM_FF_CSAM_PENDING_ACTION);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.cDirtyPages = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* not necessary */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(pVM->csam.s.pvDirtyBasePage, 0, sizeof(pVM->csam.s.pvDirtyBasePage));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(pVM->csam.s.pvDirtyFaultPage, 0, sizeof(pVM->csam.s.pvDirtyFaultPage));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(&pVM->csam.s.aDangerousInstr, 0, sizeof(pVM->csam.s.aDangerousInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.cDangerousInstr = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.iDangerousInstr = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(pVM->csam.s.pvCallInstruction, 0, sizeof(pVM->csam.s.pvCallInstruction));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.iCallInstruction = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** @note never mess with the pgdir bitmap here! */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Applies relocations to data and code managed by this
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * component. This function will be called at init and
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * whenever the VMM need to relocate itself inside the GC.
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync *
9782b553bdb12385214a3ac596aff1476bcb7cbdvboxsync * The csam will update the addresses used by the switcher.
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync *
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync * @param pVM The VM.
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync * @param offDelta Relocation delta.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(void) CSAMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (offDelta)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Adjust pgdir and page bitmap pointers. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.pPDBitmapGC = MMHyperHC2GC(pVM, pVM->csam.s.pPDGCBitmapHC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.pPDHCBitmapGC = MMHyperHC2GC(pVM, pVM->csam.s.pPDBitmapHC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync for(int i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pVM->csam.s.pPDGCBitmapHC[i])
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.pPDGCBitmapHC[i] += offDelta;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Terminates the csam.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Termination means cleaning up and freeing all resources,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the VM it self is at this point powered off or suspended.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3Term(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = CSAMR3Reset(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* @todo triggers assertion in MMHyperFree */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if 0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for(int i=0;i<CSAM_PAGEBMP_CHUNKS;i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pVM->csam.s.pPDBitmapHC[i])
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMHyperFree(pVM, pVM->csam.s.pPDBitmapHC[i]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * CSAM reset callback.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM which is reset.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
e52f819639386db020b2a635b47a415248c7fbf9vboxsyncVMMR3DECL(int) CSAMR3Reset(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Clear page bitmaps. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for(int i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
e02db9e0d46f862430895b82b10e8ecde075cf11vboxsync {
680ca45722ec7123029ced4f88dfad87b397ef52vboxsync if (pVM->csam.s.pPDBitmapHC[i])
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert((CSAM_PAGE_BITMAP_SIZE& 3) == 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMMemZero32(pVM->csam.s.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
0e77737b0ba913683e614db11463b31ca67aacbevboxsync /* Remove all CSAM page records. */
0e77737b0ba913683e614db11463b31ca67aacbevboxsync while(true)
0e77737b0ba913683e614db11463b31ca67aacbevboxsync {
0e77737b0ba913683e614db11463b31ca67aacbevboxsync PCSAMPAGEREC pPageRec = (PCSAMPAGEREC)RTAvlPVGetBestFit(&pVM->csam.s.pPageTree, 0, true);
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync if (pPageRec)
0e77737b0ba913683e614db11463b31ca67aacbevboxsync {
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync csamRemovePageRecord(pVM, pPageRec->page.pPageGC);
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync }
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync else
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync break;
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync }
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync Assert(!pVM->csam.s.pPageTree);
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync csamReinit(pVM);
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync return VINF_SUCCESS;
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync}
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync#define CSAM_SUBTRACT_PTR(a, b) *(uintptr_t *)&(a) = (uintptr_t)(a) - (uintptr_t)(b)
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync#define CSAM_ADD_PTR(a, b) *(uintptr_t *)&(a) = (uintptr_t)(a) + (uintptr_t)(b)
0e77737b0ba913683e614db11463b31ca67aacbevboxsync
0e77737b0ba913683e614db11463b31ca67aacbevboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Callback function for RTAvlPVDoWithAll
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Counts the number of records in the tree
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pNode Current node
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pcPatches Pointer to patch counter
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync */
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsyncstatic DECLCALLBACK(int) CountRecord(PAVLPVNODECORE pNode, void *pcPatches)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *(uint32_t *)pcPatches = *(uint32_t *)pcPatches + 1;
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
e98b0df488a9ec7732b1d5c2e735ce707842e975vboxsync
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Callback function for RTAvlPVDoWithAll
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Saves the state of the page record
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pNode Current node
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync * @param pVM1 VM Handle
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) SavePageState(PAVLPVNODECORE pNode, void *pVM1)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVM pVM = (PVM)pVM1;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPage = (PCSAMPAGEREC)pNode;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMPAGEREC page = *pPage;
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync PSSMHANDLE pSSM = pVM->csam.s.savedstate.pSSM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Save the page record itself */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = SSMR3PutMem(pSSM, &page, sizeof(page));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRCReturn(rc, rc);
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (page.page.pBitmap)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = SSMR3PutMem(pSSM, page.page.pBitmap, CSAM_PAGE_BITMAP_SIZE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRCReturn(rc, rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Execute state save operation.
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync * @param pVM VM Handle.
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync * @param pSSM SSM operation handle.
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync */
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsyncstatic DECLCALLBACK(int) csamr3Save(PVM pVM, PSSMHANDLE pSSM)
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync{
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync CSAM csamInfo = pVM->csam.s;
a6936eab59adc5624216e6e5e5e455fc6a40df7fvboxsync int rc;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync /*
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync * Count the number of page records in the tree (feeling lazy)
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync */
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync csamInfo.savedstate.cPageRecords = 0;
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync RTAvlPVDoWithAll(&pVM->csam.s.pPageTree, true, CountRecord, &csamInfo.savedstate.cPageRecords);
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync /*
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync * Save CSAM structure
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.savedstate.pSSM = pSSM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = SSMR3PutMem(pSSM, &csamInfo, sizeof(csamInfo));
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync AssertRCReturn(rc, rc);
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync /* Save pgdir bitmap */
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync rc = SSMR3PutMem(pSSM, csamInfo.pPDBitmapHC, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRCReturn(rc, rc);
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync {
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync if(csamInfo.pPDBitmapHC[i])
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync {
440444d68cda7866c59e2e3d3f236608ef1c316fvboxsync /* Save the page bitmap. */
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync rc = SSMR3PutMem(pSSM, csamInfo.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRCReturn(rc, rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync /*
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync * Save page records
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync */
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync rc = RTAvlPVDoWithAll(&pVM->csam.s.pPageTree, true, SavePageState, pVM);
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync AssertRCReturn(rc, rc);
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync /** @note we don't restore aDangerousInstr; it will be recreated automatically. */
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync return VINF_SUCCESS;
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync}
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync/**
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync * Execute state load operation.
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync *
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync * @returns VBox status code.
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync * @param pVM VM Handle.
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync * @param pSSM SSM operation handle.
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync * @param u32Version Data layout version.
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync */
8e8844a522f5d335f177a0313b03067d79cce201vboxsyncstatic DECLCALLBACK(int) csamr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
8e8844a522f5d335f177a0313b03067d79cce201vboxsync{
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync int rc;
8e8844a522f5d335f177a0313b03067d79cce201vboxsync CSAM csamInfo;
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync if (u32Version != CSAM_SSM_VERSION)
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync {
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync AssertMsgFailed(("csamR3Load: Invalid version u32Version=%d!\n", u32Version));
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync }
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync pVM->csam.s.savedstate.pSSM = pSSM;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync /*
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync * Restore CSAM structure
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync */
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync rc = SSMR3GetMem(pSSM, &csamInfo, sizeof(csamInfo));
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync AssertRCReturn(rc, rc);
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync pVM->csam.s.fGatesChecked = csamInfo.fGatesChecked;
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync pVM->csam.s.fScanningStarted = csamInfo.fScanningStarted;
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync /* Restore dirty code page info. */
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync pVM->csam.s.cDirtyPages = csamInfo.cDirtyPages;
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync memcpy(pVM->csam.s.pvDirtyBasePage, csamInfo.pvDirtyBasePage, sizeof(pVM->csam.s.pvDirtyBasePage));
5e797edc29f96c8367de4fbf5874171c24a89ba7vboxsync memcpy(pVM->csam.s.pvDirtyFaultPage, csamInfo.pvDirtyFaultPage, sizeof(pVM->csam.s.pvDirtyFaultPage));
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync /* Restore possible code page */
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync pVM->csam.s.cPossibleCodePages = csamInfo.cPossibleCodePages;
8e8844a522f5d335f177a0313b03067d79cce201vboxsync memcpy(pVM->csam.s.pvPossibleCodePage, csamInfo.pvPossibleCodePage, sizeof(pVM->csam.s.pvPossibleCodePage));
8e8844a522f5d335f177a0313b03067d79cce201vboxsync
9a12d720d4db6c26d09600ddab781ad8df5e1826vboxsync /* Restore pgdir bitmap (we'll change the pointers next). */
8e8844a522f5d335f177a0313b03067d79cce201vboxsync rc = SSMR3GetMem(pSSM, pVM->csam.s.pPDBitmapHC, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR));
9a12d720d4db6c26d09600ddab781ad8df5e1826vboxsync AssertRCReturn(rc, rc);
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync /*
03319aeaef07ef63a404237f2cb56199131f4a03vboxsync * Restore page bitmaps
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync */
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync for (unsigned i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync {
79b24ef0ab7cd4a03a3571b3954c52ab8b573137vboxsync if(pVM->csam.s.pPDBitmapHC[i])
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync {
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync rc = MMHyperAlloc(pVM, CSAM_PAGE_BITMAP_SIZE, 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDBitmapHC[i]);
7082d29724f6c3788977a51591b0379fd3acbf72vboxsync if (RT_FAILURE(rc))
7082d29724f6c3788977a51591b0379fd3acbf72vboxsync {
7082d29724f6c3788977a51591b0379fd3acbf72vboxsync Log(("MMR3HyperAlloc failed with %d\n", rc));
7082d29724f6c3788977a51591b0379fd3acbf72vboxsync return rc;
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync }
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync /* Convert to GC pointer. */
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync pVM->csam.s.pPDGCBitmapHC[i] = MMHyperHC2GC(pVM, pVM->csam.s.pPDBitmapHC[i]);
f827fea1108b8f8a1a5f63318f6ec3cf4a9e7010vboxsync Assert(pVM->csam.s.pPDGCBitmapHC[i]);
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync /* Restore the bitmap. */
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync rc = SSMR3GetMem(pSSM, pVM->csam.s.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync AssertRCReturn(rc, rc);
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync }
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync else
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync {
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync Assert(!pVM->csam.s.pPDGCBitmapHC[i]);
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync pVM->csam.s.pPDGCBitmapHC[i] = 0;
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync }
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync }
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync /*
f827fea1108b8f8a1a5f63318f6ec3cf4a9e7010vboxsync * Restore page records
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync */
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync for (uint32_t i=0;i<csamInfo.savedstate.cPageRecords + csamInfo.savedstate.cPatchPageRecords;i++)
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync {
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync CSAMPAGEREC page;
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync PCSAMPAGE pPage;
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync rc = SSMR3GetMem(pSSM, &page, sizeof(page));
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync AssertRCReturn(rc, rc);
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync /*
fe49486f3c0fc3c327138e9a8f9ea9911d7c0d64vboxsync * Recreate the page record
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync */
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pPage = csamCreatePageRecord(pVM, page.page.pPageGC, page.page.enmTag, page.page.fCode32, page.page.fMonitorInvalidation);
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync AssertReturn(pPage, VERR_NO_MEMORY);
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pPage->GCPhys = page.page.GCPhys;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pPage->fFlags = page.page.fFlags;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pPage->u64Hash = page.page.u64Hash;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync if (page.page.pBitmap)
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync {
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync rc = SSMR3GetMem(pSSM, pPage->pBitmap, CSAM_PAGE_BITMAP_SIZE);
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync AssertRCReturn(rc, rc);
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync }
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync else
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync {
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync MMR3HeapFree(pPage->pBitmap);
8e8844a522f5d335f177a0313b03067d79cce201vboxsync pPage->pBitmap = 0;
8e8844a522f5d335f177a0313b03067d79cce201vboxsync }
8e8844a522f5d335f177a0313b03067d79cce201vboxsync }
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync /** @note we don't restore aDangerousInstr; it will be recreated automatically. */
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync memset(&pVM->csam.s.aDangerousInstr, 0, sizeof(pVM->csam.s.aDangerousInstr));
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pVM->csam.s.cDangerousInstr = 0;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pVM->csam.s.iDangerousInstr = 0;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync return VINF_SUCCESS;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync}
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync/**
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync * Convert guest context address to host context pointer
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync *
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync * @returns VBox status code.
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync * @param pVM The VM to operate on.
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync * @param pCacheRec Address conversion cache record
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync * @param pGCPtr Guest context pointer
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync *
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync * @returns Host context pointer or NULL in case of an error
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync *
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync */
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsyncstatic R3PTRTYPE(void *) CSAMGCVirtToHCVirt(PVM pVM, PCSAMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr)
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync{
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync int rc;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync R3PTRTYPE(void *) pHCPtr;
8e8844a522f5d335f177a0313b03067d79cce201vboxsync
8e8844a522f5d335f177a0313b03067d79cce201vboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeAddrConv, a);
8e8844a522f5d335f177a0313b03067d79cce201vboxsync
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync pHCPtr = PATMR3GCPtrToHCPtr(pVM, pGCPtr);
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync if (pHCPtr) return pHCPtr;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync if (pCacheRec->pPageLocStartHC)
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync {
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync uint32_t offset = pGCPtr & PAGE_OFFSET_MASK;
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync if (pCacheRec->pGuestLoc == (pGCPtr & PAGE_BASE_GC_MASK))
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync {
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeAddrConv, a);
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync return pCacheRec->pPageLocStartHC + offset;
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync }
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync }
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync rc = PGMPhysGCPtr2HCPtr(pVM, pGCPtr, &pHCPtr);
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync if (rc != VINF_SUCCESS)
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync {
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync//// AssertMsgRC(rc, ("MMR3PhysGCVirt2HCVirtEx failed for %VRv\n", pGCPtr));
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeAddrConv, a);
50eab0c7ce9efeebd02c186d598f1db900f0c717vboxsync return NULL;
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync }
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync////invalid? Assert(sizeof(R3PTRTYPE(uint8_t*)) == sizeof(uint32_t));
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync pCacheRec->pPageLocStartHC = (R3PTRTYPE(uint8_t*))((RTHCUINTPTR)pHCPtr & PAGE_BASE_HC_MASK);
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync pCacheRec->pGuestLoc = pGCPtr & PAGE_BASE_GC_MASK;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeAddrConv, a);
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync return pHCPtr;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync}
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync/**
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync * Read callback for disassembly function; supports reading bytes that cross a page boundary
50eab0c7ce9efeebd02c186d598f1db900f0c717vboxsync *
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync * @returns VBox status code.
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync * @param pSrc GC source pointer
3dde2f85d4cf477621a3128887a2c08a8bca7c01vboxsync * @param pDest HC destination pointer
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync * @param size Number of bytes to read
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync * @param dwUserdata Callback specific user data (pCpu)
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync *
46df4404c8dbbf3672e7aae8cd0b2770356e5b73vboxsync */
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsyncstatic DECLCALLBACK(int) CSAMR3ReadBytes(RTUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata)
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync{
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync DISCPUSTATE *pCpu = (DISCPUSTATE *)pvUserdata;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync PVM pVM = (PVM)pCpu->apvUserData[0];
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync RTHCUINTPTR pInstrHC = (RTHCUINTPTR)pCpu->apvUserData[1];
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync RTGCUINTPTR32 pInstrGC = (uintptr_t)pCpu->apvUserData[2];
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync int orgsize = size;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync /* We are not interested in patched instructions, so read the original opcode bytes. */
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync /** @note single instruction patches (int3) are checked in CSAMR3AnalyseCallback */
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync for (int i=0;i<orgsize;i++)
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync {
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync int rc = PATMR3QueryOpcode(pVM, (RTRCPTR)pSrc, pDest);
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync if (RT_SUCCESS(rc))
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync {
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync pSrc++;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync pDest++;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync size--;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync }
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync else
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync break;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync }
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync if (size == 0)
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync return VINF_SUCCESS;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync if (PAGE_ADDRESS(pInstrGC) != PAGE_ADDRESS(pSrc + size - 1) && !PATMIsPatchGCAddr(pVM, pSrc))
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync {
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync return PGMPhysSimpleReadGCPtr(pVM, pDest, pSrc, size);
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync }
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync else
65b61798a61dd4c32cce448db1dac70bba8d5cf5vboxsync {
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync Assert(pInstrHC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* pInstrHC is the base address; adjust according to the GC pointer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pInstrHC = pInstrHC + (pSrc - pInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memcpy(pDest, (void *)pInstrHC, size);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncinline int CSAMR3DISInstr(PVM pVM, DISCPUSTATE *pCpu, RTRCPTR InstrGC, uint8_t *InstrHC, uint32_t *pOpsize, char *pszOutput)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (pCpu)->pfnReadBytes = CSAMR3ReadBytes;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (pCpu)->apvUserData[0] = pVM;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (pCpu)->apvUserData[1] = InstrHC;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (pCpu)->apvUserData[2] = (void *)InstrGC; Assert(sizeof(InstrGC) <= sizeof(pCpu->apvUserData[0]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return DISInstrEx(pCpu, InstrGC, 0, pOpsize, pszOutput, OPTYPE_ALL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* We are interested in everything except harmless stuff */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return DISInstrEx(pCpu, InstrGC, 0, pOpsize, pszOutput, ~(OPTYPE_INVALID | OPTYPE_HARMLESS | OPTYPE_RRM_MASK));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Analyses the instructions following the cli for compliance with our heuristics for cli
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCpu CPU disassembly state
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstrGC Guest context pointer to privileged instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCurInstrGC Guest context pointer to the current instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCacheRec GC to HC cache record
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pUserData User pointer (callback specific)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int CSAMR3AnalyseCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMP2GLOOKUPREC pCacheRec, void *pUserData)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = (PCSAMPAGE)pUserData;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch(pCpu->pCurInstr->opcode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_INT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pCpu->param1.flags & USE_IMMEDIATE8);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCpu->param1.parval == 3)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync //two byte int 3
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_ILLUD2:
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync /* This appears to be some kind of kernel panic in Linux 2.4; no point to continue. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_RETN:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_INT3:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_INVALID:
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync#if 1
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* removing breaks win2k guests? */
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync case OP_IRET:
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // Check for exit points
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync switch (pCpu->pCurInstr->opcode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync /* It's not a good idea to patch pushf instructions:
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync * - increases the chance of conflicts (code jumping to the next instruction)
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync * - better to patch the cli
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync * - code that branches before the cli will likely hit an int 3
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync * - in general doesn't offer any benefits as we don't allow nested patch blocks (IF is always 1)
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync */
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync case OP_PUSHF:
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync case OP_POPF:
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync break;
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync case OP_CLI:
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t cbInstr = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t opsize = pCpu->opsize;
49748bb305bd71f672cd083af208f4bb08c5d6abvboxsync
49748bb305bd71f672cd083af208f4bb08c5d6abvboxsync PATMR3AddHint(pVM, pCurInstrGC, (pPage->fCode32) ? PATMFL_CODE32 : 0);
49748bb305bd71f672cd083af208f4bb08c5d6abvboxsync
49748bb305bd71f672cd083af208f4bb08c5d6abvboxsync /* Make sure the instructions that follow the cli have not been encountered before. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (true)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync DISCPUSTATE cpu;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint8_t *pCurInstrHC = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cbInstr + opsize >= SIZEOF_NEARJUMP32)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC + opsize, &pPage) == true)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* We've scanned the next instruction(s) already. This means we've followed a branch that ended up there before -> dangerous!! */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PATMR3DetectConflict(pVM, pCurInstrGC, pCurInstrGC + opsize);
b9ca93dd1ad44cb8b27679dc5624be2f7b7f7af5vboxsync break;
b9ca93dd1ad44cb8b27679dc5624be2f7b7f7af5vboxsync }
b9ca93dd1ad44cb8b27679dc5624be2f7b7f7af5vboxsync pCurInstrGC += opsize;
b9ca93dd1ad44cb8b27679dc5624be2f7b7f7af5vboxsync cbInstr += opsize;
b9ca93dd1ad44cb8b27679dc5624be2f7b7f7af5vboxsync
b9ca93dd1ad44cb8b27679dc5624be2f7b7f7af5vboxsync pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
7c3417bbf525c03163d54d151a277a981d5d61b6vboxsync if (pCurInstrHC == NULL)
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync {
8b984478b755f4d3091b977d9beac9fb7434279fvboxsync Log(("CSAMGCVirtToHCVirt failed for %VRv\n", pCurInstrGC));
8b984478b755f4d3091b977d9beac9fb7434279fvboxsync break;
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync }
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync Assert(VALID_PTR(pCurInstrHC));
51d4024e2984de499ecd878341898f71f55cf9e0vboxsync
51d4024e2984de499ecd878341898f71f55cf9e0vboxsync cpu.mode = (pPage->fCode32) ? CPUMODE_32BIT : CPUMODE_16BIT;
8b984478b755f4d3091b977d9beac9fb7434279fvboxsync rc = CSAMR3DISInstr(pVM, &cpu, pCurInstrGC, pCurInstrHC, &opsize, NULL);
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync Assert(RT_SUCCESS(rc));
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync if (RT_FAILURE(rc))
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
14e483cf65160fb363043534151245ae4c215766vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_PUSH:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCpu->pCurInstr->param1 != OP_PARM_REG_CS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* no break */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_STR:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_LSL:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_LAR:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SGDT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SLDT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SIDT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SMSW:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_VERW:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_VERR:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_CPUID:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_IRET:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch(pCpu->pCurInstr->opcode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_STR:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: str!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_LSL:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: lsl!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_LAR:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: lar!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SGDT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: sgdt!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SLDT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: sldt!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SIDT:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: sidt!!\n", pCurInstrGC));
47b5427d1a541bcd269bc625c35b19d849071edfvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SMSW:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: smsw!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
3964eef78ab9593263a3a982e26216d4d166869cvboxsync case OP_VERW:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: verw!!\n", pCurInstrGC));
f02b41a7e54fc4e6b714f4e60260d94614d6e2e7vboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_VERR:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: verr!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_CPUID:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: cpuid!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_PUSH:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: push cs!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_IRET:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Privileged instruction at %VRv: iret!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PATMR3HasBeenPatched(pVM, pCurInstrGC) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PATMR3InstallPatch(pVM, pCurInstrGC, (pPage->fCode32) ? PATMFL_CODE32 : 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("PATMR3InstallPatch failed with %d\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCpu->pCurInstr->opcode == OP_IRET)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS; /* Look no further in this branch. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_JMP:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_CALL:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // return or jump/call through a jump table
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (OP_PARM_VTYPE(pCpu->pCurInstr->param1) != OP_PARM_J)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch(pCpu->pCurInstr->opcode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
e7081fdf0305eaa621e0dd6decf8b28c33febc58vboxsync case OP_JMP:
3123bb2477edc752585e4bbd8e4cfedaf87997d1vboxsync Log(("Control Flow instruction at %VRv: jmp!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_CALL:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Control Flow instruction at %VRv: call!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
78a205e3fc6719d59e8c561b3d287d3a4f879852vboxsync return VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
78a205e3fc6719d59e8c561b3d287d3a4f879852vboxsync#ifdef CSAM_ANALYSE_BEYOND_RET
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
78a205e3fc6719d59e8c561b3d287d3a4f879852vboxsync * Wrapper for csamAnalyseCodeStream for call instructions.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
78a205e3fc6719d59e8c561b3d287d3a4f879852vboxsync * @param pInstrGC Guest context pointer to privileged instruction
78a205e3fc6719d59e8c561b3d287d3a4f879852vboxsync * @param pCurInstrGC Guest context pointer to the current instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fCode32 16 or 32 bits code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pfnCSAMR3Analyse Callback for testing the disassembled instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pUserData User pointer (callback specific)
47b5427d1a541bcd269bc625c35b19d849071edfvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamAnalyseCallCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMCALLEXITREC CallExitRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMCALLEXITREC pOldCallRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t i;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CallExitRec.cInstrAfterRet = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pOldCallRec = pCacheRec->pCallExitRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->pCallExitRec = &CallExitRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamAnalyseCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (i=0;i<CallExitRec.cInstrAfterRet;i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCurInstrGC = CallExitRec.pInstrAfterRetGC[i];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Check if we've previously encountered the instruction after the ret. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync DISCPUSTATE cpu;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t opsize;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint8_t *pCurInstrHC = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync char szOutput[256];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* New address; let's take a look at it. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage = csamCreatePageRecord(pVM, pCurInstrGC, CSAM_TAG_CSAM, fCode32);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NO_MEMORY;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
47b5427d1a541bcd269bc625c35b19d849071edfvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /**
3e6d3b0af632bdcd931b5149915c7b8be1a732cdvboxsync * Some generic requirements for recognizing an adjacent function:
47b5427d1a541bcd269bc625c35b19d849071edfvboxsync * - alignment fillers that consist of:
a11c569636fa6838bd423f4631a9660a5a84204bvboxsync * - nop
a11c569636fa6838bd423f4631a9660a5a84204bvboxsync * - lea genregX, [genregX (+ 0)]
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * - push ebp after the filler (can extend this later); aligned at at least a 4 byte boundary
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (int j=0;j<16;j++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCurInstrHC == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMGCVirtToHCVirt failed for %VRv\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(VALID_PTR(pCurInstrHC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cpu.mode = (fCode32) ? CPUMODE_32BIT : CPUMODE_16BIT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeDisasm, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc2 = CSAMR3DISInstr(pVM, &cpu, pCurInstrGC, pCurInstrHC, &opsize, szOutput);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc2)) Log(("CSAM Call Analysis: %s", szOutput));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc2 = CSAMR3DISInstr(pVM, &cpu, pCurInstrGC, pCurInstrHC, &opsize, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeDisasm, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc2))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Disassembly failed at %VRv with %Rrc (probably page not present) -> return to caller\n", pCurInstrGC, rc2));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrBytesRead, opsize);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RCPTRTYPE(uint8_t *) addr = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pJmpPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PAGE_ADDRESS(pCurInstrGC) != PAGE_ADDRESS(pCurInstrGC + opsize - 1))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!PGMGstIsPagePresent(pVM, pCurInstrGC + opsize - 1))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /// @todo fault in the page
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Page for current instruction %VRv is not present!!\n", pCurInstrGC));
7235946d51c4e7b209b12cefb8a3924660a9d46bvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync //all is fine, let's continue
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamR3CheckPageRecord(pVM, pCurInstrGC + opsize - 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch (cpu.pCurInstr->opcode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_NOP:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_INT3:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break; /* acceptable */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_LEA:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Must be similar to:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * lea esi, [esi]
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * lea esi, [esi+0]
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Any register is allowed as long as source and destination are identical.
0f5d1b2abd9e82c7ee46f1327287c44856604bcbvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( cpu.param1.flags != USE_REG_GEN32
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || ( cpu.param2.flags != USE_REG_GEN32
e17bd6c32a8dd64f2d42838f9028216465e2caf0vboxsync && ( !(cpu.param2.flags & USE_REG_GEN32)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || !(cpu.param2.flags & (USE_DISPLACEMENT8|USE_DISPLACEMENT16|USE_DISPLACEMENT32))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || cpu.param2.parval != 0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || cpu.param1.base.reg_gen32 != cpu.param2.base.reg_gen32
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_function;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_PUSH:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( (pCurInstrGC & 0x3) != 0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || cpu.param1.flags != USE_REG_GEN32
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || cpu.param1.base.reg_gen32 != USE_REG_EBP
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_function;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMCALLEXITREC CallExitRec2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CallExitRec2.cInstrAfterRet = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->pCallExitRec = &CallExitRec2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Analyse the function. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Found new function at %VRv\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunction);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamAnalyseCallCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_function;
47b5427d1a541bcd269bc625c35b19d849071edfvboxsync }
47b5427d1a541bcd269bc625c35b19d849071edfvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case OP_SUB:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( (pCurInstrGC & 0x3) != 0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || cpu.param1.flags != USE_REG_GEN32
0f5d1b2abd9e82c7ee46f1327287c44856604bcbvboxsync || cpu.param1.base.reg_gen32 != USE_REG_ESP
c20b837b2c912dd4dcaaa676e15acd2b230108f0vboxsync )
c20b837b2c912dd4dcaaa676e15acd2b230108f0vboxsync {
0f5d1b2abd9e82c7ee46f1327287c44856604bcbvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
0f5d1b2abd9e82c7ee46f1327287c44856604bcbvboxsync goto next_function;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
0f5d1b2abd9e82c7ee46f1327287c44856604bcbvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
0f5d1b2abd9e82c7ee46f1327287c44856604bcbvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMCALLEXITREC CallExitRec2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CallExitRec2.cInstrAfterRet = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->pCallExitRec = &CallExitRec2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Analyse the function. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Found new function at %VRv\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunction);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamAnalyseCallCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_function;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync default:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatScanNextFunctionFailed);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_function;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Mark it as scanned. */
96d8c2c77873591a51233b013fc1ec8bc774a096vboxsync csamMarkCode(pVM, pPage, pCurInstrGC, opsize, true);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCurInstrGC += opsize;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } /* for at most 16 instructions */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncnext_function:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ; /* MSVC complains otherwise */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncdone:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->pCallExitRec = pOldCallRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define csamAnalyseCallCodeStream csamAnalyseCodeStream
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
96d8c2c77873591a51233b013fc1ec8bc774a096vboxsync * Disassembles the code stream until the callback function detects a failure or decides everything is acceptable
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstrGC Guest context pointer to privileged instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCurInstrGC Guest context pointer to the current instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fCode32 16 or 32 bits code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pfnCSAMR3Analyse Callback for testing the disassembled instruction
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pUserData User pointer (callback specific)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamAnalyseCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync DISCPUSTATE cpu;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = (PCSAMPAGE)pUserData;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t opsize;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync R3PTRTYPE(uint8_t *) pCurInstrHC = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync char szOutput[256];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("csamAnalyseCodeStream: code at %VRv depth=%d\n", pCurInstrGC, pCacheRec->depth));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.fScanningStarted = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->depth++;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Limit the call depth. (rather arbitrary upper limit; too low and we won't detect certain
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * cpuid instructions in Linux kernels; too high and we waste too much time scanning code)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (512 is necessary to detect cpuid instructions in Red Hat EL4; see defect 1355)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note we are using a lot of stack here. couple of 100k when we go to the full depth (!)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCacheRec->depth > 512)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
ee5858e9d955811dae9e6b8ecbb336cc6d0e7197vboxsync LogFlow(("CSAM: maximum calldepth reached for %VRv\n", pCurInstrGC));
b45d66c0e496e2fd861479202f3d43aad592bd14vboxsync pCacheRec->depth--;
b45d66c0e496e2fd861479202f3d43aad592bd14vboxsync return VINF_SUCCESS; //let's not go on forever
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!PATMIsPatchGCAddr(pVM, pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamR3CheckPageRecord(pVM, pCurInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while(rc == VWRN_CONTINUE_ANALYSIS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, pCurInstrGC, &pPage) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* New address; let's take a look at it. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage = csamCreatePageRecord(pVM, pCurInstrGC, CSAM_TAG_CSAM, fCode32);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NO_MEMORY;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("Code at %VRv has been scanned before\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pCurInstrHC == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMGCVirtToHCVirt failed for %VRv\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_PATCHING_REFUSED;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(VALID_PTR(pCurInstrHC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cpu.mode = (fCode32) ? CPUMODE_32BIT : CPUMODE_16BIT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeDisasm, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef DEBUG
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc2 = CSAMR3DISInstr(pVM, &cpu, pCurInstrGC, pCurInstrHC, &opsize, szOutput);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc2)) Log(("CSAM Analysis: %s", szOutput));
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync#else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc2 = CSAMR3DISInstr(pVM, &cpu, pCurInstrGC, pCurInstrHC, &opsize, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeDisasm, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc2))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Disassembly failed at %VRv with %Rrc (probably page not present) -> return to caller\n", pCurInstrGC, rc2));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync }
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrBytesRead, opsize);
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync csamMarkCode(pVM, pPage, pCurInstrGC, opsize, true);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RCPTRTYPE(uint8_t *) addr = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pJmpPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PAGE_ADDRESS(pCurInstrGC) != PAGE_ADDRESS(pCurInstrGC + opsize - 1))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!PGMGstIsPagePresent(pVM, pCurInstrGC + opsize - 1))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /// @todo fault in the page
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Page for current instruction %VRv is not present!!\n", pCurInstrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_please;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync //all is fine, let's continue
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync csamR3CheckPageRecord(pVM, pCurInstrGC + opsize - 1);
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync }
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If it's harmless, then don't bother checking it (the disasm tables had better be accurate!)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ((cpu.pCurInstr->optype & ~OPTYPE_RRM_MASK) == OPTYPE_HARMLESS)
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync {
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync AssertMsg(pfnCSAMR3Analyse(pVM, &cpu, pInstrGC, pCurInstrGC, pCacheRec, (void *)pPage) == VWRN_CONTINUE_ANALYSIS, ("Instruction incorrectly marked harmless?!?!?\n"));
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync goto next_please;
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_ANALYSE_BEYOND_RET
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Remember the address of the instruction following the ret in case the parent instruction was a call. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( pCacheRec->pCallExitRec
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && cpu.pCurInstr->opcode == OP_RETN
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && pCacheRec->pCallExitRec->cInstrAfterRet < CSAM_MAX_CALLEXIT_RET)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->pCallExitRec->pInstrAfterRetGC[pCacheRec->pCallExitRec->cInstrAfterRet] = pCurInstrGC + opsize;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->pCallExitRec->cInstrAfterRet++;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync#endif
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync rc = pfnCSAMR3Analyse(pVM, &cpu, pInstrGC, pCurInstrGC, pCacheRec, (void *)pPage);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VINF_SUCCESS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // For our first attempt, we'll handle only simple relative jumps and calls (immediate offset coded in instruction)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( ((cpu.pCurInstr->optype & OPTYPE_CONTROLFLOW) && (OP_PARM_VTYPE(cpu.pCurInstr->param1) == OP_PARM_J))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || (cpu.pCurInstr->opcode == OP_CALL && cpu.param1.flags == USE_DISPLACEMENT32)) /* simple indirect call (call dword ptr [address]) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* 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) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( cpu.pCurInstr->opcode == OP_CALL
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && cpu.param1.flags == USE_DISPLACEMENT32)
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync {
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync addr = 0;
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync PGMPhysSimpleReadGCPtr(pVM, &addr, (RTRCUINTPTR)cpu.param1.disp32, sizeof(addr));
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync }
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync addr = CSAMResolveBranch(&cpu, pCurInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (addr == 0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("We don't support far jumps here!! (%08X)\n", cpu.param1.flags));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!PATMIsPatchGCAddr(pVM, addr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync /* If the target address lies in a patch generated jump, then special action needs to be taken. */
ec588a4ac8429a8b6c744544818b3ce3b2c75690vboxsync PATMR3DetectConflict(pVM, pCurInstrGC, addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Same page? */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PAGE_ADDRESS(addr) != PAGE_ADDRESS(pCurInstrGC ))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!PGMGstIsPagePresent(pVM, addr))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Page for current instruction %VRv is not present!!\n", addr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto next_please;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* All is fine, let's continue. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamR3CheckPageRecord(pVM, addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pJmpPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, addr, &pJmpPage) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pJmpPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* New branch target; let's take a look at it. */
afed5ab737f4aacfae3fe73776f40e989190a7cavboxsync pJmpPage = csamCreatePageRecord(pVM, addr, CSAM_TAG_CSAM, fCode32);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pJmpPage == NULL)
ee5858e9d955811dae9e6b8ecbb336cc6d0e7197vboxsync {
b45d66c0e496e2fd861479202f3d43aad592bd14vboxsync rc = VERR_NO_MEMORY;
b45d66c0e496e2fd861479202f3d43aad592bd14vboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPage);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cpu.pCurInstr->opcode == OP_CALL)
96d8c2c77873591a51233b013fc1ec8bc774a096vboxsync rc = csamAnalyseCallCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamAnalyseCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc != VINF_SUCCESS) {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
96d8c2c77873591a51233b013fc1ec8bc774a096vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cpu.pCurInstr->opcode == OP_JMP)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {//unconditional jump; return to caller
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VWRN_CONTINUE_ANALYSIS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } //if ((cpu.pCurInstr->optype & OPTYPE_CONTROLFLOW) && (OP_PARM_VTYPE(cpu.pCurInstr->param1) == OP_PARM_J))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_SCAN_JUMP_TABLE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( cpu.pCurInstr->opcode == OP_JMP
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (cpu.param1.flags & (USE_DISPLACEMENT32|USE_INDEX|USE_SCALE)) == (USE_DISPLACEMENT32|USE_INDEX|USE_SCALE)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR pJumpTableGC = (RTRCPTR)cpu.param1.disp32;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint8_t *pJumpTableHC;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc2;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Jump through jump table\n"));
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc2 = PGMPhysGCPtr2HCPtr(pVM, pJumpTableGC, (PRTHCPTR)&pJumpTableHC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc2 == VINF_SUCCESS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (uint32_t i=0;i<2;i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t fFlags;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync addr = pJumpTableGC + cpu.param1.scale * i;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Same page? */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PAGE_ADDRESS(addr) != PAGE_ADDRESS(pJumpTableGC))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync addr = *(RTRCPTR *)(pJumpTableHC + cpu.param1.scale * i);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc2 = PGMGstGetPage(pVM, addr, &fFlags, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( rc2 != VINF_SUCCESS
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || (fFlags & X86_PTE_US)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || !(fFlags & X86_PTE_P)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Jump to %VRv\n", addr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pJmpPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, addr, &pJmpPage) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pJmpPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* New branch target; let's take a look at it. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pJmpPage = csamCreatePageRecord(pVM, addr, CSAM_TAG_CSAM, fCode32);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pJmpPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VERR_NO_MEMORY;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPage);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamAnalyseCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc != VINF_SUCCESS) {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc != VWRN_CONTINUE_ANALYSIS) {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break; //done!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncnext_please:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cpu.pCurInstr->opcode == OP_JMP)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync goto done;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCurInstrGC += opsize;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncdone:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCacheRec->depth--;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Calculates the 64 bits hash value for the current page
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns hash value
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
96d8c2c77873591a51233b013fc1ec8bc774a096vboxsync * @param pInstr Page address
c33db29e7b41467a35675031f5f5233839909083vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncuint64_t csamR3CalcPageHash(PVM pVM, RTRCPTR pInstr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t hash = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t val[5];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert((pInstr & PAGE_OFFSET_MASK) == 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPhysSimpleReadGCPtr(pVM, &val[0], pInstr, sizeof(val[0]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamR3CalcPageHash: page %VRv not present!!\n", pInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return ~0ULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPhysSimpleReadGCPtr(pVM, &val[1], pInstr+1024, sizeof(val[0]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamR3CalcPageHash: page %VRv not present!!\n", pInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return ~0ULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPhysSimpleReadGCPtr(pVM, &val[2], pInstr+2048, sizeof(val[0]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamR3CalcPageHash: page %VRv not present!!\n", pInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return ~0ULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPhysSimpleReadGCPtr(pVM, &val[3], pInstr+3072, sizeof(val[0]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamR3CalcPageHash: page %VRv not present!!\n", pInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return ~0ULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPhysSimpleReadGCPtr(pVM, &val[4], pInstr+4092, sizeof(val[0]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamR3CalcPageHash: page %VRv not present!!\n", pInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return ~0ULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // don't want to get division by zero traps
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync val[2] |= 1;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync val[4] |= 1;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync hash = (uint64_t)val[0] * (uint64_t)val[1] / (uint64_t)val[2] + (val[3]%val[4]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return (hash == ~0ULL) ? hash - 1 : hash;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Notify CSAM of a page flush
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync * @returns VBox status code
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync * @param pVM The VM to operate on.
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync * @param addr GC address of the page to flush
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fRemovePage Page removal flag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsyncstatic int csamFlushPage(PVM pVM, RTRCPTR addr, bool fRemovePage)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPageRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTGCPHYS GCPhys = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t fFlags = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!CSAMIsEnabled(pVM))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeFlushPage, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync addr = addr & PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Note: searching for the page in our tree first is more expensive (skipped flushes are two orders of magnitude more common)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync if (pVM->csam.s.pPageTree == NULL)
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync {
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync }
ec588a4ac8429a8b6c744544818b3ce3b2c75690vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMGstGetPage(pVM, addr, &fFlags, &GCPhys);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Returned at a very early stage (no paging yet presumably). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc == VERR_NOT_SUPPORTED)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( (fFlags & X86_PTE_US)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || rc == VERR_PGM_PHYS_PAGE_RESERVED
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* User page -> not relevant for us. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrFlushesSkipped, 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc != VERR_PAGE_NOT_PRESENT && rc != VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgFailed(("PGMR3GetPage %VRv failed with %Rrc\n", addr, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
c33db29e7b41467a35675031f5f5233839909083vboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)addr);
c33db29e7b41467a35675031f5f5233839909083vboxsync if (pPageRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( GCPhys == pPageRec->page.GCPhys
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (fFlags & X86_PTE_P))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrFlushesSkipped, 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
a27fbcbb29ffc2196c2ebd0f2dad92f40c7ec65dvboxsync }
a27fbcbb29ffc2196c2ebd0f2dad92f40c7ec65dvboxsync
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync Log(("CSAMR3FlushPage: page %VRv has changed -> FLUSH (rc=%Rrc) (Phys: %VGp vs %VGp)\n", addr, rc, GCPhys, pPageRec->page.GCPhys));
315f443a509c31db47b8f5cb94d26e54c3d5c497vboxsync
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrFlushes, 1);
7cced997f7e362bb903898de921271b5e1011e3dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (fRemovePage)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamRemovePageRecord(pVM, addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMMarkPage(pVM, addr, false);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec->page.GCPhys = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec->page.fFlags = 0;
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync rc = PGMGstGetPage(pVM, addr, &pPageRec->page.fFlags, &pPageRec->page.GCPhys);
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync if (rc == VINF_SUCCESS)
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync pPageRec->page.u64Hash = csamR3CalcPageHash(pVM, addr);
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync if (pPageRec->page.pBitmap == NULL)
ec588a4ac8429a8b6c744544818b3ce3b2c75690vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec->page.pBitmap = (uint8_t *)MMR3HeapAllocZ(pVM, MM_TAG_CSAM_PATCH, CSAM_PAGE_BITMAP_SIZE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPageRec->page.pBitmap);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.pBitmap == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VERR_NO_MEMORY;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memset(pPageRec->page.pBitmap, 0, CSAM_PAGE_BITMAP_SIZE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Inform patch manager about the flush; no need to repeat the above check twice.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PATMR3FlushPage(pVM, addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeFlushPage, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Notify CSAM of a page flush
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param addr GC address of the page to flush
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsyncVMMR3DECL(int) CSAMR3FlushPage(PVM pVM, RTRCPTR addr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return csamFlushPage(pVM, addr, true /* remove page record */);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
8e8844a522f5d335f177a0313b03067d79cce201vboxsync * Remove a CSAM monitored page. Use with care!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param addr GC address of the page to flush
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3RemovePage(PVM pVM, RTRCPTR addr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPageRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync addr = addr & PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamRemovePageRecord(pVM, addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PATMR3FlushPage(pVM, addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Check a page record in case a page has been changed
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code. (trap handled or not)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstrGC GC instruction pointer
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
a27fbcbb29ffc2196c2ebd0f2dad92f40c7ec65dvboxsyncint csamR3CheckPageRecord(PVM pVM, RTRCPTR pInstrGC)
a27fbcbb29ffc2196c2ebd0f2dad92f40c7ec65dvboxsync{
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync PCSAMPAGEREC pPageRec;
315f443a509c31db47b8f5cb94d26e54c3d5c497vboxsync uint64_t u64hash;
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync
7cced997f7e362bb903898de921271b5e1011e3dvboxsync pInstrGC = pInstrGC & PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)pInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync u64hash = csamR3CalcPageHash(pVM, pInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (u64hash != pPageRec->page.u64Hash)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamFlushPage(pVM, pInstrGC, false /* don't remove page record */);
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync }
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync else
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync return VWRN_CSAM_PAGE_NOT_FOUND;
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync return VINF_SUCCESS;
ec588a4ac8429a8b6c744544818b3ce3b2c75690vboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Returns monitor description based on CSAM tag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @return description string
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param enmTag Owner tag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncconst char *csamGetMonitorDescription(CSAMTAG enmTag)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (enmTag == CSAM_TAG_PATM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return "CSAM-PATM self-modifying code monitor handler";
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (enmTag == CSAM_TAG_REM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return "CSAM-REM self-modifying code monitor handler";
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(enmTag == CSAM_TAG_CSAM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return "CSAM self-modifying code monitor handler";
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Adds page record to our lookup tree
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns CSAMPAGE ptr or NULL if failure
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param GCPtr Page address
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param enmTag Owner tag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fCode32 16 or 32 bits code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fMonitorInvalidation Monitor page invalidation flag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PCSAMPAGE csamCreatePageRecord(PVM pVM, RTRCPTR GCPtr, CSAMTAG enmTag, bool fCode32, bool fMonitorInvalidation)
8e8844a522f5d335f177a0313b03067d79cce201vboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPage;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync bool ret;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("New page record for %VRv\n", GCPtr & PAGE_BASE_GC_MASK));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage = (PCSAMPAGEREC)MMR3HeapAllocZ(pVM, MM_TAG_CSAM_PATCH, sizeof(CSAMPAGEREC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgFailed(("csamCreatePageRecord: Out of memory!!!!\n"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Round down to page boundary. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync GCPtr = (GCPtr & PAGE_BASE_GC_MASK);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->Core.Key = (AVLPVKEY)GCPtr;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.pPageGC = GCPtr;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.fCode32 = fCode32;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.fMonitorInvalidation = fMonitorInvalidation;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.enmTag = enmTag;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.fMonitorActive = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.pBitmap = (uint8_t *)MMR3HeapAllocZ(pVM, MM_TAG_CSAM_PATCH, PAGE_SIZE/sizeof(uint8_t));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMGstGetPage(pVM, GCPtr, &pPage->page.fFlags, &pPage->page.GCPhys);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.u64Hash = csamR3CalcPageHash(pVM, GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ret = RTAvlPVInsert(&pVM->csam.s.pPageTree, &pPage->Core);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(ret);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_MONITOR_CODE_PAGES
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRelease(!fInCSAMCodePageInvalidate);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch (enmTag)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_PATM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_REM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_CSAM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtr, GCPtr + (PAGE_SIZE - 1) /* inclusive! */,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamGetMonitorDescription(enmTag));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %VRv failed with %Rrc\n", GCPtr, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("PGMR3HandlerVirtualRegisterEx for %VRv failed with %Rrc\n", GCPtr, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Could fail, because it's already monitored. Don't treat that condition as fatal. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Prefetch it in case it's not there yet. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPrefetchPage(pVM, GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMShwModifyPage(pVM, GCPtr, 1, 0, ~(uint64_t)X86_PTE_RW);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->page.fMonitorActive = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageMonitor);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync default:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break; /* to shut up GCC */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamCreatePageRecord %VRv HCPhys=%VGp\n", GCPtr, pPage->page.GCPhys));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_WITH_STATISTICS
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch (enmTag)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_CSAM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageCSAM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_PATM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPagePATM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_REM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageREM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync default:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break; /* to shut up GCC */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (fMonitorInvalidation)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrPagesInv);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return &pPage->page;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Monitors a code page (if not already monitored)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pPageAddrGC The page to monitor
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param enmTag Monitor tag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3MonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPageRec = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync bool fMonitorInvalidation;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Dirty pages must be handled before calling this function!. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!pVM->csam.s.cDirtyPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pVM->csam.s.fScanningStarted == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS; /* too early */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageAddrGC &= PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMR3MonitorPage %VRv %d\n", pPageAddrGC, enmTag));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** @todo implicit assumption */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fMonitorInvalidation = (enmTag == CSAM_TAG_PATM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t fFlags;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMGstGetPage(pVM, pPageAddrGC, &fFlags, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( rc == VINF_SUCCESS
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (fFlags & X86_PTE_US))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* We don't care about user pages. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrUserPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamCreatePageRecord(pVM, pPageAddrGC, enmTag, true /* 32 bits code */, fMonitorInvalidation);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPageRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** @todo reference count */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPageRec->page.fMonitorActive);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_MONITOR_CODE_PAGES
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pPageRec->page.fMonitorActive)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMR3MonitorPage: activate monitoring for %VRv\n", pPageAddrGC));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, pPageAddrGC, pPageAddrGC + (PAGE_SIZE - 1) /* inclusive! */,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamGetMonitorDescription(enmTag));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %VRv failed with %Rrc\n", pPageAddrGC, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("PGMR3HandlerVirtualRegisterEx for %VRv failed with %Rrc\n", pPageAddrGC, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Could fail, because it's already monitored. Don't treat that condition as fatal. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Prefetch it in case it's not there yet. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPrefetchPage(pVM, pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMShwModifyPage(pVM, pPageAddrGC, 1, 0, ~(uint64_t)X86_PTE_RW);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageMonitor);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec->page.fMonitorActive = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec->page.fMonitorInvalidation = fMonitorInvalidation;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( !pPageRec->page.fMonitorInvalidation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && fMonitorInvalidation)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPageRec->page.fMonitorActive);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PGMHandlerVirtualChangeInvalidateCallback(pVM, pPageRec->page.pPageGC, CSAMCodePageInvalidate);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec->page.fMonitorInvalidation = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrPagesInv);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Prefetch it in case it's not there yet. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPrefetchPage(pVM, pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Make sure it's readonly. Page invalidation may have modified the attributes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMShwModifyPage(pVM, pPageAddrGC, 1, 0, ~(uint64_t)X86_PTE_RW);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if 0 /* def VBOX_STRICT -> very annoying) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.fMonitorActive)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t fPageShw;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTHCPHYS GCPhys;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMShwGetPage(pVM, pPageAddrGC, &fPageShw, &GCPhys);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// AssertMsg( (rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// || !(fPageShw & X86_PTE_RW)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// || (pPageRec->page.GCPhys == 0), ("Shadow page flags for %VRv (%RHp) aren't readonly (%VX64)!!\n", pPageAddrGC, GCPhys, fPageShw));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.GCPhys == 0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Prefetch it in case it's not there yet. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPrefetchPage(pVM, pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* The page was changed behind our back. It won't be made read-only until the next SyncCR3, so force it here. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMShwModifyPage(pVM, pPageAddrGC, 1, 0, ~(uint64_t)X86_PTE_RW);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* CSAM_MONITOR_CODE_PAGES */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Unmonitors a code page
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pPageAddrGC The page to monitor
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param enmTag Monitor tag
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3UnmonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageAddrGC &= PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMR3UnmonitorPage %VRv %d\n", pPageAddrGC, enmTag));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(enmTag == CSAM_TAG_REM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_STRICT
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPageRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pPageRec && pPageRec->page.enmTag == enmTag);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return CSAMR3RemovePage(pVM, pPageAddrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Removes a page record from our lookup tree
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param GCPtr Page address
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamRemovePageRecord(PVM pVM, RTRCPTR GCPtr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGEREC pPageRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamRemovePageRecord %VRv\n", GCPtr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVRemove(&pVM->csam.s.pPageTree, (AVLPVKEY)GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrRemovedPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef CSAM_MONITOR_CODE_PAGES
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.fMonitorActive)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* @todo -> this is expensive (cr3 reload)!!!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * if this happens often, then reuse it instead!!!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!fInCSAMCodePageInvalidate);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPageMonitor);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PGMHandlerVirtualDeregister(pVM, GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.enmTag == CSAM_TAG_PATM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Make sure the recompiler flushes its cache as this page is no longer monitored. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatPageRemoveREMFlush);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CPUMSetChangedFlags(pVM, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_WITH_STATISTICS
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch (pPageRec->page.enmTag)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_CSAM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPageCSAM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_PATM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPagePATM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case CSAM_TAG_REM:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_DEC(&pVM->csam.s.StatPageREM);
9c425bdea5f0991df62922b1584b805a86f2f898vboxsync break;
9c425bdea5f0991df62922b1584b805a86f2f898vboxsync default:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break; /* to shut up GCC */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.pBitmap) MMR3HeapFree(pPageRec->page.pBitmap);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMR3HeapFree(pPageRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertFailed();
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Callback for delayed writes from non-EMT threads
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM VM Handle.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbBuf How much it's reading/writing.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(void) CSAMDelayedWriteHandler(PVM pVM, RTRCPTR GCPtr, size_t cbBuf)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = PATMR3PatchWrite(pVM, GCPtr, cbBuf);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * #PF Handler callback for virtual access handler ranges.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Important to realize that a physical page in a range can have aliases, and
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * for ALL and WRITE handlers these will also trigger.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VINF_SUCCESS if the handler have carried out the operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM VM Handle.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pvPtr The HC mapping of that address.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pvBuf What the guest is reading/writing.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbBuf How much it's reading/writing.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param enmAccessType The access type.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pvUser User argument.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) CSAMCodePageWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(enmAccessType == PGMACCESSTYPE_WRITE);
18db01bbe01d709ed64ef78717e98b94b7fee056vboxsync Log(("CSAMCodePageWriteHandler: write to %VGv size=%d\n", GCPtr, cbBuf));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
18db01bbe01d709ed64ef78717e98b94b7fee056vboxsync if (VM_IS_EMT(pVM))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PATMR3PatchWrite(pVM, GCPtr, cbBuf);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Queue the write instead otherwise we'll get concurrency issues. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** @note in theory not correct to let it write the data first before disabling a patch!
c20b837b2c912dd4dcaaa676e15acd2b230108f0vboxsync * (if it writes the same data as the patch jump and we replace it with obsolete opcodes)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
c20b837b2c912dd4dcaaa676e15acd2b230108f0vboxsync Log(("CSAMCodePageWriteHandler: delayed write!\n"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertCompileSize(RTRCPTR, 4);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = VMR3ReqCallEx(pVM, VMREQDEST_ANY, NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (PFNRT)CSAMDelayedWriteHandler, 3, pVM, (RTRCPTR)GCPtr, cbBuf);
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertRC(rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_PGM_HANDLER_DO_DEFAULT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * #PF Handler callback for invalidation of virtual access handler ranges.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM VM Handle.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param GCPtr The virtual address the guest has changed.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) CSAMCodePageInvalidate(PVM pVM, RTGCPTR GCPtr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fInCSAMCodePageInvalidate = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("CSAMCodePageInvalidate %VGv\n", GCPtr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** @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. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamFlushPage(pVM, GCPtr, false /* don't remove page! */);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fInCSAMCodePageInvalidate = false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync/**
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync * Check if the current instruction has already been checked before
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync *
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync * @returns VBox status code. (trap handled or not)
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync * @param pVM The VM to operate on.
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync * @param pInstr Instruction pointer
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync * @param pPage CSAM patch structure pointer
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync */
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsyncbool csamIsCodeScanned(PVM pVM, RTRCPTR pInstr, PCSAMPAGE *pPage)
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync{
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync PCSAMPAGEREC pPageRec;
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync uint32_t offset;
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync STAM_PROFILE_START(&pVM->csam.s.StatTimeCheckAddr, a);
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync offset = pInstr & PAGE_OFFSET_MASK;
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync pInstr = pInstr & PAGE_BASE_GC_MASK;
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync Assert(pPage);
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync if (*pPage && (*pPage)->pPageGC == pInstr)
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync {
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync if ((*pPage)->pBitmap == NULL || ASMBitTest((*pPage)->pBitmap, offset))
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync {
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrKnownPagesHC, 1);
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
69a0f42fa2c531eb2cffb6d6f482d828d9adab34vboxsync return true;
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync }
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync return false;
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync }
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync
5dda7f07dab8a954e6c4cf2378b15f921e60d9aavboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)pInstr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage) *pPage= &pPageRec->page;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec->page.pBitmap == NULL || ASMBitTest(pPageRec->page.pBitmap, offset))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrKnownPagesHC, 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage) *pPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTimeCheckAddr, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Mark an instruction in a page as scanned/not scanned
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pPage Patch structure pointer
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstr Instruction pointer
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param opsize Instruction size
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fScanned Mark as scanned or not
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void csamMarkCode(PVM pVM, PCSAMPAGE pPage, RTRCPTR pInstr, uint32_t opsize, bool fScanned)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("csamMarkCodeAsScanned %VRv opsize=%d\n", pInstr, opsize));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMMarkPage(pVM, pInstr, fScanned);
c657bea826c7455c93bd45eaebab63a4c7742c42vboxsync
c657bea826c7455c93bd45eaebab63a4c7742c42vboxsync /** @todo should recreate empty bitmap if !fScanned */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage->pBitmap == NULL)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (fScanned)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // retn instructions can be scanned more than once
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (ASMBitTest(pPage->pBitmap, pInstr & PAGE_OFFSET_MASK) == 0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->uSize += opsize;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_ADD(&pVM->csam.s.StatNrInstr, 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPage->uSize >= PAGE_SIZE)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Scanned full page (%VRv) -> free bitmap\n", pInstr & PAGE_BASE_GC_MASK));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MMR3HeapFree(pPage->pBitmap);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPage->pBitmap = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMBitSet(pPage->pBitmap, pInstr & PAGE_OFFSET_MASK);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMBitClear(pPage->pBitmap, pInstr & PAGE_OFFSET_MASK);
afed5ab737f4aacfae3fe73776f40e989190a7cavboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Mark an instruction in a page as scanned/not scanned
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync * @returns VBox status code.
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstr Instruction pointer
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param opsize Instruction size
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fScanned Mark as scanned or not
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3MarkCode(PVM pVM, RTRCPTR pInstr, uint32_t opsize, bool fScanned)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!fScanned); /* other case not implemented. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!PATMIsPatchGCAddr(pVM, pInstr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (csamIsCodeScanned(pVM, pInstr, &pPage) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(fScanned == true); /* other case should not be possible */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMR3MarkCode: %VRv size=%d fScanned=%d\n", pInstr, opsize, fScanned));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamMarkCode(pVM, pPage, pInstr, opsize, fScanned);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Scan and analyse code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCtxCore CPU context
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstrGC Instruction pointer
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3CheckCodeEx(PVM pVM, PCPUMCTXCORE pCtxCore, RTRCPTR pInstrGC)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (EMIsRawRing0Enabled(pVM) == false || PATMIsPatchGCAddr(pVM, pInstrGC) == true)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // No use
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (CSAMIsEnabled(pVM))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Assuming 32 bits code for now. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(SELMGetCpuModeFromSelector(pVM, pCtxCore->eflags, pCtxCore->cs, &pCtxCore->csHid) == CPUMODE_32BIT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pInstrGC = SELMToFlat(pVM, DIS_SELREG_CS, pCtxCore, pInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return CSAMR3CheckCode(pVM, pInstrGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Scan and analyse code
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pInstrGC Instruction pointer (0:32 virtual address)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3CheckCode(PVM pVM, RTRCPTR pInstrGC)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (EMIsRawRing0Enabled(pVM) == false || PATMIsPatchGCAddr(pVM, pInstrGC) == true)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // No use
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (CSAMIsEnabled(pVM))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // Cache record for PATMGCVirtToHCVirt
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMP2GLOOKUPREC cacheRec = {0};
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTime, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamAnalyseCallCodeStream(pVM, pInstrGC, pInstrGC, true /* 32 bits code */, CSAMR3AnalyseCallback, pPage, &cacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTime, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (rc != VINF_SUCCESS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("csamAnalyseCodeStream failed with %d\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
afed5ab737f4aacfae3fe73776f40e989190a7cavboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Flush dirty code pages
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamR3FlushDirtyPages(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatFlushDirtyPages, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (uint32_t i=0;i<pVM->csam.s.cDirtyPages;i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync PCSAMPAGEREC pPageRec;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR GCPtr = pVM->csam.s.pvDirtyBasePage[i];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync GCPtr = GCPtr & PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Notify the recompiler that this page has been changed. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync REMR3NotifyCodePageChanged(pVM, GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Enable write protection again. (use the fault address as it might be an alias) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMShwModifyPage(pVM, pVM->csam.s.pvDirtyFaultPage[i], 1, 0, ~(uint64_t)X86_PTE_RW);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(rc == VINF_SUCCESS || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMR3FlushDirtyPages: flush %VRv (modifypage rc=%Rrc)\n", pVM->csam.s.pvDirtyBasePage[i], rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pPageRec && pPageRec->page.enmTag == CSAM_TAG_REM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t fFlags;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMGstGetPage(pVM, GCPtr, &fFlags, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( rc == VINF_SUCCESS
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (fFlags & X86_PTE_US))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* We don't care about user pages. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamRemovePageRecord(pVM, GCPtr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_COUNTER_INC(&pVM->csam.s.StatNrUserPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.cDirtyPages = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatFlushDirtyPages, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Flush potential new code pages
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int csamR3FlushCodePages(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (uint32_t i=0;i<pVM->csam.s.cPossibleCodePages;i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR GCPtr = pVM->csam.s.pvPossibleCodePage[i];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync GCPtr = GCPtr & PAGE_BASE_GC_MASK;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
afed5ab737f4aacfae3fe73776f40e989190a7cavboxsync Log(("csamR3FlushCodePages: %VRv\n", GCPtr));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PGMShwSetPage(pVM, GCPtr, 1, 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Resync the page to make sure instruction fetch will fault */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMMarkPage(pVM, GCPtr, false);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.cPossibleCodePages = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
ab1239d8445aa1fd4afddb7d0c8b90bbdc742010vboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Perform any pending actions
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3DoPendingAction(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamR3FlushDirtyPages(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync csamR3FlushCodePages(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync VM_FF_CLEAR(pVM, VM_FF_CSAM_PENDING_ACTION);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Analyse interrupt and trap gates
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param iGate Start gate
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cGates Number of gates to check
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3CheckGates(PVM pVM, uint32_t iGate, uint32_t cGates)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint16_t cbIDT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR GCPtrIDT = CPUMGetGuestIDTR(pVM, &cbIDT);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t iGateEnd;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t maxGates;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync VBOXIDTE aIDT[256];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVBOXIDTE pGuestIdte;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (EMIsRawRing0Enabled(pVM) == false)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Enabling interrupt gates only works when raw ring 0 is enabled. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync //AssertFailed();
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* We only check all gates once during a session */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( !pVM->csam.s.fGatesChecked
19b725c530eb49600728765de7ed451cbe290740vboxsync && cGates != 256)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS; /* too early */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* We only check all gates once during a session */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( pVM->csam.s.fGatesChecked
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && cGates != 1)
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync return VINF_SUCCESS; /* ignored */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(cGates <= 256);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!GCPtrIDT || cGates > 256)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VERR_INVALID_PARAMETER;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cGates != 1)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.fGatesChecked = true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i=0;i<RT_ELEMENTS(pVM->csam.s.pvCallInstruction);i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR pHandler = pVM->csam.s.pvCallInstruction[i];
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pHandler)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMP2GLOOKUPREC cacheRec = {0}; /* Cache record for PATMGCVirtToHCVirt. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = NULL;
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync Log(("CSAMCheckGates: checking previous call instruction %VRv\n", pHandler));
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync STAM_PROFILE_START(&pVM->csam.s.StatTime, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamAnalyseCodeStream(pVM, pHandler, pHandler, true, CSAMR3AnalyseCallback, pPage, &cacheRec);
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTime, a);
ec588a4ac8429a8b6c744544818b3ce3b2c75690vboxsync if (rc != VINF_SUCCESS)
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync {
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync Log(("CSAMCheckGates: csamAnalyseCodeStream failed with %d\n", rc));
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync continue;
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync }
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Determine valid upper boundary. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync maxGates = (cbIDT+1) / sizeof(VBOXIDTE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(iGate < maxGates);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (iGate > maxGates)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VERR_INVALID_PARAMETER;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (iGate + cGates > maxGates)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cGates = maxGates - iGate;
19b725c530eb49600728765de7ed451cbe290740vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync GCPtrIDT = GCPtrIDT + iGate * sizeof(VBOXIDTE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync iGateEnd = iGate + cGates;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatCheckGates, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Get IDT entries.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (PAGE_ADDRESS(GCPtrIDT) == PAGE_ADDRESS(GCPtrIDT+cGates*sizeof(VBOXIDTE)))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Just convert the IDT address to a HC pointer. The whole IDT fits in one page. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrIDT, (PRTHCPTR)&pGuestIdte);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgRC(rc, ("Failed to read IDTE! rc=%Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatCheckGates, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
10e1bc06b2908a0af56d92ffdbadd25b36a5ef61vboxsync {
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync /* Slow method when it crosses a page boundary. */
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync rc = PGMPhysSimpleReadGCPtr(pVM, aIDT, GCPtrIDT, cGates*sizeof(VBOXIDTE));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
8f7bc6ad2b7bbcb4b3b96248cd2478e45f2e3b88vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgRC(rc, ("Failed to read IDTE! rc=%Rrc\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatCheckGates, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync pGuestIdte = &aIDT[0];
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync }
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync for (/*iGate*/; iGate<iGateEnd; iGate++, pGuestIdte++)
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync {
ec588a4ac8429a8b6c744544818b3ce3b2c75690vboxsync Assert(TRPMR3GetGuestTrapHandler(pVM, iGate) == TRPM_INVALID_HANDLER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
9b45880674da6f82ca27cc28b0272de3dd3cc7dfvboxsync if ( pGuestIdte->Gen.u1Present
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32 || pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (pGuestIdte->Gen.u2DPL == 3 || pGuestIdte->Gen.u2DPL == 0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR pHandler;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMP2GLOOKUPREC cacheRec = {0}; /* Cache record for PATMGCVirtToHCVirt. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCSAMPAGE pPage = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync SELMSELINFO selInfo;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHandler = VBOXIDTE_OFFSET(*pGuestIdte);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHandler = SELMToFlatBySel(pVM, pGuestIdte->Gen.u16SegSel, pHandler);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = SELMR3GetSelectorInfo(pVM, pGuestIdte->Gen.u16SegSel, &selInfo);
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync if ( RT_FAILURE(rc)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || selInfo.GCPtrBase != 0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || selInfo.cbLimit != ~0U
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Refuse to patch a handler whose idt cs selector isn't wide open. */
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync Log(("CSAMCheckGates: check gate %d failed due to rc %Rrc GCPtrBase=%VRv limit=%x\n", iGate, rc, selInfo.GCPtrBase, selInfo.cbLimit));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync continue;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMCheckGates: check trap gate %d at %04X:%08X (flat %VRv)\n", iGate, pGuestIdte->Gen.u16SegSel, VBOXIDTE_OFFSET(*pGuestIdte), pHandler));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMCheckGates: check interrupt gate %d at %04X:%08X (flat %VRv)\n", iGate, pGuestIdte->Gen.u16SegSel, VBOXIDTE_OFFSET(*pGuestIdte), pHandler));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_START(&pVM->csam.s.StatTime, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = csamAnalyseCodeStream(pVM, pHandler, pHandler, true, CSAMR3AnalyseCallback, pPage, &cacheRec);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatTime, a);
9c425bdea5f0991df62922b1584b805a86f2f898vboxsync if (rc != VINF_SUCCESS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync Log(("CSAMCheckGates: csamAnalyseCodeStream failed with %d\n", rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync continue;
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* OpenBSD guest specific patch test. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (iGate >= 0x20)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCPUMCTX pCtx;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync DISCPUSTATE cpu;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTGCUINTPTR32 aOpenBsdPushCSOffset[3] = {0x03, /* OpenBSD 3.7 & 3.8 */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync 0x2B, /* OpenBSD 4.0 installation ISO */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync 0x2F}; /* OpenBSD 4.0 after install */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pCtx = CPUMQueryGuestCtxPtr(pVM);
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i=0;i<RT_ELEMENTS(aOpenBsdPushCSOffset);i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = CPUMR3DisasmInstrCPU(pVM, pCtx, pHandler - aOpenBsdPushCSOffset[i], &cpu, NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if ( rc == VINF_SUCCESS
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && cpu.pCurInstr->opcode == OP_PUSH
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && cpu.pCurInstr->param1 == OP_PARM_REG_CS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PATMR3InstallPatch(pVM, pHandler - aOpenBsdPushCSOffset[i], PATMFL_CODE32 | PATMFL_GUEST_SPECIFIC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Installed OpenBSD interrupt handler prefix instruction (push cs) patch\n"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
9c425bdea5f0991df62922b1584b805a86f2f898vboxsync /* Trap gates and certain interrupt gates. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t fPatchFlags = PATMFL_CODE32 | PATMFL_IDTHANDLER;
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32)
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync fPatchFlags |= PATMFL_TRAPHANDLER;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fPatchFlags |= PATMFL_INTHANDLER;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync switch (iGate) {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case 8:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case 10:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case 11:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case 12:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case 13:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync case 14:
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync case 17:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fPatchFlags |= PATMFL_TRAPHANDLER_WITH_ERRORCODE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync default:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* No error code. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Installing %s gate handler for 0x%X at %VRv\n", (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32) ? "trap" : "intr", iGate, pHandler));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = PATMR3InstallPatch(pVM, pHandler, fPatchFlags);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_SUCCESS(rc) || rc == VERR_PATM_ALREADY_PATCHED)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Gate handler 0x%X is SAFE!\n", iGate));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTRCPTR pNewHandlerGC = PATMR3QueryPatchGCPtr(pVM, pHandler);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pNewHandlerGC)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = TRPMR3SetGuestTrapHandler(pVM, iGate, pNewHandlerGC);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("TRPMR3SetGuestTrapHandler %d failed with %Rrc\n", iGate, rc));
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } /* for */
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync STAM_PROFILE_STOP(&pVM->csam.s.StatCheckGates, a);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync * Record previous call instruction addresses
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param GCPtrCall Call address
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3RecordCallAddress(PVM pVM, RTRCPTR GCPtrCall)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i=0;i<RT_ELEMENTS(pVM->csam.s.pvCallInstruction);i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync if (pVM->csam.s.pvCallInstruction[i] == GCPtrCall)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("CSAMR3RecordCallAddress %VRv\n", GCPtrCall));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.pvCallInstruction[pVM->csam.s.iCallInstruction++] = GCPtrCall;
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync if (pVM->csam.s.iCallInstruction >= RT_ELEMENTS(pVM->csam.s.pvCallInstruction))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVM->csam.s.iCallInstruction = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
e4ea543752422f1139923e3e506c625b0a1827c5vboxsync * Query CSAM state (enabled/disabled)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns 0 - disabled, 1 - enabled
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync * @param pVM The VM to operate on.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncVMMR3DECL(int) CSAMR3IsEnabled(PVM pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pVM->fCSAMEnabled;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef VBOX_WITH_DEBUGGER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The '.csamoff' command.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync * @returns VBox status.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCmd Pointer to the command descriptor (as registered).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCmdHlp Pointer to command helper functions.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pVM Pointer to the current VM (if any).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param paArgs Pointer to (readonly) array of arguments.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cArgs Number of arguments in the array.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) csamr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMDisableScanning(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "CSAM Scanning disabled\n");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The '.csamon' command.
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCmd Pointer to the command descriptor (as registered).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCmdHlp Pointer to command helper functions.
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync * @param pVM Pointer to the current VM (if any).
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync * @param paArgs Pointer to (readonly) array of arguments.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cArgs Number of arguments in the array.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(int) csamr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pVM)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CSAMEnableScanning(pVM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "CSAM Scanning enabled\n");
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync