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_WRITE_BACK (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_WRITE_BACK_ALLOC)
43 #define TT_DESCRIPTOR_PAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
44 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
45 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
46 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
47 TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
48 #define TT_DESCRIPTOR_PAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
49 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
50 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
51 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
52 TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE)
53 #define TT_DESCRIPTOR_PAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
54 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
55 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
56 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
57 TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE)
59 #define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
60 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
61 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
62 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
63 TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED)
66 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
67 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
68 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
69 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
70 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC)
71 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
72 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
73 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
74 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
75 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
76 #define TT_DESCRIPTOR_LARGEPAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
77 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
78 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
79 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
80 TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE)
81 #define TT_DESCRIPTOR_LARGEPAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
82 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
83 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
84 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
85 TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE)
88 typedef enum { Level0
, Level1
,Level2
} MMU_LEVEL
;
97 MMU_ENTRY
MmuEntryCreate(MMU_LEVEL Level
,UINT32
* Table
,UINT32 Index
) {
100 Entry
.Value
= Table
[Index
];
106 UINT32
MmuEntryIsValidAddress(MMU_LEVEL Level
, UINT32 Entry
) {
107 if (Level
== Level0
) {
109 } else if (Level
== Level1
) {
110 if ((Entry
& 0x3) == 0) { // Ignored
112 } else if ((Entry
& 0x3) == 2) { // Section Type
114 } else { // Page Type
117 } else if (Level
== Level2
){
118 if ((Entry
& 0x3) == 0) { // Ignored
120 } else { // Page Type
124 DEBUG((EFI_D_ERROR
,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32
)Level
,(UINT32
)Entry
));
130 UINT32
MmuEntryGetAddress(MMU_ENTRY Entry
) {
131 if (Entry
.Level
== Level1
) {
132 if ((Entry
.Value
& 0x3) == 0) {
134 } else if ((Entry
.Value
& 0x3) == 2) { // Section Type
135 return Entry
.Value
& TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK
;
136 } else if ((Entry
.Value
& 0x3) == 1) { // Level2 Table
137 MMU_ENTRY Entry
= MmuEntryCreate(Level2
,(UINT32
*)(Entry
.Value
& 0xFFFFC000),0);
138 return MmuEntryGetAddress(Entry
);
139 } else { // Page Type
142 } else if (Entry
.Level
== Level2
) {
143 if ((Entry
.Value
& 0x3) == 0) { // Ignored
145 } else if ((Entry
.Value
& 0x3) == 1) { // Large Page
146 return Entry
.Value
& 0xFFFF0000;
147 } else if ((Entry
.Value
& 0x2) == 2) { // Small Page
148 return Entry
.Value
& 0xFFFFF000;
158 UINT32
MmuEntryGetSize(MMU_ENTRY Entry
) {
159 if (Entry
.Level
== Level1
) {
160 if ((Entry
.Value
& 0x3) == 0) {
162 } else if ((Entry
.Value
& 0x3) == 2) {
163 if (Entry
.Value
& (1 << 18))
167 } else if ((Entry
.Value
& 0x3) == 1) { // Level2 Table split 1MB section
170 DEBUG((EFI_D_ERROR
, "MmuEntryGetSize: Value:0x%X",Entry
.Value
));
174 } else if (Entry
.Level
== Level2
) {
175 if ((Entry
.Value
& 0x3) == 0) { // Ignored
177 } else if ((Entry
.Value
& 0x3) == 1) { // Large Page
179 } else if ((Entry
.Value
& 0x2) == 2) { // Small Page
191 CONST CHAR8
* MmuEntryGetAttributesName(MMU_ENTRY Entry
) {
192 if (Entry
.Level
== Level1
) {
193 if (GET_TT_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_SECTION_WRITE_BACK(0))
194 return "TT_DESCRIPTOR_SECTION_WRITE_BACK";
195 else if (GET_TT_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0))
196 return "TT_DESCRIPTOR_SECTION_WRITE_THROUGH";
197 else if (GET_TT_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_SECTION_DEVICE(0))
198 return "TT_DESCRIPTOR_SECTION_DEVICE";
199 else if (GET_TT_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_SECTION_UNCACHED(0))
200 return "TT_DESCRIPTOR_SECTION_UNCACHED";
201 else if (GET_TT_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_SECTION_STRONGLY_ORDER
)
202 return "TT_DESCRIPTOR_SECTION_STRONGLY_ORDERED";
204 return "SectionUnknown";
206 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x2) == 2)) { //Small Page
207 if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_WRITE_BACK
)
208 return "TT_DESCRIPTOR_PAGE_WRITE_BACK";
209 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH
)
210 return "TT_DESCRIPTOR_PAGE_WRITE_THROUGH";
211 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_DEVICE
)
212 return "TT_DESCRIPTOR_PAGE_DEVICE";
213 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_UNCACHED
)
214 return "TT_DESCRIPTOR_PAGE_UNCACHED";
215 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER
)
216 return "TT_DESCRIPTOR_PAGE_STRONGLY_ORDERED";
218 return "PageUnknown";
220 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x3) == 1)) { //Large Page
221 if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK
)
222 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK";
223 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH
)
224 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH";
225 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_DEVICE
)
226 return "TT_DESCRIPTOR_LARGEPAGE_DEVICE";
227 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED
)
228 return "TT_DESCRIPTOR_LARGEPAGE_UNCACHED";
230 return "LargePageUnknown";
238 UINT32
MmuEntryGetAttributes(MMU_ENTRY Entry
) {
239 if (Entry
.Level
== Level1
) {
240 if ((Entry
.Value
& 0x3) == 0) {
242 } else if ((Entry
.Value
& 0x3) == 2) {
243 return GET_TT_ATTRIBUTES(Entry
.Value
);
247 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x2) == 2)) { //Small Page
248 if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_WRITE_BACK
)
249 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
250 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH
)
251 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
252 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_DEVICE
)
253 return TT_DESCRIPTOR_SECTION_DEVICE(0);
254 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_UNCACHED
)
255 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
256 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER
)
257 return TT_DESCRIPTOR_SECTION_STRONGLY_ORDER
;
261 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x3) == 1)) { //Large Page
262 if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK
)
263 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
264 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH
)
265 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
266 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_DEVICE
)
267 return TT_DESCRIPTOR_SECTION_DEVICE(0);
268 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED
)
269 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
279 MMU_ENTRY
DumpMmuLevel(MMU_LEVEL Level
, UINT32
* Table
, MMU_ENTRY PreviousEntry
) {
280 UINT32 Index
= 0, Count
;
281 MMU_ENTRY LastEntry
, Entry
;
283 ASSERT((Level
== Level1
) || (Level
== Level2
));
285 if (Level
== Level1
) Count
= 4096;
288 // At Level1, we will get into this function because PreviousEntry is not valid
289 if (!MmuEntryIsValidAddress((MMU_LEVEL
)(Level
-1),PreviousEntry
.Value
)) {
290 // Find the first valid address
291 for (; (Index
< Count
) && (!MmuEntryIsValidAddress(Level
,Table
[Index
])); Index
++);
293 LastEntry
= MmuEntryCreate(Level
,Table
,Index
);
296 LastEntry
= PreviousEntry
;
299 for (; Index
< Count
; Index
++) {
300 Entry
= MmuEntryCreate(Level
,Table
,Index
);
301 if ((Level
== Level1
) && ((Entry
.Value
& 0x3) == 1)) { // We have got a Level2 table redirection
302 LastEntry
= DumpMmuLevel(Level2
,(UINT32
*)(Entry
.Value
& 0xFFFFFC00),LastEntry
);
303 } else if (!MmuEntryIsValidAddress(Level
,Table
[Index
])) {
304 if (MmuEntryIsValidAddress(LastEntry
.Level
,LastEntry
.Value
)) {
305 AsciiPrint("0x%08X-0x%08X\t%a\n",
306 MmuEntryGetAddress(LastEntry
),MmuEntryGetAddress(PreviousEntry
)+MmuEntryGetSize(PreviousEntry
)-1,
307 MmuEntryGetAttributesName(LastEntry
));
311 if (MmuEntryGetAttributes(LastEntry
) != MmuEntryGetAttributes(Entry
)) {
312 if (MmuEntryIsValidAddress(Level
,LastEntry
.Value
)) {
313 AsciiPrint("0x%08X-0x%08X\t%a\n",
314 MmuEntryGetAddress(LastEntry
),MmuEntryGetAddress(PreviousEntry
)+MmuEntryGetSize(PreviousEntry
)-1,
315 MmuEntryGetAttributesName(LastEntry
));
319 ASSERT(LastEntry
.Value
!= 0);
322 PreviousEntry
= Entry
;
325 if ((Level
== Level1
) && (LastEntry
.Index
!= Index
) && MmuEntryIsValidAddress(Level
,LastEntry
.Value
)) {
326 AsciiPrint("0x%08X-0x%08X\t%a\n",
327 MmuEntryGetAddress(LastEntry
),MmuEntryGetAddress(PreviousEntry
)+MmuEntryGetSize(PreviousEntry
)-1,
328 MmuEntryGetAttributesName(LastEntry
));
344 TTEntry
= ArmGetTTBR0BaseAddress();
346 AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry
);
347 AsciiPrint ("Address Range\t\tAttributes\n");
348 AsciiPrint ("____________________________________________________\n");
350 NoEntry
.Level
= (MMU_LEVEL
)200;
351 DumpMmuLevel(Level1
,TTEntry
,NoEntry
);