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