VirtualBox

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

Last change on this file since 104792 was 103005, checked in by vboxsync, 11 months ago

iprt/asm.h,*: Split out the ASMMem* and related stuff into a separate header, asm-mem.h, so that we can get the RT_ASM_PAGE_SIZE stuff out of the way.

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