2 helper file for Unit tests of the CpuPageTableLib instance of the CpuPageTableLib class
4 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "CpuPageTableLibUnitTest.h"
10 #include "../CpuPageTable.h"
13 // Global Data to validate if the page table is legal
14 // mValidMaskNoLeaf[0] is not used
15 // mValidMaskNoLeaf[1] ... mValidMaskNoLeaf [5] represent PTE ... PML5E
16 // mValidMaskNoLeaf[Index] means if it is a valid no leaf entry, entry should equal to (entry & mValidMaskNoLeaf[Index])
17 // mValidMaskLeaf[Index] means if it is a valid leaf entry, entry should equal to (entry & mValidMaskLeaf[Index])
18 // mValidMaskLeafFlag[Index] means if it is a leaf entry, if and only if ((entry & mValidMaskLeafFlag[Index]) == mValidMaskLeafFlag[Index])
20 IA32_PAGING_ENTRY mValidMaskNoLeaf
[6];
21 IA32_PAGING_ENTRY mValidMaskLeaf
[6];
22 IA32_PAGING_ENTRY mValidMaskLeafFlag
[6];
27 @param[in] MemorySpace Memory space
36 ASSERT (MemorySpace
<= 52);
37 mValidMaskNoLeaf
[0].Uint64
= 0;
38 mValidMaskLeaf
[0].Uint64
= 0;
39 mValidMaskLeafFlag
[0].Uint64
= 0;
42 // Set common part for all kinds of entrys.
44 for (Index
= 1; Index
< 6; Index
++) {
45 mValidMaskNoLeaf
[Index
].Uint64
= MAX_UINT64
;
46 mValidMaskLeaf
[Index
].Uint64
= MAX_UINT64
;
49 // bit 51:M is reserved, and should be zero
51 if (MemorySpace
- 1 < 51) {
52 mValidMaskNoLeaf
[Index
].Uint64
= BitFieldWrite64 (mValidMaskNoLeaf
[Index
].Uint64
, MemorySpace
- 1, 51, 0);
53 mValidMaskLeaf
[Index
].Uint64
= BitFieldWrite64 (mValidMaskLeaf
[Index
].Uint64
, MemorySpace
- 1, 51, 0);
58 // Handle mask for no leaf entry.
60 mValidMaskNoLeaf
[1].Uint64
= 0; // PTE can't map to page structure.
61 mValidMaskNoLeaf
[2].Pnle
.Bits
.MustBeZero
= 0; // for PML4E, bit 7 must be zero.
62 mValidMaskNoLeaf
[3].Pnle
.Bits
.MustBeZero
= 0; // for PML5E, bit 7 must be zero.
63 mValidMaskNoLeaf
[4].Pml4
.Bits
.MustBeZero
= 0; // for PML4E, bit 7 must be zero.
64 mValidMaskNoLeaf
[5].Pml4
.Bits
.MustBeZero
= 0; // for PML5E, bit 7 must be zero.
67 // Handle mask for leaf entry.
68 // No need to modification for PTE, since it doesn't have extra reserved bit
70 mValidMaskLeaf
[2].Uint64
= BitFieldWrite64 (mValidMaskLeaf
[2].Uint64
, 13, 20, 0); // bit 13-20 is reserved for PDE
71 mValidMaskLeaf
[3].Uint64
= BitFieldWrite64 (mValidMaskLeaf
[2].Uint64
, 13, 29, 0); // bit 13-29 is reserved for PDPTE
72 mValidMaskLeaf
[4].Uint64
= 0; // for PML4E, no possible to map to page.
73 mValidMaskLeaf
[5].Uint64
= 0; // for PML5E, no possible to map to page.
76 // Handle Flags to indicate it is a leaf entry.
77 // for PML4E and PML5E, no possible to map to page, so the flag should be MAX_UINT64.
79 mValidMaskLeafFlag
[1].Pce
.Present
= 1; // For PTE, as long as it is present, it maps to page
81 // For PDE and PDPTE, the bit 7 should be set to map to pages
83 mValidMaskLeafFlag
[2].Pde2M
.Bits
.MustBeOne
= 1;
84 mValidMaskLeafFlag
[2].Pde2M
.Bits
.Present
= 1;
85 mValidMaskLeafFlag
[3].Pde2M
.Bits
.MustBeOne
= 1;
86 mValidMaskLeafFlag
[3].Pde2M
.Bits
.Present
= 1;
87 mValidMaskLeafFlag
[4].Uint64
= MAX_UINT64
;
88 mValidMaskLeafFlag
[5].Uint64
= MAX_UINT64
;
92 Check if the Page table entry is valid
94 @param[in] PagingEntry The entry in page table to verify
95 @param[in] Level the level of PagingEntry.
96 @param[in] MaxLeafLevel Max leaf entry level.
97 @param[in] LinearAddress The linear address verified.
102 IsPageTableEntryValid (
103 IN IA32_PAGING_ENTRY
*PagingEntry
,
105 IN UINTN MaxLeafLevel
,
110 IA32_PAGING_ENTRY
*ChildPageEntry
;
111 UNIT_TEST_STATUS Status
;
113 if (PagingEntry
->Pce
.Present
== 0) {
114 return UNIT_TEST_PASSED
;
117 if ((PagingEntry
->Uint64
& mValidMaskLeafFlag
[Level
].Uint64
) == mValidMaskLeafFlag
[Level
].Uint64
) {
121 if (Level
> MaxLeafLevel
) {
122 DEBUG ((DEBUG_ERROR
, "ERROR: Level %d entry 0x%lx is a leaf entry, but max leaf level is %d \n", Level
, PagingEntry
->Uint64
, MaxLeafLevel
));
123 UT_ASSERT_TRUE (Level
<= MaxLeafLevel
);
126 if ((PagingEntry
->Uint64
& mValidMaskLeaf
[Level
].Uint64
) != PagingEntry
->Uint64
) {
127 DEBUG ((DEBUG_ERROR
, "ERROR: Level %d Leaf entry is 0x%lx, which reserved bit is set \n", Level
, PagingEntry
->Uint64
));
128 UT_ASSERT_EQUAL ((PagingEntry
->Uint64
& mValidMaskLeaf
[Level
].Uint64
), PagingEntry
->Uint64
);
131 return UNIT_TEST_PASSED
;
137 UT_ASSERT_NOT_EQUAL (Level
, 1);
138 if ((PagingEntry
->Uint64
& mValidMaskNoLeaf
[Level
].Uint64
) != PagingEntry
->Uint64
) {
139 DEBUG ((DEBUG_ERROR
, "ERROR: Level %d no Leaf entry is 0x%lx, which reserved bit is set \n", Level
, PagingEntry
->Uint64
));
140 UT_ASSERT_EQUAL ((PagingEntry
->Uint64
& mValidMaskNoLeaf
[Level
].Uint64
), PagingEntry
->Uint64
);
143 ChildPageEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)(((UINTN
)(PagingEntry
->Pnle
.Bits
.PageTableBaseAddress
)) << 12);
144 for (Index
= 0; Index
< 512; Index
++) {
145 Status
= IsPageTableEntryValid (&ChildPageEntry
[Index
], Level
-1, MaxLeafLevel
, Address
+ (Index
<<(9*(Level
-1) + 3)));
146 if (Status
!= UNIT_TEST_PASSED
) {
151 return UNIT_TEST_PASSED
;
155 Check if the Page table is valid
157 @param[in] PageTable The pointer to the page table.
158 @param[in] PagingMode The paging mode.
160 @retval UNIT_TEST_PASSED It is a valid Page Table
165 IN PAGING_MODE PagingMode
171 UNIT_TEST_STATUS Status
;
172 IA32_PAGING_ENTRY
*PagingEntry
;
174 if ((PagingMode
== Paging32bit
) || (PagingMode
== PagingPae
) || (PagingMode
>= PagingModeMax
)) {
176 // 32bit paging is never supported.
177 // PAE paging will be supported later.
179 return UNIT_TEST_ERROR_TEST_FAILED
;
182 MaxLeafLevel
= (UINT8
)PagingMode
;
183 MaxLevel
= (UINT8
)(PagingMode
>> 8);
185 PagingEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)PageTable
;
186 for (Index
= 0; Index
< 512; Index
++) {
187 Status
= IsPageTableEntryValid (&PagingEntry
[Index
], MaxLevel
, MaxLeafLevel
, Index
<< (9 * MaxLevel
+ 3));
188 if (Status
!= UNIT_TEST_PASSED
) {
197 Get the leaf entry for a given linear address from one entry in page table
199 @param[in] PagingEntry The entry in page table which covers the linear address
200 @param[in, out] Level On input, is the level of PagingEntry.
201 On outout, is the level of the leaf entry
202 @param[in] MaxLeafLevel Max leaf entry level.
203 @param[in] LinearAddress The linear address.
208 GetEntryFromSubPageTable (
209 IN IA32_PAGING_ENTRY
*PagingEntry
,
211 IN UINTN MaxLeafLevel
,
216 IA32_PAGING_ENTRY
*ChildPageEntry
;
218 if (PagingEntry
->Pce
.Present
== 0) {
222 if ((PagingEntry
->Uint64
& mValidMaskLeafFlag
[*Level
].Uint64
) == mValidMaskLeafFlag
[*Level
].Uint64
) {
226 return PagingEntry
->Uint64
;
232 ChildPageEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)(((UINTN
)(PagingEntry
->Pnle
.Bits
.PageTableBaseAddress
)) << 12);
234 Index
= Address
>> (*Level
* 9 + 3);
235 ASSERT (Index
== (Index
& ((1<< 9) - 1)));
237 return GetEntryFromSubPageTable (&ChildPageEntry
[Index
], Level
, MaxLeafLevel
, Address
- (Index
<< (9 * *Level
+ 3)));
241 Get the leaf entry for a given linear address from a page table
243 @param[in] PageTable The pointer to the page table.
244 @param[in] PagingMode The paging mode.
245 @param[in] LinearAddress The linear address.
246 @param[out] Level leaf entry's level.
251 GetEntryFromPageTable (
253 IN PAGING_MODE PagingMode
,
261 IA32_PAGING_ENTRY
*PagingEntry
;
263 if ((PagingMode
== Paging32bit
) || (PagingMode
== PagingPae
) || (PagingMode
>= PagingModeMax
)) {
265 // 32bit paging is never supported.
266 // PAE paging will be supported later.
271 MaxLeafLevel
= (UINT8
)PagingMode
;
272 MaxLevel
= (UINT8
)(PagingMode
>> 8);
274 Index
= Address
>> (MaxLevel
* 9 + 3);
275 ASSERT (Index
== (Index
& ((1<< 9) - 1)));
276 PagingEntry
= (IA32_PAGING_ENTRY
*)(UINTN
)PageTable
;
279 return GetEntryFromSubPageTable (&PagingEntry
[Index
], Level
, MaxLeafLevel
, Address
- (Index
<< (9 * MaxLevel
+ 3)));
283 Get max physical adrress supported by specific page mode
285 @param[in] Mode The paging mode.
300 case Paging4Level1GB
:
302 case Paging5Level1GB
:
303 return 1ull << MIN (12 + (Mode
>> 8) * 9, 52);