3 * Copyright (c) 2011, ARM Limited. All rights reserved.
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
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.
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>
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)
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)
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)
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)
67 typedef enum { Level0
, Level1
,Level2
} MMU_LEVEL
;
85 Entry
.Value
= Table
[Index
];
92 MmuEntryIsValidAddress (
97 if (Level
== Level0
) {
99 } else if (Level
== Level1
) {
100 if ((Entry
& 0x3) == 0) { // Ignored
102 } else if ((Entry
& 0x3) == 2) { // Section Type
104 } else { // Page Type
107 } else if (Level
== Level2
){
108 if ((Entry
& 0x3) == 0) { // Ignored
110 } else { // Page Type
114 DEBUG((EFI_D_ERROR
,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32
)Level
,(UINT32
)Entry
));
125 if (Entry
.Level
== Level1
) {
126 if ((Entry
.Value
& 0x3) == 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
136 } else if (Entry
.Level
== Level2
) {
137 if ((Entry
.Value
& 0x3) == 0) { // Ignored
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;
157 if (Entry
.Level
== Level1
) {
158 if ((Entry
.Value
& 0x3) == 0) {
160 } else if ((Entry
.Value
& 0x3) == 2) {
161 if (Entry
.Value
& (1 << 18))
165 } else if ((Entry
.Value
& 0x3) == 1) { // Level2 Table split 1MB section
168 DEBUG((EFI_D_ERROR
, "MmuEntryGetSize: Value:0x%X",Entry
.Value
));
172 } else if (Entry
.Level
== Level2
) {
173 if ((Entry
.Value
& 0x3) == 0) { // Ignored
175 } else if ((Entry
.Value
& 0x3) == 1) { // Large Page
177 } else if ((Entry
.Value
& 0x2) == 2) { // Small Page
190 MmuEntryGetAttributesName (
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";
209 return "SectionUnknown";
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";
224 return "PageUnknown";
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";
237 return "LargePageUnknown";
246 MmuEntryGetAttributes (
250 if (Entry
.Level
== Level1
) {
251 if ((Entry
.Value
& 0x3) == 0) {
253 } else if ((Entry
.Value
& 0x3) == 2) {
254 return GET_TT_ATTRIBUTES(Entry
.Value
);
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
;
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);
294 IN MMU_ENTRY PreviousEntry
297 UINT32 Index
= 0, Count
;
298 MMU_ENTRY LastEntry
, Entry
;
300 ASSERT((Level
== Level1
) || (Level
== Level2
));
302 if (Level
== Level1
) Count
= 4096;
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
++);
310 LastEntry
= MmuEntryCreate(Level
,Table
,Index
);
313 LastEntry
= PreviousEntry
;
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
));
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
));
336 ASSERT(LastEntry
.Value
!= 0);
339 PreviousEntry
= Entry
;
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
));
361 TTEntry
= ArmGetTTBR0BaseAddress();
363 AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry
);
364 AsciiPrint ("Address Range\t\tAttributes\n");
365 AsciiPrint ("____________________________________________________\n");
367 NoEntry
.Level
= (MMU_LEVEL
)200;
368 DumpMmuLevel(Level1
,TTEntry
,NoEntry
);