VirtualBox

source: vbox/trunk/src/VBox/VMM/PATM/VMMAll/CSAMAll.cpp@ 19360

Last change on this file since 19360 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.8 KB
Line 
1/* $Id: CSAMAll.cpp 19141 2009-04-23 13:52:18Z vboxsync $ */
2/** @file
3 * CSAM - Guest OS Code Scanning and Analysis Manager - Any Context
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_CSAM
27#include <VBox/cpum.h>
28#include <VBox/stam.h>
29#include <VBox/patm.h>
30#include <VBox/csam.h>
31#include <VBox/pgm.h>
32#include <VBox/mm.h>
33#include <VBox/sup.h>
34#include <VBox/mm.h>
35#include <VBox/param.h>
36#include <iprt/avl.h>
37#include "CSAMInternal.h"
38#include <VBox/vm.h>
39#include <VBox/vmm.h>
40#include <VBox/dbg.h>
41#include <VBox/err.h>
42#include <VBox/log.h>
43#include <iprt/assert.h>
44#include <VBox/dis.h>
45#include <VBox/disopcode.h>
46#include <iprt/string.h>
47#include <iprt/asm.h>
48
49/**
50 * Check if this page needs to be analysed by CSAM
51 *
52 * @returns VBox status code
53 * @param pVM The VM to operate on.
54 * @param pvFault Fault address
55 */
56VMMDECL(int) CSAMExecFault(PVM pVM, RTRCPTR pvFault)
57{
58 if(!CSAMIsEnabled(pVM))
59 return VINF_SUCCESS;
60
61 LogFlow(("CSAMGCExecFault: for page %08X scanned=%d\n", pvFault, CSAMIsPageScanned(pVM, pvFault)));
62
63 if(CSAMIsPageScanned(pVM, pvFault))
64 {
65 // Already checked!
66 STAM_COUNTER_ADD(&pVM->csam.s.StatNrKnownPagesGC, 1);
67 return VINF_SUCCESS;
68 }
69
70 STAM_COUNTER_ADD(&pVM->csam.s.StatNrTraps, 1);
71 VMCPU_FF_SET(VMMGetCpu0(pVM), VMCPU_FF_CSAM_SCAN_PAGE);
72 return VINF_CSAM_PENDING_ACTION;
73}
74
75
76/**
77 * Check if this page was previously scanned by CSAM
78 *
79 * @returns true -> scanned, false -> not scanned
80 * @param pVM The VM to operate on.
81 * @param pPage GC page address
82 */
83VMMDECL(bool) CSAMIsPageScanned(PVM pVM, RTRCPTR pPage)
84{
85 int pgdir, bit;
86 uintptr_t page;
87
88 page = (uintptr_t)pPage;
89 pgdir = page >> X86_PAGE_4M_SHIFT;
90 bit = (page & X86_PAGE_4M_OFFSET_MASK) >> X86_PAGE_4K_SHIFT;
91
92 Assert(pgdir < CSAM_PGDIRBMP_CHUNKS);
93 Assert(bit < PAGE_SIZE);
94
95 return pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir] && ASMBitTest((void *)pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir], bit);
96}
97
98
99
100/**
101 * Mark a page as scanned/not scanned
102 *
103 * @note: we always mark it as scanned, even if we haven't completely done so
104 *
105 * @returns VBox status code.
106 * @param pVM The VM to operate on.
107 * @param pPage GC page address (not necessarily aligned)
108 * @param fScanned Mark as scanned or not scanned
109 *
110 */
111VMMDECL(int) CSAMMarkPage(PVM pVM, RTRCPTR pPage, bool fScanned)
112{
113 int pgdir, bit;
114 uintptr_t page;
115
116#ifdef LOG_ENABLED
117 if (fScanned && !CSAMIsPageScanned(pVM, pPage))
118 Log(("CSAMMarkPage %RRv\n", pPage));
119#endif
120
121 if(!CSAMIsEnabled(pVM))
122 return VINF_SUCCESS;
123
124 page = (uintptr_t)pPage;
125 pgdir = page >> X86_PAGE_4M_SHIFT;
126 bit = (page & X86_PAGE_4M_OFFSET_MASK) >> X86_PAGE_4K_SHIFT;
127
128 Assert(pgdir < CSAM_PGDIRBMP_CHUNKS);
129 Assert(bit < PAGE_SIZE);
130
131 if(!CTXSUFF(pVM->csam.s.pPDBitmap)[pgdir])
132 {
133 STAM_COUNTER_INC(&pVM->csam.s.StatBitmapAlloc);
134 int rc = MMHyperAlloc(pVM, CSAM_PAGE_BITMAP_SIZE, 0, MM_TAG_CSAM, (void **)&pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir]);
135 if (RT_FAILURE(rc))
136 {
137 Log(("MMR3HyperAlloc failed with %d\n", rc));
138 return rc;
139 }
140#ifdef IN_RC
141 pVM->csam.s.pPDHCBitmapGC[pgdir] = MMHyperRCToR3(pVM, (RCPTRTYPE(void*))pVM->csam.s.pPDBitmapGC[pgdir]);
142 if (!pVM->csam.s.pPDHCBitmapGC[pgdir])
143 {
144 Log(("MMHyperHC2GC failed for %RRv\n", pVM->csam.s.pPDBitmapGC[pgdir]));
145 return rc;
146 }
147#else
148 pVM->csam.s.pPDGCBitmapHC[pgdir] = MMHyperR3ToRC(pVM, pVM->csam.s.pPDBitmapHC[pgdir]);
149 if (!pVM->csam.s.pPDGCBitmapHC[pgdir])
150 {
151 Log(("MMHyperHC2GC failed for %RHv\n", pVM->csam.s.pPDBitmapHC[pgdir]));
152 return rc;
153 }
154#endif
155 }
156 if(fScanned)
157 ASMBitSet((void *)pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir], bit);
158 else
159 ASMBitClear((void *)pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir], bit);
160
161 return VINF_SUCCESS;
162}
163
164/**
165 * Check if this page needs to be analysed by CSAM.
166 *
167 * This function should only be called for supervisor pages and
168 * only when CSAM is enabled. Leaving these selection criteria
169 * to the caller simplifies the interface (PTE passing).
170 *
171 * Note that the page has not yet been synced, so the TLB trick
172 * (which wasn't ever active anyway) cannot be applied.
173 *
174 * @returns true if the page should be marked not present because
175 * CSAM want need to scan it.
176 * @returns false if the page was already scanned.
177 * @param pVM The VM to operate on.
178 * @param GCPtr GC pointer of page
179 */
180VMMDECL(bool) CSAMDoesPageNeedScanning(PVM pVM, RTRCPTR GCPtr)
181{
182 if(!CSAMIsEnabled(pVM))
183 return false;
184
185 if(CSAMIsPageScanned(pVM, GCPtr))
186 {
187 /* Already checked! */
188 STAM_COUNTER_ADD(&CTXSUFF(pVM->csam.s.StatNrKnownPages), 1);
189 return false;
190 }
191 STAM_COUNTER_ADD(&CTXSUFF(pVM->csam.s.StatNrPageNP), 1);
192 return true;
193}
194
195
196/**
197 * Remember a possible code page for later inspection
198 *
199 * @returns VBox status code.
200 * @param pVM The VM to operate on.
201 * @param GCPtr GC pointer of page
202 */
203VMMDECL(void) CSAMMarkPossibleCodePage(PVM pVM, RTRCPTR GCPtr)
204{
205 if (pVM->csam.s.cPossibleCodePages < RT_ELEMENTS(pVM->csam.s.pvPossibleCodePage))
206 {
207 pVM->csam.s.pvPossibleCodePage[pVM->csam.s.cPossibleCodePages++] = (RTRCPTR)GCPtr;
208 VMCPU_FF_SET(VMMGetCpu0(pVM), VMCPU_FF_CSAM_PENDING_ACTION);
209 }
210 return;
211}
212
213
214/**
215 * Turn on code scanning
216 *
217 * @returns VBox status code.
218 * @param pVM The VM to operate on.
219 */
220VMMDECL(int) CSAMEnableScanning(PVM pVM)
221{
222 pVM->fCSAMEnabled = true;
223 return VINF_SUCCESS;
224}
225
226/**
227 * Turn off code scanning
228 *
229 * @returns VBox status code.
230 * @param pVM The VM to operate on.
231 */
232VMMDECL(int) CSAMDisableScanning(PVM pVM)
233{
234 pVM->fCSAMEnabled = false;
235 return VINF_SUCCESS;
236}
237
238
239/**
240 * Check if we've scanned this instruction before. If true, then we can emulate
241 * it instead of returning to ring 3.
242 *
243 * Using a simple array here as there are generally few mov crx instructions and
244 * tree lookup is likely to be more expensive. (as it would also have to be offset based)
245 *
246 * @returns boolean
247 * @param pVM The VM to operate on.
248 * @param GCPtr GC pointer of page table entry
249 */
250VMMDECL(bool) CSAMIsKnownDangerousInstr(PVM pVM, RTRCPTR GCPtr)
251{
252 for (uint32_t i=0;i<pVM->csam.s.cDangerousInstr;i++)
253 {
254 if (pVM->csam.s.aDangerousInstr[i] == (RTRCPTR)GCPtr)
255 {
256 STAM_COUNTER_INC(&pVM->csam.s.StatInstrCacheHit);
257 return true;
258 }
259 }
260 /* Record that we're about to process it in ring 3. */
261 pVM->csam.s.aDangerousInstr[pVM->csam.s.iDangerousInstr++] = (RTRCPTR)GCPtr;
262 pVM->csam.s.iDangerousInstr &= CSAM_MAX_DANGR_INSTR_MASK;
263
264 if (++pVM->csam.s.cDangerousInstr > CSAM_MAX_DANGR_INSTR)
265 pVM->csam.s.cDangerousInstr = CSAM_MAX_DANGR_INSTR;
266
267 STAM_COUNTER_INC(&pVM->csam.s.StatInstrCacheMiss);
268 return false;
269}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette