]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
OvmfPkg/AcpiPlatformDxe: replay QEMU_LOADER_WRITE_POINTER commands at S3
[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
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
3402aac7 27EFI_STATUS\r
aeb61534
A
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
f6be48e9
KK
300 // In this case any bits set in the 'NextSectionAttributes' are garbage and were set from\r
301 // bits that are actually part of the pagetable address. We clear it out to zero so that\r
302 // the SyncCacheConfigPage will use the page attributes instead of trying to convert the\r
303 // section attributes into page attributes\r
304 NextSectionAttributes = 0;\r
2cf4b608 305 Status = SyncCacheConfigPage (\r
306 i,FirstLevelTable[i],\r
8ea50d2e 307 NumberOfDescriptors, MemorySpaceMap,\r
2cf4b608 308 &NextRegionBase,&NextRegionLength,&NextSectionAttributes);\r
309 ASSERT_EFI_ERROR (Status);\r
310 } else {\r
311 // We do not support yet 16MB sections\r
312 ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);\r
aeb61534 313\r
2cf4b608 314 // start on a new region\r
315 if (NextSectionAttributes != 0) {\r
316 // Convert Section Attributes into GCD Attributes\r
317 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
318 ASSERT_EFI_ERROR (Status);\r
aeb61534 319\r
2cf4b608 320 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
321 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
aeb61534 322\r
2cf4b608 323 NextRegionLength = 0;\r
324 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
325 NextSectionAttributes = 0;\r
326 }\r
327 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
328 }\r
aeb61534
A
329 } // section entry loop\r
330\r
2cf4b608 331 if (NextSectionAttributes != 0) {\r
332 // Convert Section Attributes into GCD Attributes\r
333 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
334 ASSERT_EFI_ERROR (Status);\r
335\r
336 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
337 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
338 }\r
339\r
5b53eaff
OM
340 FreePool (MemorySpaceMap);\r
341\r
aeb61534
A
342 return EFI_SUCCESS;\r
343}\r
344\r
345\r
346\r
347EFI_STATUS\r
348UpdatePageEntries (\r
349 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
350 IN UINT64 Length,\r
351 IN UINT64 Attributes,\r
352 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
353 )\r
354{\r
355 EFI_STATUS Status;\r
356 UINT32 EntryValue;\r
357 UINT32 EntryMask;\r
358 UINT32 FirstLevelIdx;\r
359 UINT32 Offset;\r
360 UINT32 NumPageEntries;\r
361 UINT32 Descriptor;\r
362 UINT32 p;\r
363 UINT32 PageTableIndex;\r
364 UINT32 PageTableEntry;\r
bb02cb80 365 UINT32 CurrentPageTableEntry;\r
366 VOID *Mva;\r
aeb61534
A
367\r
368 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
369 volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
370\r
920cb926
A
371 Status = EFI_SUCCESS;\r
372\r
aeb61534
A
373 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
374 // EntryValue: values at bit positions specified by EntryMask\r
1bfda055 375 EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK;\r
376 EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
aeb61534
A
377 // Although the PI spec is unclear on this the GCD guarantees that only\r
378 // one Attribute bit is set at a time, so we can safely use a switch statement\r
379 switch (Attributes) {\r
380 case EFI_MEMORY_UC:\r
381 // modify cacheability attributes\r
1bfda055 382 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
9207c5d7 383 // map to strongly ordered\r
384 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
aeb61534
A
385 break;\r
386\r
387 case EFI_MEMORY_WC:\r
388 // modify cacheability attributes\r
1bfda055 389 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
aeb61534 390 // map to normal non-cachable\r
1bfda055 391 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
aeb61534
A
392 break;\r
393\r
394 case EFI_MEMORY_WT:\r
395 // modify cacheability attributes\r
1bfda055 396 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
aeb61534 397 // write through with no-allocate\r
1bfda055 398 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
aeb61534
A
399 break;\r
400\r
401 case EFI_MEMORY_WB:\r
402 // modify cacheability attributes\r
1bfda055 403 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
aeb61534 404 // write back (with allocate)\r
1bfda055 405 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
aeb61534
A
406 break;\r
407\r
408 case EFI_MEMORY_WP:\r
409 case EFI_MEMORY_XP:\r
410 case EFI_MEMORY_UCE:\r
411 // cannot be implemented UEFI definition unclear for ARM\r
412 // Cause a page fault if these ranges are accessed.\r
1bfda055 413 EntryValue = TT_DESCRIPTOR_PAGE_TYPE_FAULT;\r
225290eb 414 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
aeb61534
A
415 break;\r
416\r
417 default:\r
418 return EFI_UNSUPPORTED;\r
aeb61534
A
419 }\r
420\r
11c20f4e 421 // Obtain page table base\r
1bfda055 422 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
aeb61534 423\r
11c20f4e 424 // Calculate number of 4KB page table entries to change\r
2297613a 425 NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
3402aac7 426\r
11c20f4e 427 // Iterate for the number of 4KB pages to change\r
aeb61534 428 Offset = 0;\r
11c20f4e 429 for(p = 0; p < NumPageEntries; p++) {\r
430 // Calculate index into first level translation table for page table value\r
3402aac7 431\r
1bfda055 432 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
433 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
aeb61534 434\r
11c20f4e 435 // Read the descriptor from the first level page table\r
aeb61534
A
436 Descriptor = FirstLevelTable[FirstLevelIdx];\r
437\r
11c20f4e 438 // Does this descriptor need to be converted from section entry to 4K pages?\r
1bfda055 439 if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {\r
440 Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
aeb61534 441 if (EFI_ERROR(Status)) {\r
11c20f4e 442 // Exit for loop\r
3402aac7
RC
443 break;\r
444 }\r
445\r
11c20f4e 446 // Re-read descriptor\r
aeb61534
A
447 Descriptor = FirstLevelTable[FirstLevelIdx];\r
448 }\r
449\r
11c20f4e 450 // Obtain page table base address\r
1bfda055 451 PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);\r
aeb61534 452\r
11c20f4e 453 // Calculate index into the page table\r
1bfda055 454 PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
455 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
aeb61534 456\r
11c20f4e 457 // Get the entry\r
bb02cb80 458 CurrentPageTableEntry = PageTable[PageTableIndex];\r
aeb61534 459\r
11c20f4e 460 // Mask off appropriate fields\r
bb02cb80 461 PageTableEntry = CurrentPageTableEntry & ~EntryMask;\r
aeb61534 462\r
11c20f4e 463 // Mask in new attributes and/or permissions\r
aeb61534
A
464 PageTableEntry |= EntryValue;\r
465\r
466 if (VirtualMask != 0) {\r
467 // Make this virtual address point at a physical page\r
468 PageTableEntry &= ~VirtualMask;\r
469 }\r
3402aac7 470\r
bb02cb80 471 if (CurrentPageTableEntry != PageTableEntry) {\r
1bfda055 472 Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
473 if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {\r
bb02cb80 474 // The current section mapping is cacheable so Clean/Invalidate the MVA of the page\r
475 // Note assumes switch(Attributes), not ARMv7 possibilities\r
2297613a 476 WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
bb02cb80 477 }\r
478\r
3402aac7
RC
479 // Only need to update if we are changing the entry\r
480 PageTable[PageTableIndex] = PageTableEntry;\r
bb02cb80 481 ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
482 }\r
aeb61534
A
483\r
484 Status = EFI_SUCCESS;\r
2297613a 485 Offset += TT_DESCRIPTOR_PAGE_SIZE;\r
3402aac7 486\r
11c20f4e 487 } // End first level translation table loop\r
aeb61534
A
488\r
489 return Status;\r
490}\r
491\r
492\r
493\r
494EFI_STATUS\r
495UpdateSectionEntries (\r
496 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
497 IN UINT64 Length,\r
498 IN UINT64 Attributes,\r
499 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
500 )\r
501{\r
502 EFI_STATUS Status = EFI_SUCCESS;\r
503 UINT32 EntryMask;\r
504 UINT32 EntryValue;\r
505 UINT32 FirstLevelIdx;\r
506 UINT32 NumSections;\r
507 UINT32 i;\r
bb02cb80 508 UINT32 CurrentDescriptor;\r
aeb61534 509 UINT32 Descriptor;\r
bb02cb80 510 VOID *Mva;\r
aeb61534
A
511 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
512\r
513 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
514 // EntryValue: values at bit positions specified by EntryMask\r
515\r
3402aac7 516 // Make sure we handle a section range that is unmapped\r
1bfda055 517 EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK;\r
518 EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
f659880b 519\r
aeb61534
A
520 // Although the PI spec is unclear on this the GCD guarantees that only\r
521 // one Attribute bit is set at a time, so we can safely use a switch statement\r
522 switch(Attributes) {\r
523 case EFI_MEMORY_UC:\r
524 // modify cacheability attributes\r
1bfda055 525 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
9207c5d7 526 // map to strongly ordered\r
527 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
aeb61534
A
528 break;\r
529\r
530 case EFI_MEMORY_WC:\r
531 // modify cacheability attributes\r
1bfda055 532 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
aeb61534 533 // map to normal non-cachable\r
1bfda055 534 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
aeb61534
A
535 break;\r
536\r
537 case EFI_MEMORY_WT:\r
538 // modify cacheability attributes\r
1bfda055 539 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
aeb61534 540 // write through with no-allocate\r
1bfda055 541 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
aeb61534
A
542 break;\r
543\r
544 case EFI_MEMORY_WB:\r
545 // modify cacheability attributes\r
1bfda055 546 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
aeb61534 547 // write back (with allocate)\r
1bfda055 548 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
aeb61534
A
549 break;\r
550\r
551 case EFI_MEMORY_WP:\r
552 case EFI_MEMORY_XP:\r
553 case EFI_MEMORY_RP:\r
554 case EFI_MEMORY_UCE:\r
555 // cannot be implemented UEFI definition unclear for ARM\r
556 // Cause a page fault if these ranges are accessed.\r
1bfda055 557 EntryValue = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
225290eb 558 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
aeb61534
A
559 break;\r
560\r
561\r
562 default:\r
563 return EFI_UNSUPPORTED;\r
aeb61534
A
564 }\r
565\r
566 // obtain page table base\r
1bfda055 567 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
aeb61534
A
568\r
569 // calculate index into first level translation table for start of modification\r
1bfda055 570 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
571 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
aeb61534
A
572\r
573 // calculate number of 1MB first level entries this applies to\r
1bfda055 574 NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
3402aac7 575\r
aeb61534
A
576 // iterate through each descriptor\r
577 for(i=0; i<NumSections; i++) {\r
bb02cb80 578 CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
aeb61534
A
579\r
580 // has this descriptor already been coverted to pages?\r
1bfda055 581 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
aeb61534 582 // forward this 1MB range to page table function instead\r
1bfda055 583 Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);\r
aeb61534
A
584 } else {\r
585 // still a section entry\r
3402aac7 586\r
aeb61534 587 // mask off appropriate fields\r
bb02cb80 588 Descriptor = CurrentDescriptor & ~EntryMask;\r
aeb61534
A
589\r
590 // mask in new attributes and/or permissions\r
591 Descriptor |= EntryValue;\r
592 if (VirtualMask != 0) {\r
593 Descriptor &= ~VirtualMask;\r
594 }\r
595\r
bb02cb80 596 if (CurrentDescriptor != Descriptor) {\r
1bfda055 597 Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
598 if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {\r
bb02cb80 599 // The current section mapping is cacheable so Clean/Invalidate the MVA of the section\r
600 // Note assumes switch(Attributes), not ARMv7 possabilities\r
601 WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
602 }\r
603\r
3402aac7 604 // Only need to update if we are changing the descriptor\r
bb02cb80 605 FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
606 ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
607 }\r
aeb61534
A
608\r
609 Status = EFI_SUCCESS;\r
610 }\r
611 }\r
612\r
613 return Status;\r
614}\r
615\r
3402aac7 616EFI_STATUS\r
aeb61534
A
617ConvertSectionToPages (\r
618 IN EFI_PHYSICAL_ADDRESS BaseAddress\r
619 )\r
620{\r
621 EFI_STATUS Status;\r
622 EFI_PHYSICAL_ADDRESS PageTableAddr;\r
623 UINT32 FirstLevelIdx;\r
624 UINT32 SectionDescriptor;\r
625 UINT32 PageTableDescriptor;\r
626 UINT32 PageDescriptor;\r
2cf4b608 627 UINT32 Index;\r
aeb61534
A
628\r
629 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
630 volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
631\r
225290eb 632 DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));\r
aeb61534 633\r
b34e4db3 634 // Obtain page table base\r
1bfda055 635 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
aeb61534 636\r
b34e4db3 637 // Calculate index into first level translation table for start of modification\r
1bfda055 638 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
639 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
aeb61534 640\r
b34e4db3 641 // Get section attributes and convert to page attributes\r
aeb61534 642 SectionDescriptor = FirstLevelTable[FirstLevelIdx];\r
6adbd5b4 643 PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);\r
aeb61534 644\r
b34e4db3 645 // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)\r
aeb61534
A
646 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr);\r
647 if (EFI_ERROR(Status)) {\r
648 return Status;\r
649 }\r
650\r
651 PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;\r
652\r
b34e4db3 653 // Write the page table entries out\r
2cf4b608 654 for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
655 PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;\r
aeb61534
A
656 }\r
657\r
b34e4db3 658 // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
2297613a 659 WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE);\r
aeb61534 660\r
b34e4db3 661 // Formulate page table entry, Domain=0, NS=0\r
1bfda055 662 PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
aeb61534 663\r
b34e4db3 664 // Write the page table entry out, replacing section entry\r
aeb61534
A
665 FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;\r
666\r
667 return EFI_SUCCESS;\r
668}\r
669\r
670\r
671\r
672EFI_STATUS\r
673SetMemoryAttributes (\r
674 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
675 IN UINT64 Length,\r
676 IN UINT64 Attributes,\r
677 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
678 )\r
679{\r
680 EFI_STATUS Status;\r
3402aac7 681\r
aeb61534 682 if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {\r
11c20f4e 683 // Is the base and length a multiple of 1 MB?\r
225290eb 684 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
aeb61534
A
685 Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);\r
686 } else {\r
11c20f4e 687 // Base and/or length is not a multiple of 1 MB\r
225290eb 688 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
aeb61534
A
689 Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);\r
690 }\r
691\r
11c20f4e 692 // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
aeb61534 693 // flush and invalidate pages\r
11c20f4e 694 //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ?\r
aeb61534 695 ArmCleanInvalidateDataCache ();\r
11c20f4e 696\r
aeb61534
A
697 ArmInvalidateInstructionCache ();\r
698\r
11c20f4e 699 // Invalidate all TLB entries so changes are synced\r
700 ArmInvalidateTlb ();\r
aeb61534
A
701\r
702 return Status;\r
703}\r
2e969d2e
OM
704\r
705UINT64\r
706EfiAttributeToArmAttribute (\r
707 IN UINT64 EfiAttributes\r
708 )\r
709{\r
710 UINT64 ArmAttributes;\r
711\r
712 switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {\r
713 case EFI_MEMORY_UC:\r
714 // Map to strongly ordered\r
715 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
716 break;\r
717\r
718 case EFI_MEMORY_WC:\r
719 // Map to normal non-cachable\r
720 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
721 break;\r
722\r
723 case EFI_MEMORY_WT:\r
724 // Write through with no-allocate\r
725 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
726 break;\r
727\r
728 case EFI_MEMORY_WB:\r
729 // Write back (with allocate)\r
730 ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
731 break;\r
732\r
733 case EFI_MEMORY_WP:\r
734 case EFI_MEMORY_XP:\r
735 case EFI_MEMORY_RP:\r
736 case EFI_MEMORY_UCE:\r
737 default:\r
738 // Cannot be implemented UEFI definition unclear for ARM\r
739 // Cause a page fault if these ranges are accessed.\r
740 ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
741 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): Unsupported attribute %x will page fault on access\n", EfiAttributes));\r
742 break;\r
743 }\r
744\r
745 // Determine protection attributes\r
746 if (EfiAttributes & EFI_MEMORY_WP) {\r
747 ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
748 } else {\r
749 ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
750 }\r
751\r
752 // Determine eXecute Never attribute\r
753 if (EfiAttributes & EFI_MEMORY_XP) {\r
754 ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
755 }\r
756\r
757 return ArmAttributes;\r
758}\r
759\r
760EFI_STATUS\r
761GetMemoryRegionPage (\r
762 IN UINT32 *PageTable,\r
763 IN OUT UINTN *BaseAddress,\r
764 OUT UINTN *RegionLength,\r
765 OUT UINTN *RegionAttributes\r
766 )\r
767{\r
768 UINT32 PageAttributes;\r
769 UINT32 TableIndex;\r
770 UINT32 PageDescriptor;\r
771\r
772 // Convert the section attributes into page attributes\r
773 PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);\r
774\r
775 // Calculate index into first level translation table for start of modification\r
b75d7605 776 TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
2e969d2e
OM
777 ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
778\r
779 // Go through the page table to find the end of the section\r
780 for (; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {\r
781 // Get the section at the given index\r
782 PageDescriptor = PageTable[TableIndex];\r
783\r
784 if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {\r
785 // Case: End of the boundary of the region\r
786 return EFI_SUCCESS;\r
787 } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
788 if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {\r
789 *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;\r
790 } else {\r
791 // Case: End of the boundary of the region\r
792 return EFI_SUCCESS;\r
793 }\r
794 } else {\r
795 // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.\r
796 ASSERT(0);\r
797 return EFI_SUCCESS;\r
798 }\r
799 }\r
800\r
801 return EFI_NOT_FOUND;\r
802}\r
803\r
804EFI_STATUS\r
805GetMemoryRegion (\r
806 IN OUT UINTN *BaseAddress,\r
807 OUT UINTN *RegionLength,\r
808 OUT UINTN *RegionAttributes\r
809 )\r
810{\r
811 EFI_STATUS Status;\r
812 UINT32 TableIndex;\r
813 UINT32 PageAttributes;\r
814 UINT32 PageTableIndex;\r
815 UINT32 SectionDescriptor;\r
816 ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
817 UINT32 *PageTable;\r
818\r
819 // Initialize the arguments\r
820 *RegionLength = 0;\r
821\r
822 // Obtain page table base\r
823 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
824\r
825 // Calculate index into first level translation table for start of modification\r
826 TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
827 ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);\r
828\r
829 // Get the section at the given index\r
830 SectionDescriptor = FirstLevelTable[TableIndex];\r
831\r
832 // If 'BaseAddress' belongs to the section then round it to the section boundary\r
833 if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
834 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))\r
835 {\r
836 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;\r
837 *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;\r
838 } else {\r
839 // Otherwise, we round it to the page boundary\r
840 *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;\r
841\r
842 // Get the attribute at the page table level (Level 2)\r
843 PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
844\r
845 // Calculate index into first level translation table for start of modification\r
b75d7605 846 PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
2e969d2e
OM
847 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
848\r
849 PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;\r
850 *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |\r
851 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);\r
852 }\r
853\r
854 for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {\r
855 // Get the section at the given index\r
856 SectionDescriptor = FirstLevelTable[TableIndex];\r
857\r
858 // If the entry is a level-2 page table then we scan it to find the end of the region\r
5ad9b48f 859 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {\r
2e969d2e
OM
860 // Extract the page table location from the descriptor\r
861 PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
862\r
863 // Scan the page table to find the end of the region.\r
864 Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);\r
865\r
866 // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop\r
867 if (Status == EFI_SUCCESS) {\r
868 break;\r
869 }\r
870 } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
871 ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {\r
872 if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {\r
873 // If the attributes of the section differ from the one targeted then we exit the loop\r
874 break;\r
875 } else {\r
876 *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;\r
877 }\r
878 } else {\r
879 // If we are on an invalid section then it means it is the end of our section.\r
880 break;\r
881 }\r
882 }\r
883\r
884 return EFI_SUCCESS;\r
885}\r