]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
12ca5b26673e834932e5a522d5e8b1e48943df39
[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, ARM Ltd. All rights reserved.<BR>
6 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
7
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16
17 --*/
18
19 #include <Library/MemoryAllocationLib.h>
20 #include "CpuDxe.h"
21
22 EFI_STATUS
23 SectionToGcdAttributes (
24 IN UINT32 SectionAttributes,
25 OUT UINT64 *GcdAttributes
26 )
27 {
28 *GcdAttributes = 0;
29
30 // determine cacheability attributes
31 switch(SectionAttributes & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) {
32 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED:
33 *GcdAttributes |= EFI_MEMORY_UC;
34 break;
35 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE:
36 *GcdAttributes |= EFI_MEMORY_UC;
37 break;
38 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
39 *GcdAttributes |= EFI_MEMORY_WT;
40 break;
41 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
42 *GcdAttributes |= EFI_MEMORY_WB;
43 break;
44 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE:
45 *GcdAttributes |= EFI_MEMORY_WC;
46 break;
47 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC:
48 *GcdAttributes |= EFI_MEMORY_WB;
49 break;
50 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE:
51 *GcdAttributes |= EFI_MEMORY_UC;
52 break;
53 default:
54 return EFI_UNSUPPORTED;
55 }
56
57 // determine protection attributes
58 switch(SectionAttributes & TT_DESCRIPTOR_SECTION_AP_MASK) {
59 case TT_DESCRIPTOR_SECTION_AP_NO_NO: // no read, no write
60 //*GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;
61 break;
62
63 case TT_DESCRIPTOR_SECTION_AP_RW_NO:
64 case TT_DESCRIPTOR_SECTION_AP_RW_RW:
65 // normal read/write access, do not add additional attributes
66 break;
67
68 // read only cases map to write-protect
69 case TT_DESCRIPTOR_SECTION_AP_RO_NO:
70 case TT_DESCRIPTOR_SECTION_AP_RO_RO:
71 *GcdAttributes |= EFI_MEMORY_RO;
72 break;
73
74 default:
75 return EFI_UNSUPPORTED;
76 }
77
78 // now process eXectue Never attribute
79 if ((SectionAttributes & TT_DESCRIPTOR_SECTION_XN_MASK) != 0 ) {
80 *GcdAttributes |= EFI_MEMORY_XP;
81 }
82
83 return EFI_SUCCESS;
84 }
85
86 EFI_STATUS
87 PageToGcdAttributes (
88 IN UINT32 PageAttributes,
89 OUT UINT64 *GcdAttributes
90 )
91 {
92 *GcdAttributes = 0;
93
94 // determine cacheability attributes
95 switch(PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {
96 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:
97 *GcdAttributes |= EFI_MEMORY_UC;
98 break;
99 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:
100 *GcdAttributes |= EFI_MEMORY_UC;
101 break;
102 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
103 *GcdAttributes |= EFI_MEMORY_WT;
104 break;
105 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
106 *GcdAttributes |= EFI_MEMORY_WB;
107 break;
108 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:
109 *GcdAttributes |= EFI_MEMORY_WC;
110 break;
111 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:
112 *GcdAttributes |= EFI_MEMORY_WB;
113 break;
114 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:
115 *GcdAttributes |= EFI_MEMORY_UC;
116 break;
117 default:
118 return EFI_UNSUPPORTED;
119 }
120
121 // determine protection attributes
122 switch(PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {
123 case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write
124 //*GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;
125 break;
126
127 case TT_DESCRIPTOR_PAGE_AP_RW_NO:
128 case TT_DESCRIPTOR_PAGE_AP_RW_RW:
129 // normal read/write access, do not add additional attributes
130 break;
131
132 // read only cases map to write-protect
133 case TT_DESCRIPTOR_PAGE_AP_RO_NO:
134 case TT_DESCRIPTOR_PAGE_AP_RO_RO:
135 *GcdAttributes |= EFI_MEMORY_RO;
136 break;
137
138 default:
139 return EFI_UNSUPPORTED;
140 }
141
142 // now process eXectue Never attribute
143 if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {
144 *GcdAttributes |= EFI_MEMORY_XP;
145 }
146
147 return EFI_SUCCESS;
148 }
149
150 EFI_STATUS
151 SyncCacheConfigPage (
152 IN UINT32 SectionIndex,
153 IN UINT32 FirstLevelDescriptor,
154 IN UINTN NumberOfDescriptors,
155 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
156 IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,
157 IN OUT UINT64 *NextRegionLength,
158 IN OUT UINT32 *NextSectionAttributes
159 )
160 {
161 EFI_STATUS Status;
162 UINT32 i;
163 volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;
164 UINT32 NextPageAttributes = 0;
165 UINT32 PageAttributes = 0;
166 UINT32 BaseAddress;
167 UINT64 GcdAttributes;
168
169 // Get the Base Address from FirstLevelDescriptor;
170 BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
171
172 // Convert SectionAttributes into PageAttributes
173 NextPageAttributes =
174 TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |
175 TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);
176
177 // obtain page table base
178 SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
179
180 for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {
181 if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {
182 // extract attributes (cacheability and permissions)
183 PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);
184
185 if (NextPageAttributes == 0) {
186 // start on a new region
187 *NextRegionLength = 0;
188 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
189 NextPageAttributes = PageAttributes;
190 } else if (PageAttributes != NextPageAttributes) {
191 // Convert Section Attributes into GCD Attributes
192 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
193 ASSERT_EFI_ERROR (Status);
194
195 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
196 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
197
198 // start on a new region
199 *NextRegionLength = 0;
200 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
201 NextPageAttributes = PageAttributes;
202 }
203 } else if (NextPageAttributes != 0) {
204 // Convert Page Attributes into GCD Attributes
205 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
206 ASSERT_EFI_ERROR (Status);
207
208 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
209 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
210
211 *NextRegionLength = 0;
212 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
213 NextPageAttributes = 0;
214 }
215 *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;
216 }
217
218 // Convert back PageAttributes into SectionAttributes
219 *NextSectionAttributes =
220 TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |
221 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);
222
223 return EFI_SUCCESS;
224 }
225
226 EFI_STATUS
227 SyncCacheConfig (
228 IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
229 )
230 {
231 EFI_STATUS Status;
232 UINT32 i;
233 EFI_PHYSICAL_ADDRESS NextRegionBase;
234 UINT64 NextRegionLength;
235 UINT32 NextSectionAttributes = 0;
236 UINT32 SectionAttributes = 0;
237 UINT64 GcdAttributes;
238 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
239 UINTN NumberOfDescriptors;
240 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
241
242
243 DEBUG ((EFI_D_PAGE, "SyncCacheConfig()\n"));
244
245 // This code assumes MMU is enabled and filed with section translations
246 ASSERT (ArmMmuEnabled ());
247
248 //
249 // Get the memory space map from GCD
250 //
251 MemorySpaceMap = NULL;
252 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
253 ASSERT_EFI_ERROR (Status);
254
255
256 // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs
257 // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a
258 // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were
259 // a client) to update its copy of the attributes. This is bad architecture and should be replaced
260 // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
261
262 // obtain page table base
263 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());
264
265 // Get the first region
266 NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
267
268 // iterate through each 1MB descriptor
269 NextRegionBase = NextRegionLength = 0;
270 for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {
271 if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
272 // extract attributes (cacheability and permissions)
273 SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
274
275 if (NextSectionAttributes == 0) {
276 // start on a new region
277 NextRegionLength = 0;
278 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
279 NextSectionAttributes = SectionAttributes;
280 } else if (SectionAttributes != NextSectionAttributes) {
281 // Convert Section Attributes into GCD Attributes
282 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
283 ASSERT_EFI_ERROR (Status);
284
285 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
286 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
287
288 // start on a new region
289 NextRegionLength = 0;
290 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
291 NextSectionAttributes = SectionAttributes;
292 }
293 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
294 } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {
295 // In this case any bits set in the 'NextSectionAttributes' are garbage and were set from
296 // bits that are actually part of the pagetable address. We clear it out to zero so that
297 // the SyncCacheConfigPage will use the page attributes instead of trying to convert the
298 // section attributes into page attributes
299 NextSectionAttributes = 0;
300 Status = SyncCacheConfigPage (
301 i,FirstLevelTable[i],
302 NumberOfDescriptors, MemorySpaceMap,
303 &NextRegionBase,&NextRegionLength,&NextSectionAttributes);
304 ASSERT_EFI_ERROR (Status);
305 } else {
306 // We do not support yet 16MB sections
307 ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);
308
309 // start on a new region
310 if (NextSectionAttributes != 0) {
311 // Convert Section Attributes into GCD Attributes
312 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
313 ASSERT_EFI_ERROR (Status);
314
315 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
316 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
317
318 NextRegionLength = 0;
319 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
320 NextSectionAttributes = 0;
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-cachable
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) {
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) {
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
461 // If 'BaseAddress' belongs to the section then round it to the section boundary
462 if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||
463 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))
464 {
465 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;
466 *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;
467 } else {
468 // Otherwise, we round it to the page boundary
469 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;
470
471 // Get the attribute at the page table level (Level 2)
472 PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
473
474 // Calculate index into first level translation table for start of modification
475 PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
476 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);
477
478 PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;
479 *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |
480 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);
481 }
482
483 for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {
484 // Get the section at the given index
485 SectionDescriptor = FirstLevelTable[TableIndex];
486
487 // If the entry is a level-2 page table then we scan it to find the end of the region
488 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {
489 // Extract the page table location from the descriptor
490 PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
491
492 // Scan the page table to find the end of the region.
493 Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);
494
495 // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop
496 if (Status == EFI_SUCCESS) {
497 break;
498 }
499 } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||
500 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {
501 if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {
502 // If the attributes of the section differ from the one targeted then we exit the loop
503 break;
504 } else {
505 *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;
506 }
507 } else {
508 // If we are on an invalid section then it means it is the end of our section.
509 break;
510 }
511 }
512
513 return EFI_SUCCESS;
514 }