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