VirtualBox

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

Last change on this file since 99404 was 99404, checked in by vboxsync, 23 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1/** @file
2 This library implements CpuPageTableLib that are generic for IA32 family CPU.
3
4 Copyright (c) 2022, 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 UINT64 RegionStart,
162 IN IA32_MAP_ATTRIBUTE *ParentMapAttribute,
163 IN OUT IA32_MAP_ENTRY *Map,
164 IN OUT UINTN *MapCount,
165 IN UINTN MapCapacity,
166 IN IA32_MAP_ENTRY **LastEntry,
167 IN IA32_MAP_ENTRY *OneEntry
168 )
169{
170 IA32_PAGING_ENTRY *PagingEntry;
171 UINTN Index;
172 IA32_MAP_ATTRIBUTE MapAttribute;
173 UINT64 RegionLength;
174
175 ASSERT (OneEntry != NULL);
176
177 PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;
178 RegionLength = REGION_LENGTH (Level);
179
180 for (Index = 0; Index < 512; Index++, RegionStart += RegionLength) {
181 if (PagingEntry[Index].Pce.Present == 0) {
182 continue;
183 }
184
185 if (IsPle (&PagingEntry[Index], Level)) {
186 ASSERT (Level == 1 || Level == 2 || Level == 3);
187
188 if (Level == 1) {
189 MapAttribute.Uint64 = PageTableLibGetPte4KMapAttribute (&PagingEntry[Index].Pte4K, ParentMapAttribute);
190 } else {
191 MapAttribute.Uint64 = PageTableLibGetPleBMapAttribute (&PagingEntry[Index].PleB, ParentMapAttribute);
192 }
193
194 if ((*LastEntry != NULL) &&
195 ((*LastEntry)->LinearAddress + (*LastEntry)->Length == RegionStart) &&
196 (IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&(*LastEntry)->Attribute) + (*LastEntry)->Length
197 == IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (&MapAttribute)) &&
198 (IA32_MAP_ATTRIBUTE_ATTRIBUTES (&(*LastEntry)->Attribute) == IA32_MAP_ATTRIBUTE_ATTRIBUTES (&MapAttribute))
199 )
200 {
201 //
202 // Extend LastEntry.
203 //
204 (*LastEntry)->Length += RegionLength;
205 } else {
206 if (*MapCount < MapCapacity) {
207 //
208 // LastEntry points to next map entry in the array.
209 //
210 *LastEntry = &Map[*MapCount];
211 } else {
212 //
213 // LastEntry points to library internal map entry.
214 //
215 *LastEntry = OneEntry;
216 }
217
218 //
219 // Set LastEntry.
220 //
221 (*LastEntry)->LinearAddress = RegionStart;
222 (*LastEntry)->Length = RegionLength;
223 (*LastEntry)->Attribute.Uint64 = MapAttribute.Uint64;
224 (*MapCount)++;
225 }
226 } else {
227 MapAttribute.Uint64 = PageTableLibGetPnleMapAttribute (&PagingEntry[Index].Pnle, ParentMapAttribute);
228 PageTableLibParsePnle (
229 IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle),
230 Level - 1,
231 RegionStart,
232 &MapAttribute,
233 Map,
234 MapCount,
235 MapCapacity,
236 LastEntry,
237 OneEntry
238 );
239 }
240 }
241}
242
243/**
244 Parse page table.
245
246 @param[in] PageTable Pointer to the page table.
247 @param[in] PagingMode The paging mode.
248 @param[out] Map Return an array that describes multiple linear address ranges.
249 @param[in, out] MapCount On input, the maximum number of entries that Map can hold.
250 On output, the number of entries in Map.
251
252 @retval RETURN_UNSUPPORTED PageLevel is not 5 or 4.
253 @retval RETURN_INVALID_PARAMETER MapCount is NULL.
254 @retval RETURN_INVALID_PARAMETER *MapCount is not 0 but Map is NULL.
255 @retval RETURN_BUFFER_TOO_SMALL *MapCount is too small.
256 @retval RETURN_SUCCESS Page table is parsed successfully.
257**/
258RETURN_STATUS
259EFIAPI
260PageTableParse (
261 IN UINTN PageTable,
262 IN PAGING_MODE PagingMode,
263 OUT IA32_MAP_ENTRY *Map,
264 IN OUT UINTN *MapCount
265 )
266{
267 UINTN MapCapacity;
268 IA32_MAP_ATTRIBUTE NopAttribute;
269 IA32_MAP_ENTRY *LastEntry;
270 IA32_MAP_ENTRY OneEntry;
271 UINTN MaxLevel;
272
273 if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {
274 //
275 // 32bit paging is never supported.
276 //
277 return RETURN_UNSUPPORTED;
278 }
279
280 if (MapCount == NULL) {
281 return RETURN_INVALID_PARAMETER;
282 }
283
284 if ((*MapCount != 0) && (Map == NULL)) {
285 return RETURN_INVALID_PARAMETER;
286 }
287
288 if (PageTable == 0) {
289 *MapCount = 0;
290 return RETURN_SUCCESS;
291 }
292
293 //
294 // Page table layout is as below:
295 //
296 // [IA32_CR3]
297 // |
298 // |
299 // V
300 // [IA32_PML5E]
301 // ...
302 // [IA32_PML5E] --> [IA32_PML4E]
303 // ...
304 // [IA32_PML4E] --> [IA32_PDPTE_1G] --> 1G aligned physical address
305 // ...
306 // [IA32_PDPTE] --> [IA32_PDE_2M] --> 2M aligned physical address
307 // ...
308 // [IA32_PDE] --> [IA32_PTE_4K] --> 4K aligned physical address
309 // ...
310 // [IA32_PTE_4K] --> 4K aligned physical address
311 //
312
313 NopAttribute.Uint64 = 0;
314 NopAttribute.Bits.Present = 1;
315 NopAttribute.Bits.ReadWrite = 1;
316 NopAttribute.Bits.UserSupervisor = 1;
317
318 MaxLevel = (UINT8)(PagingMode >> 8);
319 MapCapacity = *MapCount;
320 *MapCount = 0;
321 LastEntry = NULL;
322 PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, 0, &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry);
323
324 if (*MapCount > MapCapacity) {
325 return RETURN_BUFFER_TOO_SMALL;
326 }
327
328 return RETURN_SUCCESS;
329}
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