VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllGst.h@ 72207

Last change on this file since 72207 was 69474, checked in by vboxsync, 7 years ago

*: scm updates - header files should have 'svn:keywords=Id Revision' too (doesn't mean they have to use them).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 26.4 KB
Line 
1/* $Id: PGMAllGst.h 69474 2017-10-28 13:12:06Z vboxsync $ */
2/** @file
3 * VBox - Page Manager, Guest Paging Template - All context code.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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* Internal Functions *
21*******************************************************************************/
22RT_C_DECLS_BEGIN
23#if PGM_GST_TYPE == PGM_TYPE_32BIT \
24 || PGM_GST_TYPE == PGM_TYPE_PAE \
25 || PGM_GST_TYPE == PGM_TYPE_AMD64
26static int PGM_GST_NAME(Walk)(PVMCPU pVCpu, RTGCPTR GCPtr, PGSTPTWALK pWalk);
27#endif
28PGM_GST_DECL(int, GetPage)(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys);
29PGM_GST_DECL(int, ModifyPage)(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask);
30PGM_GST_DECL(int, GetPDE)(PVMCPU pVCpu, RTGCPTR GCPtr, PX86PDEPAE pPDE);
31PGM_GST_DECL(bool, HandlerVirtualUpdate)(PVM pVM, uint32_t cr4);
32RT_C_DECLS_END
33
34
35#if PGM_GST_TYPE == PGM_TYPE_32BIT \
36 || PGM_GST_TYPE == PGM_TYPE_PAE \
37 || PGM_GST_TYPE == PGM_TYPE_AMD64
38
39
40DECLINLINE(int) PGM_GST_NAME(WalkReturnNotPresent)(PVMCPU pVCpu, PGSTPTWALK pWalk, int iLevel)
41{
42 NOREF(iLevel); NOREF(pVCpu);
43 pWalk->Core.fNotPresent = true;
44 pWalk->Core.uLevel = (uint8_t)iLevel;
45 return VERR_PAGE_TABLE_NOT_PRESENT;
46}
47
48DECLINLINE(int) PGM_GST_NAME(WalkReturnBadPhysAddr)(PVMCPU pVCpu, PGSTPTWALK pWalk, int rc, int iLevel)
49{
50 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc); NOREF(pVCpu);
51 pWalk->Core.fBadPhysAddr = true;
52 pWalk->Core.uLevel = (uint8_t)iLevel;
53 return VERR_PAGE_TABLE_NOT_PRESENT;
54}
55
56DECLINLINE(int) PGM_GST_NAME(WalkReturnRsvdError)(PVMCPU pVCpu, PGSTPTWALK pWalk, int iLevel)
57{
58 NOREF(pVCpu);
59 pWalk->Core.fRsvdError = true;
60 pWalk->Core.uLevel = (uint8_t)iLevel;
61 return VERR_PAGE_TABLE_NOT_PRESENT;
62}
63
64
65/**
66 * Performs a guest page table walk.
67 *
68 * @returns VBox status code.
69 * @retval VINF_SUCCESS on success.
70 * @retval VERR_PAGE_TABLE_NOT_PRESENT on failure. Check pWalk for details.
71 *
72 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
73 * @param GCPtr The guest virtual address to walk by.
74 * @param pWalk Where to return the walk result. This is always set.
75 */
76DECLINLINE(int) PGM_GST_NAME(Walk)(PVMCPU pVCpu, RTGCPTR GCPtr, PGSTPTWALK pWalk)
77{
78 int rc;
79
80 /*
81 * Init the walking structure.
82 */
83 RT_ZERO(*pWalk);
84 pWalk->Core.GCPtr = GCPtr;
85
86# if PGM_GST_TYPE == PGM_TYPE_32BIT \
87 || PGM_GST_TYPE == PGM_TYPE_PAE
88 /*
89 * Boundary check for PAE and 32-bit (prevents trouble further down).
90 */
91 if (RT_UNLIKELY(GCPtr >= _4G))
92 return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 8);
93# endif
94
95 uint32_t register fEffective = X86_PTE_RW | X86_PTE_US | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A | 1;
96 {
97# if PGM_GST_TYPE == PGM_TYPE_AMD64
98 /*
99 * The PMLE4.
100 */
101 rc = pgmGstGetLongModePML4PtrEx(pVCpu, &pWalk->pPml4);
102 if (RT_SUCCESS(rc)) { /* probable */ }
103 else return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 4, rc);
104
105 PX86PML4E register pPml4e;
106 pWalk->pPml4e = pPml4e = &pWalk->pPml4->a[(GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK];
107 X86PML4E register Pml4e;
108 pWalk->Pml4e.u = Pml4e.u = pPml4e->u;
109
110 if (Pml4e.n.u1Present) { /* probable */ }
111 else return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 4);
112
113 if (RT_LIKELY(GST_IS_PML4E_VALID(pVCpu, Pml4e))) { /* likely */ }
114 else return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 4);
115
116 pWalk->Core.fEffective = fEffective = ((uint32_t)Pml4e.u & (X86_PML4E_RW | X86_PML4E_US | X86_PML4E_PWT | X86_PML4E_PCD | X86_PML4E_A))
117 | ((uint32_t)(Pml4e.u >> 63) ^ 1) /*NX */;
118
119 /*
120 * The PDPE.
121 */
122 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pml4e.u & X86_PML4E_PG_MASK, &pWalk->pPdpt);
123 if (RT_SUCCESS(rc)) { /* probable */ }
124 else return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 3, rc);
125
126# elif PGM_GST_TYPE == PGM_TYPE_PAE
127 rc = pgmGstGetPaePDPTPtrEx(pVCpu, &pWalk->pPdpt);
128 if (RT_SUCCESS(rc)) { /* probable */ }
129 else return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 8, rc);
130# endif
131 }
132 {
133# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
134 PX86PDPE register pPdpe;
135 pWalk->pPdpe = pPdpe = &pWalk->pPdpt->a[(GCPtr >> GST_PDPT_SHIFT) & GST_PDPT_MASK];
136 X86PDPE register Pdpe;
137 pWalk->Pdpe.u = Pdpe.u = pPdpe->u;
138
139 if (Pdpe.n.u1Present) { /* probable */ }
140 else return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 3);
141
142 if (RT_LIKELY(GST_IS_PDPE_VALID(pVCpu, Pdpe))) { /* likely */ }
143 else return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 3);
144
145# if PGM_GST_TYPE == PGM_TYPE_AMD64
146 pWalk->Core.fEffective = fEffective &= ((uint32_t)Pdpe.u & (X86_PDPE_RW | X86_PDPE_US | X86_PDPE_PWT | X86_PDPE_PCD | X86_PDPE_A))
147 | ((uint32_t)(Pdpe.u >> 63) ^ 1) /*NX */;
148# else
149 pWalk->Core.fEffective = fEffective = X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A
150 | ((uint32_t)Pdpe.u & (X86_PDPE_PWT | X86_PDPE_PCD))
151 | ((uint32_t)(Pdpe.u >> 63) ^ 1) /*NX */;
152# endif
153
154 /*
155 * The PDE.
156 */
157 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pdpe.u & X86_PDPE_PG_MASK, &pWalk->pPd);
158 if (RT_SUCCESS(rc)) { /* probable */ }
159 else return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 2, rc);
160# elif PGM_GST_TYPE == PGM_TYPE_32BIT
161 rc = pgmGstGet32bitPDPtrEx(pVCpu, &pWalk->pPd);
162 if (RT_SUCCESS(rc)) { /* probable */ }
163 else return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 8, rc);
164# endif
165 }
166 {
167 PGSTPDE register pPde;
168 pWalk->pPde = pPde = &pWalk->pPd->a[(GCPtr >> GST_PD_SHIFT) & GST_PD_MASK];
169 GSTPDE Pde;
170 pWalk->Pde.u = Pde.u = pPde->u;
171 if (Pde.n.u1Present) { /* probable */ }
172 else return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 2);
173 if (Pde.n.u1Size && GST_IS_PSE_ACTIVE(pVCpu))
174 {
175 if (RT_LIKELY(GST_IS_BIG_PDE_VALID(pVCpu, Pde))) { /* likely */ }
176 else return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 2);
177
178 /*
179 * We're done.
180 */
181# if PGM_GST_TYPE == PGM_TYPE_32BIT
182 fEffective &= Pde.u & (X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PWT | X86_PDE4M_PCD | X86_PDE4M_A);
183# else
184 fEffective &= ((uint32_t)Pde.u & (X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PWT | X86_PDE4M_PCD | X86_PDE4M_A))
185 | ((uint32_t)(Pde.u >> 63) ^ 1) /*NX */;
186# endif
187 fEffective |= (uint32_t)Pde.u & (X86_PDE4M_D | X86_PDE4M_G);
188 fEffective |= (uint32_t)(Pde.u & X86_PDE4M_PAT) >> X86_PDE4M_PAT_SHIFT;
189 pWalk->Core.fEffective = fEffective;
190
191 pWalk->Core.fEffectiveRW = !!(fEffective & X86_PTE_RW);
192 pWalk->Core.fEffectiveUS = !!(fEffective & X86_PTE_US);
193# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
194 pWalk->Core.fEffectiveNX = !(fEffective & 1) && GST_IS_NX_ACTIVE(pVCpu);
195# else
196 pWalk->Core.fEffectiveNX = false;
197# endif
198 pWalk->Core.fBigPage = true;
199 pWalk->Core.fSucceeded = true;
200
201 pWalk->Core.GCPhys = GST_GET_BIG_PDE_GCPHYS(pVCpu->CTX_SUFF(pVM), Pde)
202 | (GCPtr & GST_BIG_PAGE_OFFSET_MASK);
203 PGM_A20_APPLY_TO_VAR(pVCpu, pWalk->Core.GCPhys);
204 return VINF_SUCCESS;
205 }
206
207 if (RT_UNLIKELY(!GST_IS_PDE_VALID(pVCpu, Pde)))
208 return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 2);
209# if PGM_GST_TYPE == PGM_TYPE_32BIT
210 pWalk->Core.fEffective = fEffective &= Pde.u & (X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD | X86_PDE_A);
211# else
212 pWalk->Core.fEffective = fEffective &= ((uint32_t)Pde.u & (X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD | X86_PDE_A))
213 | ((uint32_t)(Pde.u >> 63) ^ 1) /*NX */;
214# endif
215
216 /*
217 * The PTE.
218 */
219 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GST_GET_PDE_GCPHYS(Pde), &pWalk->pPt);
220 if (RT_SUCCESS(rc)) { /* probable */ }
221 else return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 1, rc);
222 }
223 {
224 PGSTPTE register pPte;
225 pWalk->pPte = pPte = &pWalk->pPt->a[(GCPtr >> GST_PT_SHIFT) & GST_PT_MASK];
226 GSTPTE register Pte;
227 pWalk->Pte.u = Pte.u = pPte->u;
228
229 if (Pte.n.u1Present) { /* probable */ }
230 else return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 1);
231
232 if (RT_LIKELY(GST_IS_PTE_VALID(pVCpu, Pte))) { /* likely */ }
233 else return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 1);
234
235 /*
236 * We're done.
237 */
238# if PGM_GST_TYPE == PGM_TYPE_32BIT
239 fEffective &= Pte.u & (X86_PTE_RW | X86_PTE_US | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A);
240# else
241 fEffective &= ((uint32_t)Pte.u & (X86_PTE_RW | X86_PTE_US | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A))
242 | ((uint32_t)(Pte.u >> 63) ^ 1) /*NX */;
243# endif
244 fEffective |= (uint32_t)Pte.u & (X86_PTE_D | X86_PTE_PAT | X86_PTE_G);
245 pWalk->Core.fEffective = fEffective;
246
247 pWalk->Core.fEffectiveRW = !!(fEffective & X86_PTE_RW);
248 pWalk->Core.fEffectiveUS = !!(fEffective & X86_PTE_US);
249# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
250 pWalk->Core.fEffectiveNX = !(fEffective & 1) && GST_IS_NX_ACTIVE(pVCpu);
251# else
252 pWalk->Core.fEffectiveNX = false;
253# endif
254 pWalk->Core.fSucceeded = true;
255
256 pWalk->Core.GCPhys = GST_GET_PDE_GCPHYS(Pte)
257 | (GCPtr & PAGE_OFFSET_MASK);
258 return VINF_SUCCESS;
259 }
260}
261
262#endif /* 32BIT, PAE, AMD64 */
263
264/**
265 * Gets effective Guest OS page information.
266 *
267 * When GCPtr is in a big page, the function will return as if it was a normal
268 * 4KB page. If the need for distinguishing between big and normal page becomes
269 * necessary at a later point, a PGMGstGetPage Ex() will be created for that
270 * purpose.
271 *
272 * @returns VBox status code.
273 * @param pVCpu The cross context virtual CPU structure.
274 * @param GCPtr Guest Context virtual address of the page.
275 * @param pfFlags Where to store the flags. These are X86_PTE_*, even for big pages.
276 * @param pGCPhys Where to store the GC physical address of the page.
277 * This is page aligned!
278 */
279PGM_GST_DECL(int, GetPage)(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys)
280{
281#if PGM_GST_TYPE == PGM_TYPE_REAL \
282 || PGM_GST_TYPE == PGM_TYPE_PROT
283 /*
284 * Fake it.
285 */
286 if (pfFlags)
287 *pfFlags = X86_PTE_P | X86_PTE_RW | X86_PTE_US;
288 if (pGCPhys)
289 *pGCPhys = GCPtr & PAGE_BASE_GC_MASK;
290 NOREF(pVCpu);
291 return VINF_SUCCESS;
292
293#elif PGM_GST_TYPE == PGM_TYPE_32BIT \
294 || PGM_GST_TYPE == PGM_TYPE_PAE \
295 || PGM_GST_TYPE == PGM_TYPE_AMD64
296
297 GSTPTWALK Walk;
298 int rc = PGM_GST_NAME(Walk)(pVCpu, GCPtr, &Walk);
299 if (RT_FAILURE(rc))
300 return rc;
301
302 if (pGCPhys)
303 *pGCPhys = Walk.Core.GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
304
305 if (pfFlags)
306 {
307 if (!Walk.Core.fBigPage)
308 *pfFlags = (Walk.Pte.u & ~(GST_PTE_PG_MASK | X86_PTE_RW | X86_PTE_US)) /* NX not needed */
309 | (Walk.Core.fEffectiveRW ? X86_PTE_RW : 0)
310 | (Walk.Core.fEffectiveUS ? X86_PTE_US : 0)
311# if PGM_WITH_NX(PGM_GST_TYPE, PGM_GST_TYPE)
312 | (Walk.Core.fEffectiveNX ? X86_PTE_PAE_NX : 0)
313# endif
314 ;
315 else
316 {
317 *pfFlags = (Walk.Pde.u & ~(GST_PTE_PG_MASK | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PS)) /* NX not needed */
318 | ((Walk.Pde.u & X86_PDE4M_PAT) >> X86_PDE4M_PAT_SHIFT)
319 | (Walk.Core.fEffectiveRW ? X86_PTE_RW : 0)
320 | (Walk.Core.fEffectiveUS ? X86_PTE_US : 0)
321# if PGM_WITH_NX(PGM_GST_TYPE, PGM_GST_TYPE)
322 | (Walk.Core.fEffectiveNX ? X86_PTE_PAE_NX : 0)
323# endif
324 ;
325 }
326 }
327
328 return VINF_SUCCESS;
329
330#else
331# error "shouldn't be here!"
332 /* something else... */
333 return VERR_NOT_SUPPORTED;
334#endif
335}
336
337
338/**
339 * Modify page flags for a range of pages in the guest's tables
340 *
341 * The existing flags are ANDed with the fMask and ORed with the fFlags.
342 *
343 * @returns VBox status code.
344 * @param pVCpu The cross context virtual CPU structure.
345 * @param GCPtr Virtual address of the first page in the range. Page aligned!
346 * @param cb Size (in bytes) of the page range to apply the modification to. Page aligned!
347 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
348 * @param fMask The AND mask - page flags X86_PTE_*.
349 */
350PGM_GST_DECL(int, ModifyPage)(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
351{
352 Assert((cb & PAGE_OFFSET_MASK) == 0); RT_NOREF_PV(cb);
353
354#if PGM_GST_TYPE == PGM_TYPE_32BIT \
355 || PGM_GST_TYPE == PGM_TYPE_PAE \
356 || PGM_GST_TYPE == PGM_TYPE_AMD64
357 for (;;)
358 {
359 GSTPTWALK Walk;
360 int rc = PGM_GST_NAME(Walk)(pVCpu, GCPtr, &Walk);
361 if (RT_FAILURE(rc))
362 return rc;
363
364 if (!Walk.Core.fBigPage)
365 {
366 /*
367 * 4KB Page table, process
368 *
369 * Walk pages till we're done.
370 */
371 unsigned iPTE = (GCPtr >> GST_PT_SHIFT) & GST_PT_MASK;
372 while (iPTE < RT_ELEMENTS(Walk.pPt->a))
373 {
374 GSTPTE Pte = Walk.pPt->a[iPTE];
375 Pte.u = (Pte.u & (fMask | X86_PTE_PAE_PG_MASK))
376 | (fFlags & ~GST_PTE_PG_MASK);
377 Walk.pPt->a[iPTE] = Pte;
378
379 /* next page */
380 cb -= PAGE_SIZE;
381 if (!cb)
382 return VINF_SUCCESS;
383 GCPtr += PAGE_SIZE;
384 iPTE++;
385 }
386 }
387 else
388 {
389 /*
390 * 2/4MB Page table
391 */
392 GSTPDE PdeNew;
393# if PGM_GST_TYPE == PGM_TYPE_32BIT
394 PdeNew.u = (Walk.Pde.u & (fMask | ((fMask & X86_PTE_PAT) << X86_PDE4M_PAT_SHIFT) | GST_PDE_BIG_PG_MASK | X86_PDE4M_PG_HIGH_MASK | X86_PDE4M_PS))
395# else
396 PdeNew.u = (Walk.Pde.u & (fMask | ((fMask & X86_PTE_PAT) << X86_PDE4M_PAT_SHIFT) | GST_PDE_BIG_PG_MASK | X86_PDE4M_PS))
397# endif
398 | (fFlags & ~GST_PTE_PG_MASK)
399 | ((fFlags & X86_PTE_PAT) << X86_PDE4M_PAT_SHIFT);
400 *Walk.pPde = PdeNew;
401
402 /* advance */
403 const unsigned cbDone = GST_BIG_PAGE_SIZE - (GCPtr & GST_BIG_PAGE_OFFSET_MASK);
404 if (cbDone >= cb)
405 return VINF_SUCCESS;
406 cb -= cbDone;
407 GCPtr += cbDone;
408 }
409 }
410
411#else
412 /* real / protected mode: ignore. */
413 NOREF(pVCpu); NOREF(GCPtr); NOREF(fFlags); NOREF(fMask);
414 return VINF_SUCCESS;
415#endif
416}
417
418
419/**
420 * Retrieve guest PDE information.
421 *
422 * @returns VBox status code.
423 * @param pVCpu The cross context virtual CPU structure.
424 * @param GCPtr Guest context pointer.
425 * @param pPDE Pointer to guest PDE structure.
426 */
427PGM_GST_DECL(int, GetPDE)(PVMCPU pVCpu, RTGCPTR GCPtr, PX86PDEPAE pPDE)
428{
429#if PGM_GST_TYPE == PGM_TYPE_32BIT \
430 || PGM_GST_TYPE == PGM_TYPE_PAE \
431 || PGM_GST_TYPE == PGM_TYPE_AMD64
432
433# if PGM_GST_TYPE != PGM_TYPE_AMD64
434 /* Boundary check. */
435 if (RT_UNLIKELY(GCPtr >= _4G))
436 return VERR_PAGE_TABLE_NOT_PRESENT;
437# endif
438
439# if PGM_GST_TYPE == PGM_TYPE_32BIT
440 unsigned iPd = (GCPtr >> GST_PD_SHIFT) & GST_PD_MASK;
441 PX86PD pPd = pgmGstGet32bitPDPtr(pVCpu);
442
443# elif PGM_GST_TYPE == PGM_TYPE_PAE
444 unsigned iPd = 0; /* shut up gcc */
445 PCX86PDPAE pPd = pgmGstGetPaePDPtr(pVCpu, GCPtr, &iPd, NULL);
446
447# elif PGM_GST_TYPE == PGM_TYPE_AMD64
448 PX86PML4E pPml4eIgn;
449 X86PDPE PdpeIgn;
450 unsigned iPd = 0; /* shut up gcc */
451 PCX86PDPAE pPd = pgmGstGetLongModePDPtr(pVCpu, GCPtr, &pPml4eIgn, &PdpeIgn, &iPd);
452 /* Note! We do not return an effective PDE here like we do for the PTE in GetPage method. */
453# endif
454
455 if (RT_LIKELY(pPd))
456 pPDE->u = (X86PGPAEUINT)pPd->a[iPd].u;
457 else
458 pPDE->u = 0;
459 return VINF_SUCCESS;
460
461#else
462 NOREF(pVCpu); NOREF(GCPtr); NOREF(pPDE);
463 AssertFailed();
464 return VERR_NOT_IMPLEMENTED;
465#endif
466}
467
468
469#if ( PGM_GST_TYPE == PGM_TYPE_32BIT \
470 || PGM_GST_TYPE == PGM_TYPE_PAE \
471 || PGM_GST_TYPE == PGM_TYPE_AMD64) \
472 && defined(VBOX_WITH_RAW_MODE)
473/**
474 * Updates one virtual handler range.
475 *
476 * @returns 0
477 * @param pNode Pointer to a PGMVIRTHANDLER.
478 * @param pvUser Pointer to a PGMVHUARGS structure (see PGM.cpp).
479 */
480static DECLCALLBACK(int) PGM_GST_NAME(VirtHandlerUpdateOne)(PAVLROGCPTRNODECORE pNode, void *pvUser)
481{
482 PPGMHVUSTATE pState = (PPGMHVUSTATE)pvUser;
483 PVM pVM = pState->pVM;
484 PVMCPU pVCpu = pState->pVCpu;
485 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
486 PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
487
488 Assert(pCurType->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR); NOREF(pCurType);
489
490# if PGM_GST_TYPE == PGM_TYPE_32BIT
491 PX86PD pPDSrc = pgmGstGet32bitPDPtr(pVCpu);
492# endif
493
494 RTGCPTR GCPtr = pCur->Core.Key;
495# if PGM_GST_TYPE != PGM_TYPE_AMD64
496 /* skip all stuff above 4GB if not AMD64 mode. */
497 if (RT_UNLIKELY(GCPtr >= _4G))
498 return 0;
499# endif
500
501 unsigned offPage = GCPtr & PAGE_OFFSET_MASK;
502 unsigned iPage = 0;
503 while (iPage < pCur->cPages)
504 {
505# if PGM_GST_TYPE == PGM_TYPE_32BIT
506 X86PDE Pde = pPDSrc->a[GCPtr >> X86_PD_SHIFT];
507# elif PGM_GST_TYPE == PGM_TYPE_PAE
508 X86PDEPAE Pde = pgmGstGetPaePDE(pVCpu, GCPtr);
509# elif PGM_GST_TYPE == PGM_TYPE_AMD64
510 X86PDEPAE Pde = pgmGstGetLongModePDE(pVCpu, GCPtr);
511# endif
512# if PGM_GST_TYPE == PGM_TYPE_32BIT
513 bool const fBigPage = Pde.b.u1Size && (pState->cr4 & X86_CR4_PSE);
514# else
515 bool const fBigPage = Pde.b.u1Size;
516# endif
517 if ( Pde.n.u1Present
518 && ( !fBigPage
519 ? GST_IS_PDE_VALID(pVCpu, Pde)
520 : GST_IS_BIG_PDE_VALID(pVCpu, Pde)) )
521 {
522 if (!fBigPage)
523 {
524 /*
525 * Normal page table.
526 */
527 PGSTPT pPT;
528 int rc = PGM_GCPHYS_2_PTR_V2(pVM, pVCpu, GST_GET_PDE_GCPHYS(Pde), &pPT);
529 if (RT_SUCCESS(rc))
530 {
531 for (unsigned iPTE = (GCPtr >> GST_PT_SHIFT) & GST_PT_MASK;
532 iPTE < RT_ELEMENTS(pPT->a) && iPage < pCur->cPages;
533 iPTE++, iPage++, GCPtr += PAGE_SIZE, offPage = 0)
534 {
535 GSTPTE Pte = pPT->a[iPTE];
536 RTGCPHYS GCPhysNew;
537 if (Pte.n.u1Present)
538 GCPhysNew = PGM_A20_APPLY(pVCpu, (RTGCPHYS)(pPT->a[iPTE].u & GST_PTE_PG_MASK) + offPage);
539 else
540 GCPhysNew = NIL_RTGCPHYS;
541 if (pCur->aPhysToVirt[iPage].Core.Key != GCPhysNew)
542 {
543 if (pCur->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS)
544 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
545#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
546 AssertReleaseMsg(!pCur->aPhysToVirt[iPage].offNextAlias,
547 ("{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} GCPhysNew=%RGp\n",
548 pCur->aPhysToVirt[iPage].Core.Key, pCur->aPhysToVirt[iPage].Core.KeyLast,
549 pCur->aPhysToVirt[iPage].offVirtHandler, pCur->aPhysToVirt[iPage].offNextAlias, GCPhysNew));
550#endif
551 pCur->aPhysToVirt[iPage].Core.Key = GCPhysNew;
552 pState->fTodo |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
553 }
554 }
555 }
556 else
557 {
558 /* not-present. */
559 offPage = 0;
560 AssertRC(rc);
561 for (unsigned iPTE = (GCPtr >> GST_PT_SHIFT) & GST_PT_MASK;
562 iPTE < RT_ELEMENTS(pPT->a) && iPage < pCur->cPages;
563 iPTE++, iPage++, GCPtr += PAGE_SIZE)
564 {
565 if (pCur->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS)
566 {
567 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
568#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
569 AssertReleaseMsg(!pCur->aPhysToVirt[iPage].offNextAlias,
570 ("{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
571 pCur->aPhysToVirt[iPage].Core.Key, pCur->aPhysToVirt[iPage].Core.KeyLast,
572 pCur->aPhysToVirt[iPage].offVirtHandler, pCur->aPhysToVirt[iPage].offNextAlias));
573#endif
574 pCur->aPhysToVirt[iPage].Core.Key = NIL_RTGCPHYS;
575 pState->fTodo |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
576 }
577 }
578 }
579 }
580 else
581 {
582 /*
583 * 2/4MB page.
584 */
585 RTGCPHYS GCPhys = (RTGCPHYS)GST_GET_PDE_GCPHYS(Pde);
586 for (unsigned i4KB = (GCPtr >> GST_PT_SHIFT) & GST_PT_MASK;
587 i4KB < PAGE_SIZE / sizeof(GSTPDE) && iPage < pCur->cPages;
588 i4KB++, iPage++, GCPtr += PAGE_SIZE, offPage = 0)
589 {
590 RTGCPHYS GCPhysNew = PGM_A20_APPLY(pVCpu, GCPhys + (i4KB << PAGE_SHIFT) + offPage);
591 if (pCur->aPhysToVirt[iPage].Core.Key != GCPhysNew)
592 {
593 if (pCur->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS)
594 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
595#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
596 AssertReleaseMsg(!pCur->aPhysToVirt[iPage].offNextAlias,
597 ("{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} GCPhysNew=%RGp\n",
598 pCur->aPhysToVirt[iPage].Core.Key, pCur->aPhysToVirt[iPage].Core.KeyLast,
599 pCur->aPhysToVirt[iPage].offVirtHandler, pCur->aPhysToVirt[iPage].offNextAlias, GCPhysNew));
600#endif
601 pCur->aPhysToVirt[iPage].Core.Key = GCPhysNew;
602 pState->fTodo |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
603 }
604 }
605 } /* pde type */
606 }
607 else
608 {
609 /* not-present / invalid. */
610 Log(("VirtHandler: Not present / invalid Pde=%RX64\n", (uint64_t)Pde.u));
611 for (unsigned cPages = (GST_PT_MASK + 1) - ((GCPtr >> GST_PT_SHIFT) & GST_PT_MASK);
612 cPages && iPage < pCur->cPages;
613 iPage++, GCPtr += PAGE_SIZE)
614 {
615 if (pCur->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS)
616 {
617 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
618 pCur->aPhysToVirt[iPage].Core.Key = NIL_RTGCPHYS;
619 pState->fTodo |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
620 }
621 }
622 offPage = 0;
623 }
624 } /* for pages in virtual mapping. */
625
626 return 0;
627}
628#endif /* 32BIT, PAE and AMD64 + VBOX_WITH_RAW_MODE */
629
630
631/**
632 * Updates the virtual page access handlers.
633 *
634 * @returns true if bits were flushed.
635 * @returns false if bits weren't flushed.
636 * @param pVM The cross context VM structure.
637 * @param cr4 The cr4 register value.
638 */
639PGM_GST_DECL(bool, HandlerVirtualUpdate)(PVM pVM, uint32_t cr4)
640{
641#if ( PGM_GST_TYPE == PGM_TYPE_32BIT \
642 || PGM_GST_TYPE == PGM_TYPE_PAE \
643 || PGM_GST_TYPE == PGM_TYPE_AMD64) \
644 && defined(VBOX_WITH_RAW_MODE)
645
646 /** @todo
647 * In theory this is not sufficient: the guest can change a single page in a range with invlpg
648 */
649
650 /*
651 * Resolve any virtual address based access handlers to GC physical addresses.
652 * This should be fairly quick.
653 */
654 RTUINT fTodo = 0;
655
656 pgmLock(pVM);
657 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3HandlerVirtualUpdate), a);
658
659 for (VMCPUID i = 0; i < pVM->cCpus; i++)
660 {
661 PGMHVUSTATE State;
662 PVMCPU pVCpu = &pVM->aCpus[i];
663
664 State.pVM = pVM;
665 State.pVCpu = pVCpu;
666 State.fTodo = pVCpu->pgm.s.fSyncFlags;
667 State.cr4 = cr4;
668 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, PGM_GST_NAME(VirtHandlerUpdateOne), &State);
669
670 fTodo |= State.fTodo;
671 }
672 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3HandlerVirtualUpdate), a);
673
674
675 /*
676 * Set / reset bits?
677 */
678 if (fTodo & PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL)
679 {
680 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3HandlerVirtualReset), b);
681 Log(("HandlerVirtualUpdate: resets bits\n"));
682 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, pgmHandlerVirtualResetOne, pVM);
683
684 for (VMCPUID i = 0; i < pVM->cCpus; i++)
685 {
686 PVMCPU pVCpu = &pVM->aCpus[i];
687 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
688 }
689
690 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3HandlerVirtualReset), b);
691 }
692 pgmUnlock(pVM);
693
694 return !!(fTodo & PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL);
695
696#else /* real / protected */
697 NOREF(pVM); NOREF(cr4);
698 return false;
699#endif
700}
701
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