VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingProtect.c@ 102157

Last change on this file since 102157 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1/* $Id: bs3-cmn-PagingProtect.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * BS3Kit - Bs3PagingProtect
4 */
5
6/*
7 * Copyright (C) 2007-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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "bs3kit-template-header.h"
42#include "bs3-cmn-paging.h"
43#include <iprt/asm-amd64-x86.h>
44#include <iprt/param.h>
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#if 0
51# define BS3PAGING_DPRINTF1(a) Bs3TestPrintf a
52#else
53# define BS3PAGING_DPRINTF1(a) do { } while (0)
54#endif
55#if 0
56# define BS3PAGING_DPRINTF2(a) Bs3TestPrintf a
57#else
58# define BS3PAGING_DPRINTF2(a) do { } while (0)
59#endif
60
61
62static void *bs3PagingBuildPaeTable(uint64_t uTmpl, uint64_t cbIncrement, BS3MEMKIND enmKind, int *prc)
63{
64 uint64_t BS3_FAR *pau64 = (uint64_t BS3_FAR *)Bs3MemAlloc(enmKind, _4K);
65 if (pau64)
66 {
67 unsigned i;
68 for (i = 0; i < _4K / sizeof(uint64_t); i++, uTmpl += cbIncrement)
69 pau64[i] = uTmpl;
70 }
71 else
72 *prc = VERR_NO_MEMORY;
73 return pau64;
74}
75
76
77#undef bs3PagingGetLegacyPte
78BS3_CMN_DEF(X86PTE BS3_FAR *, bs3PagingGetLegacyPte,(RTCCUINTXREG cr3, uint32_t uFlat, bool fUseInvlPg, int *prc))
79{
80 X86PTE BS3_FAR *pPTE = NULL;
81#if TMPL_BITS == 16
82 uint32_t const uMaxAddr = BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode) ? _1M - 1 : BS3_SEL_TILED_AREA_SIZE - 1;
83#else
84 uint32_t const uMaxAddr = UINT32_MAX;
85#endif
86 BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: cr3=%RX32 uFlat=%RX32 uMaxAddr=%RX32\n", (uint32_t)cr3, uFlat, uMaxAddr));
87
88 *prc = VERR_OUT_OF_RANGE;
89 if (cr3 <= uMaxAddr)
90 {
91 unsigned const iPde = (uFlat >> X86_PD_SHIFT) & X86_PD_MASK;
92 PX86PD const pPD = (PX86PD)Bs3XptrFlatToCurrent(cr3 & X86_CR3_PAGE_MASK);
93
94 BS3_ASSERT(pPD->a[iPde].b.u1Present);
95 if (pPD->a[iPde].b.u1Present)
96 {
97 unsigned const iPte = (uFlat >> X86_PT_SHIFT) & X86_PT_MASK;
98
99 BS3_ASSERT(pPD->a[iPde].b.u1Present);
100 BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: pPD=%p iPde=%#x: %#RX32\n", pPD, iPde, pPD->a[iPde]));
101 if (pPD->a[iPde].b.u1Present)
102 {
103 if (!pPD->a[iPde].b.u1Size)
104 {
105 if (pPD->a[iPde].u <= uMaxAddr)
106 pPTE = &((X86PT BS3_FAR *)Bs3XptrFlatToCurrent(pPD->a[iPde].u & ~(uint32_t)PAGE_OFFSET_MASK))->a[iPte];
107 else
108 BS3PAGING_DPRINTF1(("bs3PagingGetLegacyPte: out of range! iPde=%#x: %#x\n", iPde, pPD->a[iPde].u));
109 }
110 else
111 {
112 X86PT BS3_FAR *pPT;
113 uint32_t uPte = (pPD->a[iPde].u & ~(uint32_t)(X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_PG_HIGH_MASK)) \
114 | X86_PTE_D;
115 if (pPD->a[iPde].b.u1Global)
116 uPte |= X86_PTE_G;
117 if (pPD->a[iPde].b.u1PAT)
118 uPte |= X86_PTE_PAT;
119
120 pPT = (X86PT BS3_FAR *)bs3PagingBuildPaeTable(RT_MAKE_U64(uPte, uPte | PAGE_SIZE),
121 RT_MAKE_U64(PAGE_SIZE*2, PAGE_SIZE*2),
122 uMaxAddr > _1M ? BS3MEMKIND_TILED : BS3MEMKIND_REAL, prc);
123
124 BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: Built pPT=%p uPte=%RX32\n", pPT, uPte));
125 if (pPT)
126 {
127 ASMAtomicUoWriteU32(&pPD->a[iPde].u,
128 Bs3SelPtrToFlat(pPT)
129 | ( pPD->a[iPde].u
130 & ~(uint32_t)(X86_PTE_PG_MASK | X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_D)));
131 BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: iPde=%#x: %#RX32\n", iPde, pPD->a[iPde].u));
132 if (fUseInvlPg)
133 ASMInvalidatePage(uFlat);
134 pPTE = &pPT->a[iPte];
135 }
136 }
137 }
138 }
139 }
140 else
141 BS3PAGING_DPRINTF1(("bs3PagingGetLegacyPte: out of range! cr3=%#x\n", cr3));
142 return pPTE;
143}
144
145
146/**
147 * Get the PTE for an address, given a PAE or long mode CR3.
148 *
149 * @returns Pointer to the PTE on success, NULL on failure.
150 * @param cr3 The CR3.
151 * @param bMode Indicates whether it's PAE or long mode.
152 * @param uFlat The address for which we want the PTE.
153 * @param fUseInvlPg Whether we can use invalidate page when
154 * replacing large pages.
155 * @param prc Updated only on failure.
156 */
157#undef bs3PagingGetPaePte
158BS3_CMN_DEF(X86PTEPAE BS3_FAR *, bs3PagingGetPaePte,(RTCCUINTXREG cr3, uint8_t bMode, uint64_t uFlat, bool fUseInvlPg, int *prc))
159{
160 X86PTEPAE BS3_FAR *pPTE = NULL;
161#if TMPL_BITS == 16
162 uint32_t const uMaxAddr = BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode) ? _1M - 1 : BS3_SEL_TILED_AREA_SIZE - 1;
163#else
164 uintptr_t const uMaxAddr = ~(uintptr_t)0;
165#endif
166
167 *prc = VERR_OUT_OF_RANGE;
168 if ((cr3 & X86_CR3_AMD64_PAGE_MASK) <= uMaxAddr)
169 {
170 X86PDPAE BS3_FAR *pPD;
171 if (BS3_MODE_IS_64BIT_SYS(bMode))
172 {
173 unsigned const iPml4e = (uFlat >> X86_PML4_SHIFT) & X86_PML4_MASK;
174 X86PML4 BS3_FAR *pPml4 = (X86PML4 BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_AMD64_PAGE_MASK);
175 BS3_ASSERT(pPml4->a[iPml4e].n.u1Present);
176 if ((pPml4->a[iPml4e].u & X86_PML4E_PG_MASK) <= uMaxAddr)
177 {
178 unsigned const iPdpte = (uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
179 X86PDPT BS3_FAR *pPdpt = (X86PDPT BS3_FAR *)Bs3XptrFlatToCurrent(pPml4->a[iPml4e].u & X86_PML4E_PG_MASK);
180 BS3_ASSERT(pPdpt->a[iPdpte].n.u1Present);
181 if (!pPdpt->a[iPdpte].b.u1Size)
182 {
183 if ((pPdpt->a[iPdpte].u & X86_PDPE_PG_MASK) <= uMaxAddr)
184 pPD = (X86PDPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPdpt->a[iPdpte].u & ~(uint64_t)PAGE_OFFSET_MASK);
185 else
186 BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! iPdpte=%#x: %RX64 max=%RX32\n",
187 iPdpte, pPdpt->a[iPdpte].u, (uint32_t)uMaxAddr));
188 }
189 else
190 {
191 /* Split 1GB page. */
192 pPD = (X86PDPAE BS3_FAR *)bs3PagingBuildPaeTable(pPdpt->a[iPdpte].u, _2M,
193 uMaxAddr > _1M ? BS3MEMKIND_TILED : BS3MEMKIND_REAL, prc);
194 if (pPD)
195 {
196 ASMAtomicUoWriteU64(&pPdpt->a[iPdpte].u,
197 Bs3SelPtrToFlat(pPD)
198 | ( pPdpt->a[iPdpte].u
199 & ~(uint64_t)(X86_PDPE_PG_MASK | X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_D)));
200 if (fUseInvlPg)
201 ASMInvalidatePage(uFlat);
202 }
203 }
204 }
205 }
206 //else if (uFlat <= UINT32_MAX) - fixme!
207 else if (!(uFlat >> 32))
208 {
209 unsigned const iPdpte = ((uint32_t)uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
210 X86PDPT BS3_FAR *pPdpt = (X86PDPT BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_PAE_PAGE_MASK);
211 BS3_ASSERT(pPdpt->a[iPdpte].n.u1Present);
212 if ((pPdpt->a[iPdpte].u & X86_PDPE_PG_MASK) <= uMaxAddr)
213 pPD = (X86PDPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPdpt->a[iPdpte].u & X86_PDPE_PG_MASK);
214 else
215 BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! iPdpte=%#x: %RX64 max=%RX32\n",
216 iPdpte, pPdpt->a[iPdpte].u, (uint32_t)uMaxAddr));
217 }
218 else
219 {
220 pPD = NULL;
221 BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! uFlat=%#RX64 max=%RX32\n", uFlat, (uint32_t)uMaxAddr));
222 }
223 if (pPD)
224 {
225 unsigned const iPte = (uFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
226 unsigned const iPde = (uFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
227 if (!pPD->a[iPde].b.u1Size)
228 {
229 if ((pPD->a[iPde].u & X86_PDE_PAE_PG_MASK) <= uMaxAddr)
230 pPTE = &((X86PTPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPD->a[iPde].u & ~(uint64_t)PAGE_OFFSET_MASK))->a[iPte];
231 else
232 BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! iPde=%#x: %RX64 max=%RX32\n",
233 iPde, pPD->a[iPde].u, (uint32_t)uMaxAddr));
234 }
235 else
236 {
237 /* Split 2MB page. */
238 X86PTPAE BS3_FAR *pPT;
239 uint64_t uTmpl = pPD->a[iPde].u & ~(uint64_t)(X86_PDE4M_G | X86_PDE4M_PS | X86_PDE4M_PAT);
240 if (!pPD->a[iPde].b.u1Global)
241 uTmpl |= X86_PTE_G;
242 if (!pPD->a[iPde].b.u1PAT)
243 uTmpl |= X86_PTE_PAT;
244
245 pPT = (X86PTPAE BS3_FAR *)bs3PagingBuildPaeTable(uTmpl, PAGE_SIZE,
246 uMaxAddr > _1M ? BS3MEMKIND_TILED : BS3MEMKIND_REAL, prc);
247 if (pPT)
248 {
249 ASMAtomicUoWriteU64(&pPD->a[iPde].u,
250 Bs3SelPtrToFlat(pPT)
251 | ( pPD->a[iPde].u
252 & ~(uint64_t)(X86_PTE_PAE_PG_MASK | X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_D)));
253 if (fUseInvlPg)
254 ASMInvalidatePage(uFlat);
255 pPTE = &pPT->a[iPte];
256 }
257 }
258 }
259 }
260 else
261 BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! cr3=%#RX32 uMaxAddr=%#RX32\n", (uint32_t)cr3, (uint32_t)uMaxAddr));
262 return pPTE;
263}
264
265
266#undef Bs3PagingProtect
267BS3_CMN_DEF(int, Bs3PagingProtect,(uint64_t uFlat, uint64_t cb, uint64_t fSet, uint64_t fClear))
268{
269#if ARCH_BITS == 16
270 if (!BS3_MODE_IS_V86(g_bBs3CurrentMode))
271#endif
272 {
273 RTCCUINTXREG const cr3 = ASMGetCR3();
274 RTCCUINTXREG const cr4 = g_uBs3CpuDetected & BS3CPU_F_CPUID ? ASMGetCR4() : 0;
275 bool const fLegacyPTs = !(cr4 & X86_CR4_PAE);
276 bool const fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486
277 && ( cb < UINT64_C(16)*PAGE_SIZE
278 || (cr4 & X86_CR4_PGE));
279 unsigned cEntries;
280 int rc;
281
282 /*
283 * Adjust the range parameters.
284 */
285 cb += uFlat & PAGE_OFFSET_MASK;
286 cb = RT_ALIGN_64(cb, PAGE_SIZE);
287 uFlat &= ~(uint64_t)PAGE_OFFSET_MASK;
288
289 fSet &= ~X86_PTE_PAE_PG_MASK;
290 fClear &= ~X86_PTE_PAE_PG_MASK;
291
292 BS3PAGING_DPRINTF1(("Bs3PagingProtect: uFlat=%RX64 cb=%RX64 fSet=%RX64 fClear=%RX64 %s %s\n", uFlat, cb, fSet, fClear,
293 fLegacyPTs ? "legacy" : "pae/amd64", fUseInvlPg ? "invlpg" : "reload-cr3"));
294 if (fLegacyPTs)
295 {
296 /*
297 * Legacy page tables.
298 */
299 while ((uint32_t)cb > 0)
300 {
301 PX86PTE pPte = BS3_CMN_FAR_NM(bs3PagingGetLegacyPte)(cr3, (uint32_t)uFlat, fUseInvlPg, &rc);
302 if (!pPte)
303 return rc;
304
305 cEntries = X86_PG_ENTRIES - ((uFlat >> X86_PT_SHIFT) & X86_PT_MASK);
306 while (cEntries-- > 0 && cb > 0)
307 {
308 pPte->u &= ~(uint32_t)fClear;
309 pPte->u |= (uint32_t)fSet;
310 if (fUseInvlPg)
311 ASMInvalidatePage(uFlat);
312
313 pPte++;
314 uFlat += PAGE_SIZE;
315 cb -= PAGE_SIZE;
316 }
317 }
318 }
319 else
320 {
321 /*
322 * Long mode or PAE page tables (at this level they are the same).
323 */
324 while (cb > 0)
325 {
326 PX86PTEPAE pPte = BS3_CMN_FAR_NM(bs3PagingGetPaePte)(cr3, g_bBs3CurrentMode, uFlat, fUseInvlPg, &rc);
327 if (!pPte)
328 return rc;
329
330 cEntries = X86_PG_ENTRIES - ((uFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
331 while (cEntries-- > 0 && cb > 0)
332 {
333 pPte->u &= ~fClear;
334 pPte->u |= fSet;
335 if (fUseInvlPg)
336 ASMInvalidatePage(uFlat);
337
338 pPte++;
339 uFlat += PAGE_SIZE;
340 cb -= PAGE_SIZE;
341 }
342 }
343 }
344
345 /*
346 * Flush the TLB if we didn't use INVLPG above.
347 */
348 BS3PAGING_DPRINTF2(("Bs3PagingProtect: reloading cr3=%RX32\n", (uint32_t)cr3));
349 //if (!fUseInvlPg)
350 ASMSetCR3(cr3);
351 BS3PAGING_DPRINTF2(("Bs3PagingProtect: reloaded cr3=%RX32\n", (uint32_t)cr3));
352 }
353#if ARCH_BITS == 16
354 /*
355 * We can do this stuff in v8086 mode.
356 */
357 else
358 return Bs3SwitchFromV86To16BitAndCallC((FPFNBS3FAR)Bs3PagingProtect_f16, sizeof(uint64_t) * 4, uFlat, cb, fSet, fClear);
359#endif
360 return VINF_SUCCESS;
361}
362
363
364#undef Bs3PagingProtectPtr
365BS3_CMN_DEF(int, Bs3PagingProtectPtr,(void *pv, size_t cb, uint64_t fSet, uint64_t fClear))
366{
367#if ARCH_BITS == 16
368 return BS3_CMN_NM(Bs3PagingProtect)(Bs3SelPtrToFlat(pv), cb, fSet, fClear);
369#else
370 return BS3_CMN_NM(Bs3PagingProtect)((uintptr_t)pv, cb, fSet, fClear);
371#endif
372}
373
374
375#undef Bs3PagingGetPte
376BS3_CMN_DEF(void BS3_FAR *, Bs3PagingGetPte,(uint64_t uFlat, int *prc))
377{
378 RTCCUINTXREG const cr3 = ASMGetCR3();
379 RTCCUINTXREG const cr4 = g_uBs3CpuDetected & BS3CPU_F_CPUID ? ASMGetCR4() : 0;
380 bool const fLegacyPTs = !(cr4 & X86_CR4_PAE);
381 bool const fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486;
382 int rc;
383 if (!prc)
384 prc = &rc;
385 if (!fLegacyPTs)
386 return BS3_CMN_FAR_NM(bs3PagingGetPaePte)(cr3, g_bBs3CurrentMode, uFlat, fUseInvlPg, prc);
387 if (uFlat < _4G)
388 return BS3_CMN_FAR_NM(bs3PagingGetLegacyPte)(cr3, (uint32_t)uFlat, fUseInvlPg, prc);
389 *prc = VERR_OUT_OF_RANGE;
390 return NULL;
391}
392
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