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