3 * Copyright (c) 2011-2012, 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_NG_GLOBAL | \
31 TT_DESCRIPTOR_SECTION_S_NOT_SHARED | \
32 TT_DESCRIPTOR_SECTION_DOMAIN(0) | \
33 TT_DESCRIPTOR_SECTION_AP_RW_RW | \
34 TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED)
37 #define TT_DESCRIPTOR_PAGE_STRONGLY_ORDER (TT_DESCRIPTOR_PAGE_TYPE_PAGE | \
38 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
39 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
40 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
41 TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED)
44 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
45 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
46 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
47 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
48 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC)
49 #define TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
50 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
51 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
52 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
53 TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC)
54 #define TT_DESCRIPTOR_LARGEPAGE_DEVICE (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
55 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
56 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
57 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
58 TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE)
59 #define TT_DESCRIPTOR_LARGEPAGE_UNCACHED (TT_DESCRIPTOR_PAGE_TYPE_LARGEPAGE | \
60 TT_DESCRIPTOR_PAGE_NG_GLOBAL | \
61 TT_DESCRIPTOR_PAGE_S_NOT_SHARED | \
62 TT_DESCRIPTOR_PAGE_AP_RW_RW | \
63 TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE)
66 typedef enum { Level0
, Level1
,Level2
} MMU_LEVEL
;
84 Entry
.Value
= Table
[Index
];
91 MmuEntryIsValidAddress (
96 if (Level
== Level0
) {
98 } else if (Level
== Level1
) {
99 if ((Entry
& 0x3) == 0) { // Ignored
101 } else if ((Entry
& 0x3) == 2) { // Section Type
103 } else { // Page Type
106 } else if (Level
== Level2
){
107 if ((Entry
& 0x3) == 0) { // Ignored
109 } else { // Page Type
113 DEBUG((EFI_D_ERROR
,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32
)Level
,(UINT32
)Entry
));
124 if (Entry
.Level
== Level1
) {
125 if ((Entry
.Value
& 0x3) == 0) {
127 } else if ((Entry
.Value
& 0x3) == 2) { // Section Type
128 return Entry
.Value
& TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK
;
129 } else if ((Entry
.Value
& 0x3) == 1) { // Level2 Table
130 MMU_ENTRY Level2Entry
= MmuEntryCreate (Level2
,(UINT32
*)(Entry
.Value
& 0xFFFFC000),0);
131 return MmuEntryGetAddress (Level2Entry
);
132 } else { // Page Type
135 } else if (Entry
.Level
== Level2
) {
136 if ((Entry
.Value
& 0x3) == 0) { // Ignored
138 } else if ((Entry
.Value
& 0x3) == 1) { // Large Page
139 return Entry
.Value
& 0xFFFF0000;
140 } else if ((Entry
.Value
& 0x2) == 2) { // Small Page
141 return Entry
.Value
& 0xFFFFF000;
156 if (Entry
.Level
== Level1
) {
157 if ((Entry
.Value
& 0x3) == 0) {
159 } else if ((Entry
.Value
& 0x3) == 2) {
160 if (Entry
.Value
& (1 << 18))
164 } else if ((Entry
.Value
& 0x3) == 1) { // Level2 Table split 1MB section
167 DEBUG((EFI_D_ERROR
, "MmuEntryGetSize: Value:0x%X",Entry
.Value
));
171 } else if (Entry
.Level
== Level2
) {
172 if ((Entry
.Value
& 0x3) == 0) { // Ignored
174 } else if ((Entry
.Value
& 0x3) == 1) { // Large Page
176 } else if ((Entry
.Value
& 0x2) == 2) { // Small Page
189 MmuEntryGetAttributesName (
195 if (Entry
.Level
== Level1
) {
196 Value
= GET_TT_ATTRIBUTES(Entry
.Value
) | TT_DESCRIPTOR_SECTION_NS_MASK
;
197 if (Value
== TT_DESCRIPTOR_SECTION_WRITE_BACK(0))
198 return "TT_DESCRIPTOR_SECTION_WRITE_BACK";
199 else if (Value
== TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0))
200 return "TT_DESCRIPTOR_SECTION_WRITE_THROUGH";
201 else if (Value
== TT_DESCRIPTOR_SECTION_DEVICE(0))
202 return "TT_DESCRIPTOR_SECTION_DEVICE";
203 else if (Value
== TT_DESCRIPTOR_SECTION_UNCACHED(0))
204 return "TT_DESCRIPTOR_SECTION_UNCACHED";
205 else if (Value
== TT_DESCRIPTOR_SECTION_STRONGLY_ORDER
)
206 return "TT_DESCRIPTOR_SECTION_STRONGLY_ORDERED";
208 return "SectionUnknown";
210 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x2) == 2)) { //Small Page
211 Value
= GET_TT_PAGE_ATTRIBUTES(Entry
.Value
);
212 if (Value
== TT_DESCRIPTOR_PAGE_WRITE_BACK
)
213 return "TT_DESCRIPTOR_PAGE_WRITE_BACK";
214 else if (Value
== TT_DESCRIPTOR_PAGE_WRITE_THROUGH
)
215 return "TT_DESCRIPTOR_PAGE_WRITE_THROUGH";
216 else if (Value
== TT_DESCRIPTOR_PAGE_DEVICE
)
217 return "TT_DESCRIPTOR_PAGE_DEVICE";
218 else if (Value
== TT_DESCRIPTOR_PAGE_UNCACHED
)
219 return "TT_DESCRIPTOR_PAGE_UNCACHED";
220 else if (Value
== TT_DESCRIPTOR_PAGE_STRONGLY_ORDER
)
221 return "TT_DESCRIPTOR_PAGE_STRONGLY_ORDERED";
223 return "PageUnknown";
225 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x3) == 1)) { //Large Page
226 Value
= GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
);
227 if (Value
== TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK
)
228 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK";
229 else if (Value
== TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH
)
230 return "TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH";
231 else if (Value
== TT_DESCRIPTOR_LARGEPAGE_DEVICE
)
232 return "TT_DESCRIPTOR_LARGEPAGE_DEVICE";
233 else if (Value
== TT_DESCRIPTOR_LARGEPAGE_UNCACHED
)
234 return "TT_DESCRIPTOR_LARGEPAGE_UNCACHED";
236 return "LargePageUnknown";
245 MmuEntryGetAttributes (
249 if (Entry
.Level
== Level1
) {
250 if ((Entry
.Value
& 0x3) == 0) {
252 } else if ((Entry
.Value
& 0x3) == 2) {
253 return GET_TT_ATTRIBUTES(Entry
.Value
);
257 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x2) == 2)) { //Small Page
258 if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_WRITE_BACK
)
259 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
260 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_WRITE_THROUGH
)
261 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
262 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_DEVICE
)
263 return TT_DESCRIPTOR_SECTION_DEVICE(0);
264 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_UNCACHED
)
265 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
266 else if (GET_TT_PAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_PAGE_STRONGLY_ORDER
)
267 return TT_DESCRIPTOR_SECTION_STRONGLY_ORDER
;
271 } else if ((Entry
.Level
== Level2
) && ((Entry
.Value
& 0x3) == 1)) { //Large Page
272 if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_WRITE_BACK
)
273 return TT_DESCRIPTOR_SECTION_WRITE_BACK(0);
274 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_WRITE_THROUGH
)
275 return TT_DESCRIPTOR_SECTION_WRITE_THROUGH(0);
276 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_DEVICE
)
277 return TT_DESCRIPTOR_SECTION_DEVICE(0);
278 else if (GET_TT_LARGEPAGE_ATTRIBUTES(Entry
.Value
) == TT_DESCRIPTOR_LARGEPAGE_UNCACHED
)
279 return TT_DESCRIPTOR_SECTION_UNCACHED(0);
293 IN MMU_ENTRY PreviousEntry
296 UINT32 Index
= 0, Count
;
297 MMU_ENTRY LastEntry
, Entry
;
299 ASSERT((Level
== Level1
) || (Level
== Level2
));
301 if (Level
== Level1
) Count
= 4096;
304 // At Level1, we will get into this function because PreviousEntry is not valid
305 if (!MmuEntryIsValidAddress((MMU_LEVEL
)(Level
-1),PreviousEntry
.Value
)) {
306 // Find the first valid address
307 for (; (Index
< Count
) && (!MmuEntryIsValidAddress(Level
,Table
[Index
])); Index
++);
309 LastEntry
= MmuEntryCreate(Level
,Table
,Index
);
312 LastEntry
= PreviousEntry
;
315 for (; Index
< Count
; Index
++) {
316 Entry
= MmuEntryCreate(Level
,Table
,Index
);
317 if ((Level
== Level1
) && ((Entry
.Value
& 0x3) == 1)) { // We have got a Level2 table redirection
318 LastEntry
= DumpMmuLevel(Level2
,(UINT32
*)(Entry
.Value
& 0xFFFFFC00),LastEntry
);
319 } else if (!MmuEntryIsValidAddress(Level
,Table
[Index
])) {
320 if (MmuEntryIsValidAddress(LastEntry
.Level
,LastEntry
.Value
)) {
321 AsciiPrint("0x%08X-0x%08X\t%a\n",
322 MmuEntryGetAddress(LastEntry
),MmuEntryGetAddress(PreviousEntry
)+MmuEntryGetSize(PreviousEntry
)-1,
323 MmuEntryGetAttributesName(LastEntry
));
327 if (MmuEntryGetAttributes(LastEntry
) != MmuEntryGetAttributes(Entry
)) {
328 if (MmuEntryIsValidAddress(Level
,LastEntry
.Value
)) {
329 AsciiPrint("0x%08X-0x%08X\t%a\n",
330 MmuEntryGetAddress(LastEntry
),MmuEntryGetAddress(PreviousEntry
)+MmuEntryGetSize(PreviousEntry
)-1,
331 MmuEntryGetAttributesName(LastEntry
));
335 ASSERT(LastEntry
.Value
!= 0);
338 PreviousEntry
= Entry
;
341 if ((Level
== Level1
) && (LastEntry
.Index
!= Index
) && MmuEntryIsValidAddress(Level
,LastEntry
.Value
)) {
342 AsciiPrint("0x%08X-0x%08X\t%a\n",
343 MmuEntryGetAddress(LastEntry
),MmuEntryGetAddress(PreviousEntry
)+MmuEntryGetSize(PreviousEntry
)-1,
344 MmuEntryGetAttributesName(LastEntry
));
360 TTEntry
= ArmGetTTBR0BaseAddress();
362 AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry
);
363 AsciiPrint ("Address Range\t\tAttributes\n");
364 AsciiPrint ("____________________________________________________\n");
366 NoEntry
.Level
= (MMU_LEVEL
)200;
367 DumpMmuLevel(Level1
,TTEntry
,NoEntry
);