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