VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c@ 109019

Last change on this file since 109019 was 101291, checked in by vboxsync, 19 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 11.7 KB
Line 
1/** @file
2 This library implements CpuPageTableLib that are generic for IA32 family CPU.
3
4 Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include "CpuPageTable.h"
10
11/**
12 Return the attribute of a 2M/1G page table entry.
13
14 @param[in] PleB Pointer to a 2M/1G page table entry.
15 @param[in] ParentMapAttribute Pointer to the parent attribute.
16
17 @return Attribute of the 2M/1G page table entry.
18**/
19UINT64
20PageTableLibGetPleBMapAttribute (
21 IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE *PleB,
22 IN IA32_MAP_ATTRIBUTE *ParentMapAttribute
23 )
24{
25 IA32_MAP_ATTRIBUTE MapAttribute;
26
27 //
28 // PageTableBaseAddress cannot be assigned field to field
29 // because their bit positions are different in IA32_MAP_ATTRIBUTE and IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE.
30 //
31 MapAttribute.Uint64 = IA32_PLEB_PAGE_TABLE_BASE_ADDRESS (PleB);
32
33 MapAttribute.Bits.Present = ParentMapAttribute->Bits.Present & PleB->Bits.Present;
34 MapAttribute.Bits.ReadWrite = ParentMapAttribute->Bits.ReadWrite & PleB->Bits.ReadWrite;
35 MapAttribute.Bits.UserSupervisor = ParentMapAttribute->Bits.UserSupervisor & PleB->Bits.UserSupervisor;
36 MapAttribute.Bits.Nx = ParentMapAttribute->Bits.Nx | PleB->Bits.Nx;
37 MapAttribute.Bits.WriteThrough = PleB->Bits.WriteThrough;
38 MapAttribute.Bits.CacheDisabled = PleB->Bits.CacheDisabled;
39 MapAttribute.Bits.Accessed = PleB->Bits.Accessed;
40
41 MapAttribute.Bits.Pat = PleB->Bits.Pat;
42 MapAttribute.Bits.Dirty = PleB->Bits.Dirty;
43 MapAttribute.Bits.Global = PleB->Bits.Global;
44 MapAttribute.Bits.ProtectionKey = PleB->Bits.ProtectionKey;
45
46 return MapAttribute.Uint64;
47}
48
49/**
50 Return the attribute of a 4K page table entry.
51
52 @param[in] Pte4K Pointer to a 4K page table entry.
53 @param[in] ParentMapAttribute Pointer to the parent attribute.
54
55 @return Attribute of the 4K page table entry.
56**/
57UINT64
58PageTableLibGetPte4KMapAttribute (
59 IN IA32_PTE_4K *Pte4K,
60 IN IA32_MAP_ATTRIBUTE *ParentMapAttribute
61 )
62{
63 IA32_MAP_ATTRIBUTE MapAttribute;
64
65 MapAttribute.Uint64 = IA32_PTE4K_PAGE_TABLE_BASE_ADDRESS (Pte4K);
66
67 MapAttribute.Bits.Present = ParentMapAttribute->Bits.Present & Pte4K->Bits.Present;
68 MapAttribute.Bits.ReadWrite = ParentMapAttribute->Bits.ReadWrite & Pte4K->Bits.ReadWrite;
69 MapAttribute.Bits.UserSupervisor = ParentMapAttribute->Bits.UserSupervisor & Pte4K->Bits.UserSupervisor;
70 MapAttribute.Bits.Nx = ParentMapAttribute->Bits.Nx | Pte4K->Bits.Nx;
71 MapAttribute.Bits.WriteThrough = Pte4K->Bits.WriteThrough;
72 MapAttribute.Bits.CacheDisabled = Pte4K->Bits.CacheDisabled;
73 MapAttribute.Bits.Accessed = Pte4K->Bits.Accessed;
74
75 MapAttribute.Bits.Pat = Pte4K->Bits.Pat;
76 MapAttribute.Bits.Dirty = Pte4K->Bits.Dirty;
77 MapAttribute.Bits.Global = Pte4K->Bits.Global;
78 MapAttribute.Bits.ProtectionKey = Pte4K->Bits.ProtectionKey;
79
80 return MapAttribute.Uint64;
81}
82
83/**
84 Return the attribute of a non-leaf page table entry.
85
86 @param[in] Pnle Pointer to a non-leaf page table entry.
87 @param[in] ParentMapAttribute Pointer to the parent attribute.
88
89 @return Attribute of the non-leaf page table entry.
90**/
91UINT64
92PageTableLibGetPnleMapAttribute (
93 IN IA32_PAGE_NON_LEAF_ENTRY *Pnle,
94 IN IA32_MAP_ATTRIBUTE *ParentMapAttribute
95 )
96{
97 IA32_MAP_ATTRIBUTE MapAttribute;
98
99 MapAttribute.Uint64 = Pnle->Uint64;
100
101 MapAttribute.Bits.Present = ParentMapAttribute->Bits.Present & Pnle->Bits.Present;
102 MapAttribute.Bits.ReadWrite = ParentMapAttribute->Bits.ReadWrite & Pnle->Bits.ReadWrite;
103 MapAttribute.Bits.UserSupervisor = ParentMapAttribute->Bits.UserSupervisor & Pnle->Bits.UserSupervisor;
104 MapAttribute.Bits.Nx = ParentMapAttribute->Bits.Nx | Pnle->Bits.Nx;
105 MapAttribute.Bits.WriteThrough = Pnle->Bits.WriteThrough;
106 MapAttribute.Bits.CacheDisabled = Pnle->Bits.CacheDisabled;
107 MapAttribute.Bits.Accessed = Pnle->Bits.Accessed;
108 return MapAttribute.Uint64;
109}
110
111/**
112 Return TRUE when the page table entry is a leaf entry that points to the physical address memory.
113 Return FALSE when the page table entry is a non-leaf entry that points to the page table entries.
114
115 @param[in] PagingEntry Pointer to the page table entry.
116 @param[in] Level Page level where the page table entry resides in.
117
118 @retval TRUE It's a leaf entry.
119 @retval FALSE It's a non-leaf entry.
120**/
121BOOLEAN
122IsPle (
123 IN IA32_PAGING_ENTRY *PagingEntry,
124 IN UINTN Level
125 )
126{
127 //
128 // PML5E and PML4E are always non-leaf entries.
129 //
130 if (Level == 1) {
131 return TRUE;
132 }
133
134 if (((Level == 3) || (Level == 2))) {
135 if (PagingEntry->PleB.Bits.MustBeOne == 1) {
136 return TRUE;
137 }
138 }
139
140 return FALSE;
141}
142
143/**
144 Recursively parse the non-leaf page table entries.
145
146 @param[in] PageTableBaseAddress The base address of the 512 non-leaf page table entries in the specified level.
147 @param[in] Level Page level. Could be 5, 4, 3, 2, 1.
148 @param[in] RegionStart The base linear address of the region covered by the non-leaf page table entries.
149 @param[in] ParentMapAttribute The mapping attribute of the parent entries.
150 @param[in, out] Map Pointer to an array that describes multiple linear address ranges.
151 @param[in, out] MapCount Pointer to a UINTN that hold the actual number of entries in the Map.
152 @param[in] MapCapacity The maximum number of entries the Map can hold.
153 @param[in] LastEntry Pointer to last map entry.
154 @param[in] OneEntry Pointer to a library internal storage that holds one map entry.
155 It's used when Map array is used up.
156**/
157VOID
158PageTableLibParsePnle (
159 IN UINT64 PageTableBaseAddress,
160 IN UINTN Level,
161 IN UINTN MaxLevel,
162 IN UINT64 RegionStart,
163 IN IA32_MAP_ATTRIBUTE *ParentMapAttribute,
164 IN OUT IA32_MAP_ENTRY *Map,
165 IN OUT UINTN *MapCount,
166 IN UINTN MapCapacity,
167 IN IA32_MAP_ENTRY **LastEntry,
168 IN IA32_MAP_ENTRY *OneEntry
169 )
170{
171 IA32_PAGING_ENTRY *PagingEntry;
172 UINTN Index;
173 IA32_MAP_ATTRIBUTE MapAttribute;
174 UINT64 RegionLength;
175 UINTN PagingEntryNumber;
176
177 ASSERT (OneEntry != NULL);
178
179 PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;
180 RegionLength = REGION_LENGTH (Level);
181 PagingEntryNumber = ((MaxLevel == 3) && (Level == 3)) ? MAX_PAE_PDPTE_NUM : 512;
182
183 for (Index = 0; Index < PagingEntryNumber; Index++, RegionStart += RegionLength) {
184 if (PagingEntry[Index].Pce.Present == 0) {
185 continue;
186 }
187
188 if (IsPle (&PagingEntry[Index], Level)) {
189 ASSERT (Level == 1 || Level == 2 || Level == 3);
190
191 if (Level == 1) {
192 MapAttribute.Uint64 = PageTableLibGetPte4KMapAttribute (&PagingEntry[Index].Pte4K, ParentMapAttribute);
193 } else {
194 MapAttribute.Uint64 = PageTableLibGetPleBMapAttribute (&PagingEntry[Index].PleB, ParentMapAttribute);
195 }
196
197 if ((*LastEntry != NULL) &&
198 ((*LastEntry)->LinearAddress + (*LastEntry)->Length == RegionStart) &&
199 (IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&(*LastEntry)->Attribute) + (*LastEntry)->Length
200 == IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&MapAttribute)) &&
201 (IA32_MAP_ATTRIBUTE_ATTRIBUTES (&(*LastEntry)->Attribute) == IA32_MAP_ATTRIBUTE_ATTRIBUTES (&MapAttribute))
202 )
203 {
204 //
205 // Extend LastEntry.
206 //
207 (*LastEntry)->Length += RegionLength;
208 } else {
209 if (*MapCount < MapCapacity) {
210 //
211 // LastEntry points to next map entry in the array.
212 //
213 *LastEntry = &Map[*MapCount];
214 } else {
215 //
216 // LastEntry points to library internal map entry.
217 //
218 *LastEntry = OneEntry;
219 }
220
221 //
222 // Set LastEntry.
223 //
224 (*LastEntry)->LinearAddress = RegionStart;
225 (*LastEntry)->Length = RegionLength;
226 (*LastEntry)->Attribute.Uint64 = MapAttribute.Uint64;
227 (*MapCount)++;
228 }
229 } else {
230 MapAttribute.Uint64 = PageTableLibGetPnleMapAttribute (&PagingEntry[Index].Pnle, ParentMapAttribute);
231 PageTableLibParsePnle (
232 IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle),
233 Level - 1,
234 MaxLevel,
235 RegionStart,
236 &MapAttribute,
237 Map,
238 MapCount,
239 MapCapacity,
240 LastEntry,
241 OneEntry
242 );
243 }
244 }
245}
246
247/**
248 Parse page table.
249
250 @param[in] PageTable Pointer to the page table.
251 @param[in] PagingMode The paging mode.
252 @param[out] Map Return an array that describes multiple linear address ranges.
253 @param[in, out] MapCount On input, the maximum number of entries that Map can hold.
254 On output, the number of entries in Map.
255
256 @retval RETURN_UNSUPPORTED PageLevel is not 5 or 4.
257 @retval RETURN_INVALID_PARAMETER MapCount is NULL.
258 @retval RETURN_INVALID_PARAMETER *MapCount is not 0 but Map is NULL.
259 @retval RETURN_BUFFER_TOO_SMALL *MapCount is too small.
260 @retval RETURN_SUCCESS Page table is parsed successfully.
261**/
262RETURN_STATUS
263EFIAPI
264PageTableParse (
265 IN UINTN PageTable,
266 IN PAGING_MODE PagingMode,
267 OUT IA32_MAP_ENTRY *Map,
268 IN OUT UINTN *MapCount
269 )
270{
271 UINTN MapCapacity;
272 IA32_MAP_ATTRIBUTE NopAttribute;
273 IA32_MAP_ENTRY *LastEntry;
274 IA32_MAP_ENTRY OneEntry;
275 UINTN MaxLevel;
276 UINTN Index;
277 IA32_PAGING_ENTRY BufferInStack[MAX_PAE_PDPTE_NUM];
278
279 if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
280 //
281 // 32bit paging is never supported.
282 //
283 return RETURN_UNSUPPORTED;
284 }
285
286 if (MapCount == NULL) {
287 return RETURN_INVALID_PARAMETER;
288 }
289
290 if ((*MapCount != 0) && (Map == NULL)) {
291 return RETURN_INVALID_PARAMETER;
292 }
293
294 if (PageTable == 0) {
295 *MapCount = 0;
296 return RETURN_SUCCESS;
297 }
298
299 if (PagingMode == PagingPae) {
300 CopyMem (BufferInStack, (VOID *)PageTable, sizeof (BufferInStack));
301 for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {
302 BufferInStack[Index].Pnle.Bits.ReadWrite = 1;
303 BufferInStack[Index].Pnle.Bits.UserSupervisor = 1;
304 BufferInStack[Index].Pnle.Bits.Nx = 0;
305 }
306
307 PageTable = (UINTN)BufferInStack;
308 }
309
310 //
311 // Page table layout is as below:
312 //
313 // [IA32_CR3]
314 // |
315 // |
316 // V
317 // [IA32_PML5E]
318 // ...
319 // [IA32_PML5E] --> [IA32_PML4E]
320 // ...
321 // [IA32_PML4E] --> [IA32_PDPTE_1G] --> 1G aligned physical address
322 // ...
323 // [IA32_PDPTE] --> [IA32_PDE_2M] --> 2M aligned physical address
324 // ...
325 // [IA32_PDE] --> [IA32_PTE_4K] --> 4K aligned physical address
326 // ...
327 // [IA32_PTE_4K] --> 4K aligned physical address
328 //
329
330 NopAttribute.Uint64 = 0;
331 NopAttribute.Bits.Present = 1;
332 NopAttribute.Bits.ReadWrite = 1;
333 NopAttribute.Bits.UserSupervisor = 1;
334
335 MaxLevel = (UINT8)(PagingMode >> 8);
336 MapCapacity = *MapCount;
337 *MapCount = 0;
338 LastEntry = NULL;
339 PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, MaxLevel, 0, &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry);
340
341 if (*MapCount > MapCapacity) {
342 return RETURN_BUFFER_TOO_SMALL;
343 }
344
345 return RETURN_SUCCESS;
346}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette