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