VirtualBox

source: vbox/trunk/src/VBox/VMM/PGMGst.h@ 17425

Last change on this file since 17425 was 17215, checked in by vboxsync, 16 years ago

Split up the definitions and the guest code. Otherwise we'll end up using e.g. wrong masks in Bth code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.7 KB
Line 
1/* $Id: PGMGst.h 17215 2009-02-27 16:33:19Z vboxsync $ */
2/** @file
3 * VBox - Page Manager / Monitor, Guest Paging Template.
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* Internal Functions *
25*******************************************************************************/
26__BEGIN_DECLS
27/* r3 */
28PGM_GST_DECL(int, InitData)(PVM pVM, PPGMMODEDATA pModeData, bool fResolveGCAndR0);
29PGM_GST_DECL(int, Enter)(PVM pVM, RTGCPHYS GCPhysCR3);
30PGM_GST_DECL(int, Relocate)(PVM pVM, RTGCPTR offDelta);
31PGM_GST_DECL(int, Exit)(PVM pVM);
32
33#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
34static DECLCALLBACK(int) pgmR3Gst32BitWriteHandlerCR3(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
35static DECLCALLBACK(int) pgmR3GstPAEWriteHandlerCR3(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
36#endif
37
38/* all */
39PGM_GST_DECL(int, GetPage)(PVM pVM, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys);
40PGM_GST_DECL(int, ModifyPage)(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask);
41PGM_GST_DECL(int, GetPDE)(PVM pVM, RTGCPTR GCPtr, PX86PDEPAE pPDE);
42#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
43PGM_GST_DECL(int, MonitorCR3)(PVM pVM, RTGCPHYS GCPhysCR3);
44PGM_GST_DECL(int, UnmonitorCR3)(PVM pVM);
45#endif
46__END_DECLS
47
48
49/**
50 * Initializes the guest bit of the paging mode data.
51 *
52 * @returns VBox status code.
53 * @param pVM The VM handle.
54 * @param fResolveGCAndR0 Indicate whether or not GC and Ring-0 symbols can be resolved now.
55 * This is used early in the init process to avoid trouble with PDM
56 * not being initialized yet.
57 */
58PGM_GST_DECL(int, InitData)(PVM pVM, PPGMMODEDATA pModeData, bool fResolveGCAndR0)
59{
60 Assert(pModeData->uGstType == PGM_GST_TYPE);
61
62 /* Ring-3 */
63 pModeData->pfnR3GstRelocate = PGM_GST_NAME(Relocate);
64 pModeData->pfnR3GstExit = PGM_GST_NAME(Exit);
65 pModeData->pfnR3GstGetPDE = PGM_GST_NAME(GetPDE);
66 pModeData->pfnR3GstGetPage = PGM_GST_NAME(GetPage);
67 pModeData->pfnR3GstModifyPage = PGM_GST_NAME(ModifyPage);
68#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
69 pModeData->pfnR3GstMonitorCR3 = PGM_GST_NAME(MonitorCR3);
70 pModeData->pfnR3GstUnmonitorCR3 = PGM_GST_NAME(UnmonitorCR3);
71#endif
72
73#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
74# if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE
75 pModeData->pfnR3GstWriteHandlerCR3 = PGM_GST_NAME(WriteHandlerCR3);
76 pModeData->pszR3GstWriteHandlerCR3 = "Guest CR3 Write access handler";
77 pModeData->pfnR3GstPAEWriteHandlerCR3 = PGM_GST_NAME(WriteHandlerCR3);
78 pModeData->pszR3GstPAEWriteHandlerCR3 = "Guest CR3 Write access handler (PAE)";
79# else
80 pModeData->pfnR3GstWriteHandlerCR3 = NULL;
81 pModeData->pszR3GstWriteHandlerCR3 = NULL;
82 pModeData->pfnR3GstPAEWriteHandlerCR3 = NULL;
83 pModeData->pszR3GstPAEWriteHandlerCR3 = NULL;
84# endif
85#endif
86
87 if (fResolveGCAndR0)
88 {
89 int rc;
90
91#if PGM_SHW_TYPE != PGM_TYPE_AMD64 /* No AMD64 for traditional virtualization, only VT-x and AMD-V. */
92 /* GC */
93 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(GetPage), &pModeData->pfnRCGstGetPage);
94 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(GetPage), rc), rc);
95 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(ModifyPage), &pModeData->pfnRCGstModifyPage);
96 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(ModifyPage), rc), rc);
97 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(GetPDE), &pModeData->pfnRCGstGetPDE);
98 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(GetPDE), rc), rc);
99# ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
100 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(MonitorCR3), &pModeData->pfnRCGstMonitorCR3);
101 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(MonitorCR3), rc), rc);
102 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(UnmonitorCR3), &pModeData->pfnRCGstUnmonitorCR3);
103 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(UnmonitorCR3), rc), rc);
104# endif
105# ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
106# if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE
107 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(WriteHandlerCR3), &pModeData->pfnRCGstWriteHandlerCR3);
108 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(WriteHandlerCR3), rc), rc);
109 rc = PDMR3LdrGetSymbolRC(pVM, NULL, PGM_GST_NAME_RC_STR(WriteHandlerCR3), &pModeData->pfnRCGstPAEWriteHandlerCR3);
110 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_RC_STR(WriteHandlerCR3), rc), rc);
111# endif
112# endif
113#endif /* Not AMD64 shadow paging. */
114
115 /* Ring-0 */
116 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(GetPage), &pModeData->pfnR0GstGetPage);
117 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(GetPage), rc), rc);
118 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(ModifyPage), &pModeData->pfnR0GstModifyPage);
119 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(ModifyPage), rc), rc);
120 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(GetPDE), &pModeData->pfnR0GstGetPDE);
121 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(GetPDE), rc), rc);
122#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
123 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(MonitorCR3), &pModeData->pfnR0GstMonitorCR3);
124 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(MonitorCR3), rc), rc);
125 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(UnmonitorCR3), &pModeData->pfnR0GstUnmonitorCR3);
126 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(UnmonitorCR3), rc), rc);
127#endif
128#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
129# if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE
130 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(WriteHandlerCR3), &pModeData->pfnR0GstWriteHandlerCR3);
131 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(WriteHandlerCR3), rc), rc);
132 rc = PDMR3LdrGetSymbolR0(pVM, NULL, PGM_GST_NAME_R0_STR(WriteHandlerCR3), &pModeData->pfnR0GstPAEWriteHandlerCR3);
133 AssertMsgRCReturn(rc, ("%s -> rc=%Rrc\n", PGM_GST_NAME_R0_STR(WriteHandlerCR3), rc), rc);
134# endif
135#endif
136 }
137
138 return VINF_SUCCESS;
139}
140
141
142/**
143 * Enters the guest mode.
144 *
145 * @returns VBox status code.
146 * @param pVM VM handle.
147 * @param GCPhysCR3 The physical address from the CR3 register.
148 */
149PGM_GST_DECL(int, Enter)(PVM pVM, RTGCPHYS GCPhysCR3)
150{
151 /*
152 * Map and monitor CR3
153 */
154#ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
155 int rc = PGM_BTH_PFN(MapCR3, pVM)(pVM, GCPhysCR3);
156#else
157 int rc = PGM_BTH_NAME(MapCR3)(pVM, GCPhysCR3);
158 if (RT_SUCCESS(rc) && !pVM->pgm.s.fMappingsFixed)
159 rc = PGM_GST_NAME(MonitorCR3)(pVM, GCPhysCR3);
160#endif
161 return rc;
162}
163
164
165/**
166 * Relocate any GC pointers related to guest mode paging.
167 *
168 * @returns VBox status code.
169 * @param pVM The VM handle.
170 * @param offDelta The reloation offset.
171 */
172PGM_GST_DECL(int, Relocate)(PVM pVM, RTGCPTR offDelta)
173{
174 /* nothing special to do here - InitData does the job. */
175 return VINF_SUCCESS;
176}
177
178
179/**
180 * Exits the guest mode.
181 *
182 * @returns VBox status code.
183 * @param pVM VM handle.
184 */
185PGM_GST_DECL(int, Exit)(PVM pVM)
186{
187 int rc;
188
189#ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
190 rc = PGM_BTH_PFN(UnmapCR3, pVM)(pVM);
191#else
192 rc = PGM_GST_NAME(UnmonitorCR3)(pVM);
193 if (RT_SUCCESS(rc))
194 rc = PGM_BTH_NAME(UnmapCR3)(pVM);
195#endif
196 return rc;
197}
198
199
200#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
201
202#if PGM_GST_TYPE == PGM_TYPE_32BIT
203/**
204 * Physical write access for the Guest CR3 in 32-bit mode.
205 *
206 * @returns VINF_SUCCESS if the handler have carried out the operation.
207 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
208 * @param pVM VM Handle.
209 * @param GCPhys The physical address the guest is writing to.
210 * @param pvPhys The HC mapping of that address.
211 * @param pvBuf What the guest is reading/writing.
212 * @param cbBuf How much it's reading/writing.
213 * @param enmAccessType The access type.
214 * @param pvUser User argument.
215 */
216static DECLCALLBACK(int) pgmR3Gst32BitWriteHandlerCR3(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
217{
218 AssertMsg(!pVM->pgm.s.fMappingsFixed, ("Shouldn't be registered when mappings are fixed!\n"));
219 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
220 Log2(("pgmR3Gst32BitWriteHandlerCR3: ff=%#x GCPhys=%RGp pvPhys=%p cbBuf=%d pvBuf={%.*Rhxs}\n", pVM->fForcedActions, GCPhys, pvPhys, cbBuf, cbBuf, pvBuf));
221
222 /*
223 * Do the write operation.
224 */
225 memcpy(pvPhys, pvBuf, cbBuf);
226 if ( !pVM->pgm.s.fMappingsFixed
227 && !VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL))
228 {
229 /*
230 * Check for conflicts.
231 */
232 const RTGCPTR offPD = GCPhys & PAGE_OFFSET_MASK;
233 const unsigned iPD1 = offPD / sizeof(X86PDE);
234 const unsigned iPD2 = (unsigned)(offPD + cbBuf - 1) / sizeof(X86PDE);
235 Assert(iPD1 - iPD2 <= 1);
236 if ( ( pVM->pgm.s.pGst32BitPdR3->a[iPD1].n.u1Present
237 && pgmGetMapping(pVM, iPD1 << X86_PD_SHIFT) )
238 || ( iPD1 != iPD2
239 && pVM->pgm.s.pGst32BitPdR3->a[iPD2].n.u1Present
240 && pgmGetMapping(pVM, iPD2 << X86_PD_SHIFT) )
241 )
242 {
243 Log(("pgmR3Gst32BitWriteHandlerCR3: detected conflict. iPD1=%#x iPD2=%#x GCPhys=%RGp\n", iPD1, iPD2, GCPhys));
244 STAM_COUNTER_INC(&pVM->pgm.s.StatR3GuestPDWriteConflict);
245 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
246 }
247 }
248
249 STAM_COUNTER_INC(&pVM->pgm.s.StatR3GuestPDWrite);
250 return VINF_SUCCESS;
251}
252#endif /* 32BIT */
253
254#if PGM_GST_TYPE == PGM_TYPE_PAE
255
256/**
257 * Physical write access handler for the Guest CR3 in PAE mode.
258 *
259 * @returns VINF_SUCCESS if the handler have carried out the operation.
260 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
261 * @param pVM VM Handle.
262 * @param GCPhys The physical address the guest is writing to.
263 * @param pvPhys The HC mapping of that address.
264 * @param pvBuf What the guest is reading/writing.
265 * @param cbBuf How much it's reading/writing.
266 * @param enmAccessType The access type.
267 * @param pvUser User argument.
268 */
269static DECLCALLBACK(int) pgmR3GstPAEWriteHandlerCR3(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
270{
271 AssertMsg(!pVM->pgm.s.fMappingsFixed, ("Shouldn't be registered when mappings are fixed!\n"));
272 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
273 Log2(("pgmR3GstPAEWriteHandlerCR3: ff=%#x GCPhys=%RGp pvPhys=%p cbBuf=%d pvBuf={%.*Rhxs}\n", pVM->fForcedActions, GCPhys, pvPhys, cbBuf, cbBuf, pvBuf));
274
275 /*
276 * Do the write operation.
277 */
278 memcpy(pvPhys, pvBuf, cbBuf);
279 if ( !pVM->pgm.s.fMappingsFixed
280 && !VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL))
281 {
282 /*
283 * Check if any of the PDs have changed.
284 * We'll simply check all of them instead of figuring out which one/two to check.
285 */
286 for (unsigned i = 0; i < 4; i++)
287 {
288 if ( pVM->pgm.s.pGstPaePdptR3->a[i].n.u1Present
289 && (pVM->pgm.s.pGstPaePdptR3->a[i].u & X86_PDPE_PG_MASK) != pVM->pgm.s.aGCPhysGstPaePDsMonitored[i])
290 {
291 Log(("pgmR3GstPAEWriteHandlerCR3: detected updated PDPE; [%d] = %#llx, Old GCPhys=%RGp\n",
292 i, pVM->pgm.s.pGstPaePdptR3->a[i].u, pVM->pgm.s.aGCPhysGstPaePDsMonitored[i]));
293 /*
294 * The PD has changed.
295 * We will schedule a monitoring update for the next TLB Flush,
296 * InvalidatePage or SyncCR3.
297 *
298 * This isn't perfect, because a lazy page sync might be dealing with an half
299 * updated PDPE. However, we assume that the guest OS is disabling interrupts
300 * and being extremely careful (cmpxchg8b) when updating a PDPE where it's
301 * executing.
302 */
303 pVM->pgm.s.fSyncFlags |= PGM_SYNC_MONITOR_CR3;
304 }
305 }
306 }
307 /*
308 * Flag a updating of the monitor at the next crossroad so we don't monitor the
309 * wrong pages for soo long that they can be reused as code pages and freak out
310 * the recompiler or something.
311 */
312 else
313 pVM->pgm.s.fSyncFlags |= PGM_SYNC_MONITOR_CR3;
314
315
316 STAM_COUNTER_INC(&pVM->pgm.s.StatR3GuestPDWrite);
317 return VINF_SUCCESS;
318}
319
320#endif /* PAE */
321#endif /* !VBOX_WITH_PGMPOOL_PAGING_ONLY */
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