]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/CpuDxe/Mmu.c
EmbeddedPkg/Ebl: Fix EBL copy file command
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / 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
aeb61534 5\r
d6ebcab7 6This program and the accompanying materials \r
aeb61534
A
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
14\r
15--*/\r
16\r
17#include "CpuDxe.h"\r
1bfda055 18//FIXME: Remove this ARMv7 specific header\r
19#include <Chipset/ArmV7.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
f659880b
A
155/**\r
156 Searches memory descriptors covered by given memory range.\r
157\r
158 This function searches into the Gcd Memory Space for descriptors\r
159 (from StartIndex to EndIndex) that contains the memory range\r
160 specified by BaseAddress and Length.\r
161\r
162 @param MemorySpaceMap Gcd Memory Space Map as array.\r
163 @param NumberOfDescriptors Number of descriptors in map.\r
164 @param BaseAddress BaseAddress for the requested range.\r
165 @param Length Length for the requested range.\r
166 @param StartIndex Start index into the Gcd Memory Space Map.\r
167 @param EndIndex End index into the Gcd Memory Space Map.\r
168\r
169 @retval EFI_SUCCESS Search successfully.\r
170 @retval EFI_NOT_FOUND The requested descriptors does not exist.\r
171\r
172**/\r
173EFI_STATUS\r
174SearchGcdMemorySpaces (\r
175 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
176 IN UINTN NumberOfDescriptors,\r
177 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
178 IN UINT64 Length,\r
179 OUT UINTN *StartIndex,\r
180 OUT UINTN *EndIndex\r
181 )\r
182{\r
183 UINTN Index;\r
184\r
185 *StartIndex = 0;\r
186 *EndIndex = 0;\r
187 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
188 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&\r
189 BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
190 *StartIndex = Index;\r
191 }\r
192 if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&\r
193 BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
194 *EndIndex = Index;\r
195 return EFI_SUCCESS;\r
196 }\r
197 }\r
198 return EFI_NOT_FOUND;\r
199}\r
200\r
201\r
202/**\r
203 Sets the attributes for a specified range in Gcd Memory Space Map.\r
204\r
205 This function sets the attributes for a specified range in\r
206 Gcd Memory Space Map.\r
207\r
208 @param MemorySpaceMap Gcd Memory Space Map as array\r
209 @param NumberOfDescriptors Number of descriptors in map\r
210 @param BaseAddress BaseAddress for the range\r
211 @param Length Length for the range\r
212 @param Attributes Attributes to set\r
213\r
214 @retval EFI_SUCCESS Memory attributes set successfully\r
215 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space\r
216\r
217**/\r
218EFI_STATUS\r
219SetGcdMemorySpaceAttributes (\r
220 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
221 IN UINTN NumberOfDescriptors,\r
222 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
223 IN UINT64 Length,\r
224 IN UINT64 Attributes\r
225 )\r
226{\r
227 EFI_STATUS Status;\r
228 UINTN Index;\r
229 UINTN StartIndex;\r
230 UINTN EndIndex;\r
231 EFI_PHYSICAL_ADDRESS RegionStart;\r
232 UINT64 RegionLength;\r
233\r
234 //\r
235 // Get all memory descriptors covered by the memory range\r
236 //\r
237 Status = SearchGcdMemorySpaces (\r
238 MemorySpaceMap,\r
239 NumberOfDescriptors,\r
240 BaseAddress,\r
241 Length,\r
242 &StartIndex,\r
243 &EndIndex\r
244 );\r
245 if (EFI_ERROR (Status)) {\r
246 return Status;\r
247 }\r
248\r
249 //\r
250 // Go through all related descriptors and set attributes accordingly\r
251 //\r
252 for (Index = StartIndex; Index <= EndIndex; Index++) {\r
253 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
254 continue;\r
255 }\r
256 //\r
257 // Calculate the start and end address of the overlapping range\r
258 //\r
259 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {\r
260 RegionStart = BaseAddress;\r
261 } else {\r
262 RegionStart = MemorySpaceMap[Index].BaseAddress;\r
263 }\r
264 if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {\r
265 RegionLength = BaseAddress + Length - RegionStart;\r
266 } else {\r
267 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;\r
268 }\r
269 //\r
270 // Set memory attributes according to MTRR attribute and the original attribute of descriptor\r
271 //\r
272 gDS->SetMemorySpaceAttributes (\r
273 RegionStart,\r
274 RegionLength,\r
275 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)\r
276 );\r
277 }\r
278\r
279 return EFI_SUCCESS;\r
280}\r
aeb61534 281\r
2cf4b608 282EFI_STATUS\r
283SyncCacheConfigPage (\r
284 IN UINT32 SectionIndex,\r
285 IN UINT32 FirstLevelDescriptor,\r
286 IN UINTN NumberOfDescriptors,\r
287 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
288 IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,\r
289 IN OUT UINT64 *NextRegionLength,\r
290 IN OUT UINT32 *NextSectionAttributes\r
291 )\r
292{\r
293 EFI_STATUS Status;\r
294 UINT32 i;\r
295 volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;\r
296 UINT32 NextPageAttributes = 0;\r
297 UINT32 PageAttributes = 0;\r
298 UINT32 BaseAddress;\r
299 UINT64 GcdAttributes;\r
300\r
301 // Get the Base Address from FirstLevelDescriptor;\r
302 BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
303\r
304 // Convert SectionAttributes into PageAttributes\r
305 NextPageAttributes =\r
306 TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |\r
307 TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);\r
308\r
309 // obtain page table base\r
310 SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
311\r
312 for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {\r
313 if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
314 // extract attributes (cacheability and permissions)\r
315 PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);\r
316\r
317 if (NextPageAttributes == 0) {\r
318 // start on a new region\r
319 *NextRegionLength = 0;\r
320 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
321 NextPageAttributes = PageAttributes;\r
322 } else if (PageAttributes != NextPageAttributes) {\r
323 // Convert Section Attributes into GCD Attributes\r
324 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
325 ASSERT_EFI_ERROR (Status);\r
326\r
327 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
328 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
329\r
330 // start on a new region\r
331 *NextRegionLength = 0;\r
332 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
333 NextPageAttributes = PageAttributes;\r
334 }\r
335 } else if (NextPageAttributes != 0) {\r
336 // Convert Page Attributes into GCD Attributes\r
337 Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
338 ASSERT_EFI_ERROR (Status);\r
339\r
340 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
341 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
342\r
343 *NextRegionLength = 0;\r
344 *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
345 NextPageAttributes = 0;\r
346 }\r
347 *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;\r
348 }\r
349\r
350 // Convert back PageAttributes into SectionAttributes\r
351 *NextSectionAttributes =\r
352 TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |\r
353 TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);\r
354\r
355 return EFI_SUCCESS;\r
356}\r
aeb61534
A
357\r
358EFI_STATUS\r
359SyncCacheConfig (\r
360 IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol\r
361 )\r
362{\r
f659880b
A
363 EFI_STATUS Status;\r
364 UINT32 i;\r
f659880b
A
365 EFI_PHYSICAL_ADDRESS NextRegionBase;\r
366 UINT64 NextRegionLength;\r
2cf4b608 367 UINT32 NextSectionAttributes = 0;\r
368 UINT32 SectionAttributes = 0;\r
f659880b 369 UINT64 GcdAttributes;\r
aeb61534 370 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
f659880b
A
371 UINTN NumberOfDescriptors;\r
372 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
aeb61534
A
373\r
374\r
225290eb 375 DEBUG ((EFI_D_PAGE, "SyncCacheConfig()\n"));\r
f659880b 376\r
aeb61534
A
377 // This code assumes MMU is enabled and filed with section translations\r
378 ASSERT (ArmMmuEnabled ());\r
379\r
f659880b
A
380 //\r
381 // Get the memory space map from GCD\r
382 //\r
383 MemorySpaceMap = NULL;\r
384 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
385 ASSERT_EFI_ERROR (Status);\r
386\r
aeb61534
A
387\r
388 // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs\r
389 // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a\r
390 // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were\r
391 // a client) to update its copy of the attributes. This is bad architecture and should be replaced\r
392 // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.\r
393\r
394 // obtain page table base\r
1bfda055 395 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());\r
aeb61534 396\r
2cf4b608 397 // Get the first region\r
398 NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
aeb61534
A
399\r
400 // iterate through each 1MB descriptor\r
401 NextRegionBase = NextRegionLength = 0;\r
2cf4b608 402 for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {\r
403 if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {\r
404 // extract attributes (cacheability and permissions)\r
405 SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
406\r
407 if (NextSectionAttributes == 0) {\r
408 // start on a new region\r
409 NextRegionLength = 0;\r
410 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
411 NextSectionAttributes = SectionAttributes;\r
412 } else if (SectionAttributes != NextSectionAttributes) {\r
413 // Convert Section Attributes into GCD Attributes\r
414 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
f659880b 415 ASSERT_EFI_ERROR (Status);\r
aeb61534
A
416\r
417 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
f659880b
A
418 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
419\r
aeb61534
A
420 // start on a new region\r
421 NextRegionLength = 0;\r
2cf4b608 422 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
423 NextSectionAttributes = SectionAttributes;\r
aeb61534 424 }\r
2cf4b608 425 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
426 } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {\r
427 Status = SyncCacheConfigPage (\r
428 i,FirstLevelTable[i],\r
8ea50d2e 429 NumberOfDescriptors, MemorySpaceMap,\r
2cf4b608 430 &NextRegionBase,&NextRegionLength,&NextSectionAttributes);\r
431 ASSERT_EFI_ERROR (Status);\r
432 } else {\r
433 // We do not support yet 16MB sections\r
434 ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);\r
aeb61534 435\r
2cf4b608 436 // start on a new region\r
437 if (NextSectionAttributes != 0) {\r
438 // Convert Section Attributes into GCD Attributes\r
439 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
440 ASSERT_EFI_ERROR (Status);\r
aeb61534 441\r
2cf4b608 442 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
443 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
aeb61534 444\r
2cf4b608 445 NextRegionLength = 0;\r
446 NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
447 NextSectionAttributes = 0;\r
448 }\r
449 NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
450 }\r
aeb61534
A
451 } // section entry loop\r
452\r
2cf4b608 453 if (NextSectionAttributes != 0) {\r
454 // Convert Section Attributes into GCD Attributes\r
455 Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
456 ASSERT_EFI_ERROR (Status);\r
457\r
458 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
459 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
460 }\r
461\r
aeb61534
A
462 return EFI_SUCCESS;\r
463}\r
464\r
465\r
466\r
467EFI_STATUS\r
468UpdatePageEntries (\r
469 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
470 IN UINT64 Length,\r
471 IN UINT64 Attributes,\r
472 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
473 )\r
474{\r
475 EFI_STATUS Status;\r
476 UINT32 EntryValue;\r
477 UINT32 EntryMask;\r
478 UINT32 FirstLevelIdx;\r
479 UINT32 Offset;\r
480 UINT32 NumPageEntries;\r
481 UINT32 Descriptor;\r
482 UINT32 p;\r
483 UINT32 PageTableIndex;\r
484 UINT32 PageTableEntry;\r
bb02cb80 485 UINT32 CurrentPageTableEntry;\r
486 VOID *Mva;\r
aeb61534
A
487\r
488 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
489 volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
490\r
920cb926
A
491 Status = EFI_SUCCESS;\r
492\r
aeb61534
A
493 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
494 // EntryValue: values at bit positions specified by EntryMask\r
1bfda055 495 EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK;\r
496 EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
aeb61534
A
497 // Although the PI spec is unclear on this the GCD guarantees that only\r
498 // one Attribute bit is set at a time, so we can safely use a switch statement\r
499 switch (Attributes) {\r
500 case EFI_MEMORY_UC:\r
501 // modify cacheability attributes\r
1bfda055 502 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
503 if (FeaturePcdGet(PcdEfiUncachedMemoryToStronglyOrdered)) {\r
2ac288f9 504 // map to strongly ordered\r
505 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
1bfda055 506 } else {\r
2ac288f9 507 // map to normal non-cachable\r
508 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
1bfda055 509 }\r
aeb61534
A
510 break;\r
511\r
512 case EFI_MEMORY_WC:\r
513 // modify cacheability attributes\r
1bfda055 514 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
aeb61534 515 // map to normal non-cachable\r
1bfda055 516 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
aeb61534
A
517 break;\r
518\r
519 case EFI_MEMORY_WT:\r
520 // modify cacheability attributes\r
1bfda055 521 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
aeb61534 522 // write through with no-allocate\r
1bfda055 523 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
aeb61534
A
524 break;\r
525\r
526 case EFI_MEMORY_WB:\r
527 // modify cacheability attributes\r
1bfda055 528 EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
aeb61534 529 // write back (with allocate)\r
1bfda055 530 EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
aeb61534
A
531 break;\r
532\r
533 case EFI_MEMORY_WP:\r
534 case EFI_MEMORY_XP:\r
535 case EFI_MEMORY_UCE:\r
536 // cannot be implemented UEFI definition unclear for ARM\r
537 // Cause a page fault if these ranges are accessed.\r
1bfda055 538 EntryValue = TT_DESCRIPTOR_PAGE_TYPE_FAULT;\r
225290eb 539 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
aeb61534
A
540 break;\r
541\r
542 default:\r
543 return EFI_UNSUPPORTED;\r
aeb61534
A
544 }\r
545\r
546 // obtain page table base\r
1bfda055 547 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
aeb61534
A
548\r
549 // calculate number of 4KB page table entries to change\r
2297613a 550 NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
aeb61534
A
551 \r
552 // iterate for the number of 4KB pages to change\r
553 Offset = 0;\r
554 for(p=0; p<NumPageEntries; p++) {\r
555 // calculate index into first level translation table for page table value\r
556 \r
1bfda055 557 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
558 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
aeb61534
A
559\r
560 // read the descriptor from the first level page table\r
561 Descriptor = FirstLevelTable[FirstLevelIdx];\r
562\r
563 // does this descriptor need to be converted from section entry to 4K pages?\r
1bfda055 564 if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {\r
565 Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
aeb61534
A
566 if (EFI_ERROR(Status)) {\r
567 // exit for loop\r
568 break; \r
569 } \r
570 \r
571 // re-read descriptor\r
572 Descriptor = FirstLevelTable[FirstLevelIdx];\r
573 }\r
574\r
575 // obtain page table base address\r
1bfda055 576 PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);\r
aeb61534
A
577\r
578 // calculate index into the page table\r
1bfda055 579 PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
580 ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
aeb61534
A
581\r
582 // get the entry\r
bb02cb80 583 CurrentPageTableEntry = PageTable[PageTableIndex];\r
aeb61534
A
584\r
585 // mask off appropriate fields\r
bb02cb80 586 PageTableEntry = CurrentPageTableEntry & ~EntryMask;\r
aeb61534
A
587\r
588 // mask in new attributes and/or permissions\r
589 PageTableEntry |= EntryValue;\r
590\r
591 if (VirtualMask != 0) {\r
592 // Make this virtual address point at a physical page\r
593 PageTableEntry &= ~VirtualMask;\r
594 }\r
aeb61534 595 \r
bb02cb80 596 if (CurrentPageTableEntry != PageTableEntry) {\r
1bfda055 597 Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
598 if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {\r
bb02cb80 599 // The current section mapping is cacheable so Clean/Invalidate the MVA of the page\r
600 // Note assumes switch(Attributes), not ARMv7 possibilities\r
2297613a 601 WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
bb02cb80 602 }\r
603\r
604 // Only need to update if we are changing the entry \r
605 PageTable[PageTableIndex] = PageTableEntry; \r
606 ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
607 }\r
aeb61534
A
608\r
609 Status = EFI_SUCCESS;\r
2297613a 610 Offset += TT_DESCRIPTOR_PAGE_SIZE;\r
aeb61534
A
611 \r
612 } // end first level translation table loop\r
613\r
614 return Status;\r
615}\r
616\r
617\r
618\r
619EFI_STATUS\r
620UpdateSectionEntries (\r
621 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
622 IN UINT64 Length,\r
623 IN UINT64 Attributes,\r
624 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
625 )\r
626{\r
627 EFI_STATUS Status = EFI_SUCCESS;\r
628 UINT32 EntryMask;\r
629 UINT32 EntryValue;\r
630 UINT32 FirstLevelIdx;\r
631 UINT32 NumSections;\r
632 UINT32 i;\r
bb02cb80 633 UINT32 CurrentDescriptor;\r
aeb61534 634 UINT32 Descriptor;\r
bb02cb80 635 VOID *Mva;\r
aeb61534
A
636 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
637\r
638 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
639 // EntryValue: values at bit positions specified by EntryMask\r
640\r
f659880b 641 // Make sure we handle a section range that is unmapped \r
1bfda055 642 EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK;\r
643 EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
f659880b 644\r
aeb61534
A
645 // Although the PI spec is unclear on this the GCD guarantees that only\r
646 // one Attribute bit is set at a time, so we can safely use a switch statement\r
647 switch(Attributes) {\r
648 case EFI_MEMORY_UC:\r
649 // modify cacheability attributes\r
1bfda055 650 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
651 if (FeaturePcdGet(PcdEfiUncachedMemoryToStronglyOrdered)) {\r
2ac288f9 652 // map to strongly ordered\r
653 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
1bfda055 654 } else {\r
2ac288f9 655 // map to normal non-cachable\r
656 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
1bfda055 657 }\r
aeb61534
A
658 break;\r
659\r
660 case EFI_MEMORY_WC:\r
661 // modify cacheability attributes\r
1bfda055 662 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
aeb61534 663 // map to normal non-cachable\r
1bfda055 664 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
aeb61534
A
665 break;\r
666\r
667 case EFI_MEMORY_WT:\r
668 // modify cacheability attributes\r
1bfda055 669 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
aeb61534 670 // write through with no-allocate\r
1bfda055 671 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
aeb61534
A
672 break;\r
673\r
674 case EFI_MEMORY_WB:\r
675 // modify cacheability attributes\r
1bfda055 676 EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
aeb61534 677 // write back (with allocate)\r
1bfda055 678 EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
aeb61534
A
679 break;\r
680\r
681 case EFI_MEMORY_WP:\r
682 case EFI_MEMORY_XP:\r
683 case EFI_MEMORY_RP:\r
684 case EFI_MEMORY_UCE:\r
685 // cannot be implemented UEFI definition unclear for ARM\r
686 // Cause a page fault if these ranges are accessed.\r
1bfda055 687 EntryValue = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
225290eb 688 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
aeb61534
A
689 break;\r
690\r
691\r
692 default:\r
693 return EFI_UNSUPPORTED;\r
aeb61534
A
694 }\r
695\r
696 // obtain page table base\r
1bfda055 697 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
aeb61534
A
698\r
699 // calculate index into first level translation table for start of modification\r
1bfda055 700 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
701 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
aeb61534
A
702\r
703 // calculate number of 1MB first level entries this applies to\r
1bfda055 704 NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
aeb61534
A
705 \r
706 // iterate through each descriptor\r
707 for(i=0; i<NumSections; i++) {\r
bb02cb80 708 CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
aeb61534
A
709\r
710 // has this descriptor already been coverted to pages?\r
1bfda055 711 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
aeb61534 712 // forward this 1MB range to page table function instead\r
1bfda055 713 Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);\r
aeb61534
A
714 } else {\r
715 // still a section entry\r
716 \r
717 // mask off appropriate fields\r
bb02cb80 718 Descriptor = CurrentDescriptor & ~EntryMask;\r
aeb61534
A
719\r
720 // mask in new attributes and/or permissions\r
721 Descriptor |= EntryValue;\r
722 if (VirtualMask != 0) {\r
723 Descriptor &= ~VirtualMask;\r
724 }\r
725\r
bb02cb80 726 if (CurrentDescriptor != Descriptor) {\r
1bfda055 727 Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
728 if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {\r
bb02cb80 729 // The current section mapping is cacheable so Clean/Invalidate the MVA of the section\r
730 // Note assumes switch(Attributes), not ARMv7 possabilities\r
731 WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
732 }\r
733\r
734 // Only need to update if we are changing the descriptor \r
735 FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
736 ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
737 }\r
aeb61534
A
738\r
739 Status = EFI_SUCCESS;\r
740 }\r
741 }\r
742\r
743 return Status;\r
744}\r
745\r
746EFI_STATUS \r
747ConvertSectionToPages (\r
748 IN EFI_PHYSICAL_ADDRESS BaseAddress\r
749 )\r
750{\r
751 EFI_STATUS Status;\r
752 EFI_PHYSICAL_ADDRESS PageTableAddr;\r
753 UINT32 FirstLevelIdx;\r
754 UINT32 SectionDescriptor;\r
755 UINT32 PageTableDescriptor;\r
756 UINT32 PageDescriptor;\r
2cf4b608 757 UINT32 Index;\r
aeb61534
A
758\r
759 volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
760 volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
761\r
225290eb 762 DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));\r
aeb61534
A
763\r
764 // obtain page table base\r
1bfda055 765 FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
aeb61534
A
766\r
767 // calculate index into first level translation table for start of modification\r
1bfda055 768 FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
769 ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
aeb61534
A
770\r
771 // get section attributes and convert to page attributes\r
772 SectionDescriptor = FirstLevelTable[FirstLevelIdx];\r
1bfda055 773 PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
774 PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(SectionDescriptor,0);\r
775 PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(SectionDescriptor);\r
776 PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN(SectionDescriptor,0);\r
777 PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG(SectionDescriptor);\r
778 PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S(SectionDescriptor);\r
aeb61534
A
779\r
780 // allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)\r
781 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr);\r
782 if (EFI_ERROR(Status)) {\r
783 return Status;\r
784 }\r
785\r
786 PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;\r
787\r
788 // write the page table entries out\r
2cf4b608 789 for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
790 PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;\r
aeb61534
A
791 }\r
792\r
793 // flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
2297613a 794 WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE);\r
aeb61534
A
795\r
796 // formulate page table entry, Domain=0, NS=0\r
1bfda055 797 PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
aeb61534
A
798\r
799 // write the page table entry out, repalcing section entry\r
800 FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;\r
801\r
802 return EFI_SUCCESS;\r
803}\r
804\r
805\r
806\r
807EFI_STATUS\r
808SetMemoryAttributes (\r
809 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
810 IN UINT64 Length,\r
811 IN UINT64 Attributes,\r
812 IN EFI_PHYSICAL_ADDRESS VirtualMask\r
813 )\r
814{\r
815 EFI_STATUS Status;\r
816 \r
817 if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {\r
818 // is the base and length a multiple of 1 MB?\r
225290eb 819 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
aeb61534
A
820 Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);\r
821 } else {\r
822 // base and/or length is not a multiple of 1 MB\r
225290eb 823 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
aeb61534
A
824 Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);\r
825 }\r
826\r
827 // flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
828 // flush and invalidate pages\r
829 ArmCleanInvalidateDataCache ();\r
830 \r
831 ArmInvalidateInstructionCache ();\r
832\r
833 // invalidate all TLB entries so changes are synced\r
834 ArmInvalidateTlb (); \r
835\r
836 return Status;\r
837}\r
838\r
839\r
840/**\r
841 This function modifies the attributes for the memory region specified by BaseAddress and\r
842 Length from their current attributes to the attributes specified by Attributes.\r
843\r
844 @param This The EFI_CPU_ARCH_PROTOCOL instance.\r
845 @param BaseAddress The physical address that is the start address of a memory region.\r
846 @param Length The size in bytes of the memory region.\r
847 @param Attributes The bit mask of attributes to set for the memory region.\r
848\r
849 @retval EFI_SUCCESS The attributes were set for the memory region.\r
850 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
851 BaseAddress and Length cannot be modified.\r
852 @retval EFI_INVALID_PARAMETER Length is zero.\r
853 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
854 the memory resource range.\r
855 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
856 resource range specified by BaseAddress and Length.\r
857 The bit mask of attributes is not support for the memory resource\r
858 range specified by BaseAddress and Length.\r
859\r
860**/\r
861EFI_STATUS\r
862EFIAPI\r
863CpuSetMemoryAttributes (\r
864 IN EFI_CPU_ARCH_PROTOCOL *This,\r
865 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
866 IN UINT64 Length,\r
867 IN UINT64 Attributes\r
868 )\r
869{\r
225290eb 870 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress, Length, Attributes));\r
2297613a 871 if ( ((BaseAddress & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0) || ((Length & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0)){\r
bb02cb80 872 // minimum granularity is SIZE_4KB (4KB on ARM)\r
873 DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx): minimum ganularity is SIZE_4KB\n", BaseAddress, Length, Attributes));\r
aeb61534
A
874 return EFI_UNSUPPORTED;\r
875 }\r
876 \r
877 return SetMemoryAttributes (BaseAddress, Length, Attributes, 0);\r
878}\r
879\r
880\r
881\r
882//\r
883// Add a new protocol to support \r
884//\r
885\r
886EFI_STATUS\r
887EFIAPI\r
888CpuConvertPagesToUncachedVirtualAddress (\r
889 IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,\r
890 IN EFI_PHYSICAL_ADDRESS Address,\r
891 IN UINTN Length,\r
892 IN EFI_PHYSICAL_ADDRESS VirtualMask,\r
893 OUT UINT64 *Attributes OPTIONAL\r
894 )\r
895{\r
896 EFI_STATUS Status;\r
897 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
898 \r
899 \r
900 if (Attributes != NULL) {\r
901 Status = gDS->GetMemorySpaceDescriptor (Address, &GcdDescriptor);\r
902 if (!EFI_ERROR (Status)) {\r
903 *Attributes = GcdDescriptor.Attributes;\r
904 }\r
905 }\r
225290eb 906\r
aeb61534
A
907 //\r
908 // Make this address range page fault if accessed. If it is a DMA buffer than this would \r
909 // be the PCI address. Code should always use the CPU address, and we will or in VirtualMask\r
910 // to that address. \r
911 //\r
f659880b 912 Status = SetMemoryAttributes (Address, Length, EFI_MEMORY_WP, 0);\r
aeb61534
A
913 if (!EFI_ERROR (Status)) {\r
914 Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_UC, VirtualMask);\r
915 }\r
916\r
6f72e28d 917 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "ConvertPagesToUncachedVirtualAddress()\n Unmapped 0x%08lx Mapped 0x%08lx 0x%x bytes\n", Address, Address | VirtualMask, Length));\r
918\r
aeb61534
A
919 return Status;\r
920}\r
921\r
922\r
923EFI_STATUS\r
924EFIAPI\r
6f72e28d 925CpuReconvertPages (\r
aeb61534
A
926 IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,\r
927 IN EFI_PHYSICAL_ADDRESS Address,\r
928 IN UINTN Length,\r
929 IN EFI_PHYSICAL_ADDRESS VirtualMask,\r
930 IN UINT64 Attributes\r
931 )\r
932{\r
933 EFI_STATUS Status;\r
6f72e28d 934\r
935 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuReconvertPages(%lx, %x, %lx, %lx)\n", Address, Length, VirtualMask, Attributes));\r
936 \r
937 //\r
aeb61534
A
938 // Unmap the alaised Address\r
939 //\r
f659880b 940 Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP, 0);\r
aeb61534
A
941 if (!EFI_ERROR (Status)) {\r
942 //\r
943 // Restore atttributes\r
944 //\r
945 Status = SetMemoryAttributes (Address, Length, Attributes, 0);\r
946 }\r
947 \r
948 return Status;\r
949}\r
950\r
951\r
952VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = {\r
953 CpuConvertPagesToUncachedVirtualAddress,\r
6f72e28d 954 CpuReconvertPages\r
aeb61534 955};\r