VirtualBox

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

Last change on this file since 60777 was 60777, checked in by vboxsync, 9 years ago

bs3kit: Must atomically replace large pages in case of very tiny TLB.

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