VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllShw.h@ 93582

Last change on this file since 93582 was 93554, checked in by vboxsync, 3 years ago

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.7 KB
Line 
1/* $Id: PGMAllShw.h 93554 2022-02-02 22:57:02Z vboxsync $ */
2/** @file
3 * VBox - Page Manager, Shadow Paging Template - All context code.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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* Defined Constants And Macros *
21*********************************************************************************************************************************/
22#undef SHWUINT
23#undef SHWPT
24#undef PSHWPT
25#undef SHWPTE
26#undef PSHWPTE
27#undef SHWPD
28#undef PSHWPD
29#undef SHWPDE
30#undef PSHWPDE
31#undef SHW_PDE_PG_MASK
32#undef SHW_PD_SHIFT
33#undef SHW_PD_MASK
34#undef SHW_PDE_ATOMIC_SET
35#undef SHW_PDE_ATOMIC_SET2
36#undef SHW_PDE_IS_P
37#undef SHW_PDE_IS_A
38#undef SHW_PDE_IS_BIG
39#undef SHW_PTE_PG_MASK
40#undef SHW_PTE_IS_P
41#undef SHW_PTE_IS_RW
42#undef SHW_PTE_IS_US
43#undef SHW_PTE_IS_A
44#undef SHW_PTE_IS_D
45#undef SHW_PTE_IS_P_RW
46#undef SHW_PTE_IS_TRACK_DIRTY
47#undef SHW_PTE_GET_HCPHYS
48#undef SHW_PTE_GET_U
49#undef SHW_PTE_LOG64
50#undef SHW_PTE_SET
51#undef SHW_PTE_ATOMIC_SET
52#undef SHW_PTE_ATOMIC_SET2
53#undef SHW_PTE_SET_RO
54#undef SHW_PTE_SET_RW
55#undef SHW_PT_SHIFT
56#undef SHW_PT_MASK
57#undef SHW_TOTAL_PD_ENTRIES
58#undef SHW_PDPT_SHIFT
59#undef SHW_PDPT_MASK
60#undef SHW_PDPE_PG_MASK
61
62#if PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_NESTED_32BIT
63# define SHWUINT uint32_t
64# define SHWPT X86PT
65# define PSHWPT PX86PT
66# define SHWPTE X86PTE
67# define PSHWPTE PX86PTE
68# define SHWPD X86PD
69# define PSHWPD PX86PD
70# define SHWPDE X86PDE
71# define PSHWPDE PX86PDE
72# define SHW_PDE_PG_MASK X86_PDE_PG_MASK
73# define SHW_PD_SHIFT X86_PD_SHIFT
74# define SHW_PD_MASK X86_PD_MASK
75# define SHW_TOTAL_PD_ENTRIES X86_PG_ENTRIES
76# define SHW_PDE_IS_P(Pde) ( (Pde).u & X86_PDE_P )
77# define SHW_PDE_IS_A(Pde) ( (Pde).u & X86_PDE_A )
78# define SHW_PDE_IS_BIG(Pde) ( (Pde).u & X86_PDE_PS )
79# define SHW_PDE_ATOMIC_SET(Pde, uNew) do { ASMAtomicWriteU32(&(Pde).u, (uNew)); } while (0)
80# define SHW_PDE_ATOMIC_SET2(Pde, Pde2) do { ASMAtomicWriteU32(&(Pde).u, (Pde2).u); } while (0)
81# define SHW_PTE_PG_MASK X86_PTE_PG_MASK
82# define SHW_PTE_IS_P(Pte) ( (Pte).u & X86_PTE_P )
83# define SHW_PTE_IS_RW(Pte) ( (Pte).u & X86_PTE_RW )
84# define SHW_PTE_IS_US(Pte) ( (Pte).u & X86_PTE_US )
85# define SHW_PTE_IS_A(Pte) ( (Pte).u & X86_PTE_A )
86# define SHW_PTE_IS_D(Pte) ( (Pte).u & X86_PTE_D )
87# define SHW_PTE_IS_P_RW(Pte) ( ((Pte).u & (X86_PTE_P | X86_PTE_RW)) == (X86_PTE_P | X86_PTE_RW) )
88# define SHW_PTE_IS_TRACK_DIRTY(Pte) ( !!((Pte).u & PGM_PTFLAGS_TRACK_DIRTY) )
89# define SHW_PTE_GET_HCPHYS(Pte) ( (Pte).u & X86_PTE_PG_MASK )
90# define SHW_PTE_LOG64(Pte) ( (uint64_t)(Pte).u )
91# define SHW_PTE_GET_U(Pte) ( (Pte).u ) /**< Use with care. */
92# define SHW_PTE_SET(Pte, uNew) do { (Pte).u = (uNew); } while (0)
93# define SHW_PTE_ATOMIC_SET(Pte, uNew) do { ASMAtomicWriteU32(&(Pte).u, (uNew)); } while (0)
94# define SHW_PTE_ATOMIC_SET2(Pte, Pte2) do { ASMAtomicWriteU32(&(Pte).u, (Pte2).u); } while (0)
95# define SHW_PTE_SET_RO(Pte) do { (Pte).u &= ~(X86PGUINT)X86_PTE_RW; } while (0)
96# define SHW_PTE_SET_RW(Pte) do { (Pte).u |= X86_PTE_RW; } while (0)
97# define SHW_PT_SHIFT X86_PT_SHIFT
98# define SHW_PT_MASK X86_PT_MASK
99
100#elif PGM_SHW_TYPE == PGM_TYPE_EPT
101# define SHWUINT uint64_t
102# define SHWPT EPTPT
103# define PSHWPT PEPTPT
104# define SHWPTE EPTPTE
105# define PSHWPTE PEPTPTE
106# define SHWPD EPTPD
107# define PSHWPD PEPTPD
108# define SHWPDE EPTPDE
109# define PSHWPDE PEPTPDE
110# define SHW_PDE_PG_MASK EPT_PDE_PG_MASK
111# define SHW_PD_SHIFT EPT_PD_SHIFT
112# define SHW_PD_MASK EPT_PD_MASK
113# define SHW_PDE_IS_P(Pde) ( (Pde).u & EPT_E_READ /* always set*/ )
114# define SHW_PDE_IS_A(Pde) ( 1 ) /* We don't use EPT_E_ACCESSED, use with care! */
115# define SHW_PDE_IS_BIG(Pde) ( (Pde).u & EPT_E_LEAF )
116# define SHW_PDE_ATOMIC_SET(Pde, uNew) do { ASMAtomicWriteU64(&(Pde).u, (uNew)); } while (0)
117# define SHW_PDE_ATOMIC_SET2(Pde, Pde2) do { ASMAtomicWriteU64(&(Pde).u, (Pde2).u); } while (0)
118# define SHW_PTE_PG_MASK EPT_PTE_PG_MASK
119# define SHW_PTE_IS_P(Pte) ( (Pte).u & EPT_E_READ ) /* Approximation, works for us. */
120# define SHW_PTE_IS_RW(Pte) ( (Pte).u & EPT_E_WRITE )
121# define SHW_PTE_IS_US(Pte) ( true )
122# define SHW_PTE_IS_A(Pte) ( true )
123# define SHW_PTE_IS_D(Pte) ( true )
124# define SHW_PTE_IS_P_RW(Pte) ( ((Pte).u & (EPT_E_READ | EPT_E_WRITE)) == (EPT_E_READ | EPT_E_WRITE) )
125# define SHW_PTE_IS_TRACK_DIRTY(Pte) ( false )
126# define SHW_PTE_GET_HCPHYS(Pte) ( (Pte).u & EPT_PTE_PG_MASK )
127# define SHW_PTE_LOG64(Pte) ( (Pte).u )
128# define SHW_PTE_GET_U(Pte) ( (Pte).u ) /**< Use with care. */
129# define SHW_PTE_SET(Pte, uNew) do { (Pte).u = (uNew); } while (0)
130# define SHW_PTE_ATOMIC_SET(Pte, uNew) do { ASMAtomicWriteU64(&(Pte).u, (uNew)); } while (0)
131# define SHW_PTE_ATOMIC_SET2(Pte, Pte2) do { ASMAtomicWriteU64(&(Pte).u, (Pte2).u); } while (0)
132# define SHW_PTE_SET_RO(Pte) do { (Pte).u &= ~(uint64_t)EPT_E_WRITE; } while (0)
133# define SHW_PTE_SET_RW(Pte) do { (Pte).u |= EPT_E_WRITE; } while (0)
134# define SHW_PT_SHIFT EPT_PT_SHIFT
135# define SHW_PT_MASK EPT_PT_MASK
136# define SHW_PDPT_SHIFT EPT_PDPT_SHIFT
137# define SHW_PDPT_MASK EPT_PDPT_MASK
138# define SHW_PDPE_PG_MASK EPT_PDPE_PG_MASK
139# define SHW_TOTAL_PD_ENTRIES (EPT_PG_AMD64_ENTRIES * EPT_PG_AMD64_PDPE_ENTRIES)
140
141#else
142# define SHWUINT uint64_t
143# define SHWPT PGMSHWPTPAE
144# define PSHWPT PPGMSHWPTPAE
145# define SHWPTE PGMSHWPTEPAE
146# define PSHWPTE PPGMSHWPTEPAE
147# define SHWPD X86PDPAE
148# define PSHWPD PX86PDPAE
149# define SHWPDE X86PDEPAE
150# define PSHWPDE PX86PDEPAE
151# define SHW_PDE_PG_MASK X86_PDE_PAE_PG_MASK
152# define SHW_PD_SHIFT X86_PD_PAE_SHIFT
153# define SHW_PD_MASK X86_PD_PAE_MASK
154# define SHW_PDE_IS_P(Pde) ( (Pde).u & X86_PDE_P )
155# define SHW_PDE_IS_A(Pde) ( (Pde).u & X86_PDE_A )
156# define SHW_PDE_IS_BIG(Pde) ( (Pde).u & X86_PDE_PS )
157# define SHW_PDE_ATOMIC_SET(Pde, uNew) do { ASMAtomicWriteU64(&(Pde).u, (uNew)); } while (0)
158# define SHW_PDE_ATOMIC_SET2(Pde, Pde2) do { ASMAtomicWriteU64(&(Pde).u, (Pde2).u); } while (0)
159# define SHW_PTE_PG_MASK X86_PTE_PAE_PG_MASK
160# define SHW_PTE_IS_P(Pte) PGMSHWPTEPAE_IS_P(Pte)
161# define SHW_PTE_IS_RW(Pte) PGMSHWPTEPAE_IS_RW(Pte)
162# define SHW_PTE_IS_US(Pte) PGMSHWPTEPAE_IS_US(Pte)
163# define SHW_PTE_IS_A(Pte) PGMSHWPTEPAE_IS_A(Pte)
164# define SHW_PTE_IS_D(Pte) PGMSHWPTEPAE_IS_D(Pte)
165# define SHW_PTE_IS_P_RW(Pte) PGMSHWPTEPAE_IS_P_RW(Pte)
166# define SHW_PTE_IS_TRACK_DIRTY(Pte) PGMSHWPTEPAE_IS_TRACK_DIRTY(Pte)
167# define SHW_PTE_GET_HCPHYS(Pte) PGMSHWPTEPAE_GET_HCPHYS(Pte)
168# define SHW_PTE_LOG64(Pte) PGMSHWPTEPAE_GET_LOG(Pte)
169# define SHW_PTE_GET_U(Pte) PGMSHWPTEPAE_GET_U(Pte) /**< Use with care. */
170# define SHW_PTE_SET(Pte, uNew) PGMSHWPTEPAE_SET(Pte, uNew)
171# define SHW_PTE_ATOMIC_SET(Pte, uNew) PGMSHWPTEPAE_ATOMIC_SET(Pte, uNew)
172# define SHW_PTE_ATOMIC_SET2(Pte, Pte2) PGMSHWPTEPAE_ATOMIC_SET2(Pte, Pte2)
173# define SHW_PTE_SET_RO(Pte) PGMSHWPTEPAE_SET_RO(Pte)
174# define SHW_PTE_SET_RW(Pte) PGMSHWPTEPAE_SET_RW(Pte)
175# define SHW_PT_SHIFT X86_PT_PAE_SHIFT
176# define SHW_PT_MASK X86_PT_PAE_MASK
177
178# if PGM_SHW_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_NESTED_AMD64 || /* whatever: */ PGM_SHW_TYPE == PGM_TYPE_NONE
179# define SHW_PDPT_SHIFT X86_PDPT_SHIFT
180# define SHW_PDPT_MASK X86_PDPT_MASK_AMD64
181# define SHW_PDPE_PG_MASK X86_PDPE_PG_MASK
182# define SHW_TOTAL_PD_ENTRIES (X86_PG_AMD64_ENTRIES * X86_PG_AMD64_PDPE_ENTRIES)
183
184# elif PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED_PAE
185# define SHW_PDPT_SHIFT X86_PDPT_SHIFT
186# define SHW_PDPT_MASK X86_PDPT_MASK_PAE
187# define SHW_PDPE_PG_MASK X86_PDPE_PG_MASK
188# define SHW_TOTAL_PD_ENTRIES (X86_PG_PAE_ENTRIES * X86_PG_PAE_PDPE_ENTRIES)
189
190# else
191# error "Misconfigured PGM_SHW_TYPE or something..."
192# endif
193#endif
194
195#if PGM_SHW_TYPE == PGM_TYPE_NONE && PGM_TYPE_IS_NESTED_OR_EPT(PGM_SHW_TYPE)
196# error "PGM_TYPE_IS_NESTED_OR_EPT is true for PGM_TYPE_NONE!"
197#endif
198
199
200
201/*********************************************************************************************************************************
202* Internal Functions *
203*********************************************************************************************************************************/
204RT_C_DECLS_BEGIN
205PGM_SHW_DECL(int, GetPage)(PVMCPUCC pVCpu, RTGCUINTPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys);
206PGM_SHW_DECL(int, ModifyPage)(PVMCPUCC pVCpu, RTGCUINTPTR GCPtr, size_t cbPages, uint64_t fFlags, uint64_t fMask, uint32_t fOpFlags);
207PGM_SHW_DECL(int, Enter)(PVMCPUCC pVCpu, bool fIs64BitsPagingMode);
208PGM_SHW_DECL(int, Exit)(PVMCPUCC pVCpu);
209#ifdef IN_RING3
210PGM_SHW_DECL(int, Relocate)(PVMCPUCC pVCpu, RTGCPTR offDelta);
211#endif
212RT_C_DECLS_END
213
214
215/**
216 * Enters the shadow mode.
217 *
218 * @returns VBox status code.
219 * @param pVCpu The cross context virtual CPU structure.
220 * @param fIs64BitsPagingMode New shadow paging mode is for 64 bits? (only relevant for 64 bits guests on a 32 bits AMD-V nested paging host)
221 */
222PGM_SHW_DECL(int, Enter)(PVMCPUCC pVCpu, bool fIs64BitsPagingMode)
223{
224#if PGM_TYPE_IS_NESTED_OR_EPT(PGM_SHW_TYPE)
225
226# if PGM_TYPE_IS_NESTED(PGM_SHW_TYPE) && HC_ARCH_BITS == 32
227 /* Must distinguish between 32 and 64 bits guest paging modes as we'll use
228 a different shadow paging root/mode in both cases. */
229 RTGCPHYS GCPhysCR3 = (fIs64BitsPagingMode) ? RT_BIT_64(63) : RT_BIT_64(62);
230# else
231 RTGCPHYS GCPhysCR3 = RT_BIT_64(63); NOREF(fIs64BitsPagingMode);
232# endif
233 PPGMPOOLPAGE pNewShwPageCR3;
234 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
235
236 Assert((HMIsNestedPagingActive(pVM) || VM_IS_NEM_ENABLED(pVM)) == pVM->pgm.s.fNestedPaging);
237 Assert(pVM->pgm.s.fNestedPaging);
238 Assert(!pVCpu->pgm.s.pShwPageCR3R3);
239
240 PGM_LOCK_VOID(pVM);
241
242 int rc = pgmPoolAlloc(pVM, GCPhysCR3, PGMPOOLKIND_ROOT_NESTED, PGMPOOLACCESS_DONTCARE, PGM_A20_IS_ENABLED(pVCpu),
243 NIL_PGMPOOL_IDX, UINT32_MAX, true /*fLockPage*/,
244 &pNewShwPageCR3);
245 AssertLogRelRCReturnStmt(rc, PGM_UNLOCK(pVM), rc);
246
247 pVCpu->pgm.s.pShwPageCR3R3 = (R3PTRTYPE(PPGMPOOLPAGE))MMHyperCCToR3(pVM, pNewShwPageCR3);
248 pVCpu->pgm.s.pShwPageCR3R0 = (R0PTRTYPE(PPGMPOOLPAGE))MMHyperCCToR0(pVM, pNewShwPageCR3);
249
250 PGM_UNLOCK(pVM);
251
252 Log(("Enter nested shadow paging mode: root %RHv phys %RHp\n", pVCpu->pgm.s.pShwPageCR3R3, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key));
253#else
254 NOREF(pVCpu); NOREF(fIs64BitsPagingMode);
255#endif
256 return VINF_SUCCESS;
257}
258
259
260/**
261 * Exits the shadow mode.
262 *
263 * @returns VBox status code.
264 * @param pVCpu The cross context virtual CPU structure.
265 */
266PGM_SHW_DECL(int, Exit)(PVMCPUCC pVCpu)
267{
268#if PGM_TYPE_IS_NESTED_OR_EPT(PGM_SHW_TYPE)
269 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
270 if (pVCpu->pgm.s.CTX_SUFF(pShwPageCR3))
271 {
272 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
273
274 PGM_LOCK_VOID(pVM);
275
276 /* Do *not* unlock this page as we have two of them floating around in the 32-bit host & 64-bit guest case.
277 * We currently assert when you try to free one of them; don't bother to really allow this.
278 *
279 * Note that this is two nested paging root pages max. This isn't a leak. They are reused.
280 */
281 /* pgmPoolUnlockPage(pPool, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)); */
282
283 pgmPoolFreeByPage(pPool, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3), NIL_PGMPOOL_IDX, UINT32_MAX);
284 pVCpu->pgm.s.pShwPageCR3R3 = 0;
285 pVCpu->pgm.s.pShwPageCR3R0 = 0;
286
287 PGM_UNLOCK(pVM);
288
289 Log(("Leave nested shadow paging mode\n"));
290 }
291#else
292 RT_NOREF_PV(pVCpu);
293#endif
294 return VINF_SUCCESS;
295}
296
297
298/**
299 * Gets effective page information (from the VMM page directory).
300 *
301 * @returns VBox status code.
302 * @param pVCpu The cross context virtual CPU structure.
303 * @param GCPtr Guest Context virtual address of the page.
304 * @param pfFlags Where to store the flags. These are X86_PTE_*.
305 * @param pHCPhys Where to store the HC physical address of the page.
306 * This is page aligned.
307 * @remark You should use PGMMapGetPage() for pages in a mapping.
308 */
309PGM_SHW_DECL(int, GetPage)(PVMCPUCC pVCpu, RTGCUINTPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys)
310{
311#if PGM_SHW_TYPE == PGM_TYPE_NONE
312 RT_NOREF(pVCpu, GCPtr);
313 AssertFailed();
314 *pfFlags = 0;
315 *pHCPhys = NIL_RTHCPHYS;
316 return VERR_PGM_SHW_NONE_IPE;
317
318#else /* PGM_SHW_TYPE != PGM_TYPE_NONE */
319 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
320
321 PGM_LOCK_ASSERT_OWNER(pVM);
322
323 /*
324 * Get the PDE.
325 */
326# if PGM_SHW_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_NESTED_AMD64
327 X86PDEPAE Pde;
328
329 /* PML4 */
330 X86PML4E Pml4e = pgmShwGetLongModePML4E(pVCpu, GCPtr);
331 if (!(Pml4e.u & X86_PML4E_P))
332 return VERR_PAGE_TABLE_NOT_PRESENT;
333
334 /* PDPT */
335 PX86PDPT pPDPT;
336 int rc = PGM_HCPHYS_2_PTR(pVM, pVCpu, Pml4e.u & X86_PML4E_PG_MASK, &pPDPT);
337 if (RT_FAILURE(rc))
338 return rc;
339 const unsigned iPDPT = (GCPtr >> SHW_PDPT_SHIFT) & SHW_PDPT_MASK;
340 X86PDPE Pdpe = pPDPT->a[iPDPT];
341 if (!(Pdpe.u & X86_PDPE_P))
342 return VERR_PAGE_TABLE_NOT_PRESENT;
343
344 /* PD */
345 PX86PDPAE pPd;
346 rc = PGM_HCPHYS_2_PTR(pVM, pVCpu, Pdpe.u & X86_PDPE_PG_MASK, &pPd);
347 if (RT_FAILURE(rc))
348 return rc;
349 const unsigned iPd = (GCPtr >> SHW_PD_SHIFT) & SHW_PD_MASK;
350 Pde = pPd->a[iPd];
351
352 /* Merge accessed, write, user and no-execute bits into the PDE. */
353 AssertCompile(X86_PML4E_A == X86_PDPE_A && X86_PML4E_A == X86_PDE_A);
354 AssertCompile(X86_PML4E_RW == X86_PDPE_RW && X86_PML4E_RW == X86_PDE_RW);
355 AssertCompile(X86_PML4E_US == X86_PDPE_US && X86_PML4E_US == X86_PDE_US);
356 AssertCompile(X86_PML4E_NX == X86_PDPE_LM_NX && X86_PML4E_NX == X86_PDE_PAE_NX);
357 Pde.u &= (Pml4e.u & Pdpe.u) | ~(X86PGPAEUINT)(X86_PML4E_A | X86_PML4E_RW | X86_PML4E_US);
358 Pde.u |= (Pml4e.u | Pdpe.u) & X86_PML4E_NX;
359
360# elif PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED_PAE
361 X86PDEPAE Pde = pgmShwGetPaePDE(pVCpu, GCPtr);
362
363# elif PGM_SHW_TYPE == PGM_TYPE_EPT
364 PEPTPD pPDDst;
365 int rc = pgmShwGetEPTPDPtr(pVCpu, GCPtr, NULL, &pPDDst);
366 if (rc == VINF_SUCCESS) /** @todo this function isn't expected to return informational status codes. Check callers / fix. */
367 { /* likely */ }
368 else
369 {
370 AssertRC(rc);
371 return rc;
372 }
373 Assert(pPDDst);
374
375 const unsigned iPd = ((GCPtr >> SHW_PD_SHIFT) & SHW_PD_MASK);
376 EPTPDE Pde = pPDDst->a[iPd];
377
378# elif PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_NESTED_32BIT
379 X86PDE Pde = pgmShwGet32BitPDE(pVCpu, GCPtr);
380
381# else
382# error "Misconfigured PGM_SHW_TYPE or something..."
383# endif
384 if (!SHW_PDE_IS_P(Pde))
385 return VERR_PAGE_TABLE_NOT_PRESENT;
386
387 /* Deal with large pages. */
388 if (SHW_PDE_IS_BIG(Pde))
389 {
390 /*
391 * Store the results.
392 * RW and US flags depend on the entire page translation hierarchy - except for
393 * legacy PAE which has a simplified PDPE.
394 */
395 if (pfFlags)
396 {
397 *pfFlags = (Pde.u & ~SHW_PDE_PG_MASK);
398# if PGM_WITH_NX(PGM_SHW_TYPE, PGM_SHW_TYPE) || PGM_SHW_TYPE == PGM_TYPE_NESTED_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED_AMD64
399 if ( (Pde.u & X86_PTE_PAE_NX)
400# if PGM_WITH_NX(PGM_SHW_TYPE, PGM_SHW_TYPE)
401 && CPUMIsGuestNXEnabled(pVCpu) /** @todo why do we have to check the guest state here? */
402# endif
403 )
404 *pfFlags |= X86_PTE_PAE_NX;
405# endif
406 }
407
408 if (pHCPhys)
409 *pHCPhys = (Pde.u & SHW_PDE_PG_MASK) + (GCPtr & (RT_BIT(SHW_PD_SHIFT) - 1) & X86_PAGE_4K_BASE_MASK);
410
411 return VINF_SUCCESS;
412 }
413
414 /*
415 * Get PT entry.
416 */
417 PSHWPT pPT;
418 int rc2 = PGM_HCPHYS_2_PTR(pVM, pVCpu, Pde.u & SHW_PDE_PG_MASK, &pPT);
419 if (RT_FAILURE(rc2))
420 return rc2;
421 const unsigned iPt = (GCPtr >> SHW_PT_SHIFT) & SHW_PT_MASK;
422 SHWPTE Pte = pPT->a[iPt];
423 if (!SHW_PTE_IS_P(Pte))
424 return VERR_PAGE_NOT_PRESENT;
425
426 /*
427 * Store the results.
428 * RW and US flags depend on the entire page translation hierarchy - except for
429 * legacy PAE which has a simplified PDPE.
430 */
431 if (pfFlags)
432 {
433 *pfFlags = (SHW_PTE_GET_U(Pte) & ~SHW_PTE_PG_MASK)
434 & ((Pde.u & (X86_PTE_RW | X86_PTE_US)) | ~(uint64_t)(X86_PTE_RW | X86_PTE_US));
435
436# if PGM_WITH_NX(PGM_SHW_TYPE, PGM_SHW_TYPE) || PGM_SHW_TYPE == PGM_TYPE_NESTED_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED_AMD64
437 /* The NX bit is determined by a bitwise OR between the PT and PD */
438 if ( ((SHW_PTE_GET_U(Pte) | Pde.u) & X86_PTE_PAE_NX)
439# if PGM_WITH_NX(PGM_SHW_TYPE, PGM_SHW_TYPE)
440 && CPUMIsGuestNXEnabled(pVCpu) /** @todo why do we have to check the guest state here? */
441# endif
442 )
443 *pfFlags |= X86_PTE_PAE_NX;
444# endif
445 }
446
447 if (pHCPhys)
448 *pHCPhys = SHW_PTE_GET_HCPHYS(Pte);
449
450 return VINF_SUCCESS;
451#endif /* PGM_SHW_TYPE != PGM_TYPE_NONE */
452}
453
454
455/**
456 * Modify page flags for a range of pages in the shadow context.
457 *
458 * The existing flags are ANDed with the fMask and ORed with the fFlags.
459 *
460 * @returns VBox status code.
461 * @param pVCpu The cross context virtual CPU structure.
462 * @param GCPtr Virtual address of the first page in the range. Page aligned!
463 * @param cb Size (in bytes) of the range to apply the modification to. Page aligned!
464 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
465 * @param fMask The AND mask - page flags X86_PTE_*.
466 * Be extremely CAREFUL with ~'ing values because they can be 32-bit!
467 * @param fOpFlags A combination of the PGM_MK_PK_XXX flags.
468 * @remark You must use PGMMapModifyPage() for pages in a mapping.
469 */
470PGM_SHW_DECL(int, ModifyPage)(PVMCPUCC pVCpu, RTGCUINTPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask, uint32_t fOpFlags)
471{
472#if PGM_SHW_TYPE == PGM_TYPE_NONE
473 RT_NOREF(pVCpu, GCPtr, cb, fFlags, fMask, fOpFlags);
474 AssertFailed();
475 return VERR_PGM_SHW_NONE_IPE;
476
477#else /* PGM_SHW_TYPE != PGM_TYPE_NONE */
478 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
479 PGM_LOCK_ASSERT_OWNER(pVM);
480
481 /*
482 * Walk page tables and pages till we're done.
483 */
484 int rc;
485 for (;;)
486 {
487 /*
488 * Get the PDE.
489 */
490# if PGM_SHW_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_NESTED_AMD64
491 X86PDEPAE Pde;
492 /* PML4 */
493 X86PML4E Pml4e = pgmShwGetLongModePML4E(pVCpu, GCPtr);
494 if (!(Pml4e.u & X86_PML4E_P))
495 return VERR_PAGE_TABLE_NOT_PRESENT;
496
497 /* PDPT */
498 PX86PDPT pPDPT;
499 rc = PGM_HCPHYS_2_PTR(pVM, pVCpu, Pml4e.u & X86_PML4E_PG_MASK, &pPDPT);
500 if (RT_FAILURE(rc))
501 return rc;
502 const unsigned iPDPT = (GCPtr >> SHW_PDPT_SHIFT) & SHW_PDPT_MASK;
503 X86PDPE Pdpe = pPDPT->a[iPDPT];
504 if (!(Pdpe.u & X86_PDPE_P))
505 return VERR_PAGE_TABLE_NOT_PRESENT;
506
507 /* PD */
508 PX86PDPAE pPd;
509 rc = PGM_HCPHYS_2_PTR(pVM, pVCpu, Pdpe.u & X86_PDPE_PG_MASK, &pPd);
510 if (RT_FAILURE(rc))
511 return rc;
512 const unsigned iPd = (GCPtr >> SHW_PD_SHIFT) & SHW_PD_MASK;
513 Pde = pPd->a[iPd];
514
515# elif PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED_PAE
516 X86PDEPAE Pde = pgmShwGetPaePDE(pVCpu, GCPtr);
517
518# elif PGM_SHW_TYPE == PGM_TYPE_EPT
519 const unsigned iPd = ((GCPtr >> SHW_PD_SHIFT) & SHW_PD_MASK);
520 PEPTPD pPDDst;
521 EPTPDE Pde;
522
523 rc = pgmShwGetEPTPDPtr(pVCpu, GCPtr, NULL, &pPDDst);
524 if (rc != VINF_SUCCESS)
525 {
526 AssertRC(rc);
527 return rc;
528 }
529 Assert(pPDDst);
530 Pde = pPDDst->a[iPd];
531
532# else /* PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_NESTED_32BIT */
533 X86PDE Pde = pgmShwGet32BitPDE(pVCpu, GCPtr);
534# endif
535 if (!SHW_PDE_IS_P(Pde))
536 return VERR_PAGE_TABLE_NOT_PRESENT;
537
538 AssertFatal(!SHW_PDE_IS_BIG(Pde));
539
540 /*
541 * Map the page table.
542 */
543 PSHWPT pPT;
544 rc = PGM_HCPHYS_2_PTR(pVM, pVCpu, Pde.u & SHW_PDE_PG_MASK, &pPT);
545 if (RT_FAILURE(rc))
546 return rc;
547
548 unsigned iPTE = (GCPtr >> SHW_PT_SHIFT) & SHW_PT_MASK;
549 while (iPTE < RT_ELEMENTS(pPT->a))
550 {
551 if (SHW_PTE_IS_P(pPT->a[iPTE]))
552 {
553 SHWPTE const OrgPte = pPT->a[iPTE];
554 SHWPTE NewPte;
555
556 SHW_PTE_SET(NewPte, (SHW_PTE_GET_U(OrgPte) & (fMask | SHW_PTE_PG_MASK)) | (fFlags & ~SHW_PTE_PG_MASK));
557 if (!SHW_PTE_IS_P(NewPte))
558 {
559 /** @todo Some CSAM code path might end up here and upset
560 * the page pool. */
561 AssertFailed();
562 }
563 else if ( SHW_PTE_IS_RW(NewPte)
564 && !SHW_PTE_IS_RW(OrgPte)
565 && !(fOpFlags & PGM_MK_PG_IS_MMIO2) )
566 {
567 /** @todo Optimize \#PF handling by caching data. We can
568 * then use this when PGM_MK_PG_IS_WRITE_FAULT is
569 * set instead of resolving the guest physical
570 * address yet again. */
571 PGMPTWALK GstWalk;
572 rc = PGMGstGetPage(pVCpu, GCPtr, &GstWalk);
573 AssertRC(rc);
574 if (RT_SUCCESS(rc))
575 {
576 Assert((GstWalk.fEffective & X86_PTE_RW) || !(CPUMGetGuestCR0(pVCpu) & X86_CR0_WP /* allow netware hack */));
577 PPGMPAGE pPage = pgmPhysGetPage(pVM, GstWalk.GCPhys);
578 Assert(pPage);
579 if (pPage)
580 {
581 rc = pgmPhysPageMakeWritable(pVM, pPage, GstWalk.GCPhys);
582 AssertRCReturn(rc, rc);
583 Log(("%s: pgmPhysPageMakeWritable on %RGv / %RGp %R[pgmpage]\n", __PRETTY_FUNCTION__, GCPtr, GstWalk.GCPhys, pPage));
584 }
585 }
586 }
587
588 SHW_PTE_ATOMIC_SET2(pPT->a[iPTE], NewPte);
589# if PGM_SHW_TYPE == PGM_TYPE_EPT
590 HMInvalidatePhysPage(pVM, (RTGCPHYS)GCPtr);
591# else
592 PGM_INVL_PG_ALL_VCPU(pVM, GCPtr);
593# endif
594 }
595
596 /* next page */
597 cb -= HOST_PAGE_SIZE;
598 if (!cb)
599 return VINF_SUCCESS;
600 GCPtr += HOST_PAGE_SIZE;
601 iPTE++;
602 }
603 }
604#endif /* PGM_SHW_TYPE != PGM_TYPE_NONE */
605}
606
607
608#ifdef IN_RING3
609/**
610 * Relocate any GC pointers related to shadow mode paging.
611 *
612 * @returns VBox status code.
613 * @param pVCpu The cross context virtual CPU structure.
614 * @param offDelta The relocation offset.
615 */
616PGM_SHW_DECL(int, Relocate)(PVMCPUCC pVCpu, RTGCPTR offDelta)
617{
618 RT_NOREF(pVCpu, offDelta);
619 return VINF_SUCCESS;
620}
621#endif
622
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