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