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