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