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