]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c
ArmPkg/ArmLib: Improved ArmConfigureMmu Performance
[mirror_edk2.git] / ArmPkg / Library / ArmLib / ArmV7 / ArmV7Mmu.c
CommitLineData
1bfda055 1/** @file\r
2* File managing the MMU for ARMv7 architecture\r
3*\r
6f050ad6 4* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
1bfda055 5* \r
6* This program and the accompanying materials \r
7* are licensed and made available under the terms and conditions of the BSD License \r
8* which accompanies this distribution. The full text of the license may be found at \r
9* http://opensource.org/licenses/bsd-license.php \r
10*\r
11* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13*\r
14**/\r
15\r
16#include <Uefi.h> \r
17#include <Chipset/ArmV7.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/ArmLib.h>\r
21#include <Library/BaseLib.h>\r
2cf4b608 22#include <Library/DebugLib.h>\r
1bfda055 23#include "ArmV7Lib.h"\r
24#include "ArmLibPrivate.h"\r
25\r
6adbd5b4
OM
26UINT32\r
27ConvertSectionAttributesToPageAttributes (\r
28 IN UINT32 SectionAttributes,\r
29 IN BOOLEAN IsLargePage\r
30 )\r
31{\r
32 UINT32 PageAttributes;\r
33\r
34 PageAttributes = 0;\r
35 PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY (SectionAttributes, IsLargePage);\r
36 PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP (SectionAttributes);\r
37 PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN (SectionAttributes, IsLargePage);\r
38 PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG (SectionAttributes);\r
39 PageAttributes |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S (SectionAttributes);\r
40\r
41 return PageAttributes;\r
42}\r
43\r
a3202839 44STATIC\r
2cf4b608 45VOID\r
46PopulateLevel2PageTable (\r
47 IN UINT32 *SectionEntry,\r
48 IN UINT32 PhysicalBase,\r
49 IN UINT32 RemainLength,\r
50 IN ARM_MEMORY_REGION_ATTRIBUTES Attributes\r
bd6b9799 51 )\r
52{\r
2cf4b608 53 UINT32* PageEntry;\r
54 UINT32 Pages;\r
55 UINT32 Index;\r
56 UINT32 PageAttributes;\r
57 UINT32 SectionDescriptor;\r
58 UINT32 TranslationTable;\r
59 UINT32 BaseSectionAddress;\r
60\r
61 switch (Attributes) {\r
62 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:\r
7fffeef9 63 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:\r
2cf4b608 64 PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_BACK;\r
65 break;\r
66 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:\r
7fffeef9 67 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:\r
2cf4b608 68 PageAttributes = TT_DESCRIPTOR_PAGE_WRITE_THROUGH;\r
69 break;\r
70 case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:\r
7fffeef9 71 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE:\r
2cf4b608 72 PageAttributes = TT_DESCRIPTOR_PAGE_DEVICE;\r
73 break;\r
74 case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:\r
7fffeef9 75 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED:\r
2cf4b608 76 PageAttributes = TT_DESCRIPTOR_PAGE_UNCACHED;\r
77 break;\r
78 default:\r
79 PageAttributes = TT_DESCRIPTOR_PAGE_UNCACHED;\r
80 break;\r
81 }\r
82\r
83 // Check if the Section Entry has already been populated. Otherwise attach a\r
84 // Level 2 Translation Table to it\r
85 if (*SectionEntry != 0) {\r
86 // The entry must be a page table. Otherwise it exists an overlapping in the memory map\r
87 if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(*SectionEntry)) {\r
88 TranslationTable = *SectionEntry & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK;\r
89 } else if ((*SectionEntry & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {\r
90 // Case where a virtual memory map descriptor overlapped a section entry\r
91\r
92 // Allocate a Level2 Page Table for this Section\r
93 TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));\r
94 TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;\r
95\r
96 // Translate the Section Descriptor into Page Descriptor\r
6adbd5b4 97 SectionDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (*SectionEntry, FALSE);\r
2cf4b608 98\r
99 BaseSectionAddress = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(*SectionEntry);\r
100\r
101 // Populate the new Level2 Page Table for the section\r
102 PageEntry = (UINT32*)TranslationTable;\r
103 for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
104 PageEntry[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseSectionAddress + (Index << 12)) | SectionDescriptor;\r
105 }\r
106\r
107 // Overwrite the section entry to point to the new Level2 Translation Table\r
108 *SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |\r
109 (IS_ARM_MEMORY_REGION_ATTRIBUTES_SECURE(Attributes) ? (1 << 3) : 0) |\r
110 TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
111 } else {\r
112 // We do not support the other section type (16MB Section)\r
113 ASSERT(0);\r
114 return;\r
115 }\r
116 } else {\r
117 TranslationTable = (UINTN)AllocatePages(EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_PAGE_SIZE + TRANSLATION_TABLE_PAGE_ALIGNMENT));\r
118 TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_PAGE_ALIGNMENT_MASK;\r
119\r
120 ZeroMem ((VOID *)TranslationTable, TRANSLATION_TABLE_PAGE_SIZE);\r
121\r
122 *SectionEntry = (TranslationTable & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) |\r
123 (IS_ARM_MEMORY_REGION_ATTRIBUTES_SECURE(Attributes) ? (1 << 3) : 0) |\r
124 TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
125 }\r
126\r
127 PageEntry = ((UINT32 *)(TranslationTable) + ((PhysicalBase & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
128 Pages = RemainLength / TT_DESCRIPTOR_PAGE_SIZE;\r
129\r
130 for (Index = 0; Index < Pages; Index++) {\r
131 *PageEntry++ = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(PhysicalBase) | PageAttributes;\r
132 PhysicalBase += TT_DESCRIPTOR_PAGE_SIZE;\r
133 }\r
134\r
135}\r
136\r
a3202839 137STATIC\r
1bfda055 138VOID\r
139FillTranslationTable (\r
140 IN UINT32 *TranslationTable,\r
141 IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryRegion\r
142 )\r
143{\r
2cf4b608 144 UINT32 *SectionEntry;\r
1bfda055 145 UINT32 Attributes;\r
146 UINT32 PhysicalBase = MemoryRegion->PhysicalBase;\r
2cf4b608 147 UINT32 RemainLength = MemoryRegion->Length;\r
1bfda055 148 \r
2cf4b608 149 ASSERT(MemoryRegion->Length > 0);\r
150\r
1bfda055 151 switch (MemoryRegion->Attributes) {\r
152 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK:\r
153 Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(0);\r
154 break;\r
155 case ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH:\r
156 Attributes = TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);\r
157 break;\r
158 case ARM_MEMORY_REGION_ATTRIBUTE_DEVICE:\r
159 Attributes = TT_DESCRIPTOR_SECTION_DEVICE(0);\r
160 break;\r
161 case ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED:\r
162 Attributes = TT_DESCRIPTOR_SECTION_UNCACHED(0);\r
163 break;\r
7fffeef9 164 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK:\r
1bfda055 165 Attributes = TT_DESCRIPTOR_SECTION_WRITE_BACK(1);\r
166 break;\r
7fffeef9 167 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH:\r
1bfda055 168 Attributes = TT_DESCRIPTOR_SECTION_WRITE_THROUGH(1);\r
169 break;\r
7fffeef9 170 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_DEVICE:\r
1bfda055 171 Attributes = TT_DESCRIPTOR_SECTION_DEVICE(1);\r
172 break;\r
7fffeef9 173 case ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED:\r
1bfda055 174 Attributes = TT_DESCRIPTOR_SECTION_UNCACHED(1);\r
175 break;\r
176 default:\r
177 Attributes = TT_DESCRIPTOR_SECTION_UNCACHED(0);\r
178 break;\r
179 }\r
180 \r
2cf4b608 181 // Get the first section entry for this mapping\r
182 SectionEntry = TRANSLATION_TABLE_ENTRY_FOR_VIRTUAL_ADDRESS(TranslationTable, MemoryRegion->VirtualBase);\r
183\r
184 while (RemainLength != 0) {\r
185 if (PhysicalBase % TT_DESCRIPTOR_SECTION_SIZE == 0) {\r
186 if (RemainLength >= TT_DESCRIPTOR_SECTION_SIZE) {\r
187 // Case: Physical address aligned on the Section Size (1MB) && the length is greater than the Section Size\r
188 *SectionEntry++ = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(PhysicalBase) | Attributes;\r
189 PhysicalBase += TT_DESCRIPTOR_SECTION_SIZE;\r
190 } else {\r
191 // Case: Physical address aligned on the Section Size (1MB) && the length does not fill a section\r
bd6b9799 192 PopulateLevel2PageTable (SectionEntry++, PhysicalBase, RemainLength, MemoryRegion->Attributes);\r
2cf4b608 193\r
194 // It must be the last entry\r
195 break;\r
196 }\r
197 } else {\r
198 // Case: Physical address NOT aligned on the Section Size (1MB)\r
bd6b9799 199 PopulateLevel2PageTable (SectionEntry++, PhysicalBase, RemainLength, MemoryRegion->Attributes);\r
2cf4b608 200 // Aligned the address\r
201 PhysicalBase = (PhysicalBase + TT_DESCRIPTOR_SECTION_SIZE) & ~(TT_DESCRIPTOR_SECTION_SIZE-1);\r
202\r
203 // If it is the last entry\r
204 if (RemainLength < TT_DESCRIPTOR_SECTION_SIZE) {\r
205 break;\r
206 }\r
207 }\r
208 RemainLength -= TT_DESCRIPTOR_SECTION_SIZE;\r
1bfda055 209 }\r
210}\r
211\r
6f050ad6 212RETURN_STATUS\r
1bfda055 213EFIAPI\r
214ArmConfigureMmu (\r
215 IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable,\r
6f050ad6
OM
216 OUT VOID **TranslationTableBase OPTIONAL,\r
217 OUT UINTN *TranslationTableSize OPTIONAL\r
1bfda055 218 )\r
219{\r
6f050ad6 220 VOID* TranslationTable;\r
1bfda055 221 ARM_MEMORY_REGION_ATTRIBUTES TranslationTableAttribute;\r
222 UINT32 TTBRAttributes;\r
223\r
224 // Allocate pages for translation table.\r
6f050ad6
OM
225 TranslationTable = AllocatePages (EFI_SIZE_TO_PAGES (TRANSLATION_TABLE_SECTION_SIZE + TRANSLATION_TABLE_SECTION_ALIGNMENT));\r
226 if (TranslationTable == NULL) {\r
227 return RETURN_OUT_OF_RESOURCES;\r
228 }\r
229 TranslationTable = (VOID*)(((UINTN)TranslationTable + TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK);\r
1bfda055 230\r
231 if (TranslationTableBase != NULL) {\r
6f050ad6 232 *TranslationTableBase = TranslationTable;\r
1bfda055 233 }\r
234 \r
526099f9 235 if (TranslationTableSize != NULL) {\r
1bfda055 236 *TranslationTableSize = TRANSLATION_TABLE_SECTION_SIZE;\r
237 }\r
238\r
6f050ad6 239 ZeroMem (TranslationTable, TRANSLATION_TABLE_SECTION_SIZE);\r
1bfda055 240\r
6f050ad6
OM
241 // By default, mark the translation table as belonging to a uncached region\r
242 TranslationTableAttribute = ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED;\r
1bfda055 243 while (MemoryTable->Length != 0) {\r
244 // Find the memory attribute for the Translation Table\r
6f050ad6 245 if (((UINTN)TranslationTable >= MemoryTable->PhysicalBase) && ((UINTN)TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) {\r
1bfda055 246 TranslationTableAttribute = MemoryTable->Attributes;\r
247 }\r
248\r
6f050ad6 249 FillTranslationTable (TranslationTable, MemoryTable);\r
1bfda055 250 MemoryTable++;\r
251 }\r
252\r
253 // Translate the Memory Attributes into Translation Table Register Attributes\r
254 if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED) || \r
7fffeef9 255 (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED)) {\r
1bfda055 256 TTBRAttributes = TTBR_NON_CACHEABLE;\r
257 } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) || \r
7fffeef9 258 (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) {\r
1bfda055 259 TTBRAttributes = TTBR_WRITE_BACK_ALLOC;\r
260 } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) || \r
7fffeef9 261 (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) {\r
1bfda055 262 TTBRAttributes = TTBR_WRITE_THROUGH_NO_ALLOC;\r
263 } else {\r
6f050ad6
OM
264 ASSERT (0); // No support has been found for the attributes of the memory region that the translation table belongs to.\r
265 return RETURN_UNSUPPORTED;\r
1bfda055 266 }\r
267\r
ffb91edf
EC
268 ArmCleanInvalidateDataCache ();\r
269 ArmInvalidateInstructionCache ();\r
270\r
271 ArmDisableDataCache ();\r
272 ArmDisableInstructionCache();\r
273 // TLBs are also invalidated when calling ArmDisableMmu()\r
274 ArmDisableMmu ();\r
275\r
276 // Make sure nothing sneaked into the cache\r
277 ArmCleanInvalidateDataCache ();\r
278 ArmInvalidateInstructionCache ();\r
279\r
6f050ad6 280 ArmSetTTBR0 ((VOID *)(UINTN)(((UINTN)TranslationTable & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) | (TTBRAttributes & 0x7F)));\r
1bfda055 281 \r
282 ArmSetDomainAccessControl (DOMAIN_ACCESS_CONTROL_NONE(15) |\r
283 DOMAIN_ACCESS_CONTROL_NONE(14) |\r
284 DOMAIN_ACCESS_CONTROL_NONE(13) |\r
285 DOMAIN_ACCESS_CONTROL_NONE(12) |\r
286 DOMAIN_ACCESS_CONTROL_NONE(11) |\r
287 DOMAIN_ACCESS_CONTROL_NONE(10) |\r
288 DOMAIN_ACCESS_CONTROL_NONE( 9) |\r
289 DOMAIN_ACCESS_CONTROL_NONE( 8) |\r
290 DOMAIN_ACCESS_CONTROL_NONE( 7) |\r
291 DOMAIN_ACCESS_CONTROL_NONE( 6) |\r
292 DOMAIN_ACCESS_CONTROL_NONE( 5) |\r
293 DOMAIN_ACCESS_CONTROL_NONE( 4) |\r
294 DOMAIN_ACCESS_CONTROL_NONE( 3) |\r
295 DOMAIN_ACCESS_CONTROL_NONE( 2) |\r
296 DOMAIN_ACCESS_CONTROL_NONE( 1) |\r
297 DOMAIN_ACCESS_CONTROL_MANAGER(0));\r
298 \r
299 ArmEnableInstructionCache();\r
300 ArmEnableDataCache();\r
301 ArmEnableMmu();\r
6f050ad6 302 return RETURN_SUCCESS;\r
1bfda055 303}\r