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