]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Library/EblCmdLib/EblCmdMmu.c
Add ArmPlatformPkg from ARM Ltd. patch.
[mirror_edk2.git] / ArmPlatformPkg / Library / EblCmdLib / EblCmdMmu.c
1 /** @file
2 *
3 * Copyright (c) 2011, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include <PiDxe.h>
16 #include <Library/UefiLib.h>
17 #include <Library/ArmLib.h>
18 #include <Chipset/ArmV7.h>
19 #include <Library/CacheMaintenanceLib.h>
20 #include <Library/EblCmdLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/DebugLib.h>
23
24 #define GET_TT_ATTRIBUTES(TTEntry) ((TTEntry) & ~(TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK))
25 #define GET_TT_PAGE_ATTRIBUTES(TTEntry) ((TTEntry) & 0xFFF)
26 #define GET_TT_LARGEPAGE_ATTRIBUTES(TTEntry) ((TTEntry) & 0xFFFF)
27
28 // Section
29 #define TT_DESCRIPTOR_SECTION_STRONGLY_ORDER (TT_DESCRIPTOR_SECTION_TYPE_SECTION | \
30 TT_DESCRIPTOR_SECTION_NS_NON_SECURE | \
31 TT_DESCRIPTOR_SECTION_NG_GLOBAL | \
32 TT_DESCRIPTOR_SECTION_S_NOT_SHARED | \
33 TT_DESCRIPTOR_SECTION_DOMAIN(0) | \
34 TT_DESCRIPTOR_SECTION_AP_RW_RW | \
35 TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED)
36
37 // Small Page
38 #define TT_DESCRIPTOR_PAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
39 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
40 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
41 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
42 TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC)
43 #define TT_DESCRIPTOR_PAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
44 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
45 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
46 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
47 TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
48 #define TT_DESCRIPTOR_PAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
49 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
50 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
51 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
52 TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE)
53 #define TT_DESCRIPTOR_PAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
54 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
55 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
56 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
57 TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE)
58
59 #define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
60 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
61 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
62 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
63 TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED)
64
65 // Large Page
66 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
67 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
68 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
69 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
70 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC)
71 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
72 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
73 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
74 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
75 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
76 #define TT_DESCRIPTOR_LARGEPAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
77 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
78 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
79 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
80 TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE)
81 #define TT_DESCRIPTOR_LARGEPAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
82 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
83 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
84 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
85 TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE)
86
87
88 typedef enum { Level0, Level1,Level2 } MMU_LEVEL;
89
90 typedef struct {
91 MMU_LEVEL Level;
92 UINT32 Value;
93 UINT32 Index;
94 UINT32* Table;
95 } MMU_ENTRY;
96
97 MMU_ENTRY MmuEntryCreate(MMU_LEVEL Level,UINT32* Table,UINT32 Index) {
98 MMU_ENTRY Entry;
99 Entry.Level = Level;
100 Entry.Value = Table[Index];
101 Entry.Table = Table;
102 Entry.Index = Index;
103 return Entry;
104 }
105
106 UINT32 MmuEntryIsValidAddress(MMU_LEVEL Level, UINT32 Entry) {
107 if (Level == Level0) {
108 return 0;
109 } else if (Level == Level1) {
110 if ((Entry & 0x3) == 0) { // Ignored
111 return 0;
112 } else if ((Entry & 0x3) == 2) { // Section Type
113 return 1;
114 } else { // Page Type
115 return 0;
116 }
117 } else if (Level == Level2){
118 if ((Entry & 0x3) == 0) { // Ignored
119 return 0;
120 } else { // Page Type
121 return 1;
122 }
123 } else {
124 DEBUG((EFI_D_ERROR,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32)Level,(UINT32)Entry));
125 ASSERT(0);
126 return 0;
127 }
128 }
129
130 UINT32 MmuEntryGetAddress(MMU_ENTRY Entry) {
131 if (Entry.Level == Level1) {
132 if ((Entry.Value & 0x3) == 0) {
133 return 0;
134 } else if ((Entry.Value & 0x3) == 2) { // Section Type
135 return Entry.Value & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;
136 } else if ((Entry.Value & 0x3) == 1) { // Level2 Table
137 MMU_ENTRY Entry = MmuEntryCreate(Level2,(UINT32*)(Entry.Value & 0xFFFFC000),0);
138 return MmuEntryGetAddress(Entry);
139 } else { // Page Type
140 return 0;
141 }
142 } else if (Entry.Level == Level2) {
143 if ((Entry.Value & 0x3) == 0) { // Ignored
144 return 0;
145 } else if ((Entry.Value & 0x3) == 1) { // Large Page
146 return Entry.Value & 0xFFFF0000;
147 } else if ((Entry.Value & 0x2) == 2) { // Small Page
148 return Entry.Value & 0xFFFFF000;
149 } else {
150 return 0;
151 }
152 } else {
153 ASSERT(0);
154 return 0;
155 }
156 }
157
158 UINT32 MmuEntryGetSize(MMU_ENTRY Entry) {
159 if (Entry.Level == Level1) {
160 if ((Entry.Value & 0x3) == 0) {
161 return 0;
162 } else if ((Entry.Value & 0x3) == 2) {
163 if (Entry.Value & (1 << 18))
164 return 16*SIZE_1MB;
165 else
166 return SIZE_1MB;
167 } else if ((Entry.Value & 0x3) == 1) { // Level2 Table split 1MB section
168 return SIZE_1MB;
169 } else {
170 DEBUG((EFI_D_ERROR, "MmuEntryGetSize: Value:0x%X",Entry.Value));
171 ASSERT(0);
172 return 0;
173 }
174 } else if (Entry.Level == Level2) {
175 if ((Entry.Value & 0x3) == 0) { // Ignored
176 return 0;
177 } else if ((Entry.Value & 0x3) == 1) { // Large Page
178 return SIZE_64KB;
179 } else if ((Entry.Value & 0x2) == 2) { // Small Page
180 return SIZE_4KB;
181 } else {
182 ASSERT(0);
183 return 0;
184 }
185 } else {
186 ASSERT(0);
187 return 0;
188 }
189 }
190
191 CONST CHAR8* MmuEntryGetAttributesName(MMU_ENTRY Entry) {
192 if (Entry.Level == Level1) {
193 if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_WRITE_BACK(0))
194 return "TT_DESCRIPTOR_SECTION_WRITE_BACK";
195 else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0))
196 return "TT_DESCRIPTOR_SECTION_WRITE_THROUGH";
197 else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_DEVICE(0))
198 return "TT_DESCRIPTOR_SECTION_DEVICE";
199 else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_UNCACHED(0))
200 return "TT_DESCRIPTOR_SECTION_UNCACHED";
201 else if (GET_TT_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_SECTION_STRONGLY_ORDER)
202 return "TT_DESCRIPTOR_SECTION_STRONGLY_ORDERED";
203 else {
204 return "SectionUnknown";
205 }
206 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x2) == 2)) { //Small Page
207 if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_BACK)
208 return "TT_DESCRIPTOR_PAGE_WRITE_BACK";
209 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH)
210 return "TT_DESCRIPTOR_PAGE_WRITE_THROUGH";
211 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_DEVICE)
212 return "TT_DESCRIPTOR_PAGE_DEVICE";
213 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_UNCACHED)
214 return "TT_DESCRIPTOR_PAGE_UNCACHED";
215 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER)
216 return "TT_DESCRIPTOR_PAGE_STRONGLY_ORDERED";
217 else {
218 return "PageUnknown";
219 }
220 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x3) == 1)) { //Large Page
221 if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK)
222 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK";
223 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH)
224 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH";
225 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_DEVICE)
226 return "TT_DESCRIPTOR_LARGEPAGE_DEVICE";
227 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED)
228 return "TT_DESCRIPTOR_LARGEPAGE_UNCACHED";
229 else {
230 return "LargePageUnknown";
231 }
232 } else {
233 ASSERT(0);
234 return "";
235 }
236 }
237
238 UINT32 MmuEntryGetAttributes(MMU_ENTRY Entry) {
239 if (Entry.Level == Level1) {
240 if ((Entry.Value & 0x3) == 0) {
241 return 0;
242 } else if ((Entry.Value & 0x3) == 2) {
243 return GET_TT_ATTRIBUTES(Entry.Value);
244 } else {
245 return 0;
246 }
247 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x2) == 2)) { //Small Page
248 if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_BACK)
249 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
250 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH)
251 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
252 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_DEVICE)
253 return TT_DESCRIPTOR_SECTION_DEVICE(0);
254 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_UNCACHED)
255 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
256 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER)
257 return TT_DESCRIPTOR_SECTION_STRONGLY_ORDER;
258 else {
259 return 0;
260 }
261 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x3) == 1)) { //Large Page
262 if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK)
263 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
264 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH)
265 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
266 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_DEVICE)
267 return TT_DESCRIPTOR_SECTION_DEVICE(0);
268 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED)
269 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
270 else {
271 return 0;
272 }
273 } else {
274 return 0;
275 }
276 }
277
278
279 MMU_ENTRY DumpMmuLevel(MMU_LEVEL Level, UINT32* Table, MMU_ENTRY PreviousEntry) {
280 UINT32 Index = 0, Count;
281 MMU_ENTRY LastEntry, Entry;
282
283 ASSERT((Level == Level1) || (Level == Level2));
284
285 if (Level == Level1) Count = 4096;
286 else Count = 256;
287
288 // At Level1, we will get into this function because PreviousEntry is not valid
289 if (!MmuEntryIsValidAddress((MMU_LEVEL)(Level-1),PreviousEntry.Value)) {
290 // Find the first valid address
291 for (; (Index < Count) && (!MmuEntryIsValidAddress(Level,Table[Index])); Index++);
292
293 LastEntry = MmuEntryCreate(Level,Table,Index);
294 Index++;
295 } else {
296 LastEntry = PreviousEntry;
297 }
298
299 for (; Index < Count; Index++) {
300 Entry = MmuEntryCreate(Level,Table,Index);
301 if ((Level == Level1) && ((Entry.Value & 0x3) == 1)) { // We have got a Level2 table redirection
302 LastEntry = DumpMmuLevel(Level2,(UINT32*)(Entry.Value & 0xFFFFFC00),LastEntry);
303 } else if (!MmuEntryIsValidAddress(Level,Table[Index])) {
304 if (MmuEntryIsValidAddress(LastEntry.Level,LastEntry.Value)) {
305 AsciiPrint("0x%08X-0x%08X\t%a\n",
306 MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1,
307 MmuEntryGetAttributesName(LastEntry));
308 }
309 LastEntry = Entry;
310 } else {
311 if (MmuEntryGetAttributes(LastEntry) != MmuEntryGetAttributes(Entry)) {
312 if (MmuEntryIsValidAddress(Level,LastEntry.Value)) {
313 AsciiPrint("0x%08X-0x%08X\t%a\n",
314 MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1,
315 MmuEntryGetAttributesName(LastEntry));
316 }
317 LastEntry = Entry;
318 } else {
319 ASSERT(LastEntry.Value != 0);
320 }
321 }
322 PreviousEntry = Entry;
323 }
324
325 if ((Level == Level1) && (LastEntry.Index != Index) && MmuEntryIsValidAddress(Level,LastEntry.Value)) {
326 AsciiPrint("0x%08X-0x%08X\t%a\n",
327 MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1,
328 MmuEntryGetAttributesName(LastEntry));
329 }
330
331 return LastEntry;
332 }
333
334
335 EFI_STATUS
336 EblDumpMmu (
337 IN UINTN Argc,
338 IN CHAR8 **Argv
339 )
340 {
341 UINT32 *TTEntry;
342 MMU_ENTRY NoEntry;
343
344 TTEntry = ArmGetTTBR0BaseAddress();
345
346 AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry);
347 AsciiPrint ("Address Range\t\tAttributes\n");
348 AsciiPrint ("____________________________________________________\n");
349
350 NoEntry.Level = (MMU_LEVEL)200;
351 DumpMmuLevel(Level1,TTEntry,NoEntry);
352
353 return EFI_SUCCESS;
354 }