]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
ArmPkg/CpuDxe ARM: honour RO/XP attributes in SetMemoryAttributes()
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / Arm / Mmu.c
... / ...
CommitLineData
1/*++\r
2\r
3Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
4Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>\r
5Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
6Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
7\r
8This program and the accompanying materials\r
9are licensed and made available under the terms and conditions of the BSD License\r
10which accompanies this distribution. The full text of the license may be found at\r
11http://opensource.org/licenses/bsd-license.php\r
12\r
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16\r
17--*/\r
18\r
19#include <Library/MemoryAllocationLib.h>\r
20#include "CpuDxe.h"\r
21\r
22#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | \\r
23 EFI_MEMORY_WC | \\r
24 EFI_MEMORY_WT | \\r
25 EFI_MEMORY_WB | \\r
26 EFI_MEMORY_UCE | \\r
27 EFI_MEMORY_WP)\r
28\r
29// First Level Descriptors\r
30typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;\r
31\r
32// Second Level Descriptors\r
33typedef UINT32 ARM_PAGE_TABLE_ENTRY;\r
34\r
35EFI_STATUS\r
36SectionToGcdAttributes (\r
37 IN UINT32 SectionAttributes,\r
38 OUT UINT64 *GcdAttributes\r
39 )\r
40{\r
41 *GcdAttributes = 0;\r
42\r
43 // determine cacheability attributes\r
44 switch(SectionAttributes & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) {\r
45 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED:\r
46 *GcdAttributes |= EFI_MEMORY_UC;\r
47 break;\r
48 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE:\r
49 *GcdAttributes |= EFI_MEMORY_UC;\r
50 break;\r
51 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:\r
52 *GcdAttributes |= EFI_MEMORY_WT;\r
53 break;\r
54 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_NO_ALLOC:\r
55 *GcdAttributes |= EFI_MEMORY_WB;\r
56 break;\r
57 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE:\r
58 *GcdAttributes |= EFI_MEMORY_WC;\r
59 break;\r
60 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC:\r
61 *GcdAttributes |= EFI_MEMORY_WB;\r
62 break;\r
63 case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE:\r
64 *GcdAttributes |= EFI_MEMORY_UC;\r
65 break;\r
66 default:\r
67 return EFI_UNSUPPORTED;\r
68 }\r
69\r
70 // determine protection attributes\r
71 switch(SectionAttributes & TT_DESCRIPTOR_SECTION_AP_MASK) {\r
72 case TT_DESCRIPTOR_SECTION_AP_NO_NO: // no read, no write\r
73 //*GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;\r
74 break;\r
75\r
76 case TT_DESCRIPTOR_SECTION_AP_RW_NO:\r
77 case TT_DESCRIPTOR_SECTION_AP_RW_RW:\r
78 // normal read/write access, do not add additional attributes\r
79 break;\r
80\r
81 // read only cases map to write-protect\r
82 case TT_DESCRIPTOR_SECTION_AP_RO_NO:\r
83 case TT_DESCRIPTOR_SECTION_AP_RO_RO:\r
84 *GcdAttributes |= EFI_MEMORY_RO;\r
85 break;\r
86\r
87 default:\r
88 return EFI_UNSUPPORTED;\r
89 }\r
90\r
91 // now process eXectue Never attribute\r
92 if ((SectionAttributes & TT_DESCRIPTOR_SECTION_XN_MASK) != 0 ) {\r
93 *GcdAttributes |= EFI_MEMORY_XP;\r
94 }\r
95\r
96 return EFI_SUCCESS;\r
97}\r
98\r
99EFI_STATUS\r
100PageToGcdAttributes (\r
101 IN UINT32 PageAttributes,\r
102 OUT UINT64 *GcdAttributes\r
103 )\r
104{\r
105 *GcdAttributes = 0;\r
106\r
107 // determine cacheability attributes\r
108 switch(PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {\r
109 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:\r
110 *GcdAttributes |= EFI_MEMORY_UC;\r
111 break;\r
112 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:\r
113 *GcdAttributes |= EFI_MEMORY_UC;\r
114 break;\r
115 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:\r
116 *GcdAttributes |= EFI_MEMORY_WT;\r
117 break;\r
118 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:\r
119 *GcdAttributes |= EFI_MEMORY_WB;\r
120 break;\r
121 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:\r
122 *GcdAttributes |= EFI_MEMORY_WC;\r
123 break;\r
124 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:\r
125 *GcdAttributes |= EFI_MEMORY_WB;\r
126 break;\r
127 case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:\r
128 *GcdAttributes |= EFI_MEMORY_UC;\r
129 break;\r
130 default:\r
131 return EFI_UNSUPPORTED;\r
132 }\r
133\r
134 // determine protection attributes\r
135 switch(PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {\r
136 case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write\r
137 //*GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;\r
138 break;\r
139\r
140 case TT_DESCRIPTOR_PAGE_AP_RW_NO:\r
141 case TT_DESCRIPTOR_PAGE_AP_RW_RW:\r
142 // normal read/write access, do not add additional attributes\r
143 break;\r
144\r
145 // read only cases map to write-protect\r
146 case TT_DESCRIPTOR_PAGE_AP_RO_NO:\r
147 case TT_DESCRIPTOR_PAGE_AP_RO_RO:\r
148 *GcdAttributes |= EFI_MEMORY_RO;\r
149 break;\r
150\r
151 default:\r
152 return EFI_UNSUPPORTED;\r
153 }\r
154\r
155 // now process eXectue Never attribute\r
156 if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {\r
157 *GcdAttributes |= EFI_MEMORY_XP;\r
158 }\r
159\r
160 return EFI_SUCCESS;\r
161}\r
162\r
163EFI_STATUS\r
164SyncCacheConfigPage (\r
165 IN UINT32 SectionIndex,\r
166 IN UINT32 FirstLevelDescriptor,\r
167 IN UINTN NumberOfDescriptors,\r
168 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
169 IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,\r
170 IN OUT UINT64 *NextRegionLength,\r
171 IN OUT UINT32 *NextSectionAttributes\r
172 )\r
173{\r
174 EFI_STATUS Status;\r
175 UINT32 i;\r
176 volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;\r
177 UINT32 NextPageAttributes = 0;\r
178 UINT32 PageAttributes = 0;\r
179 UINT32 BaseAddress;\r
180 UINT64 GcdAttributes;\r
181\r
182 // Get the Base Address from FirstLevelDescriptor;\r
183 BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
184\r
185 // Convert SectionAttributes into PageAttributes\r
186 NextPageAttributes =\r
187 TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |\r
188 TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);\r
189\r
190 // obtain page table base\r
191 SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
192\r
193 for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {\r
194 if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
195 // extract attributes (cacheability and permissions)\r
196 PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);\r
197\r
198 if (NextPageAttributes == 0) {\r
199 // start on a new region\r
200 *NextRegionLength = 0;\r
201 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
202 NextPageAttributes = PageAttributes;\r
203 } else if (PageAttributes != NextPageAttributes) {\r
204 // Convert Section Attributes into GCD Attributes\r
205 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
206 ASSERT_EFI_ERROR (Status);\r
207\r
208 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
209 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
210\r
211 // start on a new region\r
212 *NextRegionLength = 0;\r
213 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
214 NextPageAttributes = PageAttributes;\r
215 }\r
216 } else if (NextPageAttributes != 0) {\r
217 // Convert Page Attributes into GCD Attributes\r
218 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
219 ASSERT_EFI_ERROR (Status);\r
220\r
221 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
222 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
223\r
224 *NextRegionLength = 0;\r
225 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
226 NextPageAttributes = 0;\r
227 }\r
228 *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;\r
229 }\r
230\r
231 // Convert back PageAttributes into SectionAttributes\r
232 *NextSectionAttributes =\r
233 TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |\r
234 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);\r
235\r
236 return EFI_SUCCESS;\r
237}\r
238\r
239EFI_STATUS\r
240SyncCacheConfig (\r
241 IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol\r
242 )\r
243{\r
244 EFI_STATUS Status;\r
245 UINT32 i;\r
246 EFI_PHYSICAL_ADDRESS NextRegionBase;\r
247 UINT64 NextRegionLength;\r
248 UINT32 NextSectionAttributes = 0;\r
249 UINT32 SectionAttributes = 0;\r
250 UINT64 GcdAttributes;\r
251 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
252 UINTN NumberOfDescriptors;\r
253 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
254\r
255\r
256 DEBUG ((EFI_D_PAGE, "SyncCacheConfig()\n"));\r
257\r
258 // This code assumes MMU is enabled and filed with section translations\r
259 ASSERT (ArmMmuEnabled ());\r
260\r
261 //\r
262 // Get the memory space map from GCD\r
263 //\r
264 MemorySpaceMap = NULL;\r
265 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
266 ASSERT_EFI_ERROR (Status);\r
267\r
268\r
269 // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs\r
270 // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a\r
271 // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were\r
272 // a client) to update its copy of the attributes. This is bad architecture and should be replaced\r
273 // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.\r
274\r
275 // obtain page table base\r
276 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());\r
277\r
278 // Get the first region\r
279 NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
280\r
281 // iterate through each 1MB descriptor\r
282 NextRegionBase = NextRegionLength = 0;\r
283 for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {\r
284 if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {\r
285 // extract attributes (cacheability and permissions)\r
286 SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
287\r
288 if (NextSectionAttributes == 0) {\r
289 // start on a new region\r
290 NextRegionLength = 0;\r
291 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
292 NextSectionAttributes = SectionAttributes;\r
293 } else if (SectionAttributes != NextSectionAttributes) {\r
294 // Convert Section Attributes into GCD Attributes\r
295 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
296 ASSERT_EFI_ERROR (Status);\r
297\r
298 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
299 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
300\r
301 // start on a new region\r
302 NextRegionLength = 0;\r
303 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
304 NextSectionAttributes = SectionAttributes;\r
305 }\r
306 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
307 } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {\r
308 // In this case any bits set in the 'NextSectionAttributes' are garbage and were set from\r
309 // bits that are actually part of the pagetable address. We clear it out to zero so that\r
310 // the SyncCacheConfigPage will use the page attributes instead of trying to convert the\r
311 // section attributes into page attributes\r
312 NextSectionAttributes = 0;\r
313 Status = SyncCacheConfigPage (\r
314 i,FirstLevelTable[i],\r
315 NumberOfDescriptors, MemorySpaceMap,\r
316 &NextRegionBase,&NextRegionLength,&NextSectionAttributes);\r
317 ASSERT_EFI_ERROR (Status);\r
318 } else {\r
319 // We do not support yet 16MB sections\r
320 ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);\r
321\r
322 // start on a new region\r
323 if (NextSectionAttributes != 0) {\r
324 // Convert Section Attributes into GCD Attributes\r
325 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
326 ASSERT_EFI_ERROR (Status);\r
327\r
328 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
329 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
330\r
331 NextRegionLength = 0;\r
332 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
333 NextSectionAttributes = 0;\r
334 }\r
335 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
336 }\r
337 } // section entry loop\r
338\r
339 if (NextSectionAttributes != 0) {\r
340 // Convert Section Attributes into GCD Attributes\r
341 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
342 ASSERT_EFI_ERROR (Status);\r
343\r
344 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
345 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
346 }\r
347\r
348 FreePool (MemorySpaceMap);\r
349\r
350 return EFI_SUCCESS;\r
351}\r
352\r
353\r
354\r
355EFI_STATUS\r
356UpdatePageEntries (\r
357 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
358 IN UINT64 Length,\r
359 IN UINT64 Attributes,\r
360 IN EFI_PHYSICAL_ADDRESS VirtualMask,\r
361 OUT BOOLEAN *FlushTlbs OPTIONAL\r
362 )\r
363{\r
364 EFI_STATUS Status;\r
365 UINT32 EntryValue;\r
366 UINT32 EntryMask;\r
367 UINT32 FirstLevelIdx;\r
368 UINT32 Offset;\r
369 UINT32 NumPageEntries;\r
370 UINT32 Descriptor;\r
371 UINT32 p;\r
372 UINT32 PageTableIndex;\r
373 UINT32 PageTableEntry;\r
374 UINT32 CurrentPageTableEntry;\r
375 VOID *Mva;\r
376\r
377 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
378 volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
379\r
380 Status = EFI_SUCCESS;\r
381\r
382 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
383 // EntryValue: values at bit positions specified by EntryMask\r
384 EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK | TT_DESCRIPTOR_PAGE_AP_MASK;\r
385 if ((Attributes & EFI_MEMORY_XP) != 0) {\r
386 EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE_XN;\r
387 } else {\r
388 EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
389 }\r
390\r
391 // Although the PI spec is unclear on this, the GCD guarantees that only\r
392 // one Attribute bit is set at a time, so the order of the conditionals below\r
393 // is irrelevant. If no memory attribute is specified, we preserve whatever\r
394 // memory type is set in the page tables, and update the permission attributes\r
395 // only.\r
396 if (Attributes & EFI_MEMORY_UC) {\r
397 // modify cacheability attributes\r
398 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
399 // map to strongly ordered\r
400 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
401 } else if (Attributes & EFI_MEMORY_WC) {\r
402 // modify cacheability attributes\r
403 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
404 // map to normal non-cachable\r
405 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
406 } else if (Attributes & EFI_MEMORY_WT) {\r
407 // modify cacheability attributes\r
408 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
409 // write through with no-allocate\r
410 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
411 } else if (Attributes & EFI_MEMORY_WB) {\r
412 // modify cacheability attributes\r
413 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
414 // write back (with allocate)\r
415 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
416 } else if (Attributes & CACHE_ATTRIBUTE_MASK) {\r
417 // catch unsupported memory type attributes\r
418 ASSERT (FALSE);\r
419 return EFI_UNSUPPORTED;\r
420 }\r
421\r
422 if ((Attributes & EFI_MEMORY_RO) != 0) {\r
423 EntryValue |= TT_DESCRIPTOR_PAGE_AP_RO_RO;\r
424 } else {\r
425 EntryValue |= TT_DESCRIPTOR_PAGE_AP_RW_RW;\r
426 }\r
427\r
428 // Obtain page table base\r
429 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
430\r
431 // Calculate number of 4KB page table entries to change\r
432 NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
433\r
434 // Iterate for the number of 4KB pages to change\r
435 Offset = 0;\r
436 for(p = 0; p < NumPageEntries; p++) {\r
437 // Calculate index into first level translation table for page table value\r
438\r
439 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
440 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
441\r
442 // Read the descriptor from the first level page table\r
443 Descriptor = FirstLevelTable[FirstLevelIdx];\r
444\r
445 // Does this descriptor need to be converted from section entry to 4K pages?\r
446 if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {\r
447 Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
448 if (EFI_ERROR(Status)) {\r
449 // Exit for loop\r
450 break;\r
451 }\r
452\r
453 // Re-read descriptor\r
454 Descriptor = FirstLevelTable[FirstLevelIdx];\r
455 if (FlushTlbs != NULL) {\r
456 *FlushTlbs = TRUE;\r
457 }\r
458 }\r
459\r
460 // Obtain page table base address\r
461 PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);\r
462\r
463 // Calculate index into the page table\r
464 PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
465 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
466\r
467 // Get the entry\r
468 CurrentPageTableEntry = PageTable[PageTableIndex];\r
469\r
470 // Mask off appropriate fields\r
471 PageTableEntry = CurrentPageTableEntry & ~EntryMask;\r
472\r
473 // Mask in new attributes and/or permissions\r
474 PageTableEntry |= EntryValue;\r
475\r
476 if (VirtualMask != 0) {\r
477 // Make this virtual address point at a physical page\r
478 PageTableEntry &= ~VirtualMask;\r
479 }\r
480\r
481 if (CurrentPageTableEntry != PageTableEntry) {\r
482 Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
483\r
484 // Only need to update if we are changing the entry\r
485 PageTable[PageTableIndex] = PageTableEntry;\r
486 ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
487\r
488 // Clean/invalidate the cache for this page, but only\r
489 // if we are modifying the memory type attributes\r
490 if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) {\r
491 WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
492 }\r
493 }\r
494\r
495 Status = EFI_SUCCESS;\r
496 Offset += TT_DESCRIPTOR_PAGE_SIZE;\r
497\r
498 } // End first level translation table loop\r
499\r
500 return Status;\r
501}\r
502\r
503\r
504\r
505EFI_STATUS\r
506UpdateSectionEntries (\r
507 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
508 IN UINT64 Length,\r
509 IN UINT64 Attributes,\r
510 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
511 )\r
512{\r
513 EFI_STATUS Status = EFI_SUCCESS;\r
514 UINT32 EntryMask;\r
515 UINT32 EntryValue;\r
516 UINT32 FirstLevelIdx;\r
517 UINT32 NumSections;\r
518 UINT32 i;\r
519 UINT32 CurrentDescriptor;\r
520 UINT32 Descriptor;\r
521 VOID *Mva;\r
522 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
523\r
524 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
525 // EntryValue: values at bit positions specified by EntryMask\r
526\r
527 // Make sure we handle a section range that is unmapped\r
528 EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK | TT_DESCRIPTOR_SECTION_XN_MASK |\r
529 TT_DESCRIPTOR_SECTION_AP_MASK;\r
530 EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
531\r
532 // Although the PI spec is unclear on this, the GCD guarantees that only\r
533 // one Attribute bit is set at a time, so the order of the conditionals below\r
534 // is irrelevant. If no memory attribute is specified, we preserve whatever\r
535 // memory type is set in the page tables, and update the permission attributes\r
536 // only.\r
537 if (Attributes & EFI_MEMORY_UC) {\r
538 // modify cacheability attributes\r
539 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
540 // map to strongly ordered\r
541 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
542 } else if (Attributes & EFI_MEMORY_WC) {\r
543 // modify cacheability attributes\r
544 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
545 // map to normal non-cachable\r
546 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
547 } else if (Attributes & EFI_MEMORY_WT) {\r
548 // modify cacheability attributes\r
549 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
550 // write through with no-allocate\r
551 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
552 } else if (Attributes & EFI_MEMORY_WB) {\r
553 // modify cacheability attributes\r
554 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
555 // write back (with allocate)\r
556 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
557 } else if (Attributes & CACHE_ATTRIBUTE_MASK) {\r
558 // catch unsupported memory type attributes\r
559 ASSERT (FALSE);\r
560 return EFI_UNSUPPORTED;\r
561 }\r
562\r
563 if (Attributes & EFI_MEMORY_RO) {\r
564 EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
565 } else {\r
566 EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
567 }\r
568\r
569 if (Attributes & EFI_MEMORY_XP) {\r
570 EntryValue |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
571 }\r
572\r
573 // obtain page table base\r
574 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
575\r
576 // calculate index into first level translation table for start of modification\r
577 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
578 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
579\r
580 // calculate number of 1MB first level entries this applies to\r
581 NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
582\r
583 // iterate through each descriptor\r
584 for(i=0; i<NumSections; i++) {\r
585 CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
586\r
587 // has this descriptor already been coverted to pages?\r
588 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
589 // forward this 1MB range to page table function instead\r
590 Status = UpdatePageEntries (\r
591 (FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT,\r
592 TT_DESCRIPTOR_SECTION_SIZE,\r
593 Attributes,\r
594 VirtualMask,\r
595 NULL);\r
596 } else {\r
597 // still a section entry\r
598\r
599 // mask off appropriate fields\r
600 Descriptor = CurrentDescriptor & ~EntryMask;\r
601\r
602 // mask in new attributes and/or permissions\r
603 Descriptor |= EntryValue;\r
604 if (VirtualMask != 0) {\r
605 Descriptor &= ~VirtualMask;\r
606 }\r
607\r
608 if (CurrentDescriptor != Descriptor) {\r
609 Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
610\r
611 // Only need to update if we are changing the descriptor\r
612 FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
613 ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
614\r
615 // Clean/invalidate the cache for this section, but only\r
616 // if we are modifying the memory type attributes\r
617 if (((CurrentDescriptor ^ Descriptor) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) != 0) {\r
618 WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
619 }\r
620 }\r
621\r
622 Status = EFI_SUCCESS;\r
623 }\r
624 }\r
625\r
626 return Status;\r
627}\r
628\r
629EFI_STATUS\r
630ConvertSectionToPages (\r
631 IN EFI_PHYSICAL_ADDRESS BaseAddress\r
632 )\r
633{\r
634 EFI_STATUS Status;\r
635 EFI_PHYSICAL_ADDRESS PageTableAddr;\r
636 UINT32 FirstLevelIdx;\r
637 UINT32 SectionDescriptor;\r
638 UINT32 PageTableDescriptor;\r
639 UINT32 PageDescriptor;\r
640 UINT32 Index;\r
641\r
642 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
643 volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
644\r
645 DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));\r
646\r
647 // Obtain page table base\r
648 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
649\r
650 // Calculate index into first level translation table for start of modification\r
651 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
652 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
653\r
654 // Get section attributes and convert to page attributes\r
655 SectionDescriptor = FirstLevelTable[FirstLevelIdx];\r
656 PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);\r
657\r
658 // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)\r
659 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr);\r
660 if (EFI_ERROR(Status)) {\r
661 return Status;\r
662 }\r
663\r
664 PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;\r
665\r
666 // Write the page table entries out\r
667 for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
668 PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;\r
669 }\r
670\r
671 // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
672 WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE);\r
673\r
674 // Formulate page table entry, Domain=0, NS=0\r
675 PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
676\r
677 // Write the page table entry out, replacing section entry\r
678 FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;\r
679\r
680 return EFI_SUCCESS;\r
681}\r
682\r
683\r
684\r
685EFI_STATUS\r
686SetMemoryAttributes (\r
687 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
688 IN UINT64 Length,\r
689 IN UINT64 Attributes,\r
690 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
691 )\r
692{\r
693 EFI_STATUS Status;\r
694 UINT64 ChunkLength;\r
695 BOOLEAN FlushTlbs;\r
696\r
697 if (Length == 0) {\r
698 return EFI_SUCCESS;\r
699 }\r
700\r
701 FlushTlbs = FALSE;\r
702 while (Length > 0) {\r
703 if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&\r
704 Length >= TT_DESCRIPTOR_SECTION_SIZE) {\r
705\r
706 ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;\r
707\r
708 DEBUG ((DEBUG_PAGE,\r
709 "SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n",\r
710 BaseAddress, ChunkLength, Attributes));\r
711\r
712 Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,\r
713 VirtualMask);\r
714\r
715 FlushTlbs = TRUE;\r
716 } else {\r
717\r
718 //\r
719 // Process page by page until the next section boundary, but only if\r
720 // we have more than a section's worth of area to deal with after that.\r
721 //\r
722 ChunkLength = TT_DESCRIPTOR_SECTION_SIZE -\r
723 (BaseAddress % TT_DESCRIPTOR_SECTION_SIZE);\r
724 if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) {\r
725 ChunkLength = Length;\r
726 }\r
727\r
728 DEBUG ((DEBUG_PAGE,\r
729 "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",\r
730 BaseAddress, ChunkLength, Attributes));\r
731\r
732 Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,\r
733 VirtualMask, &FlushTlbs);\r
734 }\r
735\r
736 if (EFI_ERROR (Status)) {\r
737 break;\r
738 }\r
739\r
740 BaseAddress += ChunkLength;\r
741 Length -= ChunkLength;\r
742 }\r
743\r
744 if (FlushTlbs) {\r
745 ArmInvalidateTlb ();\r
746 }\r
747 return Status;\r
748}\r
749\r
750UINT64\r
751EfiAttributeToArmAttribute (\r
752 IN UINT64 EfiAttributes\r
753 )\r
754{\r
755 UINT64 ArmAttributes;\r
756\r
757 switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {\r
758 case EFI_MEMORY_UC:\r
759 // Map to strongly ordered\r
760 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
761 break;\r
762\r
763 case EFI_MEMORY_WC:\r
764 // Map to normal non-cachable\r
765 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
766 break;\r
767\r
768 case EFI_MEMORY_WT:\r
769 // Write through with no-allocate\r
770 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
771 break;\r
772\r
773 case EFI_MEMORY_WB:\r
774 // Write back (with allocate)\r
775 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
776 break;\r
777\r
778 case EFI_MEMORY_UCE:\r
779 default:\r
780 ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
781 break;\r
782 }\r
783\r
784 // Determine protection attributes\r
785 if (EfiAttributes & EFI_MEMORY_RO) {\r
786 ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
787 } else {\r
788 ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
789 }\r
790\r
791 // Determine eXecute Never attribute\r
792 if (EfiAttributes & EFI_MEMORY_XP) {\r
793 ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
794 }\r
795\r
796 return ArmAttributes;\r
797}\r
798\r
799EFI_STATUS\r
800GetMemoryRegionPage (\r
801 IN UINT32 *PageTable,\r
802 IN OUT UINTN *BaseAddress,\r
803 OUT UINTN *RegionLength,\r
804 OUT UINTN *RegionAttributes\r
805 )\r
806{\r
807 UINT32 PageAttributes;\r
808 UINT32 TableIndex;\r
809 UINT32 PageDescriptor;\r
810\r
811 // Convert the section attributes into page attributes\r
812 PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);\r
813\r
814 // Calculate index into first level translation table for start of modification\r
815 TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
816 ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
817\r
818 // Go through the page table to find the end of the section\r
819 for (; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {\r
820 // Get the section at the given index\r
821 PageDescriptor = PageTable[TableIndex];\r
822\r
823 if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {\r
824 // Case: End of the boundary of the region\r
825 return EFI_SUCCESS;\r
826 } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
827 if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {\r
828 *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;\r
829 } else {\r
830 // Case: End of the boundary of the region\r
831 return EFI_SUCCESS;\r
832 }\r
833 } else {\r
834 // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.\r
835 ASSERT(0);\r
836 return EFI_SUCCESS;\r
837 }\r
838 }\r
839\r
840 return EFI_NOT_FOUND;\r
841}\r
842\r
843EFI_STATUS\r
844GetMemoryRegion (\r
845 IN OUT UINTN *BaseAddress,\r
846 OUT UINTN *RegionLength,\r
847 OUT UINTN *RegionAttributes\r
848 )\r
849{\r
850 EFI_STATUS Status;\r
851 UINT32 TableIndex;\r
852 UINT32 PageAttributes;\r
853 UINT32 PageTableIndex;\r
854 UINT32 SectionDescriptor;\r
855 ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
856 UINT32 *PageTable;\r
857\r
858 // Initialize the arguments\r
859 *RegionLength = 0;\r
860\r
861 // Obtain page table base\r
862 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
863\r
864 // Calculate index into first level translation table for start of modification\r
865 TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
866 ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);\r
867\r
868 // Get the section at the given index\r
869 SectionDescriptor = FirstLevelTable[TableIndex];\r
870\r
871 // If 'BaseAddress' belongs to the section then round it to the section boundary\r
872 if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
873 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))\r
874 {\r
875 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;\r
876 *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;\r
877 } else {\r
878 // Otherwise, we round it to the page boundary\r
879 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;\r
880\r
881 // Get the attribute at the page table level (Level 2)\r
882 PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
883\r
884 // Calculate index into first level translation table for start of modification\r
885 PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
886 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
887\r
888 PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;\r
889 *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |\r
890 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);\r
891 }\r
892\r
893 for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {\r
894 // Get the section at the given index\r
895 SectionDescriptor = FirstLevelTable[TableIndex];\r
896\r
897 // If the entry is a level-2 page table then we scan it to find the end of the region\r
898 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {\r
899 // Extract the page table location from the descriptor\r
900 PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
901\r
902 // Scan the page table to find the end of the region.\r
903 Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);\r
904\r
905 // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop\r
906 if (Status == EFI_SUCCESS) {\r
907 break;\r
908 }\r
909 } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
910 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {\r
911 if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {\r
912 // If the attributes of the section differ from the one targeted then we exit the loop\r
913 break;\r
914 } else {\r
915 *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;\r
916 }\r
917 } else {\r
918 // If we are on an invalid section then it means it is the end of our section.\r
919 break;\r
920 }\r
921 }\r
922\r
923 return EFI_SUCCESS;\r
924}\r