]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
2daf47ba6fe5f5cf40f1717f7d1e81ece81bba17
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / Arm / Mmu.c
1 /*++
2
3 Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2013-2021, Arm Limited. All rights reserved.<BR>
6 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10
11 --*/
12
13 #include <Library/MemoryAllocationLib.h>
14 #include "CpuDxe.h"
15
16 EFI_STATUS
17 SectionToGcdAttributes (
18 IN UINT32 SectionAttributes,
19 OUT UINT64 *GcdAttributes
20 )
21 {
22 *GcdAttributes = 0;
23
24 // determine cacheability attributes
25 switch (SectionAttributes & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) {
26 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED:
27 *GcdAttributes |= EFI_MEMORY_UC;
28 break;
29 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE:
30 *GcdAttributes |= EFI_MEMORY_UC;
31 break;
32 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
33 *GcdAttributes |= EFI_MEMORY_WT;
34 break;
35 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
36 *GcdAttributes |= EFI_MEMORY_WB;
37 break;
38 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE:
39 *GcdAttributes |= EFI_MEMORY_WC;
40 break;
41 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC:
42 *GcdAttributes |= EFI_MEMORY_WB;
43 break;
44 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE:
45 *GcdAttributes |= EFI_MEMORY_UC;
46 break;
47 default:
48 return EFI_UNSUPPORTED;
49 }
50
51 // determine protection attributes
52 switch (SectionAttributes & TT_DESCRIPTOR_SECTION_AP_MASK) {
53 case TT_DESCRIPTOR_SECTION_AP_NO_NO: // no read, no write
54 // *GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;
55 break;
56
57 case TT_DESCRIPTOR_SECTION_AP_RW_NO:
58 case TT_DESCRIPTOR_SECTION_AP_RW_RW:
59 // normal read/write access, do not add additional attributes
60 break;
61
62 // read only cases map to write-protect
63 case TT_DESCRIPTOR_SECTION_AP_RO_NO:
64 case TT_DESCRIPTOR_SECTION_AP_RO_RO:
65 *GcdAttributes |= EFI_MEMORY_RO;
66 break;
67
68 default:
69 return EFI_UNSUPPORTED;
70 }
71
72 // now process eXectue Never attribute
73 if ((SectionAttributes & TT_DESCRIPTOR_SECTION_XN_MASK) != 0 ) {
74 *GcdAttributes |= EFI_MEMORY_XP;
75 }
76
77 return EFI_SUCCESS;
78 }
79
80 EFI_STATUS
81 PageToGcdAttributes (
82 IN UINT32 PageAttributes,
83 OUT UINT64 *GcdAttributes
84 )
85 {
86 *GcdAttributes = 0;
87
88 // determine cacheability attributes
89 switch (PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {
90 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:
91 *GcdAttributes |= EFI_MEMORY_UC;
92 break;
93 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:
94 *GcdAttributes |= EFI_MEMORY_UC;
95 break;
96 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
97 *GcdAttributes |= EFI_MEMORY_WT;
98 break;
99 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
100 *GcdAttributes |= EFI_MEMORY_WB;
101 break;
102 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:
103 *GcdAttributes |= EFI_MEMORY_WC;
104 break;
105 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:
106 *GcdAttributes |= EFI_MEMORY_WB;
107 break;
108 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:
109 *GcdAttributes |= EFI_MEMORY_UC;
110 break;
111 default:
112 return EFI_UNSUPPORTED;
113 }
114
115 // determine protection attributes
116 switch (PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {
117 case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write
118 // *GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;
119 break;
120
121 case TT_DESCRIPTOR_PAGE_AP_RW_NO:
122 case TT_DESCRIPTOR_PAGE_AP_RW_RW:
123 // normal read/write access, do not add additional attributes
124 break;
125
126 // read only cases map to write-protect
127 case TT_DESCRIPTOR_PAGE_AP_RO_NO:
128 case TT_DESCRIPTOR_PAGE_AP_RO_RO:
129 *GcdAttributes |= EFI_MEMORY_RO;
130 break;
131
132 default:
133 return EFI_UNSUPPORTED;
134 }
135
136 // now process eXectue Never attribute
137 if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {
138 *GcdAttributes |= EFI_MEMORY_XP;
139 }
140
141 return EFI_SUCCESS;
142 }
143
144 EFI_STATUS
145 SyncCacheConfigPage (
146 IN UINT32 SectionIndex,
147 IN UINT32 FirstLevelDescriptor,
148 IN UINTN NumberOfDescriptors,
149 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
150 IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,
151 IN OUT UINT64 *NextRegionLength,
152 IN OUT UINT32 *NextSectionAttributes
153 )
154 {
155 EFI_STATUS Status;
156 UINT32 i;
157 volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;
158 UINT32 NextPageAttributes;
159 UINT32 PageAttributes;
160 UINT32 BaseAddress;
161 UINT64 GcdAttributes;
162
163 // Get the Base Address from FirstLevelDescriptor;
164 BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS (SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
165
166 // Convert SectionAttributes into PageAttributes
167 NextPageAttributes =
168 TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY (*NextSectionAttributes, 0) |
169 TT_DESCRIPTOR_CONVERT_TO_PAGE_AP (*NextSectionAttributes);
170
171 // obtain page table base
172 SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
173
174 for (i = 0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {
175 if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {
176 // extract attributes (cacheability and permissions)
177 PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);
178
179 if (NextPageAttributes == 0) {
180 // start on a new region
181 *NextRegionLength = 0;
182 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
183 NextPageAttributes = PageAttributes;
184 } else if (PageAttributes != NextPageAttributes) {
185 // Convert Section Attributes into GCD Attributes
186 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
187 ASSERT_EFI_ERROR (Status);
188
189 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
190 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
191
192 // start on a new region
193 *NextRegionLength = 0;
194 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
195 NextPageAttributes = PageAttributes;
196 }
197 } else if (NextPageAttributes != 0) {
198 // Convert Page Attributes into GCD Attributes
199 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
200 ASSERT_EFI_ERROR (Status);
201
202 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
203 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
204
205 *NextRegionLength = 0;
206 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
207 NextPageAttributes = 0;
208 }
209
210 *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;
211 }
212
213 // Convert back PageAttributes into SectionAttributes
214 *NextSectionAttributes =
215 TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (NextPageAttributes, 0) |
216 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (NextPageAttributes);
217
218 return EFI_SUCCESS;
219 }
220
221 EFI_STATUS
222 SyncCacheConfig (
223 IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
224 )
225 {
226 EFI_STATUS Status;
227 UINT32 i;
228 EFI_PHYSICAL_ADDRESS NextRegionBase;
229 UINT64 NextRegionLength;
230 UINT32 NextSectionAttributes;
231 UINT32 SectionAttributes;
232 UINT64 GcdAttributes;
233 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
234 UINTN NumberOfDescriptors;
235 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
236
237 DEBUG ((DEBUG_PAGE, "SyncCacheConfig()\n"));
238
239 // This code assumes MMU is enabled and filed with section translations
240 ASSERT (ArmMmuEnabled ());
241
242 //
243 // Get the memory space map from GCD
244 //
245 MemorySpaceMap = NULL;
246 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
247 ASSERT_EFI_ERROR (Status);
248
249 // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs
250 // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a
251 // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were
252 // a client) to update its copy of the attributes. This is bad architecture and should be replaced
253 // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
254
255 // obtain page table base
256 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());
257
258 // Get the first region
259 NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
260
261 // iterate through each 1MB descriptor
262 NextRegionBase = NextRegionLength = 0;
263 for (i = 0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {
264 if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
265 // extract attributes (cacheability and permissions)
266 SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
267
268 if (NextSectionAttributes == 0) {
269 // start on a new region
270 NextRegionLength = 0;
271 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
272 NextSectionAttributes = SectionAttributes;
273 } else if (SectionAttributes != NextSectionAttributes) {
274 // Convert Section Attributes into GCD Attributes
275 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
276 ASSERT_EFI_ERROR (Status);
277
278 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
279 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
280
281 // start on a new region
282 NextRegionLength = 0;
283 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
284 NextSectionAttributes = SectionAttributes;
285 }
286
287 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
288 } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (FirstLevelTable[i])) {
289 // In this case any bits set in the 'NextSectionAttributes' are garbage and were set from
290 // bits that are actually part of the pagetable address. We clear it out to zero so that
291 // the SyncCacheConfigPage will use the page attributes instead of trying to convert the
292 // section attributes into page attributes
293 NextSectionAttributes = 0;
294 Status = SyncCacheConfigPage (
295 i,
296 FirstLevelTable[i],
297 NumberOfDescriptors,
298 MemorySpaceMap,
299 &NextRegionBase,
300 &NextRegionLength,
301 &NextSectionAttributes
302 );
303 ASSERT_EFI_ERROR (Status);
304 } else {
305 // We do not support yet 16MB sections
306 ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);
307
308 // start on a new region
309 if (NextSectionAttributes != 0) {
310 // Convert Section Attributes into GCD Attributes
311 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
312 ASSERT_EFI_ERROR (Status);
313
314 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
315 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
316
317 NextRegionLength = 0;
318 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
319 NextSectionAttributes = 0;
320 }
321
322 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
323 }
324 } // section entry loop
325
326 if (NextSectionAttributes != 0) {
327 // Convert Section Attributes into GCD Attributes
328 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
329 ASSERT_EFI_ERROR (Status);
330
331 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
332 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
333 }
334
335 FreePool (MemorySpaceMap);
336
337 return EFI_SUCCESS;
338 }
339
340 UINT64
341 EfiAttributeToArmAttribute (
342 IN UINT64 EfiAttributes
343 )
344 {
345 UINT64 ArmAttributes;
346
347 switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
348 case EFI_MEMORY_UC:
349 // Map to strongly ordered
350 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0
351 break;
352
353 case EFI_MEMORY_WC:
354 // Map to normal non-cacheable
355 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0
356 break;
357
358 case EFI_MEMORY_WT:
359 // Write through with no-allocate
360 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0
361 break;
362
363 case EFI_MEMORY_WB:
364 // Write back (with allocate)
365 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1
366 break;
367
368 case EFI_MEMORY_UCE:
369 default:
370 ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;
371 break;
372 }
373
374 // Determine protection attributes
375 if ((EfiAttributes & EFI_MEMORY_RO) != 0) {
376 ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
377 } else {
378 ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
379 }
380
381 // Determine eXecute Never attribute
382 if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
383 ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;
384 }
385
386 return ArmAttributes;
387 }
388
389 EFI_STATUS
390 GetMemoryRegionPage (
391 IN UINT32 *PageTable,
392 IN OUT UINTN *BaseAddress,
393 OUT UINTN *RegionLength,
394 OUT UINTN *RegionAttributes
395 )
396 {
397 UINT32 PageAttributes;
398 UINT32 TableIndex;
399 UINT32 PageDescriptor;
400
401 // Convert the section attributes into page attributes
402 PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);
403
404 // Calculate index into first level translation table for start of modification
405 TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
406 ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);
407
408 // Go through the page table to find the end of the section
409 for ( ; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {
410 // Get the section at the given index
411 PageDescriptor = PageTable[TableIndex];
412
413 if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {
414 // Case: End of the boundary of the region
415 return EFI_SUCCESS;
416 } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {
417 if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {
418 *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;
419 } else {
420 // Case: End of the boundary of the region
421 return EFI_SUCCESS;
422 }
423 } else {
424 // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.
425 ASSERT (0);
426 return EFI_SUCCESS;
427 }
428 }
429
430 return EFI_NOT_FOUND;
431 }
432
433 EFI_STATUS
434 GetMemoryRegion (
435 IN OUT UINTN *BaseAddress,
436 OUT UINTN *RegionLength,
437 OUT UINTN *RegionAttributes
438 )
439 {
440 EFI_STATUS Status;
441 UINT32 TableIndex;
442 UINT32 PageAttributes;
443 UINT32 PageTableIndex;
444 UINT32 SectionDescriptor;
445 ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
446 UINT32 *PageTable;
447
448 // Initialize the arguments
449 *RegionLength = 0;
450
451 // Obtain page table base
452 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
453
454 // Calculate index into first level translation table for start of modification
455 TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
456 ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);
457
458 // Get the section at the given index
459 SectionDescriptor = FirstLevelTable[TableIndex];
460 if (!SectionDescriptor) {
461 return EFI_NOT_FOUND;
462 }
463
464 // If 'BaseAddress' belongs to the section then round it to the section boundary
465 if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||
466 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))
467 {
468 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;
469 *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;
470 } else {
471 // Otherwise, we round it to the page boundary
472 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;
473
474 // Get the attribute at the page table level (Level 2)
475 PageTable = (UINT32 *)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
476
477 // Calculate index into first level translation table for start of modification
478 PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
479 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);
480
481 PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;
482 *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |
483 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);
484 }
485
486 for ( ; TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {
487 // Get the section at the given index
488 SectionDescriptor = FirstLevelTable[TableIndex];
489
490 // If the entry is a level-2 page table then we scan it to find the end of the region
491 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {
492 // Extract the page table location from the descriptor
493 PageTable = (UINT32 *)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
494
495 // Scan the page table to find the end of the region.
496 Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);
497
498 // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop
499 if (Status == EFI_SUCCESS) {
500 break;
501 }
502 } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||
503 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))
504 {
505 if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {
506 // If the attributes of the section differ from the one targeted then we exit the loop
507 break;
508 } else {
509 *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;
510 }
511 } else {
512 // If we are on an invalid section then it means it is the end of our section.
513 break;
514 }
515 }
516
517 return EFI_SUCCESS;
518 }