VirtualBox

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

Last change on this file since 41829 was 41801, checked in by vboxsync, 12 years ago

Doxygen.

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

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