]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/ArmLib/ArmV7/ArmV7Mmu.c
ArmPkg/ArmLib: Fixed parameter checking in ArmConfigureMmu()
[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
5ed23684 4* Copyright (c) 2011-2012, 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
197VOID\r
198EFIAPI\r
199ArmConfigureMmu (\r
200 IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable,\r
201 OUT VOID **TranslationTableBase OPTIONAL,\r
202 OUT UINTN *TranslationTableSize OPTIONAL\r
203 )\r
204{\r
205 UINTN TranslationTable;\r
206 ARM_MEMORY_REGION_ATTRIBUTES TranslationTableAttribute;\r
207 UINT32 TTBRAttributes;\r
208\r
209 // Allocate pages for translation table.\r
bd6b9799 210 TranslationTable = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES(TRANSLATION_TABLE_SECTION_SIZE + TRANSLATION_TABLE_SECTION_ALIGNMENT));\r
1bfda055 211 TranslationTable = ((UINTN)TranslationTable + TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK;\r
212\r
213 if (TranslationTableBase != NULL) {\r
214 *TranslationTableBase = (VOID *)TranslationTable;\r
215 }\r
216 \r
526099f9 217 if (TranslationTableSize != NULL) {\r
1bfda055 218 *TranslationTableSize = TRANSLATION_TABLE_SECTION_SIZE;\r
219 }\r
220\r
221 ZeroMem ((VOID *)TranslationTable, TRANSLATION_TABLE_SECTION_SIZE);\r
222\r
bd6b9799 223 ArmCleanInvalidateDataCache ();\r
224 ArmInvalidateInstructionCache ();\r
225 ArmInvalidateTlb ();\r
1bfda055 226\r
bd6b9799 227 ArmDisableDataCache ();\r
1bfda055 228 ArmDisableInstructionCache();\r
bd6b9799 229 ArmDisableMmu ();\r
1bfda055 230\r
231 // Make sure nothing sneaked into the cache\r
bd6b9799 232 ArmCleanInvalidateDataCache ();\r
233 ArmInvalidateInstructionCache ();\r
1bfda055 234\r
2cf4b608 235 TranslationTableAttribute = (ARM_MEMORY_REGION_ATTRIBUTES)0;\r
1bfda055 236 while (MemoryTable->Length != 0) {\r
237 // Find the memory attribute for the Translation Table\r
5ed23684 238 if ((TranslationTable >= MemoryTable->PhysicalBase) && (TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) {\r
1bfda055 239 TranslationTableAttribute = MemoryTable->Attributes;\r
240 }\r
241\r
242 FillTranslationTable ((VOID *)TranslationTable, MemoryTable);\r
243 MemoryTable++;\r
244 }\r
245\r
246 // Translate the Memory Attributes into Translation Table Register Attributes\r
247 if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED) || \r
7fffeef9 248 (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED)) {\r
1bfda055 249 TTBRAttributes = TTBR_NON_CACHEABLE;\r
250 } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) || \r
7fffeef9 251 (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) {\r
1bfda055 252 TTBRAttributes = TTBR_WRITE_BACK_ALLOC;\r
253 } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) || \r
7fffeef9 254 (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) {\r
1bfda055 255 TTBRAttributes = TTBR_WRITE_THROUGH_NO_ALLOC;\r
256 } else {\r
257 //TODO: We should raise an error here\r
258 TTBRAttributes = TTBR_NON_CACHEABLE;\r
259 }\r
260\r
7fffeef9 261 ArmSetTTBR0 ((VOID *)(UINTN)((TranslationTable & ~TRANSLATION_TABLE_SECTION_ALIGNMENT_MASK) | (TTBRAttributes & 0x7F)));\r
1bfda055 262 \r
263 ArmSetDomainAccessControl (DOMAIN_ACCESS_CONTROL_NONE(15) |\r
264 DOMAIN_ACCESS_CONTROL_NONE(14) |\r
265 DOMAIN_ACCESS_CONTROL_NONE(13) |\r
266 DOMAIN_ACCESS_CONTROL_NONE(12) |\r
267 DOMAIN_ACCESS_CONTROL_NONE(11) |\r
268 DOMAIN_ACCESS_CONTROL_NONE(10) |\r
269 DOMAIN_ACCESS_CONTROL_NONE( 9) |\r
270 DOMAIN_ACCESS_CONTROL_NONE( 8) |\r
271 DOMAIN_ACCESS_CONTROL_NONE( 7) |\r
272 DOMAIN_ACCESS_CONTROL_NONE( 6) |\r
273 DOMAIN_ACCESS_CONTROL_NONE( 5) |\r
274 DOMAIN_ACCESS_CONTROL_NONE( 4) |\r
275 DOMAIN_ACCESS_CONTROL_NONE( 3) |\r
276 DOMAIN_ACCESS_CONTROL_NONE( 2) |\r
277 DOMAIN_ACCESS_CONTROL_NONE( 1) |\r
278 DOMAIN_ACCESS_CONTROL_MANAGER(0));\r
279 \r
280 ArmEnableInstructionCache();\r
281 ArmEnableDataCache();\r
282 ArmEnableMmu();\r
283}\r