VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.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: 24.4 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 Set the IA32_PTE_4K.
13
14 @param[in] Pte4K Pointer to IA32_PTE_4K.
15 @param[in] Offset The offset within the linear address range.
16 @param[in] Attribute The attribute of the linear address range.
17 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
18 Page table entry is reset to 0 before set to the new attribute when a new physical base address is set.
19 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
20**/
21VOID
22PageTableLibSetPte4K (
23 IN IA32_PTE_4K *Pte4K,
24 IN UINT64 Offset,
25 IN IA32_MAP_ATTRIBUTE *Attribute,
26 IN IA32_MAP_ATTRIBUTE *Mask
27 )
28{
29 if (Mask->Bits.PageTableBaseAddress) {
30 Pte4K->Uint64 = (IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute) + Offset) | (Pte4K->Uint64 & ~IA32_PE_BASE_ADDRESS_MASK_40);
31 }
32
33 if (Mask->Bits.Present) {
34 Pte4K->Bits.Present = Attribute->Bits.Present;
35 }
36
37 if (Mask->Bits.ReadWrite) {
38 Pte4K->Bits.ReadWrite = Attribute->Bits.ReadWrite;
39 }
40
41 if (Mask->Bits.UserSupervisor) {
42 Pte4K->Bits.UserSupervisor = Attribute->Bits.UserSupervisor;
43 }
44
45 if (Mask->Bits.WriteThrough) {
46 Pte4K->Bits.WriteThrough = Attribute->Bits.WriteThrough;
47 }
48
49 if (Mask->Bits.CacheDisabled) {
50 Pte4K->Bits.CacheDisabled = Attribute->Bits.CacheDisabled;
51 }
52
53 if (Mask->Bits.Accessed) {
54 Pte4K->Bits.Accessed = Attribute->Bits.Accessed;
55 }
56
57 if (Mask->Bits.Dirty) {
58 Pte4K->Bits.Dirty = Attribute->Bits.Dirty;
59 }
60
61 if (Mask->Bits.Pat) {
62 Pte4K->Bits.Pat = Attribute->Bits.Pat;
63 }
64
65 if (Mask->Bits.Global) {
66 Pte4K->Bits.Global = Attribute->Bits.Global;
67 }
68
69 if (Mask->Bits.ProtectionKey) {
70 Pte4K->Bits.ProtectionKey = Attribute->Bits.ProtectionKey;
71 }
72
73 if (Mask->Bits.Nx) {
74 Pte4K->Bits.Nx = Attribute->Bits.Nx;
75 }
76}
77
78/**
79 Set the IA32_PDPTE_1G or IA32_PDE_2M.
80
81 @param[in] PleB Pointer to PDPTE_1G or PDE_2M. Both share the same structure definition.
82 @param[in] Offset The offset within the linear address range.
83 @param[in] Attribute The attribute of the linear address range.
84 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
85 Page table entry is reset to 0 before set to the new attribute when a new physical base address is set.
86 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
87**/
88VOID
89PageTableLibSetPleB (
90 IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE *PleB,
91 IN UINT64 Offset,
92 IN IA32_MAP_ATTRIBUTE *Attribute,
93 IN IA32_MAP_ATTRIBUTE *Mask
94 )
95{
96 if (Mask->Bits.PageTableBaseAddress) {
97 PleB->Uint64 = (IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute) + Offset) | (PleB->Uint64 & ~IA32_PE_BASE_ADDRESS_MASK_39);
98 }
99
100 PleB->Bits.MustBeOne = 1;
101
102 if (Mask->Bits.Present) {
103 PleB->Bits.Present = Attribute->Bits.Present;
104 }
105
106 if (Mask->Bits.ReadWrite) {
107 PleB->Bits.ReadWrite = Attribute->Bits.ReadWrite;
108 }
109
110 if (Mask->Bits.UserSupervisor) {
111 PleB->Bits.UserSupervisor = Attribute->Bits.UserSupervisor;
112 }
113
114 if (Mask->Bits.WriteThrough) {
115 PleB->Bits.WriteThrough = Attribute->Bits.WriteThrough;
116 }
117
118 if (Mask->Bits.CacheDisabled) {
119 PleB->Bits.CacheDisabled = Attribute->Bits.CacheDisabled;
120 }
121
122 if (Mask->Bits.Accessed) {
123 PleB->Bits.Accessed = Attribute->Bits.Accessed;
124 }
125
126 if (Mask->Bits.Dirty) {
127 PleB->Bits.Dirty = Attribute->Bits.Dirty;
128 }
129
130 if (Mask->Bits.Pat) {
131 PleB->Bits.Pat = Attribute->Bits.Pat;
132 }
133
134 if (Mask->Bits.Global) {
135 PleB->Bits.Global = Attribute->Bits.Global;
136 }
137
138 if (Mask->Bits.ProtectionKey) {
139 PleB->Bits.ProtectionKey = Attribute->Bits.ProtectionKey;
140 }
141
142 if (Mask->Bits.Nx) {
143 PleB->Bits.Nx = Attribute->Bits.Nx;
144 }
145}
146
147/**
148 Set the IA32_PDPTE_1G, IA32_PDE_2M or IA32_PTE_4K.
149
150 @param[in] Level 3, 2 or 1.
151 @param[in] Ple Pointer to PDPTE_1G, PDE_2M or IA32_PTE_4K, depending on the Level.
152 @param[in] Offset The offset within the linear address range.
153 @param[in] Attribute The attribute of the linear address range.
154 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
155 Page table entry is reset to 0 before set to the new attribute when a new physical base address is set.
156 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
157**/
158VOID
159PageTableLibSetPle (
160 IN UINTN Level,
161 IN IA32_PAGING_ENTRY *Ple,
162 IN UINT64 Offset,
163 IN IA32_MAP_ATTRIBUTE *Attribute,
164 IN IA32_MAP_ATTRIBUTE *Mask
165 )
166{
167 if (Level == 1) {
168 PageTableLibSetPte4K (&Ple->Pte4K, Offset, Attribute, Mask);
169 } else {
170 ASSERT (Level == 2 || Level == 3);
171 PageTableLibSetPleB (&Ple->PleB, Offset, Attribute, Mask);
172 }
173}
174
175/**
176 Set the IA32_PML5, IA32_PML4, IA32_PDPTE or IA32_PDE.
177
178 @param[in] Pnle Pointer to IA32_PML5, IA32_PML4, IA32_PDPTE or IA32_PDE. All share the same structure definition.
179 @param[in] Attribute The attribute of the page directory referenced by the non-leaf.
180 @param[in] Mask The mask of the page directory referenced by the non-leaf.
181**/
182VOID
183PageTableLibSetPnle (
184 IN IA32_PAGE_NON_LEAF_ENTRY *Pnle,
185 IN IA32_MAP_ATTRIBUTE *Attribute,
186 IN IA32_MAP_ATTRIBUTE *Mask
187 )
188{
189 if (Mask->Bits.Present) {
190 Pnle->Bits.Present = Attribute->Bits.Present;
191 }
192
193 if (Mask->Bits.ReadWrite) {
194 Pnle->Bits.ReadWrite = Attribute->Bits.ReadWrite;
195 }
196
197 if (Mask->Bits.UserSupervisor) {
198 Pnle->Bits.UserSupervisor = Attribute->Bits.UserSupervisor;
199 }
200
201 if (Mask->Bits.Nx) {
202 Pnle->Bits.Nx = Attribute->Bits.Nx;
203 }
204
205 Pnle->Bits.Accessed = 0;
206
207 //
208 // Set the attributes (WT, CD, A) to 0.
209 // WT and CD determin the memory type used to access the 4K page directory referenced by this entry.
210 // So, it implictly requires PAT[0] is Write Back.
211 // Create a new parameter if caller requires to use a different memory type for accessing page directories.
212 //
213 Pnle->Bits.WriteThrough = 0;
214 Pnle->Bits.CacheDisabled = 0;
215}
216
217/**
218 Update page table to map [LinearAddress, LinearAddress + Length) with specified attribute in the specified level.
219
220 @param[in] ParentPagingEntry The pointer to the page table entry to update.
221 @param[in] ParentAttribute The accumulated attribute of all parents' attribute.
222 @param[in] Modify FALSE to indicate Buffer is not used and BufferSize is increased by the required buffer size.
223 @param[in] Buffer The free buffer to be used for page table creation/updating.
224 When Modify is TRUE, it's used from the end.
225 When Modify is FALSE, it's ignored.
226 @param[in, out] BufferSize The available buffer size.
227 Return the remaining buffer size.
228 @param[in] Level Page table level. Could be 5, 4, 3, 2, or 1.
229 @param[in] MaxLeafLevel Maximum level that can be a leaf entry. Could be 1, 2 or 3 (if Page 1G is supported).
230 @param[in] LinearAddress The start of the linear address range.
231 @param[in] Length The length of the linear address range.
232 @param[in] Offset The offset within the linear address range.
233 @param[in] Attribute The attribute of the linear address range.
234 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
235 Page table entries that map the linear address range are reset to 0 before set to the new attribute
236 when a new physical base address is set.
237 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
238
239 @retval RETURN_SUCCESS PageTable is created/updated successfully.
240**/
241RETURN_STATUS
242PageTableLibMapInLevel (
243 IN IA32_PAGING_ENTRY *ParentPagingEntry,
244 IN IA32_MAP_ATTRIBUTE *ParentAttribute,
245 IN BOOLEAN Modify,
246 IN VOID *Buffer,
247 IN OUT INTN *BufferSize,
248 IN IA32_PAGE_LEVEL Level,
249 IN IA32_PAGE_LEVEL MaxLeafLevel,
250 IN UINT64 LinearAddress,
251 IN UINT64 Length,
252 IN UINT64 Offset,
253 IN IA32_MAP_ATTRIBUTE *Attribute,
254 IN IA32_MAP_ATTRIBUTE *Mask
255 )
256{
257 RETURN_STATUS Status;
258 UINTN BitStart;
259 UINTN Index;
260 IA32_PAGING_ENTRY *PagingEntry;
261 IA32_PAGING_ENTRY *CurrentPagingEntry;
262 UINT64 RegionLength;
263 UINT64 SubLength;
264 UINT64 SubOffset;
265 UINT64 RegionMask;
266 UINT64 RegionStart;
267 IA32_MAP_ATTRIBUTE AllOneMask;
268 IA32_MAP_ATTRIBUTE PleBAttribute;
269 IA32_MAP_ATTRIBUTE NopAttribute;
270 BOOLEAN CreateNew;
271 IA32_PAGING_ENTRY OneOfPagingEntry;
272 IA32_MAP_ATTRIBUTE ChildAttribute;
273 IA32_MAP_ATTRIBUTE ChildMask;
274 IA32_MAP_ATTRIBUTE CurrentMask;
275 IA32_MAP_ATTRIBUTE LocalParentAttribute;
276
277 ASSERT (Level != 0);
278 ASSERT ((Attribute != NULL) && (Mask != NULL));
279
280 CreateNew = FALSE;
281 AllOneMask.Uint64 = ~0ull;
282
283 NopAttribute.Uint64 = 0;
284 NopAttribute.Bits.Present = 1;
285 NopAttribute.Bits.ReadWrite = 1;
286 NopAttribute.Bits.UserSupervisor = 1;
287
288 LocalParentAttribute.Uint64 = ParentAttribute->Uint64;
289 ParentAttribute = &LocalParentAttribute;
290
291 //
292 // ParentPagingEntry ONLY is deferenced for checking Present and MustBeOne bits
293 // when Modify is FALSE.
294 //
295
296 if (ParentPagingEntry->Pce.Present == 0) {
297 //
298 // The parent entry is CR3 or PML5E/PML4E/PDPTE/PDE.
299 // It does NOT point to an existing page directory.
300 //
301 ASSERT (Buffer == NULL || *BufferSize >= SIZE_4KB);
302 CreateNew = TRUE;
303 *BufferSize -= SIZE_4KB;
304
305 if (Modify) {
306 ParentPagingEntry->Uintn = (UINTN)Buffer + *BufferSize;
307 ZeroMem ((VOID *)ParentPagingEntry->Uintn, SIZE_4KB);
308 //
309 // Set default attribute bits for PML5E/PML4E/PDPTE/PDE.
310 //
311 PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute, &AllOneMask);
312 } else {
313 //
314 // Just make sure Present and MustBeZero (PageSize) bits are accurate.
315 //
316 OneOfPagingEntry.Pnle.Uint64 = 0;
317 }
318 } else if (IsPle (ParentPagingEntry, Level + 1)) {
319 //
320 // The parent entry is a PDPTE_1G or PDE_2M. Split to 2M or 4K pages.
321 // Note: it's impossible the parent entry is a PTE_4K.
322 //
323 //
324 // Use NOP attributes as the attribute of grand-parents because CPU will consider
325 // the actual attributes of grand-parents when determing the memory type.
326 //
327 PleBAttribute.Uint64 = PageTableLibGetPleBMapAttribute (&ParentPagingEntry->PleB, ParentAttribute);
328 if ((IA32_MAP_ATTRIBUTE_ATTRIBUTES (&PleBAttribute) & IA32_MAP_ATTRIBUTE_ATTRIBUTES (Mask))
329 == (IA32_MAP_ATTRIBUTE_ATTRIBUTES (Attribute) & IA32_MAP_ATTRIBUTE_ATTRIBUTES (Mask)))
330 {
331 //
332 // This function is called when the memory length is less than the region length of the parent level.
333 // No need to split the page when the attributes equal.
334 //
335 return RETURN_SUCCESS;
336 }
337
338 ASSERT (Buffer == NULL || *BufferSize >= SIZE_4KB);
339 CreateNew = TRUE;
340 *BufferSize -= SIZE_4KB;
341 PageTableLibSetPle (Level, &OneOfPagingEntry, 0, &PleBAttribute, &AllOneMask);
342 if (Modify) {
343 //
344 // Create 512 child-level entries that map to 2M/4K.
345 //
346 ParentPagingEntry->Uintn = (UINTN)Buffer + *BufferSize;
347 ZeroMem ((VOID *)ParentPagingEntry->Uintn, SIZE_4KB);
348
349 //
350 // Set NOP attributes
351 // Note: Should NOT inherit the attributes from the original entry because a zero RW bit
352 // will make the entire region read-only even the child entries set the RW bit.
353 //
354 PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute, &AllOneMask);
355
356 RegionLength = REGION_LENGTH (Level);
357 PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);
358 for (SubOffset = 0, Index = 0; Index < 512; Index++) {
359 PagingEntry[Index].Uint64 = OneOfPagingEntry.Uint64 + SubOffset;
360 SubOffset += RegionLength;
361 }
362 }
363 } else {
364 //
365 // It's a non-leaf entry
366 //
367 ChildAttribute.Uint64 = 0;
368 ChildMask.Uint64 = 0;
369
370 //
371 // If the inheritable attributes in the parent entry conflicts with the requested attributes,
372 // let the child entries take the parent attributes and
373 // loosen the attribute in the parent entry
374 // E.g.: when PDPTE[0].ReadWrite = 0 but caller wants to map [0-2MB] as ReadWrite = 1 (PDE[0].ReadWrite = 1)
375 // we need to change PDPTE[0].ReadWrite = 1 and let all PDE[0-255].ReadWrite = 0 in this step.
376 // when PDPTE[0].Nx = 1 but caller wants to map [0-2MB] as Nx = 0 (PDT[0].Nx = 0)
377 // we need to change PDPTE[0].Nx = 0 and let all PDE[0-255].Nx = 1 in this step.
378 if ((ParentPagingEntry->Pnle.Bits.Present == 0) && (Mask->Bits.Present == 1) && (Attribute->Bits.Present == 1)) {
379 if (Modify) {
380 ParentPagingEntry->Pnle.Bits.Present = 1;
381 }
382
383 ChildAttribute.Bits.Present = 0;
384 ChildMask.Bits.Present = 1;
385 }
386
387 if ((ParentPagingEntry->Pnle.Bits.ReadWrite == 0) && (Mask->Bits.ReadWrite == 1) && (Attribute->Bits.ReadWrite == 1)) {
388 if (Modify) {
389 ParentPagingEntry->Pnle.Bits.ReadWrite = 1;
390 }
391
392 ChildAttribute.Bits.ReadWrite = 0;
393 ChildMask.Bits.ReadWrite = 1;
394 }
395
396 if ((ParentPagingEntry->Pnle.Bits.UserSupervisor == 0) && (Mask->Bits.UserSupervisor == 1) && (Attribute->Bits.UserSupervisor == 1)) {
397 if (Modify) {
398 ParentPagingEntry->Pnle.Bits.UserSupervisor = 1;
399 }
400
401 ChildAttribute.Bits.UserSupervisor = 0;
402 ChildMask.Bits.UserSupervisor = 1;
403 }
404
405 if ((ParentPagingEntry->Pnle.Bits.Nx == 1) && (Mask->Bits.Nx == 1) && (Attribute->Bits.Nx == 0)) {
406 if (Modify) {
407 ParentPagingEntry->Pnle.Bits.Nx = 0;
408 }
409
410 ChildAttribute.Bits.Nx = 1;
411 ChildMask.Bits.Nx = 1;
412 }
413
414 if (ChildMask.Uint64 != 0) {
415 if (Modify) {
416 //
417 // Update child entries to use restrictive attribute inherited from parent.
418 // e.g.: Set PDE[0-255].ReadWrite = 0
419 //
420 PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);
421 for (Index = 0; Index < 512; Index++) {
422 if (PagingEntry[Index].Pce.Present == 0) {
423 continue;
424 }
425
426 if (IsPle (&PagingEntry[Index], Level)) {
427 PageTableLibSetPle (Level, &PagingEntry[Index], 0, &ChildAttribute, &ChildMask);
428 } else {
429 PageTableLibSetPnle (&PagingEntry[Index].Pnle, &ChildAttribute, &ChildMask);
430 }
431 }
432 }
433 }
434 }
435
436 //
437 // RegionLength: 256T (1 << 48) 512G (1 << 39), 1G (1 << 30), 2M (1 << 21) or 4K (1 << 12).
438 // RegionStart: points to the linear address that's aligned on RegionLength and lower than (LinearAddress + Offset).
439 //
440 BitStart = 12 + (Level - 1) * 9;
441 Index = (UINTN)BitFieldRead64 (LinearAddress + Offset, BitStart, BitStart + 9 - 1);
442 RegionLength = LShiftU64 (1, BitStart);
443 RegionMask = RegionLength - 1;
444 RegionStart = (LinearAddress + Offset) & ~RegionMask;
445
446 ParentAttribute->Uint64 = PageTableLibGetPnleMapAttribute (&ParentPagingEntry->Pnle, ParentAttribute);
447
448 //
449 // Apply the attribute.
450 //
451 PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);
452 while (Offset < Length && Index < 512) {
453 CurrentPagingEntry = (!Modify && CreateNew) ? &OneOfPagingEntry : &PagingEntry[Index];
454 SubLength = MIN (Length - Offset, RegionStart + RegionLength - (LinearAddress + Offset));
455 if ((Level <= MaxLeafLevel) &&
456 (((LinearAddress + Offset) & RegionMask) == 0) &&
457 (((IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute) + Offset) & RegionMask) == 0) &&
458 (SubLength == RegionLength) &&
459 ((CurrentPagingEntry->Pce.Present == 0) || IsPle (CurrentPagingEntry, Level))
460 )
461 {
462 //
463 // Create one entry mapping the entire region (1G, 2M or 4K).
464 //
465 if (Modify) {
466 //
467 // When the inheritable attributes in parent entry could override the child attributes,
468 // e.g.: Present/ReadWrite/UserSupervisor is 0 in parent entry, or
469 // Nx is 1 in parent entry,
470 // we just skip setting any value to these attributes in child.
471 // We add assertion to make sure the requested settings don't conflict with parent attributes in this case.
472 //
473 CurrentMask.Uint64 = Mask->Uint64;
474 if (ParentAttribute->Bits.Present == 0) {
475 CurrentMask.Bits.Present = 0;
476 ASSERT (CreateNew || (Mask->Bits.Present == 0) || (Attribute->Bits.Present == 0));
477 }
478
479 if (ParentAttribute->Bits.ReadWrite == 0) {
480 CurrentMask.Bits.ReadWrite = 0;
481 ASSERT (CreateNew || (Mask->Bits.ReadWrite == 0) || (Attribute->Bits.ReadWrite == 0));
482 }
483
484 if (ParentAttribute->Bits.UserSupervisor == 0) {
485 CurrentMask.Bits.UserSupervisor = 0;
486 ASSERT (CreateNew || (Mask->Bits.UserSupervisor == 0) || (Attribute->Bits.UserSupervisor == 0));
487 }
488
489 if (ParentAttribute->Bits.Nx == 1) {
490 CurrentMask.Bits.Nx = 0;
491 ASSERT (CreateNew || (Mask->Bits.Nx == 0) || (Attribute->Bits.Nx == 1));
492 }
493
494 PageTableLibSetPle (Level, CurrentPagingEntry, Offset, Attribute, &CurrentMask);
495 }
496 } else {
497 //
498 // Recursively call to create page table.
499 // There are 3 cases:
500 // a. Level cannot be a leaf entry which points to physical memory.
501 // a. Level can be a leaf entry but (LinearAddress + Offset) is NOT aligned on the RegionStart.
502 // b. Level can be a leaf entry and (LinearAddress + Offset) is aligned on RegionStart,
503 // but the length is SMALLER than the RegionLength.
504 //
505 Status = PageTableLibMapInLevel (
506 CurrentPagingEntry,
507 ParentAttribute,
508 Modify,
509 Buffer,
510 BufferSize,
511 Level - 1,
512 MaxLeafLevel,
513 LinearAddress,
514 Length,
515 Offset,
516 Attribute,
517 Mask
518 );
519 if (RETURN_ERROR (Status)) {
520 return Status;
521 }
522 }
523
524 Offset += SubLength;
525 RegionStart += RegionLength;
526 Index++;
527 }
528
529 return RETURN_SUCCESS;
530}
531
532/**
533 Create or update page table to map [LinearAddress, LinearAddress + Length) with specified attribute.
534
535 @param[in, out] PageTable The pointer to the page table to update, or pointer to NULL if a new page table is to be created.
536 @param[in] PagingMode The paging mode.
537 @param[in] Buffer The free buffer to be used for page table creation/updating.
538 @param[in, out] BufferSize The buffer size.
539 On return, the remaining buffer size.
540 The free buffer is used from the end so caller can supply the same Buffer pointer with an updated
541 BufferSize in the second call to this API.
542 @param[in] LinearAddress The start of the linear address range.
543 @param[in] Length The length of the linear address range.
544 @param[in] Attribute The attribute of the linear address range.
545 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
546 Page table entries that map the linear address range are reset to 0 before set to the new attribute
547 when a new physical base address is set.
548 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
549
550 @retval RETURN_UNSUPPORTED PagingMode is not supported.
551 @retval RETURN_INVALID_PARAMETER PageTable, BufferSize, Attribute or Mask is NULL.
552 @retval RETURN_INVALID_PARAMETER *BufferSize is not multiple of 4KB.
553 @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for page table creation/updating.
554 BufferSize is updated to indicate the expected buffer size.
555 Caller may still get RETURN_BUFFER_TOO_SMALL with the new BufferSize.
556 @retval RETURN_SUCCESS PageTable is created/updated successfully.
557**/
558RETURN_STATUS
559EFIAPI
560PageTableMap (
561 IN OUT UINTN *PageTable OPTIONAL,
562 IN PAGING_MODE PagingMode,
563 IN VOID *Buffer,
564 IN OUT UINTN *BufferSize,
565 IN UINT64 LinearAddress,
566 IN UINT64 Length,
567 IN IA32_MAP_ATTRIBUTE *Attribute,
568 IN IA32_MAP_ATTRIBUTE *Mask
569 )
570{
571 RETURN_STATUS Status;
572 IA32_PAGING_ENTRY TopPagingEntry;
573 INTN RequiredSize;
574 UINT64 MaxLinearAddress;
575 IA32_PAGE_LEVEL MaxLevel;
576 IA32_PAGE_LEVEL MaxLeafLevel;
577 IA32_MAP_ATTRIBUTE ParentAttribute;
578
579 if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
580 //
581 // 32bit paging is never supported.
582 // PAE paging will be supported later.
583 //
584 return RETURN_UNSUPPORTED;
585 }
586
587 if ((PageTable == NULL) || (BufferSize == NULL) || (Attribute == NULL) || (Mask == NULL)) {
588 return RETURN_INVALID_PARAMETER;
589 }
590
591 if (*BufferSize % SIZE_4KB != 0) {
592 //
593 // BufferSize should be multiple of 4K.
594 //
595 return RETURN_INVALID_PARAMETER;
596 }
597
598 if ((LinearAddress % SIZE_4KB != 0) || (Length % SIZE_4KB != 0)) {
599 //
600 // LinearAddress and Length should be multiple of 4K.
601 //
602 return RETURN_INVALID_PARAMETER;
603 }
604
605 if ((*BufferSize != 0) && (Buffer == NULL)) {
606 return RETURN_INVALID_PARAMETER;
607 }
608
609 MaxLeafLevel = (IA32_PAGE_LEVEL)(UINT8)PagingMode;
610 MaxLevel = (IA32_PAGE_LEVEL)(UINT8)(PagingMode >> 8);
611 MaxLinearAddress = LShiftU64 (1, 12 + MaxLevel * 9);
612
613 if ((LinearAddress > MaxLinearAddress) || (Length > MaxLinearAddress - LinearAddress)) {
614 //
615 // Maximum linear address is (1 << 48) or (1 << 57)
616 //
617 return RETURN_INVALID_PARAMETER;
618 }
619
620 TopPagingEntry.Uintn = *PageTable;
621 if (TopPagingEntry.Uintn != 0) {
622 TopPagingEntry.Pce.Present = 1;
623 TopPagingEntry.Pce.ReadWrite = 1;
624 TopPagingEntry.Pce.UserSupervisor = 1;
625 TopPagingEntry.Pce.Nx = 0;
626 }
627
628 ParentAttribute.Uint64 = 0;
629 ParentAttribute.Bits.PageTableBaseAddress = 1;
630 ParentAttribute.Bits.Present = 1;
631 ParentAttribute.Bits.ReadWrite = 1;
632 ParentAttribute.Bits.UserSupervisor = 1;
633 ParentAttribute.Bits.Nx = 0;
634
635 //
636 // Query the required buffer size without modifying the page table.
637 //
638 RequiredSize = 0;
639 Status = PageTableLibMapInLevel (
640 &TopPagingEntry,
641 &ParentAttribute,
642 FALSE,
643 NULL,
644 &RequiredSize,
645 MaxLevel,
646 MaxLeafLevel,
647 LinearAddress,
648 Length,
649 0,
650 Attribute,
651 Mask
652 );
653 if (RETURN_ERROR (Status)) {
654 return Status;
655 }
656
657 RequiredSize = -RequiredSize;
658
659 if ((UINTN)RequiredSize > *BufferSize) {
660 *BufferSize = RequiredSize;
661 return RETURN_BUFFER_TOO_SMALL;
662 }
663
664 if ((RequiredSize != 0) && (Buffer == NULL)) {
665 return RETURN_INVALID_PARAMETER;
666 }
667
668 //
669 // Update the page table when the supplied buffer is sufficient.
670 //
671 Status = PageTableLibMapInLevel (
672 &TopPagingEntry,
673 &ParentAttribute,
674 TRUE,
675 Buffer,
676 (INTN *)BufferSize,
677 MaxLevel,
678 MaxLeafLevel,
679 LinearAddress,
680 Length,
681 0,
682 Attribute,
683 Mask
684 );
685 if (!RETURN_ERROR (Status)) {
686 *PageTable = (UINTN)(TopPagingEntry.Uintn & IA32_PE_BASE_ADDRESS_MASK_40);
687 }
688
689 return Status;
690}
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