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