1 /** @file
2 *
3 * Copyright (c) 2011-2012, 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_NG_GLOBAL | \
31 TT_DESCRIPTOR_SECTION_S_NOT_SHARED | \
32 TT_DESCRIPTOR_SECTION_DOMAIN(0) | \
33 TT_DESCRIPTOR_SECTION_AP_RW_RW | \
34 TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED)
35
36 // Small Page
37 #define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
38 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
39 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
40 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
41 TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED)
42
43 // Large Page
44 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
45 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
46 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
47 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
48 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC)
49 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
50 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
51 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
52 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
53 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
54 #define TT_DESCRIPTOR_LARGEPAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
55 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
56 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
57 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
58 TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE)
59 #define TT_DESCRIPTOR_LARGEPAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
60 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
61 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
62 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
63 TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE)
64
65
66 typedef enum { Level0, Level1,Level2 } MMU_LEVEL;
67
68 typedef struct {
69 MMU_LEVEL Level;
70 UINT32 Value;
71 UINT32 Index;
72 UINT32* Table;
73 } MMU_ENTRY;
74
75 MMU_ENTRY
MmuEntryCreate(IN MMU_LEVEL Level,IN UINT32 * Table,IN UINT32 Index)76 MmuEntryCreate (
77 IN MMU_LEVEL Level,
78 IN UINT32* Table,
79 IN UINT32 Index
80 )
81 {
82 MMU_ENTRY Entry;
83 Entry.Level = Level;
84 Entry.Value = Table[Index];
85 Entry.Table = Table;
86 Entry.Index = Index;
87 return Entry;
88 }
89
90 UINT32
MmuEntryIsValidAddress(IN MMU_LEVEL Level,IN UINT32 Entry)91 MmuEntryIsValidAddress (
92 IN MMU_LEVEL Level,
93 IN UINT32 Entry
94 )
95 {
96 if (Level == Level0) {
97 return 0;
98 } else if (Level == Level1) {
99 if ((Entry & 0x3) == 0) { // Ignored
100 return 0;
101 } else if ((Entry & 0x3) == 2) { // Section Type
102 return 1;
103 } else { // Page Type
104 return 0;
105 }
106 } else if (Level == Level2){
107 if ((Entry & 0x3) == 0) { // Ignored
108 return 0;
109 } else { // Page Type
110 return 1;
111 }
112 } else {
113 DEBUG((EFI_D_ERROR,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32)Level,(UINT32)Entry));
114 ASSERT(0);
115 return 0;
116 }
117 }
118
119 UINT32
MmuEntryGetAddress(IN MMU_ENTRY Entry)120 MmuEntryGetAddress (
121 IN MMU_ENTRY Entry
122 )
123 {
124 if (Entry.Level == Level1) {
125 if ((Entry.Value & 0x3) == 0) {
126 return 0;
127 } else if ((Entry.Value & 0x3) == 2) { // Section Type
128 return Entry.Value & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;
129 } else if ((Entry.Value & 0x3) == 1) { // Level2 Table
130 MMU_ENTRY Level2Entry = MmuEntryCreate (Level2,(UINT32*)(Entry.Value & 0xFFFFC000),0);
131 return MmuEntryGetAddress (Level2Entry);
132 } else { // Page Type
133 return 0;
134 }
135 } else if (Entry.Level == Level2) {
136 if ((Entry.Value & 0x3) == 0) { // Ignored
137 return 0;
138 } else if ((Entry.Value & 0x3) == 1) { // Large Page
139 return Entry.Value & 0xFFFF0000;
140 } else if ((Entry.Value & 0x2) == 2) { // Small Page
141 return Entry.Value & 0xFFFFF000;
142 } else {
143 return 0;
144 }
145 } else {
146 ASSERT(0);
147 return 0;
148 }
149 }
150
151 UINT32
MmuEntryGetSize(IN MMU_ENTRY Entry)152 MmuEntryGetSize (
153 IN MMU_ENTRY Entry
154 )
155 {
156 if (Entry.Level == Level1) {
157 if ((Entry.Value & 0x3) == 0) {
158 return 0;
159 } else if ((Entry.Value & 0x3) == 2) {
160 if (Entry.Value & (1 << 18))
161 return 16*SIZE_1MB;
162 else
163 return SIZE_1MB;
164 } else if ((Entry.Value & 0x3) == 1) { // Level2 Table split 1MB section
165 return SIZE_1MB;
166 } else {
167 DEBUG((EFI_D_ERROR, "MmuEntryGetSize: Value:0x%X",Entry.Value));
168 ASSERT(0);
169 return 0;
170 }
171 } else if (Entry.Level == Level2) {
172 if ((Entry.Value & 0x3) == 0) { // Ignored
173 return 0;
174 } else if ((Entry.Value & 0x3) == 1) { // Large Page
175 return SIZE_64KB;
176 } else if ((Entry.Value & 0x2) == 2) { // Small Page
177 return SIZE_4KB;
178 } else {
179 ASSERT(0);
180 return 0;
181 }
182 } else {
183 ASSERT(0);
184 return 0;
185 }
186 }
187
188 CONST CHAR8*
MmuEntryGetAttributesName(IN MMU_ENTRY Entry)189 MmuEntryGetAttributesName (
190 IN MMU_ENTRY Entry
191 )
192 {
193 UINT32 Value;
194
195 if (Entry.Level == Level1) {
196 Value = GET_TT_ATTRIBUTES(Entry.Value) | TT_DESCRIPTOR_SECTION_NS_MASK;
197 if (Value == TT_DESCRIPTOR_SECTION_WRITE_BACK(0))
198 return "TT_DESCRIPTOR_SECTION_WRITE_BACK";
199 else if (Value == TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0))
200 return "TT_DESCRIPTOR_SECTION_WRITE_THROUGH";
201 else if (Value == TT_DESCRIPTOR_SECTION_DEVICE(0))
202 return "TT_DESCRIPTOR_SECTION_DEVICE";
203 else if (Value == TT_DESCRIPTOR_SECTION_UNCACHED(0))
204 return "TT_DESCRIPTOR_SECTION_UNCACHED";
205 else if (Value == TT_DESCRIPTOR_SECTION_STRONGLY_ORDER)
206 return "TT_DESCRIPTOR_SECTION_STRONGLY_ORDERED";
207 else {
208 return "SectionUnknown";
209 }
210 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x2) == 2)) { //Small Page
211 Value = GET_TT_PAGE_ATTRIBUTES(Entry.Value);
212 if (Value == TT_DESCRIPTOR_PAGE_WRITE_BACK)
213 return "TT_DESCRIPTOR_PAGE_WRITE_BACK";
214 else if (Value == TT_DESCRIPTOR_PAGE_WRITE_THROUGH)
215 return "TT_DESCRIPTOR_PAGE_WRITE_THROUGH";
216 else if (Value == TT_DESCRIPTOR_PAGE_DEVICE)
217 return "TT_DESCRIPTOR_PAGE_DEVICE";
218 else if (Value == TT_DESCRIPTOR_PAGE_UNCACHED)
219 return "TT_DESCRIPTOR_PAGE_UNCACHED";
220 else if (Value == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER)
221 return "TT_DESCRIPTOR_PAGE_STRONGLY_ORDERED";
222 else {
223 return "PageUnknown";
224 }
225 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x3) == 1)) { //Large Page
226 Value = GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value);
227 if (Value == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK)
228 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK";
229 else if (Value == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH)
230 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH";
231 else if (Value == TT_DESCRIPTOR_LARGEPAGE_DEVICE)
232 return "TT_DESCRIPTOR_LARGEPAGE_DEVICE";
233 else if (Value == TT_DESCRIPTOR_LARGEPAGE_UNCACHED)
234 return "TT_DESCRIPTOR_LARGEPAGE_UNCACHED";
235 else {
236 return "LargePageUnknown";
237 }
238 } else {
239 ASSERT(0);
240 return "";
241 }
242 }
243
244 UINT32
MmuEntryGetAttributes(IN MMU_ENTRY Entry)245 MmuEntryGetAttributes (
246 IN MMU_ENTRY Entry
247 )
248 {
249 if (Entry.Level == Level1) {
250 if ((Entry.Value & 0x3) == 0) {
251 return 0;
252 } else if ((Entry.Value & 0x3) == 2) {
253 return GET_TT_ATTRIBUTES(Entry.Value);
254 } else {
255 return 0;
256 }
257 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x2) == 2)) { //Small Page
258 if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_BACK)
259 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
260 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH)
261 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
262 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_DEVICE)
263 return TT_DESCRIPTOR_SECTION_DEVICE(0);
264 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_UNCACHED)
265 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
266 else if (GET_TT_PAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER)
267 return TT_DESCRIPTOR_SECTION_STRONGLY_ORDER;
268 else {
269 return 0;
270 }
271 } else if ((Entry.Level == Level2) && ((Entry.Value & 0x3) == 1)) { //Large Page
272 if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK)
273 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
274 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH)
275 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
276 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_DEVICE)
277 return TT_DESCRIPTOR_SECTION_DEVICE(0);
278 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry.Value) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED)
279 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
280 else {
281 return 0;
282 }
283 } else {
284 return 0;
285 }
286 }
287
288
289 MMU_ENTRY
DumpMmuLevel(IN MMU_LEVEL Level,IN UINT32 * Table,IN MMU_ENTRY PreviousEntry)290 DumpMmuLevel (
291 IN MMU_LEVEL Level,
292 IN UINT32* Table,
293 IN MMU_ENTRY PreviousEntry
294 )
295 {
296 UINT32 Index = 0, Count;
297 MMU_ENTRY LastEntry, Entry;
298
299 ASSERT((Level == Level1) || (Level == Level2));
300
301 if (Level == Level1) Count = 4096;
302 else Count = 256;
303
304 // At Level1, we will get into this function because PreviousEntry is not valid
305 if (!MmuEntryIsValidAddress((MMU_LEVEL)(Level-1),PreviousEntry.Value)) {
306 // Find the first valid address
307 for (; (Index < Count) && (!MmuEntryIsValidAddress(Level,Table[Index])); Index++);
308
309 LastEntry = MmuEntryCreate(Level,Table,Index);
310 Index++;
311 } else {
312 LastEntry = PreviousEntry;
313 }
314
315 for (; Index < Count; Index++) {
316 Entry = MmuEntryCreate(Level,Table,Index);
317 if ((Level == Level1) && ((Entry.Value & 0x3) == 1)) { // We have got a Level2 table redirection
318 LastEntry = DumpMmuLevel(Level2,(UINT32*)(Entry.Value & 0xFFFFFC00),LastEntry);
319 } else if (!MmuEntryIsValidAddress(Level,Table[Index])) {
320 if (MmuEntryIsValidAddress(LastEntry.Level,LastEntry.Value)) {
321 AsciiPrint("0x%08X-0x%08X\t%a\n",
322 MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1,
323 MmuEntryGetAttributesName(LastEntry));
324 }
325 LastEntry = Entry;
326 } else {
327 if (MmuEntryGetAttributes(LastEntry) != MmuEntryGetAttributes(Entry)) {
328 if (MmuEntryIsValidAddress(Level,LastEntry.Value)) {
329 AsciiPrint("0x%08X-0x%08X\t%a\n",
330 MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1,
331 MmuEntryGetAttributesName(LastEntry));
332 }
333 LastEntry = Entry;
334 } else {
335 ASSERT(LastEntry.Value != 0);
336 }
337 }
338 PreviousEntry = Entry;
339 }
340
341 if ((Level == Level1) && (LastEntry.Index != Index) && MmuEntryIsValidAddress(Level,LastEntry.Value)) {
342 AsciiPrint("0x%08X-0x%08X\t%a\n",
343 MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1,
344 MmuEntryGetAttributesName(LastEntry));
345 }
346
347 return LastEntry;
348 }
349
350
351 EFI_STATUS
EblDumpMmu(IN UINTN Argc,IN CHAR8 ** Argv)352 EblDumpMmu (
353 IN UINTN Argc,
354 IN CHAR8 **Argv
355 )
356 {
357 UINT32 *TTEntry;
358 MMU_ENTRY NoEntry;
359
360 TTEntry = ArmGetTTBR0BaseAddress();
361
362 AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry);
363 AsciiPrint ("Address Range\t\tAttributes\n");
364 AsciiPrint ("____________________________________________________\n");
365
366 NoEntry.Level = (MMU_LEVEL)200;
367 DumpMmuLevel(Level1,TTEntry,NoEntry);
368
369 return EFI_SUCCESS;
370 }
371