CSAM.cpp revision 997c47dc1532875eb8e995bf9993dff13071c16f
a23fd118e437af0a7877dd313db8fdaa3537c675yl * CSAM - Guest OS Code Scanning and Analysis Manager
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Copyright (C) 2006-2007 Oracle Corporation
a23fd118e437af0a7877dd313db8fdaa3537c675yl * This file is part of VirtualBox Open Source Edition (OSE), as
a23fd118e437af0a7877dd313db8fdaa3537c675yl * available from http://www.virtualbox.org. This file is free software;
a23fd118e437af0a7877dd313db8fdaa3537c675yl * you can redistribute it and/or modify it under the terms of the GNU
a23fd118e437af0a7877dd313db8fdaa3537c675yl * General Public License (GPL) as published by the Free Software
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Foundation, in version 2 as it comes in the "COPYING" file of the
a23fd118e437af0a7877dd313db8fdaa3537c675yl * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a23fd118e437af0a7877dd313db8fdaa3537c675yl * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a23fd118e437af0a7877dd313db8fdaa3537c675yl/*******************************************************************************
a23fd118e437af0a7877dd313db8fdaa3537c675yl* Header Files *
a23fd118e437af0a7877dd313db8fdaa3537c675yl*******************************************************************************/
7eced415e5dd557aef2d78483b5a7785f0e13670xw/* Enabled by default */
7eced415e5dd557aef2d78483b5a7785f0e13670xw/* Enable to monitor code pages for self-modifying code. */
7eced415e5dd557aef2d78483b5a7785f0e13670xw/* Enable to monitor all scanned pages
7eced415e5dd557aef2d78483b5a7785f0e13670xw#define CSAM_MONITOR_CSAM_CODE_PAGES */
7eced415e5dd557aef2d78483b5a7785f0e13670xw/* Enable to scan beyond ret instructions.
7eced415e5dd557aef2d78483b5a7785f0e13670xw#define CSAM_ANALYSE_BEYOND_RET */
7eced415e5dd557aef2d78483b5a7785f0e13670xw/*******************************************************************************
7eced415e5dd557aef2d78483b5a7785f0e13670xw* Internal Functions *
7eced415e5dd557aef2d78483b5a7785f0e13670xw*******************************************************************************/
7eced415e5dd557aef2d78483b5a7785f0e13670xwstatic DECLCALLBACK(int) csamr3Save(PVM pVM, PSSMHANDLE pSSM);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) csamr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) CSAMCodePageWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) CSAMCodePageInvalidate(PVM pVM, RTGCPTR GCPtr);
a23fd118e437af0a7877dd313db8fdaa3537c675ylbool csamIsCodeScanned(PVM pVM, RTRCPTR pInstr, PCSAMPAGE *pPage);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic PCSAMPAGE csamCreatePageRecord(PVM pVM, RTRCPTR GCPtr, CSAMTAG enmTag, bool fCode32, bool fMonitorInvalidation = false);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic void csamMarkCode(PVM pVM, PCSAMPAGE pPage, RTRCPTR pInstr, uint32_t opsize, bool fScanned);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic int csamAnalyseCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
a23fd118e437af0a7877dd313db8fdaa3537c675yl PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec);
a23fd118e437af0a7877dd313db8fdaa3537c675yl/** @todo Temporary for debugging. */
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic bool fInCSAMCodePageInvalidate = false;
7eced415e5dd557aef2d78483b5a7785f0e13670xw/*******************************************************************************
7eced415e5dd557aef2d78483b5a7785f0e13670xw* Global Variables *
7eced415e5dd557aef2d78483b5a7785f0e13670xw*******************************************************************************/
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) csamr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) csamr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
a23fd118e437af0a7877dd313db8fdaa3537c675yl/** Command descriptors. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, fFlags, pfnHandler pszSyntax, ....pszDescription */
7eced415e5dd557aef2d78483b5a7785f0e13670xw { "csamon", 0, 0, NULL, 0, 0, csamr3CmdOn, "", "Enable CSAM code scanning." },
7eced415e5dd557aef2d78483b5a7785f0e13670xw { "csamoff", 0, 0, NULL, 0, 0, csamr3CmdOff, "", "Disable CSAM code scanning." },
7eced415e5dd557aef2d78483b5a7785f0e13670xw * SSM descriptor table for the CSAM structure.
7eced415e5dd557aef2d78483b5a7785f0e13670xw /** @todo there are more fields that can be ignored here. */
7eced415e5dd557aef2d78483b5a7785f0e13670xw SSMFIELD_ENTRY_PAD_HC64( CSAM, Alignment0, sizeof(uint32_t)),
7eced415e5dd557aef2d78483b5a7785f0e13670xw SSMFIELD_ENTRY_RCPTR( CSAM, pPDBitmapGC), /// @todo ignore this?
7eced415e5dd557aef2d78483b5a7785f0e13670xw SSMFIELD_ENTRY_RCPTR( CSAM, pPDHCBitmapGC), /// @todo ignore this?
7eced415e5dd557aef2d78483b5a7785f0e13670xw SSMFIELD_ENTRY_IGNORE( CSAM, StatScanNextFunctionFailed),
7eced415e5dd557aef2d78483b5a7785f0e13670xw/** Fake type to simplify g_aCsamPDBitmapArray construction. */
7eced415e5dd557aef2d78483b5a7785f0e13670xwtypedef struct
7eced415e5dd557aef2d78483b5a7785f0e13670xw * SSM descriptor table for the CSAM::pPDBitmapHC array.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * SSM descriptor table for the CSAMPAGEREC structure.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Initializes the CSAM.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @returns VBox status code.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pVM The VM to operate on.
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Allocate bitmap for the page directory. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = MMR3HyperAllocOnceNoRel(pVM, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR), 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDBitmapHC);
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = MMR3HyperAllocOnceNoRel(pVM, CSAM_PGDIRBMP_CHUNKS*sizeof(RTRCPTR), 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDGCBitmapHC);
7eced415e5dd557aef2d78483b5a7785f0e13670xw pVM->csam.s.pPDBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDGCBitmapHC);
a23fd118e437af0a7877dd313db8fdaa3537c675yl pVM->csam.s.pPDHCBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Register save and load state notifiers.
7eced415e5dd557aef2d78483b5a7785f0e13670xw rc = SSMR3RegisterInternal(pVM, "CSAM", 0, CSAM_SSM_VERSION, sizeof(pVM->csam.s) + PAGE_SIZE*16,
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrTraps, STAMTYPE_COUNTER, "/CSAM/PageTraps", STAMUNIT_OCCURENCES, "The number of CSAM page traps.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatDangerousWrite, STAMTYPE_COUNTER, "/CSAM/DangerousWrites", STAMUNIT_OCCURENCES, "The number of dangerous writes that cause a context switch.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrPageNPHC, STAMTYPE_COUNTER, "/CSAM/HC/PageNotPresent", STAMUNIT_OCCURENCES, "The number of CSAM pages marked not present.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrPageNPGC, STAMTYPE_COUNTER, "/CSAM/GC/PageNotPresent", STAMUNIT_OCCURENCES, "The number of CSAM pages marked not present.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrPages, STAMTYPE_COUNTER, "/CSAM/PageRec/AddedRW", STAMUNIT_OCCURENCES, "The number of CSAM page records (RW monitoring).");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrPagesInv, STAMTYPE_COUNTER, "/CSAM/PageRec/AddedRWI", STAMUNIT_OCCURENCES, "The number of CSAM page records (RW & invalidation monitoring).");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrRemovedPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Removed", STAMUNIT_OCCURENCES, "The number of removed CSAM page records.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl 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.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrPatchPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Patch", STAMUNIT_OCCURENCES, "The number of CSAM patch page records.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrUserPages, STAMTYPE_COUNTER, "/CSAM/PageRec/Ignore/User", STAMUNIT_OCCURENCES, "The number of CSAM user page records (ignored).");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatPagePATM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/PATM", STAMUNIT_OCCURENCES, "The number of PATM page records.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatPageCSAM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/CSAM", STAMUNIT_OCCURENCES, "The number of CSAM page records.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatPageREM, STAMTYPE_COUNTER, "/CSAM/PageRec/Type/REM", STAMUNIT_OCCURENCES, "The number of REM page records.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatPageMonitor, STAMTYPE_COUNTER, "/CSAM/PageRec/Monitored", STAMUNIT_OCCURENCES, "The number of monitored pages.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatCodePageModified, STAMTYPE_COUNTER, "/CSAM/Monitor/DirtyPage", STAMUNIT_OCCURENCES, "The number of code page modifications.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrFlushes, STAMTYPE_COUNTER, "/CSAM/PageFlushes", STAMUNIT_OCCURENCES, "The number of CSAM page flushes.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrFlushesSkipped, STAMTYPE_COUNTER, "/CSAM/PageFlushesSkipped", STAMUNIT_OCCURENCES, "The number of CSAM page flushes that were skipped.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrKnownPagesHC, STAMTYPE_COUNTER, "/CSAM/HC/KnownPageRecords", STAMUNIT_OCCURENCES, "The number of known CSAM page records.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatNrKnownPagesGC, STAMTYPE_COUNTER, "/CSAM/GC/KnownPageRecords", STAMUNIT_OCCURENCES, "The number of known CSAM page records.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrInstr, STAMTYPE_COUNTER, "/CSAM/ScannedInstr", STAMUNIT_OCCURENCES, "The number of scanned instructions.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrBytesRead, STAMTYPE_COUNTER, "/CSAM/BytesRead", STAMUNIT_OCCURENCES, "The number of bytes read for scanning.");
a23fd118e437af0a7877dd313db8fdaa3537c675yl STAM_REG(pVM, &pVM->csam.s.StatNrOpcodeRead, STAMTYPE_COUNTER, "/CSAM/OpcodeBytesRead", STAMUNIT_OCCURENCES, "The number of opcode bytes read by the recompiler.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatBitmapAlloc, STAMTYPE_COUNTER, "/CSAM/Alloc/PageBitmap", STAMUNIT_OCCURENCES, "The number of page bitmap allocations.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatInstrCacheHit, STAMTYPE_COUNTER, "/CSAM/Cache/Hit", STAMUNIT_OCCURENCES, "The number of dangerous instruction cache hits.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatInstrCacheMiss, STAMTYPE_COUNTER, "/CSAM/Cache/Miss", STAMUNIT_OCCURENCES, "The number of dangerous instruction cache misses.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatScanNextFunction, STAMTYPE_COUNTER, "/CSAM/Function/Scan/Success", STAMUNIT_OCCURENCES, "The number of found functions beyond the ret border.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatScanNextFunctionFailed, STAMTYPE_COUNTER, "/CSAM/Function/Scan/Failed", STAMUNIT_OCCURENCES, "The number of refused functions beyond the ret border.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatTime, STAMTYPE_PROFILE, "/PROF/CSAM/Scan", STAMUNIT_TICKS_PER_CALL, "Scanning overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatTimeCheckAddr, STAMTYPE_PROFILE, "/PROF/CSAM/CheckAddr", STAMUNIT_TICKS_PER_CALL, "Address check overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatTimeAddrConv, STAMTYPE_PROFILE, "/PROF/CSAM/AddrConv", STAMUNIT_TICKS_PER_CALL, "Address conversion overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatTimeFlushPage, STAMTYPE_PROFILE, "/PROF/CSAM/FlushPage", STAMUNIT_TICKS_PER_CALL, "Page flushing overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatTimeDisasm, STAMTYPE_PROFILE, "/PROF/CSAM/Disasm", STAMUNIT_TICKS_PER_CALL, "Disassembly overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatFlushDirtyPages, STAMTYPE_PROFILE, "/PROF/CSAM/FlushDirtyPage", STAMUNIT_TICKS_PER_CALL, "Dirty page flushing overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw STAM_REG(pVM, &pVM->csam.s.StatCheckGates, STAMTYPE_PROFILE, "/PROF/CSAM/CheckGates", STAMUNIT_TICKS_PER_CALL, "CSAMR3CheckGates overhead.");
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Check CFGM option and enable/disable CSAM.
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "CSAMEnabled", &fEnabled);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Debugger commands.
a23fd118e437af0a7877dd313db8fdaa3537c675yl static bool fRegisteredCmds = false;
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = DBGCRegisterCommands(&g_aCmds[0], RT_ELEMENTS(g_aCmds));
a23fd118e437af0a7877dd313db8fdaa3537c675yl * (Re)initializes CSAM
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pVM The VM.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Assert alignment and sizes.
7eced415e5dd557aef2d78483b5a7785f0e13670xw AssertRelease(sizeof(pVM->csam.s) <= sizeof(pVM->csam.padding));
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Setup any fixed pointers and offsets.
7eced415e5dd557aef2d78483b5a7785f0e13670xw PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies 1 VPCU */
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* not necessary */
7eced415e5dd557aef2d78483b5a7785f0e13670xw memset(pVM->csam.s.pvDirtyBasePage, 0, sizeof(pVM->csam.s.pvDirtyBasePage));
7eced415e5dd557aef2d78483b5a7785f0e13670xw memset(pVM->csam.s.pvDirtyFaultPage, 0, sizeof(pVM->csam.s.pvDirtyFaultPage));
7eced415e5dd557aef2d78483b5a7785f0e13670xw memset(&pVM->csam.s.aDangerousInstr, 0, sizeof(pVM->csam.s.aDangerousInstr));
7eced415e5dd557aef2d78483b5a7785f0e13670xw memset(pVM->csam.s.pvCallInstruction, 0, sizeof(pVM->csam.s.pvCallInstruction));
a23fd118e437af0a7877dd313db8fdaa3537c675yl /** @note never mess with the pgdir bitmap here! */
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Applies relocations to data and code managed by this
7eced415e5dd557aef2d78483b5a7785f0e13670xw * component. This function will be called at init and
a23fd118e437af0a7877dd313db8fdaa3537c675yl * whenever the VMM need to relocate itself inside the GC.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * The csam will update the addresses used by the switcher.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pVM The VM.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param offDelta Relocation delta.
7eced415e5dd557aef2d78483b5a7785f0e13670xwVMMR3DECL(void) CSAMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* Adjust pgdir and page bitmap pointers. */
7eced415e5dd557aef2d78483b5a7785f0e13670xw pVM->csam.s.pPDBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDGCBitmapHC);
7eced415e5dd557aef2d78483b5a7785f0e13670xw pVM->csam.s.pPDHCBitmapGC = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC);
7eced415e5dd557aef2d78483b5a7785f0e13670xw for(int i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Terminates the csam.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Termination means cleaning up and freeing all resources,
7eced415e5dd557aef2d78483b5a7785f0e13670xw * the VM it self is at this point powered off or suspended.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pVM The VM to operate on.
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* @todo triggers assertion in MMHyperFree */
7eced415e5dd557aef2d78483b5a7785f0e13670xw for(int i=0;i<CSAM_PAGEBMP_CHUNKS;i++)
7eced415e5dd557aef2d78483b5a7785f0e13670xw * CSAM reset callback.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pVM The VM which is reset.
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* Clear page bitmaps. */
7eced415e5dd557aef2d78483b5a7785f0e13670xw for(int i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
7eced415e5dd557aef2d78483b5a7785f0e13670xw ASMMemZero32(pVM->csam.s.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* Remove all CSAM page records. */
7eced415e5dd557aef2d78483b5a7785f0e13670xw while(true)
7eced415e5dd557aef2d78483b5a7785f0e13670xw PCSAMPAGEREC pPageRec = (PCSAMPAGEREC)RTAvlPVGetBestFit(&pVM->csam.s.pPageTree, 0, true);
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Callback function for RTAvlPVDoWithAll
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Counts the number of records in the tree
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pNode Current node
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pcPatches Pointer to patch counter
7eced415e5dd557aef2d78483b5a7785f0e13670xwstatic DECLCALLBACK(int) CountRecord(PAVLPVNODECORE pNode, void *pcPatches)
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Callback function for RTAvlPVDoWithAll
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Saves the state of the page record
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pNode Current node
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pVM1 VM Handle
7eced415e5dd557aef2d78483b5a7785f0e13670xwstatic DECLCALLBACK(int) SavePageState(PAVLPVNODECORE pNode, void *pVM1)
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* Save the page record itself */
7eced415e5dd557aef2d78483b5a7785f0e13670xw rc = SSMR3PutMem(pSSM, page.page.pBitmap, CSAM_PAGE_BITMAP_SIZE);
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Execute state save operation.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pVM VM Handle.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pSSM SSM operation handle.
7eced415e5dd557aef2d78483b5a7785f0e13670xwstatic DECLCALLBACK(int) csamr3Save(PVM pVM, PSSMHANDLE pSSM)
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Count the number of page records in the tree (feeling lazy)
a23fd118e437af0a7877dd313db8fdaa3537c675yl RTAvlPVDoWithAll(&pVM->csam.s.pPageTree, true, CountRecord, &csamInfo.savedstate.cPageRecords);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Save CSAM structure
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Save pgdir bitmap */
7eced415e5dd557aef2d78483b5a7785f0e13670xw rc = SSMR3PutMem(pSSM, csamInfo.pPDBitmapHC, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR));
7eced415e5dd557aef2d78483b5a7785f0e13670xw for (unsigned i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Save the page bitmap. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3PutMem(pSSM, csamInfo.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Save page records
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = RTAvlPVDoWithAll(&pVM->csam.s.pPageTree, true, SavePageState, pVM);
a23fd118e437af0a7877dd313db8fdaa3537c675yl /** @note we don't restore aDangerousInstr; it will be recreated automatically. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Execute state load operation.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @returns VBox status code.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pVM VM Handle.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pSSM SSM operation handle.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param uVersion Data layout version.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param uPass The data pass.
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) csamr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
a23fd118e437af0a7877dd313db8fdaa3537c675yl AssertMsgFailed(("csamR3Load: Invalid version uVersion=%d!\n", uVersion));
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Restore CSAM structure
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3GetStructEx(pSSM, &csamInfo, sizeof(csamInfo), SSMSTRUCT_FLAGS_MEM_BAND_AID, &g_aCsamFields[0], NULL);
a23fd118e437af0a7877dd313db8fdaa3537c675yl pVM->csam.s.fScanningStarted = csamInfo.fScanningStarted;
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Restore dirty code page info. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl memcpy(pVM->csam.s.pvDirtyBasePage, csamInfo.pvDirtyBasePage, sizeof(pVM->csam.s.pvDirtyBasePage));
a23fd118e437af0a7877dd313db8fdaa3537c675yl memcpy(pVM->csam.s.pvDirtyFaultPage, csamInfo.pvDirtyFaultPage, sizeof(pVM->csam.s.pvDirtyFaultPage));
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Restore possible code page */
a23fd118e437af0a7877dd313db8fdaa3537c675yl pVM->csam.s.cPossibleCodePages = csamInfo.cPossibleCodePages;
a23fd118e437af0a7877dd313db8fdaa3537c675yl memcpy(pVM->csam.s.pvPossibleCodePage, csamInfo.pvPossibleCodePage, sizeof(pVM->csam.s.pvPossibleCodePage));
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Restore pgdir bitmap (we'll change the pointers next). */
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3GetMem(pSSM, pVM->csam.s.pPDBitmapHC, CSAM_PGDIRBMP_CHUNKS*sizeof(RTHCPTR));
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3GetStructEx(pSSM, pVM->csam.s.pPDBitmapHC, sizeof(uint8_t *) * CSAM_PGDIRBMP_CHUNKS,
a23fd118e437af0a7877dd313db8fdaa3537c675yl SSMSTRUCT_FLAGS_MEM_BAND_AID, &g_aCsamPDBitmapArray[0], NULL);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Restore page bitmaps
a23fd118e437af0a7877dd313db8fdaa3537c675yl for (unsigned i=0;i<CSAM_PGDIRBMP_CHUNKS;i++)
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = MMHyperAlloc(pVM, CSAM_PAGE_BITMAP_SIZE, 0, MM_TAG_CSAM, (void **)&pVM->csam.s.pPDBitmapHC[i]);
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Convert to GC pointer. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl pVM->csam.s.pPDGCBitmapHC[i] = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC[i]);
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Restore the bitmap. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3GetMem(pSSM, pVM->csam.s.pPDBitmapHC[i], CSAM_PAGE_BITMAP_SIZE);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Restore page records
a23fd118e437af0a7877dd313db8fdaa3537c675yl for (uint32_t i=0;i<csamInfo.savedstate.cPageRecords + csamInfo.savedstate.cPatchPageRecords;i++)
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3GetStructEx(pSSM, &page, sizeof(page), SSMSTRUCT_FLAGS_MEM_BAND_AID, &g_aCsamPageRecFields[0], NULL);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Recreate the page record
a23fd118e437af0a7877dd313db8fdaa3537c675yl pPage = csamCreatePageRecord(pVM, page.page.pPageGC, page.page.enmTag, page.page.fCode32, page.page.fMonitorInvalidation);
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = SSMR3GetMem(pSSM, pPage->pBitmap, CSAM_PAGE_BITMAP_SIZE);
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Note: we don't restore aDangerousInstr; it will be recreated automatically. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl memset(&pVM->csam.s.aDangerousInstr, 0, sizeof(pVM->csam.s.aDangerousInstr));
a23fd118e437af0a7877dd313db8fdaa3537c675yl * Convert guest context address to host context pointer
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @returns VBox status code.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pVM The VM to operate on.
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pCacheRec Address conversion cache record
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pGCPtr Guest context pointer
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @returns Host context pointer or NULL in case of an error
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic R3PTRTYPE(void *) CSAMGCVirtToHCVirt(PVM pVM, PCSAMP2GLOOKUPREC pCacheRec, RCPTRTYPE(uint8_t *) pGCPtr)
a23fd118e437af0a7877dd313db8fdaa3537c675yl if (pCacheRec->pGuestLoc == (pGCPtr & PAGE_BASE_GC_MASK))
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Release previous lock if any. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, pGCPtr, (const void **)&pHCPtr, &pCacheRec->Lock);
7eced415e5dd557aef2d78483b5a7785f0e13670xw//// AssertMsgRC(rc, ("MMR3PhysGCVirt2HCVirtEx failed for %RRv\n", pGCPtr));
a23fd118e437af0a7877dd313db8fdaa3537c675yl pCacheRec->pPageLocStartHC = (R3PTRTYPE(uint8_t*))((RTHCUINTPTR)pHCPtr & PAGE_BASE_HC_MASK);
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @callback_method_impl{FNDISREADBYTES}
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic DECLCALLBACK(int) CSAMR3ReadBytes(PDISCPUSTATE pDisState, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead)
a23fd118e437af0a7877dd313db8fdaa3537c675yl RTHCUINTPTR pInstrHC = (RTHCUINTPTR)pDisState->apvUserData[1];
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* We are not interested in patched instructions, so read the original opcode bytes.
a23fd118e437af0a7877dd313db8fdaa3537c675yl Note! single instruction patches (int3) are checked in CSAMR3AnalyseCallback */
7eced415e5dd557aef2d78483b5a7785f0e13670xw for (int i = 0; i < orgsize; i++)
7eced415e5dd557aef2d78483b5a7785f0e13670xw int rc = PATMR3QueryOpcode(pVM, (RTRCPTR)uSrcAddr, pbDst);
7eced415e5dd557aef2d78483b5a7785f0e13670xw if (PAGE_ADDRESS(pInstrGC) != PAGE_ADDRESS(uSrcAddr + cbToRead - 1) && !PATMIsPatchGCAddr(pVM, uSrcAddr))
7eced415e5dd557aef2d78483b5a7785f0e13670xw return PGMPhysSimpleReadGCPtr(pVCpu, pbDst, uSrcAddr, cbToRead);
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* pInstrHC is the base address; adjust according to the GC pointer. */
7eced415e5dd557aef2d78483b5a7785f0e13670xwDECLINLINE(int) CSAMR3DISInstr(PVM pVM, RTRCPTR InstrGC, uint8_t *InstrHC, DISCPUMODE enmCpuMode,
7eced415e5dd557aef2d78483b5a7785f0e13670xw PDISCPUSTATE pCpu, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput)
7eced415e5dd557aef2d78483b5a7785f0e13670xw return DISInstrToStrEx(InstrGC, enmCpuMode, CSAMR3ReadBytes, pVM, DISOPTYPE_ALL,
7eced415e5dd557aef2d78483b5a7785f0e13670xw /* We are interested in everything except harmless stuff */
7eced415e5dd557aef2d78483b5a7785f0e13670xw return DISInstrToStrEx(InstrGC, enmCpuMode, CSAMR3ReadBytes, pVM, ~(DISOPTYPE_INVALID | DISOPTYPE_HARMLESS | DISOPTYPE_RRM_MASK),
7eced415e5dd557aef2d78483b5a7785f0e13670xw return DISInstEx(InstrGC, enmCpuMode, ~(DISOPTYPE_INVALID | DISOPTYPE_HARMLESS | DISOPTYPE_RRM_MASK), CSAMR3ReadBytes, pVM,
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Analyses the instructions following the cli for compliance with our heuristics for cli
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pVM The VM to operate on.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pCpu CPU disassembly state
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pInstrGC Guest context pointer to privileged instruction
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pCurInstrGC Guest context pointer to the current instruction
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pCacheRec GC to HC cache record
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pUserData User pointer (callback specific)
7eced415e5dd557aef2d78483b5a7785f0e13670xwstatic int CSAMR3AnalyseCallback(PVM pVM, DISCPUSTATE *pCpu, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC,
7eced415e5dd557aef2d78483b5a7785f0e13670xw //two byte int 3
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* This appears to be some kind of kernel panic in Linux 2.4; no point to continue. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* removing breaks win2k guests? */
a23fd118e437af0a7877dd313db8fdaa3537c675yl // Check for exit points
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* It's not a good idea to patch pushf instructions:
a23fd118e437af0a7877dd313db8fdaa3537c675yl * - increases the chance of conflicts (code jumping to the next instruction)
a23fd118e437af0a7877dd313db8fdaa3537c675yl * - better to patch the cli
a23fd118e437af0a7877dd313db8fdaa3537c675yl * - code that branches before the cli will likely hit an int 3
a23fd118e437af0a7877dd313db8fdaa3537c675yl * - in general doesn't offer any benefits as we don't allow nested patch blocks (IF is always 1)
a23fd118e437af0a7877dd313db8fdaa3537c675yl PATMR3AddHint(pVM, pCurInstrGC, (fCode32) ? PATMFL_CODE32 : 0);
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* Make sure the instructions that follow the cli have not been encountered before. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl while (true)
a23fd118e437af0a7877dd313db8fdaa3537c675yl if (csamIsCodeScanned(pVM, pCurInstrGC + opsize, &pPage) == true)
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* We've scanned the next instruction(s) already. This means we've followed a branch that ended up there before -> dangerous!! */
a23fd118e437af0a7877dd313db8fdaa3537c675yl PATMR3DetectConflict(pVM, pCurInstrGC, pCurInstrGC + opsize);
a23fd118e437af0a7877dd313db8fdaa3537c675yl { /* Force pCurInstrHC out of scope after we stop using it (page lock!) */
a23fd118e437af0a7877dd313db8fdaa3537c675yl pCurInstrHC = (uint8_t *)CSAMGCVirtToHCVirt(pVM, pCacheRec, pCurInstrGC);
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("CSAMGCVirtToHCVirt failed for %RRv\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, (fCode32) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
a23fd118e437af0a7877dd313db8fdaa3537c675yl /* no break */
8347601bcb0a439f6e50fc36b4039a73d08700e1yl Log(("Privileged instruction at %RRv: str!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: lsl!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: lar!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: sgdt!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: sldt!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: sidt!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: smsw!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: verw!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: verr!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: cpuid!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: push cs!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Privileged instruction at %RRv: iret!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = PATMR3InstallPatch(pVM, pCurInstrGC, (pPage->fCode32) ? PATMFL_CODE32 : 0);
a23fd118e437af0a7877dd313db8fdaa3537c675yl return VINF_SUCCESS; /* Look no further in this branch. */
a23fd118e437af0a7877dd313db8fdaa3537c675yl // return or jump/call through a jump table
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Control Flow instruction at %RRv: jmp!!\n", pCurInstrGC));
a23fd118e437af0a7877dd313db8fdaa3537c675yl Log(("Control Flow instruction at %RRv: call!!\n", pCurInstrGC));
7eced415e5dd557aef2d78483b5a7785f0e13670xw * Wrapper for csamAnalyseCodeStream for call instructions.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @returns VBox status code.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pVM The VM to operate on.
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pInstrGC Guest context pointer to privileged instruction
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pCurInstrGC Guest context pointer to the current instruction
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param fCode32 16 or 32 bits code
7eced415e5dd557aef2d78483b5a7785f0e13670xw * @param pfnCSAMR3Analyse Callback for testing the disassembled instruction
a23fd118e437af0a7877dd313db8fdaa3537c675yl * @param pUserData User pointer (callback specific)
a23fd118e437af0a7877dd313db8fdaa3537c675ylstatic int csamAnalyseCallCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
a23fd118e437af0a7877dd313db8fdaa3537c675yl PFN_CSAMR3ANALYSE pfnCSAMR3Analyse, void *pUserData, PCSAMP2GLOOKUPREC pCacheRec)
a23fd118e437af0a7877dd313db8fdaa3537c675yl rc = csamAnalyseCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
int rc2;
#ifdef DEBUG
goto done;
goto done;
#ifdef DEBUG
rc2 = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, (fCode32) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
rc2 = CSAMR3DISInstr(pVM, pCurInstrGC, pCurInstrHC, (fCode32) ? DISCPUMODE_32BIT : DISCPUMODE_16BIT,
Log(("Disassembly failed at %RRv with %Rrc (probably page not present) -> return to caller\n", pCurInstrGC, rc2));
goto done;
goto done;
case OP_NOP:
case OP_INT3:
case OP_LEA:
goto next_function;
case OP_PUSH:
goto next_function;
csamAnalyseCallCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
goto next_function;
case OP_SUB:
goto next_function;
csamAnalyseCallCodeStream(pVM, pInstrGC, pCurInstrGC, fCode32, pfnCSAMR3Analyse, pUserData, pCacheRec);
goto next_function;
goto next_function;
done:
return rc;
* Disassembles the code stream until the callback function detects a failure or decides everything is acceptable
static int csamAnalyseCodeStream(PVM pVM, RCPTRTYPE(uint8_t *) pInstrGC, RCPTRTYPE(uint8_t *) pCurInstrGC, bool fCode32,
int rc2;
#ifdef DEBUG
goto done;
goto done;
goto done;
#ifdef DEBUG
Log(("Disassembly failed at %RRv with %Rrc (probably page not present) -> return to caller\n", pCurInstrGC, rc2));
goto done;
goto next_please;
AssertMsg(pfnCSAMR3Analyse(pVM, &cpu, pInstrGC, pCurInstrGC, pCacheRec, (void *)pPage) == VWRN_CONTINUE_ANALYSIS, ("Instruction incorrectly marked harmless?!?!?\n"));
goto next_please;
#ifdef CSAM_ANALYSE_BEYOND_RET
/* Remember the address of the instruction following the ret in case the parent instruction was a call. */
pCacheRec->pCallExitRec->pInstrAfterRetGC[pCacheRec->pCallExitRec->cInstrAfterRet] = pCurInstrGC + opsize;
goto done;
// For our first attempt, we'll handle only simple relative jumps and calls (immediate offset coded in instruction)
if ( ((cpu.pCurInstr->optype & DISOPTYPE_CONTROLFLOW) && (OP_PARM_VTYPE(cpu.pCurInstr->param1) == OP_PARM_J))
|| (cpu.pCurInstr->opcode == OP_CALL && cpu.param1.flags == DISUSE_DISPLACEMENT32)) /* simple indirect call (call dword ptr [address]) */
/* 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) */
addr = 0;
if (addr == 0)
goto next_please;
goto done;
rc = csamAnalyseCallCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
rc = csamAnalyseCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
goto done;
goto done;
} //if ((cpu.pCurInstr->optype & DISOPTYPE_CONTROLFLOW) && (OP_PARM_VTYPE(cpu.pCurInstr->param1) == OP_PARM_J))
#ifdef CSAM_SCAN_JUMP_TABLE
&& (cpu.param1.flags & (DISUSE_DISPLACEMENT32|DISUSE_INDEX|DISUSE_SCALE)) == (DISUSE_DISPLACEMENT32|DISUSE_INDEX|DISUSE_SCALE)
int rc2;
goto done;
rc = csamAnalyseCodeStream(pVM, pInstrGC, addr, fCode32, pfnCSAMR3Analyse, (void *)pJmpPage, pCacheRec);
goto done;
goto done;
done:
return rc;
int rc;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return ~0ULL;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return ~0ULL;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return ~0ULL;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return ~0ULL;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return ~0ULL;
int rc;
return VINF_SUCCESS;
* Note: searching for the page in our tree first is more expensive (skipped flushes are two orders of magnitude more common)
return VWRN_CSAM_PAGE_NOT_FOUND;
return rc;
return VINF_SUCCESS;
if (pPageRec)
return VINF_SUCCESS;
Log(("CSAMR3FlushPage: page %RRv has changed -> FLUSH (rc=%Rrc) (Phys: %RGp vs %RGp)\n", addr, rc, GCPhys, pPageRec->page.GCPhys));
if (fRemovePage)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return VWRN_CSAM_PAGE_NOT_FOUND;
int rc;
if (pPageRec)
return VINF_SUCCESS;
return VWRN_CSAM_PAGE_NOT_FOUND;
if (pPageRec)
return VWRN_CSAM_PAGE_NOT_FOUND;
return VINF_SUCCESS;
static PCSAMPAGE csamCreatePageRecord(PVM pVM, RTRCPTR GCPtr, CSAMTAG enmTag, bool fCode32, bool fMonitorInvalidation)
int rc;
bool ret;
return NULL;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
#ifdef CSAM_MONITOR_CODE_PAGES
switch (enmTag)
case CSAM_TAG_PATM:
case CSAM_TAG_REM:
#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
case CSAM_TAG_CSAM:
rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtr, GCPtr + (PAGE_SIZE - 1) /* inclusive! */,
(fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %RRv failed with %Rrc\n", GCPtr, rc));
#ifdef VBOX_WITH_STATISTICS
switch (enmTag)
case CSAM_TAG_CSAM:
case CSAM_TAG_PATM:
case CSAM_TAG_REM:
if (fMonitorInvalidation)
int rc;
bool fMonitorInvalidation;
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return VINF_SUCCESS;
#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
#ifdef CSAM_MONITOR_CODE_PAGES
rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, pPageAddrGC, pPageAddrGC + (PAGE_SIZE - 1) /* inclusive! */,
(fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %RRv failed with %Rrc\n", pPageAddrGC, rc));
// || (pPageRec->page.GCPhys == 0), ("Shadow page flags for %RRv (%RHp) aren't readonly (%RX64)!!\n", pPageAddrGC, GCPhys, fPageShw));
/* The page was changed behind our back. It won't be made read-only until the next SyncCR3, so force it here. */
return VINF_SUCCESS;
#ifdef VBOX_STRICT
if (pPageRec)
#ifdef CSAM_MONITOR_CODE_PAGES
#ifdef VBOX_WITH_STATISTICS
case CSAM_TAG_CSAM:
case CSAM_TAG_PATM:
case CSAM_TAG_REM:
AssertFailed();
return VINF_SUCCESS;
static DECLCALLBACK(int) CSAMCodePageWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
int rc;
return VINF_PGM_HANDLER_DO_DEFAULT;
rc = VMR3ReqCallVoidNoWait(pVM, VMCPUID_ANY, (PFNRT)CSAMDelayedWriteHandler, 3, pVM, (RTRCPTR)GCPtr, cbBuf);
return VINF_PGM_HANDLER_DO_DEFAULT;
fInCSAMCodePageInvalidate = true;
/** @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. */
fInCSAMCodePageInvalidate = false;
return VINF_SUCCESS;
if (pPageRec)
if (fScanned)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
Assert(SELMGetCpuModeFromSelector(VMMGetCpu0(pVM), pCtxCore->eflags, pCtxCore->cs, &pCtxCore->csHid) == DISCPUMODE_32BIT);
return VINF_SUCCESS;
int rc;
return VINF_SUCCESS;
rc = csamAnalyseCallCodeStream(pVM, pInstrGC, pInstrGC, true /* 32 bits code */, CSAMR3AnalyseCallback, pPage, &cacheRec);
return rc;
return VINF_SUCCESS;
int rc;
#ifdef VBOX_WITH_REM
Log(("CSAMR3FlushDirtyPages: flush %RRv (modifypage rc=%Rrc)\n", pVM->csam.s.pvDirtyBasePage[i], rc));
AssertMsg(RT_SUCCESS(rc) || rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("rc = %Rrc\n", rc));
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
int rc;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
if (pHandler)
return VERR_INVALID_PARAMETER;
return rc;
&& (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32 || pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
Log(("CSAMCheckGates: check gate %d failed due to rc %Rrc GCPtrBase=%RRv limit=%x\n", iGate, rc, selInfo.GCPtrBase, selInfo.cbLimit));
Log(("CSAMCheckGates: check trap gate %d at %04X:%08X (flat %RRv)\n", iGate, pGuestIdte->Gen.u16SegSel, VBOXIDTE_OFFSET(*pGuestIdte), pHandler));
Log(("CSAMCheckGates: check interrupt gate %d at %04X:%08X (flat %RRv)\n", iGate, pGuestIdte->Gen.u16SegSel, VBOXIDTE_OFFSET(*pGuestIdte), pHandler));
rc = PATMR3InstallPatch(pVM, pHandler - aOpenBsdPushCSOffset[i], PATMFL_CODE32 | PATMFL_GUEST_SPECIFIC);
switch (iGate) {
Log(("Installing %s gate handler for 0x%X at %RRv\n", (pGuestIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32) ? "trap" : "intr", iGate, pHandler));
if (pNewHandlerGC)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef VBOX_WITH_DEBUGGER
static DECLCALLBACK(int) csamr3CmdOff(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
static DECLCALLBACK(int) csamr3CmdOn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)