VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllGstSlatEpt.cpp.h@ 101309

Last change on this file since 101309 was 100232, checked in by vboxsync, 18 months ago

VMM: Nested VMX: bugref:10318 Fixed incorrect accumulation of execute permissions in the NX attribute bit while walking EPT.
This addresses the log flooding in bugref:10474 as a consequence.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1/* $Id: PGMAllGstSlatEpt.cpp.h 100232 2023-06-21 09:50:56Z vboxsync $ */
2/** @file
3 * VBox - Page Manager, Guest EPT SLAT - All context code.
4 */
5
6/*
7 * Copyright (C) 2021-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#if PGM_SLAT_TYPE != PGM_SLAT_TYPE_EPT
29# error "Unsupported SLAT type."
30#endif
31
32/**
33 * Checks if the EPT PTE permissions are valid.
34 *
35 * @returns @c true if valid, @c false otherwise.
36 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
37 * @param uEntry The EPT page table entry to check.
38 */
39DECLINLINE(bool) PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(PCVMCPUCC pVCpu, uint64_t uEntry)
40{
41 if (!(uEntry & EPT_E_READ))
42 {
43 Assert(!pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.fVmxModeBasedExecuteEpt);
44 Assert(!RT_BF_GET(pVCpu->pgm.s.uEptVpidCapMsr, VMX_BF_EPT_VPID_CAP_EXEC_ONLY));
45 NOREF(pVCpu);
46 if (uEntry & (EPT_E_WRITE | EPT_E_EXECUTE))
47 return false;
48 }
49 return true;
50}
51
52
53/**
54 * Checks if the EPT memory type is valid.
55 *
56 * @returns @c true if valid, @c false otherwise.
57 * @param uEntry The EPT page table entry to check.
58 * @param uLevel The page table walk level.
59 */
60DECLINLINE(bool) PGM_GST_SLAT_NAME_EPT(WalkIsMemTypeValid)(uint64_t uEntry, uint8_t uLevel)
61{
62 Assert(uLevel <= 3 && uLevel >= 1); NOREF(uLevel);
63 uint8_t const fEptMemTypeMask = uEntry & VMX_BF_EPT_PT_MEMTYPE_MASK;
64 switch (fEptMemTypeMask)
65 {
66 case EPT_E_MEMTYPE_WB:
67 case EPT_E_MEMTYPE_UC:
68 case EPT_E_MEMTYPE_WP:
69 case EPT_E_MEMTYPE_WT:
70 case EPT_E_MEMTYPE_WC:
71 return true;
72 }
73 return false;
74}
75
76
77/**
78 * Updates page walk result info when a not-present page is encountered.
79 *
80 * @returns VERR_PAGE_TABLE_NOT_PRESENT.
81 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
82 * @param pWalk The page walk info to update.
83 * @param uEntry The EPT PTE that is not present.
84 * @param uLevel The page table walk level.
85 */
86DECLINLINE(int) PGM_GST_SLAT_NAME_EPT(WalkReturnNotPresent)(PCVMCPUCC pVCpu, PPGMPTWALK pWalk, uint64_t uEntry, uint8_t uLevel)
87{
88 static PGMWALKFAIL const s_afEptViolations[] = { PGM_WALKFAIL_EPT_VIOLATION, PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE };
89 uint8_t const fEptVeSupported = pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.fVmxEptXcptVe;
90 uint8_t const fConvertible = RT_BOOL(uLevel == 1 || (uEntry & EPT_E_BIT_LEAF));
91 uint8_t const idxViolationType = fEptVeSupported & fConvertible & !RT_BF_GET(uEntry, VMX_BF_EPT_PT_SUPPRESS_VE);
92
93 pWalk->fNotPresent = true;
94 pWalk->uLevel = uLevel;
95 pWalk->fFailed = s_afEptViolations[idxViolationType];
96 return VERR_PAGE_TABLE_NOT_PRESENT;
97}
98
99
100/**
101 * Updates page walk result info when a bad physical address is encountered.
102 *
103 * @returns VERR_PAGE_TABLE_NOT_PRESENT .
104 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
105 * @param pWalk The page walk info to update.
106 * @param uLevel The page table walk level.
107 * @param rc The error code that caused this bad physical address situation.
108 */
109DECLINLINE(int) PGM_GST_SLAT_NAME_EPT(WalkReturnBadPhysAddr)(PCVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel, int rc)
110{
111 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc); NOREF(pVCpu);
112 pWalk->fBadPhysAddr = true;
113 pWalk->uLevel = uLevel;
114 pWalk->fFailed = PGM_WALKFAIL_EPT_VIOLATION;
115 return VERR_PAGE_TABLE_NOT_PRESENT;
116}
117
118
119/**
120 * Updates page walk result info when reserved bits are encountered.
121 *
122 * @returns VERR_PAGE_TABLE_NOT_PRESENT.
123 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
124 * @param pWalk The page walk info to update.
125 * @param uLevel The page table walk level.
126 */
127DECLINLINE(int) PGM_GST_SLAT_NAME_EPT(WalkReturnRsvdError)(PVMCPUCC pVCpu, PPGMPTWALK pWalk, uint8_t uLevel)
128{
129 NOREF(pVCpu);
130 pWalk->fRsvdError = true;
131 pWalk->uLevel = uLevel;
132 pWalk->fFailed = PGM_WALKFAIL_EPT_MISCONFIG;
133 return VERR_PAGE_TABLE_NOT_PRESENT;
134}
135
136
137/**
138 * Walks the guest's EPT page table (second-level address translation).
139 *
140 * @returns VBox status code.
141 * @retval VINF_SUCCESS on success.
142 * @retval VERR_PAGE_TABLE_NOT_PRESENT on failure. Check pWalk for details.
143 *
144 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
145 * @param GCPhysNested The nested-guest physical address to walk.
146 * @param fIsLinearAddrValid Whether the linear-address in @c GCPtrNested caused
147 * this page walk.
148 * @param GCPtrNested The nested-guest linear address that caused this
149 * translation. If @c fIsLinearAddrValid is false, pass
150 * 0.
151 * @param pWalk The page walk info.
152 * @param pSlatWalk The SLAT mode specific page walk info.
153 */
154DECLINLINE(int) PGM_GST_SLAT_NAME_EPT(Walk)(PVMCPUCC pVCpu, RTGCPHYS GCPhysNested, bool fIsLinearAddrValid, RTGCPTR GCPtrNested,
155 PPGMPTWALK pWalk, PSLATPTWALK pSlatWalk)
156{
157 Assert(fIsLinearAddrValid || GCPtrNested == 0);
158
159 /*
160 * Init walk structures.
161 */
162 RT_ZERO(*pWalk);
163 RT_ZERO(*pSlatWalk);
164
165 pWalk->GCPtr = GCPtrNested;
166 pWalk->GCPhysNested = GCPhysNested;
167 pWalk->fIsLinearAddrValid = fIsLinearAddrValid;
168 pWalk->fIsSlat = true;
169
170 /*
171 * Figure out EPT attributes that are cumulative (logical-AND) across page walks.
172 * - R, W, X_SUPER are unconditionally cumulative.
173 * See Intel spec. Table 26-7 "Exit Qualification for EPT Violations".
174 *
175 * - X_USER is cumulative but relevant only when mode-based execute control for EPT
176 * which we currently don't support it (asserted below).
177 *
178 * - MEMTYPE is not cumulative and only applicable to the final paging entry.
179 *
180 * - A, D EPT bits map to the regular page-table bit positions. Thus, they're not
181 * included in the mask below and handled separately. Accessed bits are
182 * cumulative but dirty bits are not cumulative as they're only applicable to
183 * the final paging entry.
184 */
185 Assert(!pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.fVmxModeBasedExecuteEpt);
186 uint64_t const fEptAndMask = ( PGM_PTATTRS_EPT_R_MASK
187 | PGM_PTATTRS_EPT_W_MASK
188 | PGM_PTATTRS_EPT_X_SUPER_MASK) & PGM_PTATTRS_EPT_MASK;
189
190 /*
191 * Do the walk.
192 */
193 uint64_t fEffective;
194 {
195 /*
196 * EPTP.
197 *
198 * We currently only support 4-level EPT paging.
199 * EPT 5-level paging was documented at some point (bit 7 of MSR_IA32_VMX_EPT_VPID_CAP)
200 * but for some reason seems to have been removed from subsequent specs.
201 */
202 int const rc = pgmGstGetEptPML4PtrEx(pVCpu, &pSlatWalk->pPml4);
203 if (RT_SUCCESS(rc))
204 { /* likely */ }
205 else return PGM_GST_SLAT_NAME_EPT(WalkReturnBadPhysAddr)(pVCpu, pWalk, 4, rc);
206 }
207 {
208 /*
209 * PML4E.
210 */
211 PEPTPML4E pPml4e;
212 pSlatWalk->pPml4e = pPml4e = &pSlatWalk->pPml4->a[(GCPhysNested >> SLAT_PML4_SHIFT) & SLAT_PML4_MASK];
213 EPTPML4E Pml4e;
214 pSlatWalk->Pml4e.u = Pml4e.u = pPml4e->u;
215
216 if (SLAT_IS_PGENTRY_PRESENT(pVCpu, Pml4e)) { /* probable */ }
217 else return PGM_GST_SLAT_NAME_EPT(WalkReturnNotPresent)(pVCpu, pWalk, Pml4e.u, 4);
218
219 if (RT_LIKELY( SLAT_IS_PML4E_VALID(pVCpu, Pml4e)
220 && PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(pVCpu, Pml4e.u)))
221 { /* likely */ }
222 else return PGM_GST_SLAT_NAME_EPT(WalkReturnRsvdError)(pVCpu, pWalk, 4);
223
224 uint64_t const fEptAttrs = Pml4e.u & EPT_PML4E_ATTR_MASK;
225 uint8_t const fRead = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_READ);
226 uint8_t const fWrite = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_WRITE);
227 uint8_t const fExecute = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_EXECUTE);
228 uint8_t const fAccessed = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_ACCESSED);
229 uint64_t const fEptAndBits = (fEptAttrs << PGM_PTATTRS_EPT_SHIFT) & fEptAndMask;
230 fEffective = RT_BF_MAKE(PGM_PTATTRS_R, fRead)
231 | RT_BF_MAKE(PGM_PTATTRS_W, fWrite)
232 | RT_BF_MAKE(PGM_PTATTRS_NX, !fExecute)
233 | RT_BF_MAKE(PGM_PTATTRS_A, fAccessed)
234 | fEptAndBits;
235 pWalk->fEffective = fEffective;
236
237 int const rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pml4e.u & EPT_PML4E_PG_MASK, &pSlatWalk->pPdpt);
238 if (RT_SUCCESS(rc)) { /* probable */ }
239 else return PGM_GST_SLAT_NAME_EPT(WalkReturnBadPhysAddr)(pVCpu, pWalk, 3, rc);
240 }
241 {
242 /*
243 * PDPTE.
244 */
245 PEPTPDPTE pPdpte;
246 pSlatWalk->pPdpte = pPdpte = &pSlatWalk->pPdpt->a[(GCPhysNested >> SLAT_PDPT_SHIFT) & SLAT_PDPT_MASK];
247 EPTPDPTE Pdpte;
248 pSlatWalk->Pdpte.u = Pdpte.u = pPdpte->u;
249
250 if (SLAT_IS_PGENTRY_PRESENT(pVCpu, Pdpte)) { /* probable */ }
251 else return PGM_GST_SLAT_NAME_EPT(WalkReturnNotPresent)(pVCpu, pWalk, Pdpte.u, 3);
252
253 /* The order of the following "if" and "else if" statements matter. */
254 if ( SLAT_IS_PDPE_VALID(pVCpu, Pdpte)
255 && PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(pVCpu, Pdpte.u))
256 {
257 uint64_t const fEptAttrs = Pdpte.u & EPT_PDPTE_ATTR_MASK;
258 uint8_t const fRead = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_READ);
259 uint8_t const fWrite = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_WRITE);
260 uint8_t const fExecute = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_EXECUTE);
261 uint8_t const fAccessed = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_ACCESSED);
262 uint64_t const fEptAndBits = (fEptAttrs << PGM_PTATTRS_EPT_SHIFT) & fEptAndMask;
263 fEffective &= RT_BF_MAKE(PGM_PTATTRS_R, fRead)
264 | RT_BF_MAKE(PGM_PTATTRS_W, fWrite)
265 | RT_BF_MAKE(PGM_PTATTRS_A, fAccessed)
266 | fEptAndBits;
267 fEffective |= RT_BF_MAKE(PGM_PTATTRS_NX, !fExecute);
268 pWalk->fEffective = fEffective;
269 }
270 else if ( SLAT_IS_BIG_PDPE_VALID(pVCpu, Pdpte)
271 && PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(pVCpu, Pdpte.u)
272 && PGM_GST_SLAT_NAME_EPT(WalkIsMemTypeValid)(Pdpte.u, 3))
273 {
274 uint64_t const fEptAttrs = Pdpte.u & EPT_PDPTE1G_ATTR_MASK;
275 uint8_t const fRead = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_READ);
276 uint8_t const fWrite = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_WRITE);
277 uint8_t const fExecute = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_EXECUTE);
278 uint8_t const fAccessed = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_ACCESSED);
279 uint8_t const fDirty = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_DIRTY);
280 uint8_t const fMemType = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_MEMTYPE);
281 uint64_t const fEptAndBits = (fEptAttrs << PGM_PTATTRS_EPT_SHIFT) & fEptAndMask;
282 fEffective &= RT_BF_MAKE(PGM_PTATTRS_R, fRead)
283 | RT_BF_MAKE(PGM_PTATTRS_W, fWrite)
284 | RT_BF_MAKE(PGM_PTATTRS_A, fAccessed)
285 | fEptAndBits;
286 fEffective |= RT_BF_MAKE(PGM_PTATTRS_D, fDirty)
287 | RT_BF_MAKE(PGM_PTATTRS_EPT_MEMTYPE, fMemType)
288 | RT_BF_MAKE(PGM_PTATTRS_NX, !fExecute);
289 pWalk->fEffective = fEffective;
290
291 pWalk->fGigantPage = true;
292 pWalk->fSucceeded = true;
293 pWalk->GCPhys = SLAT_GET_PDPE1G_GCPHYS(pVCpu, Pdpte)
294 | (GCPhysNested & SLAT_PAGE_1G_OFFSET_MASK);
295 PGM_A20_APPLY_TO_VAR(pVCpu, pWalk->GCPhys);
296 return VINF_SUCCESS;
297 }
298 else return PGM_GST_SLAT_NAME_EPT(WalkReturnRsvdError)(pVCpu, pWalk, 3);
299
300 int const rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pdpte.u & EPT_PDPTE_PG_MASK, &pSlatWalk->pPd);
301 if (RT_SUCCESS(rc)) { /* probable */ }
302 else return PGM_GST_SLAT_NAME_EPT(WalkReturnBadPhysAddr)(pVCpu, pWalk, 3, rc);
303 }
304 {
305 /*
306 * PDE.
307 */
308 PSLATPDE pPde;
309 pSlatWalk->pPde = pPde = &pSlatWalk->pPd->a[(GCPhysNested >> SLAT_PD_SHIFT) & SLAT_PD_MASK];
310 SLATPDE Pde;
311 pSlatWalk->Pde.u = Pde.u = pPde->u;
312
313 if (SLAT_IS_PGENTRY_PRESENT(pVCpu, Pde)) { /* probable */ }
314 else return PGM_GST_SLAT_NAME_EPT(WalkReturnNotPresent)(pVCpu, pWalk, Pde.u, 2);
315
316 /* The order of the following "if" and "else if" statements matter. */
317 if ( SLAT_IS_PDE_VALID(pVCpu, Pde)
318 && PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(pVCpu, Pde.u))
319 {
320 uint64_t const fEptAttrs = Pde.u & EPT_PDE_ATTR_MASK;
321 uint8_t const fRead = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_READ);
322 uint8_t const fWrite = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_WRITE);
323 uint8_t const fExecute = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_EXECUTE);
324 uint8_t const fAccessed = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_ACCESSED);
325 uint64_t const fEptAndBits = (fEptAttrs << PGM_PTATTRS_EPT_SHIFT) & fEptAndMask;
326 fEffective &= RT_BF_MAKE(PGM_PTATTRS_R, fRead)
327 | RT_BF_MAKE(PGM_PTATTRS_W, fWrite)
328 | RT_BF_MAKE(PGM_PTATTRS_A, fAccessed)
329 | fEptAndBits;
330 fEffective |= RT_BF_MAKE(PGM_PTATTRS_NX, !fExecute);
331 pWalk->fEffective = fEffective;
332 }
333 else if ( SLAT_IS_BIG_PDE_VALID(pVCpu, Pde)
334 && PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(pVCpu, Pde.u)
335 && PGM_GST_SLAT_NAME_EPT(WalkIsMemTypeValid)(Pde.u, 2))
336 {
337 uint64_t const fEptAttrs = Pde.u & EPT_PDE2M_ATTR_MASK;
338 uint8_t const fRead = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_READ);
339 uint8_t const fWrite = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_WRITE);
340 uint8_t const fExecute = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_EXECUTE);
341 uint8_t const fAccessed = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_ACCESSED);
342 uint8_t const fDirty = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_DIRTY);
343 uint8_t const fMemType = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_MEMTYPE);
344 uint64_t const fEptAndBits = (fEptAttrs << PGM_PTATTRS_EPT_SHIFT) & fEptAndMask;
345 fEffective &= RT_BF_MAKE(PGM_PTATTRS_R, fRead)
346 | RT_BF_MAKE(PGM_PTATTRS_W, fWrite)
347 | RT_BF_MAKE(PGM_PTATTRS_A, fAccessed)
348 | fEptAndBits;
349 fEffective |= RT_BF_MAKE(PGM_PTATTRS_D, fDirty)
350 | RT_BF_MAKE(PGM_PTATTRS_EPT_MEMTYPE, fMemType)
351 | RT_BF_MAKE(PGM_PTATTRS_NX, !fExecute);
352 pWalk->fEffective = fEffective;
353
354 pWalk->fBigPage = true;
355 pWalk->fSucceeded = true;
356 pWalk->GCPhys = SLAT_GET_PDE2M_GCPHYS(pVCpu, Pde)
357 | (GCPhysNested & SLAT_PAGE_2M_OFFSET_MASK);
358 PGM_A20_APPLY_TO_VAR(pVCpu, pWalk->GCPhys);
359 return VINF_SUCCESS;
360 }
361 else return PGM_GST_SLAT_NAME_EPT(WalkReturnRsvdError)(pVCpu, pWalk, 2);
362
363 int const rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pde.u & EPT_PDE_PG_MASK, &pSlatWalk->pPt);
364 if (RT_SUCCESS(rc)) { /* probable */ }
365 else return PGM_GST_SLAT_NAME_EPT(WalkReturnBadPhysAddr)(pVCpu, pWalk, 1, rc);
366 }
367 {
368 /*
369 * PTE.
370 */
371 PSLATPTE pPte;
372 pSlatWalk->pPte = pPte = &pSlatWalk->pPt->a[(GCPhysNested >> SLAT_PT_SHIFT) & SLAT_PT_MASK];
373 SLATPTE Pte;
374 pSlatWalk->Pte.u = Pte.u = pPte->u;
375
376 if (SLAT_IS_PGENTRY_PRESENT(pVCpu, Pte)) { /* probable */ }
377 else return PGM_GST_SLAT_NAME_EPT(WalkReturnNotPresent)(pVCpu, pWalk, Pte.u, 1);
378
379 if ( SLAT_IS_PTE_VALID(pVCpu, Pte)
380 && PGM_GST_SLAT_NAME_EPT(WalkIsPermValid)(pVCpu, Pte.u)
381 && PGM_GST_SLAT_NAME_EPT(WalkIsMemTypeValid)(Pte.u, 1))
382 { /* likely*/ }
383 else
384 return PGM_GST_SLAT_NAME_EPT(WalkReturnRsvdError)(pVCpu, pWalk, 1);
385
386 uint64_t const fEptAttrs = Pte.u & EPT_PTE_ATTR_MASK;
387 uint8_t const fRead = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_READ);
388 uint8_t const fWrite = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_WRITE);
389 uint8_t const fExecute = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_EXECUTE);
390 uint8_t const fAccessed = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_ACCESSED);
391 uint8_t const fDirty = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_DIRTY);
392 uint8_t const fMemType = RT_BF_GET(fEptAttrs, VMX_BF_EPT_PT_MEMTYPE);
393 uint64_t const fEptAndBits = (fEptAttrs << PGM_PTATTRS_EPT_SHIFT) & fEptAndMask;
394 fEffective &= RT_BF_MAKE(PGM_PTATTRS_R, fRead)
395 | RT_BF_MAKE(PGM_PTATTRS_W, fWrite)
396 | RT_BF_MAKE(PGM_PTATTRS_A, fAccessed)
397 | fEptAndBits;
398 fEffective |= RT_BF_MAKE(PGM_PTATTRS_D, fDirty)
399 | RT_BF_MAKE(PGM_PTATTRS_EPT_MEMTYPE, fMemType)
400 | RT_BF_MAKE(PGM_PTATTRS_NX, !fExecute);
401 pWalk->fEffective = fEffective;
402
403 pWalk->fSucceeded = true;
404 pWalk->GCPhys = SLAT_GET_PTE_GCPHYS(pVCpu, Pte) | (GCPhysNested & GUEST_PAGE_OFFSET_MASK);
405 return VINF_SUCCESS;
406 }
407}
408
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