]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuPageTableLib/UnitTest/TestHelper.c
5bd70c0f657fa00eff0976ace3bac3e9d9119cef
[mirror_edk2.git] / UefiCpuPkg / Library / CpuPageTableLib / UnitTest / TestHelper.c
1 /** @file
2 helper file for Unit tests of the CpuPageTableLib instance of the CpuPageTableLib class
3
4 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "CpuPageTableLibUnitTest.h"
10 #include "../CpuPageTable.h"
11
12 //
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])
19 //
20 IA32_PAGING_ENTRY mValidMaskNoLeaf[6];
21 IA32_PAGING_ENTRY mValidMaskLeaf[6];
22 IA32_PAGING_ENTRY mValidMaskLeafFlag[6];
23
24 /**
25 Init global data.
26
27 @param[in] MemorySpace Memory space
28 **/
29 VOID
30 InitGlobalData (
31 UINTN MemorySpace
32 )
33 {
34 UINTN Index;
35
36 ASSERT (MemorySpace <= 52);
37 mValidMaskNoLeaf[0].Uint64 = 0;
38 mValidMaskLeaf[0].Uint64 = 0;
39 mValidMaskLeafFlag[0].Uint64 = 0;
40
41 //
42 // Set common part for all kinds of entrys.
43 //
44 for (Index = 1; Index < 6; Index++) {
45 mValidMaskNoLeaf[Index].Uint64 = MAX_UINT64;
46 mValidMaskLeaf[Index].Uint64 = MAX_UINT64;
47
48 //
49 // bit 51:M is reserved, and should be zero
50 //
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);
54 }
55 }
56
57 //
58 // Handle mask for no leaf entry.
59 //
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.
65
66 //
67 // Handle mask for leaf entry.
68 // No need to modification for PTE, since it doesn't have extra reserved bit
69 //
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.
74
75 //
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.
78 //
79 mValidMaskLeafFlag[1].Pce.Present = 1; // For PTE, as long as it is present, it maps to page
80 //
81 // For PDE and PDPTE, the bit 7 should be set to map to pages
82 //
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;
89 }
90
91 /**
92 Check if the Page table entry is valid
93
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.
98
99 @retval Leaf entry.
100 **/
101 UNIT_TEST_STATUS
102 IsPageTableEntryValid (
103 IN IA32_PAGING_ENTRY *PagingEntry,
104 IN UINTN Level,
105 IN UINTN MaxLeafLevel,
106 IN UINT64 Address
107 )
108 {
109 UINT64 Index;
110 IA32_PAGING_ENTRY *ChildPageEntry;
111 UNIT_TEST_STATUS Status;
112
113 if (PagingEntry->Pce.Present == 0) {
114 return UNIT_TEST_PASSED;
115 }
116
117 if ((PagingEntry->Uint64 & mValidMaskLeafFlag[Level].Uint64) == mValidMaskLeafFlag[Level].Uint64) {
118 //
119 // It is a Leaf
120 //
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);
124 }
125
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);
129 }
130
131 return UNIT_TEST_PASSED;
132 }
133
134 //
135 // Not a leaf
136 //
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);
141 }
142
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) {
147 return Status;
148 }
149 }
150
151 return UNIT_TEST_PASSED;
152 }
153
154 /**
155 Check if the Page table is valid
156
157 @param[in] PageTable The pointer to the page table.
158 @param[in] PagingMode The paging mode.
159
160 @retval UNIT_TEST_PASSED It is a valid Page Table
161 **/
162 UNIT_TEST_STATUS
163 IsPageTableValid (
164 IN UINTN PageTable,
165 IN PAGING_MODE PagingMode
166 )
167 {
168 UINTN MaxLevel;
169 UINTN MaxLeafLevel;
170 UINT64 Index;
171 UNIT_TEST_STATUS Status;
172 IA32_PAGING_ENTRY *PagingEntry;
173
174 if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
175 //
176 // 32bit paging is never supported.
177 // PAE paging will be supported later.
178 //
179 return UNIT_TEST_ERROR_TEST_FAILED;
180 }
181
182 MaxLeafLevel = (UINT8)PagingMode;
183 MaxLevel = (UINT8)(PagingMode >> 8);
184
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) {
189 return Status;
190 }
191 }
192
193 return Status;
194 }
195
196 /**
197 Get the leaf entry for a given linear address from one entry in page table
198
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.
204
205 @retval Leaf entry.
206 **/
207 UINT64
208 GetEntryFromSubPageTable (
209 IN IA32_PAGING_ENTRY *PagingEntry,
210 IN OUT UINTN *Level,
211 IN UINTN MaxLeafLevel,
212 IN UINT64 Address
213 )
214 {
215 UINT64 Index;
216 IA32_PAGING_ENTRY *ChildPageEntry;
217
218 if (PagingEntry->Pce.Present == 0) {
219 return 0;
220 }
221
222 if ((PagingEntry->Uint64 & mValidMaskLeafFlag[*Level].Uint64) == mValidMaskLeafFlag[*Level].Uint64) {
223 //
224 // It is a Leaf
225 //
226 return PagingEntry->Uint64;
227 }
228
229 //
230 // Not a leaf
231 //
232 ChildPageEntry = (IA32_PAGING_ENTRY *)(UINTN)(((UINTN)(PagingEntry->Pnle.Bits.PageTableBaseAddress)) << 12);
233 *Level = *Level -1;
234 Index = Address >> (*Level * 9 + 3);
235 ASSERT (Index == (Index & ((1<< 9) - 1)));
236
237 return GetEntryFromSubPageTable (&ChildPageEntry[Index], Level, MaxLeafLevel, Address - (Index << (9 * *Level + 3)));
238 }
239
240 /**
241 Get the leaf entry for a given linear address from a page table
242
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.
247
248 @retval Leaf entry.
249 **/
250 UINT64
251 GetEntryFromPageTable (
252 IN UINTN PageTable,
253 IN PAGING_MODE PagingMode,
254 IN UINT64 Address,
255 OUT UINTN *Level
256 )
257 {
258 UINTN MaxLevel;
259 UINTN MaxLeafLevel;
260 UINT64 Index;
261 IA32_PAGING_ENTRY *PagingEntry;
262
263 if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {
264 //
265 // 32bit paging is never supported.
266 // PAE paging will be supported later.
267 //
268 return 0;
269 }
270
271 MaxLeafLevel = (UINT8)PagingMode;
272 MaxLevel = (UINT8)(PagingMode >> 8);
273
274 Index = Address >> (MaxLevel * 9 + 3);
275 ASSERT (Index == (Index & ((1<< 9) - 1)));
276 PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTable;
277 *Level = MaxLevel;
278
279 return GetEntryFromSubPageTable (&PagingEntry[Index], Level, MaxLeafLevel, Address - (Index << (9 * MaxLevel + 3)));
280 }
281
282 /**
283 Get max physical adrress supported by specific page mode
284
285 @param[in] Mode The paging mode.
286
287 @retval max address.
288 **/
289 UINT64
290 GetMaxAddress (
291 IN PAGING_MODE Mode
292 )
293 {
294 switch (Mode) {
295 case Paging32bit:
296 case PagingPae:
297 return SIZE_4GB;
298
299 case Paging4Level:
300 case Paging4Level1GB:
301 case Paging5Level:
302 case Paging5Level1GB:
303 return 1ull << MIN (12 + (Mode >> 8) * 9, 52);
304
305 default:
306 ASSERT (0);
307 return 0;
308 }
309 }