2 This library implements CpuPageTableLib that are generic for IA32 family CPU.
4 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "CpuPageTable.h"
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.
22 PageTableLibSetPte4K (
23 IN IA32_PTE_4K
*Pte4K
,
25 IN IA32_MAP_ATTRIBUTE
*Attribute
,
26 IN IA32_MAP_ATTRIBUTE
*Mask
29 if (Mask
->Bits
.PageTableBaseAddress
) {
31 // Reset all attributes when the physical address is changed.
33 Pte4K
->Uint64
= IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute
) + Offset
;
36 if (Mask
->Bits
.Present
) {
37 Pte4K
->Bits
.Present
= Attribute
->Bits
.Present
;
40 if (Mask
->Bits
.ReadWrite
) {
41 Pte4K
->Bits
.ReadWrite
= Attribute
->Bits
.ReadWrite
;
44 if (Mask
->Bits
.UserSupervisor
) {
45 Pte4K
->Bits
.UserSupervisor
= Attribute
->Bits
.UserSupervisor
;
48 if (Mask
->Bits
.WriteThrough
) {
49 Pte4K
->Bits
.WriteThrough
= Attribute
->Bits
.WriteThrough
;
52 if (Mask
->Bits
.CacheDisabled
) {
53 Pte4K
->Bits
.CacheDisabled
= Attribute
->Bits
.CacheDisabled
;
56 if (Mask
->Bits
.Accessed
) {
57 Pte4K
->Bits
.Accessed
= Attribute
->Bits
.Accessed
;
60 if (Mask
->Bits
.Dirty
) {
61 Pte4K
->Bits
.Dirty
= Attribute
->Bits
.Dirty
;
65 Pte4K
->Bits
.Pat
= Attribute
->Bits
.Pat
;
68 if (Mask
->Bits
.Global
) {
69 Pte4K
->Bits
.Global
= Attribute
->Bits
.Global
;
72 if (Mask
->Bits
.ProtectionKey
) {
73 Pte4K
->Bits
.ProtectionKey
= Attribute
->Bits
.ProtectionKey
;
77 Pte4K
->Bits
.Nx
= Attribute
->Bits
.Nx
;
82 Set the IA32_PDPTE_1G or IA32_PDE_2M.
84 @param[in] PleB Pointer to PDPTE_1G or PDE_2M. Both share the same structure definition.
85 @param[in] Offset The offset within the linear address range.
86 @param[in] Attribute The attribute of the linear address range.
87 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
88 Page table entry is reset to 0 before set to the new attribute when a new physical base address is set.
89 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
93 IN IA32_PAGE_LEAF_ENTRY_BIG_PAGESIZE
*PleB
,
95 IN IA32_MAP_ATTRIBUTE
*Attribute
,
96 IN IA32_MAP_ATTRIBUTE
*Mask
99 if (Mask
->Bits
.PageTableBaseAddress
) {
101 // Reset all attributes when the physical address is changed.
103 PleB
->Uint64
= IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute
) + Offset
;
106 PleB
->Bits
.MustBeOne
= 1;
108 if (Mask
->Bits
.Present
) {
109 PleB
->Bits
.Present
= Attribute
->Bits
.Present
;
112 if (Mask
->Bits
.ReadWrite
) {
113 PleB
->Bits
.ReadWrite
= Attribute
->Bits
.ReadWrite
;
116 if (Mask
->Bits
.UserSupervisor
) {
117 PleB
->Bits
.UserSupervisor
= Attribute
->Bits
.UserSupervisor
;
120 if (Mask
->Bits
.WriteThrough
) {
121 PleB
->Bits
.WriteThrough
= Attribute
->Bits
.WriteThrough
;
124 if (Mask
->Bits
.CacheDisabled
) {
125 PleB
->Bits
.CacheDisabled
= Attribute
->Bits
.CacheDisabled
;
128 if (Mask
->Bits
.Accessed
) {
129 PleB
->Bits
.Accessed
= Attribute
->Bits
.Accessed
;
132 if (Mask
->Bits
.Dirty
) {
133 PleB
->Bits
.Dirty
= Attribute
->Bits
.Dirty
;
136 if (Mask
->Bits
.Pat
) {
137 PleB
->Bits
.Pat
= Attribute
->Bits
.Pat
;
140 if (Mask
->Bits
.Global
) {
141 PleB
->Bits
.Global
= Attribute
->Bits
.Global
;
144 if (Mask
->Bits
.ProtectionKey
) {
145 PleB
->Bits
.ProtectionKey
= Attribute
->Bits
.ProtectionKey
;
149 PleB
->Bits
.Nx
= Attribute
->Bits
.Nx
;
154 Set the IA32_PDPTE_1G, IA32_PDE_2M or IA32_PTE_4K.
156 @param[in] Level 3, 2 or 1.
157 @param[in] Ple Pointer to PDPTE_1G, PDE_2M or IA32_PTE_4K, depending on the Level.
158 @param[in] Offset The offset within the linear address range.
159 @param[in] Attribute The attribute of the linear address range.
160 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
161 Page table entry is reset to 0 before set to the new attribute when a new physical base address is set.
162 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
167 IN IA32_PAGING_ENTRY
*Ple
,
169 IN IA32_MAP_ATTRIBUTE
*Attribute
,
170 IN IA32_MAP_ATTRIBUTE
*Mask
174 PageTableLibSetPte4K (&Ple
->Pte4K
, Offset
, Attribute
, Mask
);
176 ASSERT (Level
== 2 || Level
== 3);
177 PageTableLibSetPleB (&Ple
->PleB
, Offset
, Attribute
, Mask
);
182 Set the IA32_PML5, IA32_PML4, IA32_PDPTE or IA32_PDE.
184 @param[in] Pnle Pointer to IA32_PML5, IA32_PML4, IA32_PDPTE or IA32_PDE. All share the same structure definition.
185 @param[in] Attribute The attribute of the page directory referenced by the non-leaf.
186 @param[in] Mask The mask of the page directory referenced by the non-leaf.
189 PageTableLibSetPnle (
190 IN IA32_PAGE_NON_LEAF_ENTRY
*Pnle
,
191 IN IA32_MAP_ATTRIBUTE
*Attribute
,
192 IN IA32_MAP_ATTRIBUTE
*Mask
195 if (Mask
->Bits
.Present
) {
196 Pnle
->Bits
.Present
= Attribute
->Bits
.Present
;
199 if (Mask
->Bits
.ReadWrite
) {
200 Pnle
->Bits
.ReadWrite
= Attribute
->Bits
.ReadWrite
;
203 if (Mask
->Bits
.UserSupervisor
) {
204 Pnle
->Bits
.UserSupervisor
= Attribute
->Bits
.UserSupervisor
;
208 Pnle
->Bits
.Nx
= Attribute
->Bits
.Nx
;
211 Pnle
->Bits
.Accessed
= 0;
214 // Set the attributes (WT, CD, A) to 0.
215 // WT and CD determin the memory type used to access the 4K page directory referenced by this entry.
216 // So, it implictly requires PAT[0] is Write Back.
217 // Create a new parameter if caller requires to use a different memory type for accessing page directories.
219 Pnle
->Bits
.WriteThrough
= 0;
220 Pnle
->Bits
.CacheDisabled
= 0;
224 Update page table to map [LinearAddress, LinearAddress + Length) with specified attribute in the specified level.
226 @param[in] ParentPagingEntry The pointer to the page table entry to update.
227 @param[in] ParentAttribute The accumulated attribute of all parents' attribute.
228 @param[in] Modify FALSE to indicate Buffer is not used and BufferSize is increased by the required buffer size.
229 @param[in] Buffer The free buffer to be used for page table creation/updating.
230 When Modify is TRUE, it's used from the end.
231 When Modify is FALSE, it's ignored.
232 @param[in, out] BufferSize The available buffer size.
233 Return the remaining buffer size.
234 @param[in] Level Page table level. Could be 5, 4, 3, 2, or 1.
235 @param[in] MaxLeafLevel Maximum level that can be a leaf entry. Could be 1, 2 or 3 (if Page 1G is supported).
236 @param[in] LinearAddress The start of the linear address range.
237 @param[in] Length The length of the linear address range.
238 @param[in] Offset The offset within the linear address range.
239 @param[in] Attribute The attribute of the linear address range.
240 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
241 Page table entries that map the linear address range are reset to 0 before set to the new attribute
242 when a new physical base address is set.
243 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
245 @retval RETURN_SUCCESS PageTable is created/updated successfully.
248 PageTableLibMapInLevel (
249 IN IA32_PAGING_ENTRY
*ParentPagingEntry
,
250 IN IA32_MAP_ATTRIBUTE
*ParentAttribute
,
253 IN OUT INTN
*BufferSize
,
255 IN UINTN MaxLeafLevel
,
256 IN UINT64 LinearAddress
,
259 IN IA32_MAP_ATTRIBUTE
*Attribute
,
260 IN IA32_MAP_ATTRIBUTE
*Mask
263 RETURN_STATUS Status
;
266 IA32_PAGING_ENTRY
*PagingEntry
;
267 IA32_PAGING_ENTRY
*CurrentPagingEntry
;
273 IA32_MAP_ATTRIBUTE AllOneMask
;
274 IA32_MAP_ATTRIBUTE PleBAttribute
;
275 IA32_MAP_ATTRIBUTE NopAttribute
;
277 IA32_PAGING_ENTRY OneOfPagingEntry
;
278 IA32_MAP_ATTRIBUTE ChildAttribute
;
279 IA32_MAP_ATTRIBUTE ChildMask
;
282 ASSERT ((Attribute
!= NULL
) && (Mask
!= NULL
));
285 AllOneMask
.Uint64
= ~0ull;
287 NopAttribute
.Uint64
= 0;
288 NopAttribute
.Bits
.Present
= 1;
289 NopAttribute
.Bits
.ReadWrite
= 1;
290 NopAttribute
.Bits
.UserSupervisor
= 1;
293 // ParentPagingEntry ONLY is deferenced for checking Present and MustBeOne bits
294 // when Modify is FALSE.
297 if (ParentPagingEntry
->Pce
.Present
== 0) {
299 // The parent entry is CR3 or PML5E/PML4E/PDPTE/PDE.
300 // It does NOT point to an existing page directory.
302 ASSERT (Buffer
== NULL
|| *BufferSize
>= SIZE_4KB
);
304 *BufferSize
-= SIZE_4KB
;
307 ParentPagingEntry
->Uintn
= (UINTN
)Buffer
+ *BufferSize
;
308 ZeroMem ((VOID
*)ParentPagingEntry
->Uintn
, SIZE_4KB
);
310 // Set default attribute bits for PML5E/PML4E/PDPTE/PDE.
312 PageTableLibSetPnle (&ParentPagingEntry
->Pnle
, &NopAttribute
, &AllOneMask
);
315 // Just make sure Present and MustBeZero (PageSize) bits are accurate.
317 OneOfPagingEntry
.Pnle
.Uint64
= 0;
319 } else if (IsPle (ParentPagingEntry
, Level
+ 1)) {
321 // The parent entry is a PDPTE_1G or PDE_2M. Split to 2M or 4K pages.
322 // Note: it's impossible the parent entry is a PTE_4K.
325 // Use NOP attributes as the attribute of grand-parents because CPU will consider
326 // the actual attributes of grand-parents when determing the memory type.
328 PleBAttribute
.Uint64
= PageTableLibGetPleBMapAttribute (&ParentPagingEntry
->PleB
, ParentAttribute
);
329 if ((IA32_MAP_ATTRIBUTE_ATTRIBUTES (&PleBAttribute
) & IA32_MAP_ATTRIBUTE_ATTRIBUTES (Mask
))
330 == (IA32_MAP_ATTRIBUTE_ATTRIBUTES (Attribute
) & IA32_MAP_ATTRIBUTE_ATTRIBUTES (Mask
)))
333 // This function is called when the memory length is less than the region length of the parent level.
334 // No need to split the page when the attributes equal.
336 return RETURN_SUCCESS
;
339 ASSERT (Buffer
== NULL
|| *BufferSize
>= SIZE_4KB
);
341 *BufferSize
-= SIZE_4KB
;
342 PageTableLibSetPle (Level
, &OneOfPagingEntry
, 0, &PleBAttribute
, &AllOneMask
);
345 // Create 512 child-level entries that map to 2M/4K.
347 ParentPagingEntry
->Uintn
= (UINTN
)Buffer
+ *BufferSize
;
348 ZeroMem ((VOID
*)ParentPagingEntry
->Uintn
, SIZE_4KB
);
351 // Set NOP attributes
352 // Note: Should NOT inherit the attributes from the original entry because a zero RW bit
353 // will make the entire region read-only even the child entries set the RW bit.
355 PageTableLibSetPnle (&ParentPagingEntry
->Pnle
, &NopAttribute
, &AllOneMask
);
357 RegionLength
= REGION_LENGTH (Level
);
358 PagingEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry
->Pnle
);
359 for (SubOffset
= 0, Index
= 0; Index
< 512; Index
++) {
360 PagingEntry
[Index
].Uint64
= OneOfPagingEntry
.Uint64
+ SubOffset
;
361 SubOffset
+= RegionLength
;
366 // It's a non-leaf entry
368 ChildAttribute
.Uint64
= 0;
369 ChildMask
.Uint64
= 0;
372 // If the inheritable attributes in the parent entry conflicts with the requested attributes,
373 // let the child entries take the parent attributes and
374 // loosen the attribute in the parent entry
375 // E.g.: when PDPTE[0].ReadWrite = 0 but caller wants to map [0-2MB] as ReadWrite = 1 (PDE[0].ReadWrite = 1)
376 // we need to change PDPTE[0].ReadWrite = 1 and let all PDE[0-255].ReadWrite = 0 in this step.
377 // when PDPTE[0].Nx = 1 but caller wants to map [0-2MB] as Nx = 0 (PDT[0].Nx = 0)
378 // we need to change PDPTE[0].Nx = 0 and let all PDE[0-255].Nx = 1 in this step.
379 if ((ParentPagingEntry
->Pnle
.Bits
.Present
== 0) && (Mask
->Bits
.Present
== 1) && (Attribute
->Bits
.Present
== 1)) {
381 ParentPagingEntry
->Pnle
.Bits
.Present
= 1;
384 ChildAttribute
.Bits
.Present
= 0;
385 ChildMask
.Bits
.Present
= 1;
388 if ((ParentPagingEntry
->Pnle
.Bits
.ReadWrite
== 0) && (Mask
->Bits
.ReadWrite
== 1) && (Attribute
->Bits
.ReadWrite
== 1)) {
390 ParentPagingEntry
->Pnle
.Bits
.ReadWrite
= 1;
393 ChildAttribute
.Bits
.ReadWrite
= 0;
394 ChildMask
.Bits
.ReadWrite
= 1;
397 if ((ParentPagingEntry
->Pnle
.Bits
.UserSupervisor
== 0) && (Mask
->Bits
.UserSupervisor
== 1) && (Attribute
->Bits
.UserSupervisor
== 1)) {
399 ParentPagingEntry
->Pnle
.Bits
.UserSupervisor
= 1;
402 ChildAttribute
.Bits
.UserSupervisor
= 0;
403 ChildMask
.Bits
.UserSupervisor
= 1;
406 if ((ParentPagingEntry
->Pnle
.Bits
.Nx
== 1) && (Mask
->Bits
.Nx
== 1) && (Attribute
->Bits
.Nx
== 0)) {
408 ParentPagingEntry
->Pnle
.Bits
.Nx
= 0;
411 ChildAttribute
.Bits
.Nx
= 1;
412 ChildMask
.Bits
.Nx
= 1;
415 if (ChildMask
.Uint64
!= 0) {
418 // Update child entries to use restrictive attribute inherited from parent.
419 // e.g.: Set PDE[0-255].ReadWrite = 0
421 PagingEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry
->Pnle
);
422 for (Index
= 0; Index
< 512; Index
++) {
423 if (PagingEntry
[Index
].Pce
.Present
== 0) {
427 if (IsPle (&PagingEntry
[Index
], Level
)) {
428 PageTableLibSetPle (Level
- 1, &PagingEntry
[Index
], 0, &ChildAttribute
, &ChildMask
);
430 PageTableLibSetPnle (&PagingEntry
[Index
].Pnle
, &ChildAttribute
, &ChildMask
);
438 // RegionLength: 256T (1 << 48) 512G (1 << 39), 1G (1 << 30), 2M (1 << 21) or 4K (1 << 12).
439 // RegionStart: points to the linear address that's aligned on RegionLength and lower than (LinearAddress + Offset).
441 BitStart
= 12 + (Level
- 1) * 9;
442 Index
= (UINTN
)BitFieldRead64 (LinearAddress
+ Offset
, BitStart
, BitStart
+ 9 - 1);
443 RegionLength
= LShiftU64 (1, BitStart
);
444 RegionMask
= RegionLength
- 1;
445 RegionStart
= (LinearAddress
+ Offset
) & ~RegionMask
;
447 ParentAttribute
->Uint64
= PageTableLibGetPnleMapAttribute (&ParentPagingEntry
->Pnle
, ParentAttribute
);
450 // Apply the attribute.
452 PagingEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry
->Pnle
);
453 while (Offset
< Length
&& Index
< 512) {
454 CurrentPagingEntry
= (!Modify
&& CreateNew
) ? &OneOfPagingEntry
: &PagingEntry
[Index
];
455 SubLength
= MIN (Length
- Offset
, RegionStart
+ RegionLength
- (LinearAddress
+ Offset
));
456 if ((Level
<= MaxLeafLevel
) &&
457 (((LinearAddress
+ Offset
) & RegionMask
) == 0) &&
458 (((IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute
) + Offset
) & RegionMask
) == 0) &&
459 (SubLength
== RegionLength
) &&
460 ((CurrentPagingEntry
->Pce
.Present
== 0) || IsPle (CurrentPagingEntry
, Level
))
464 // Create one entry mapping the entire region (1G, 2M or 4K).
467 PageTableLibSetPle (Level
, CurrentPagingEntry
, Offset
, Attribute
, Mask
);
471 // Recursively call to create page table.
472 // There are 3 cases:
473 // a. Level cannot be a leaf entry which points to physical memory.
474 // a. Level can be a leaf entry but (LinearAddress + Offset) is NOT aligned on the RegionStart.
475 // b. Level can be a leaf entry and (LinearAddress + Offset) is aligned on RegionStart,
476 // but the length is SMALLER than the RegionLength.
478 Status
= PageTableLibMapInLevel (
492 if (RETURN_ERROR (Status
)) {
498 RegionStart
+= RegionLength
;
502 return RETURN_SUCCESS
;
506 Create or update page table to map [LinearAddress, LinearAddress + Length) with specified attribute.
508 @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.
509 @param[in] PagingMode The paging mode.
510 @param[in] Buffer The free buffer to be used for page table creation/updating.
511 @param[in, out] BufferSize The buffer size.
512 On return, the remaining buffer size.
513 The free buffer is used from the end so caller can supply the same Buffer pointer with an updated
514 BufferSize in the second call to this API.
515 @param[in] LinearAddress The start of the linear address range.
516 @param[in] Length The length of the linear address range.
517 @param[in] Attribute The attribute of the linear address range.
518 All non-reserved fields in IA32_MAP_ATTRIBUTE are supported to set in the page table.
519 Page table entries that map the linear address range are reset to 0 before set to the new attribute
520 when a new physical base address is set.
521 @param[in] Mask The mask used for attribute. The corresponding field in Attribute is ignored if that in Mask is 0.
523 @retval RETURN_UNSUPPORTED PagingMode is not supported.
524 @retval RETURN_INVALID_PARAMETER PageTable, BufferSize, Attribute or Mask is NULL.
525 @retval RETURN_INVALID_PARAMETER *BufferSize is not multiple of 4KB.
526 @retval RETURN_BUFFER_TOO_SMALL The buffer is too small for page table creation/updating.
527 BufferSize is updated to indicate the expected buffer size.
528 Caller may still get RETURN_BUFFER_TOO_SMALL with the new BufferSize.
529 @retval RETURN_SUCCESS PageTable is created/updated successfully.
534 IN OUT UINTN
*PageTable OPTIONAL
,
535 IN PAGING_MODE PagingMode
,
537 IN OUT UINTN
*BufferSize
,
538 IN UINT64 LinearAddress
,
540 IN IA32_MAP_ATTRIBUTE
*Attribute
,
541 IN IA32_MAP_ATTRIBUTE
*Mask
544 RETURN_STATUS Status
;
545 IA32_PAGING_ENTRY TopPagingEntry
;
547 UINT64 MaxLinearAddress
;
550 IA32_MAP_ATTRIBUTE ParentAttribute
;
552 if ((PagingMode
== Paging32bit
) || (PagingMode
== PagingPae
) || (PagingMode
>= PagingModeMax
)) {
554 // 32bit paging is never supported.
555 // PAE paging will be supported later.
557 return RETURN_UNSUPPORTED
;
560 if ((PageTable
== NULL
) || (BufferSize
== NULL
) || (Attribute
== NULL
) || (Mask
== NULL
)) {
561 return RETURN_INVALID_PARAMETER
;
564 if (*BufferSize
% SIZE_4KB
!= 0) {
566 // BufferSize should be multiple of 4K.
568 return RETURN_INVALID_PARAMETER
;
571 if ((LinearAddress
% SIZE_4KB
!= 0) || (Length
% SIZE_4KB
!= 0)) {
573 // LinearAddress and Length should be multiple of 4K.
575 return RETURN_INVALID_PARAMETER
;
578 if ((*BufferSize
!= 0) && (Buffer
== NULL
)) {
579 return RETURN_INVALID_PARAMETER
;
582 MaxLeafLevel
= (UINT8
)PagingMode
;
583 MaxLevel
= (UINT8
)(PagingMode
>> 8);
584 MaxLinearAddress
= LShiftU64 (1, 12 + MaxLevel
* 9);
586 if ((LinearAddress
> MaxLinearAddress
) || (Length
> MaxLinearAddress
- LinearAddress
)) {
588 // Maximum linear address is (1 << 48) or (1 << 57)
590 return RETURN_INVALID_PARAMETER
;
593 TopPagingEntry
.Uintn
= *PageTable
;
594 if (TopPagingEntry
.Uintn
!= 0) {
595 TopPagingEntry
.Pce
.Present
= 1;
596 TopPagingEntry
.Pce
.ReadWrite
= 1;
597 TopPagingEntry
.Pce
.UserSupervisor
= 1;
598 TopPagingEntry
.Pce
.Nx
= 0;
601 ParentAttribute
.Uint64
= 0;
602 ParentAttribute
.Bits
.PageTableBaseAddress
= 1;
603 ParentAttribute
.Bits
.Present
= 1;
604 ParentAttribute
.Bits
.ReadWrite
= 1;
605 ParentAttribute
.Bits
.UserSupervisor
= 1;
606 ParentAttribute
.Bits
.Nx
= 0;
609 // Query the required buffer size without modifying the page table.
612 Status
= PageTableLibMapInLevel (
626 if (RETURN_ERROR (Status
)) {
630 RequiredSize
= -RequiredSize
;
632 if ((UINTN
)RequiredSize
> *BufferSize
) {
633 *BufferSize
= RequiredSize
;
634 return RETURN_BUFFER_TOO_SMALL
;
637 if ((RequiredSize
!= 0) && (Buffer
== NULL
)) {
638 return RETURN_INVALID_PARAMETER
;
642 // Update the page table when the supplied buffer is sufficient.
644 ParentAttribute
.Uint64
= 0;
645 ParentAttribute
.Bits
.PageTableBaseAddress
= 1;
646 ParentAttribute
.Bits
.Present
= 1;
647 ParentAttribute
.Bits
.ReadWrite
= 1;
648 ParentAttribute
.Bits
.UserSupervisor
= 1;
649 ParentAttribute
.Bits
.Nx
= 0;
651 Status
= PageTableLibMapInLevel (
665 if (!RETURN_ERROR (Status
)) {
666 *PageTable
= (UINTN
)(TopPagingEntry
.Uintn
& IA32_PE_BASE_ADDRESS_MASK_40
);