1/** @file 2* 3* Copyright (c) 2011-2012, 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_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) 35 36// Small Page 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) 42 43// Large Page 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) 64 65 66typedef enum { Level0, Level1,Level2 } MMU_LEVEL; 67 68typedef struct { 69 MMU_LEVEL Level; 70 UINT32 Value; 71 UINT32 Index; 72 UINT32* Table; 73} MMU_ENTRY; 74 75MMU_ENTRY 76MmuEntryCreate ( 77 IN MMU_LEVEL Level, 78 IN UINT32* Table, 79 IN UINT32 Index 80 ) 81{ 82 MMU_ENTRY Entry; 83 Entry.Level = Level; 84 Entry.Value = Table[Index]; 85 Entry.Table = Table; 86 Entry.Index = Index; 87 return Entry; 88} 89 90UINT32 91MmuEntryIsValidAddress ( 92 IN MMU_LEVEL Level, 93 IN UINT32 Entry 94 ) 95{ 96 if (Level == Level0) { 97 return 0; 98 } else if (Level == Level1) { 99 if ((Entry & 0x3) == 0) { // Ignored 100 return 0; 101 } else if ((Entry & 0x3) == 2) { // Section Type 102 return 1; 103 } else { // Page Type 104 return 0; 105 } 106 } else if (Level == Level2){ 107 if ((Entry & 0x3) == 0) { // Ignored 108 return 0; 109 } else { // Page Type 110 return 1; 111 } 112 } else { 113 DEBUG((EFI_D_ERROR,"MmuEntryIsValidAddress: Level:%d Entry:0x%X\n",(UINT32)Level,(UINT32)Entry)); 114 ASSERT(0); 115 return 0; 116 } 117} 118 119UINT32 120MmuEntryGetAddress ( 121 IN MMU_ENTRY Entry 122 ) 123{ 124 if (Entry.Level == Level1) { 125 if ((Entry.Value & 0x3) == 0) { 126 return 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 133 return 0; 134 } 135 } else if (Entry.Level == Level2) { 136 if ((Entry.Value & 0x3) == 0) { // Ignored 137 return 0; 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; 142 } else { 143 return 0; 144 } 145 } else { 146 ASSERT(0); 147 return 0; 148 } 149} 150 151UINT32 152MmuEntryGetSize ( 153 IN MMU_ENTRY Entry 154 ) 155{ 156 if (Entry.Level == Level1) { 157 if ((Entry.Value & 0x3) == 0) { 158 return 0; 159 } else if ((Entry.Value & 0x3) == 2) { 160 if (Entry.Value & (1 << 18)) 161 return 16*SIZE_1MB; 162 else 163 return SIZE_1MB; 164 } else if ((Entry.Value & 0x3) == 1) { // Level2 Table split 1MB section 165 return SIZE_1MB; 166 } else { 167 DEBUG((EFI_D_ERROR, "MmuEntryGetSize: Value:0x%X",Entry.Value)); 168 ASSERT(0); 169 return 0; 170 } 171 } else if (Entry.Level == Level2) { 172 if ((Entry.Value & 0x3) == 0) { // Ignored 173 return 0; 174 } else if ((Entry.Value & 0x3) == 1) { // Large Page 175 return SIZE_64KB; 176 } else if ((Entry.Value & 0x2) == 2) { // Small Page 177 return SIZE_4KB; 178 } else { 179 ASSERT(0); 180 return 0; 181 } 182 } else { 183 ASSERT(0); 184 return 0; 185 } 186} 187 188CONST CHAR8* 189MmuEntryGetAttributesName ( 190 IN MMU_ENTRY Entry 191 ) 192{ 193 UINT32 Value; 194 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"; 207 else { 208 return "SectionUnknown"; 209 } 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"; 222 else { 223 return "PageUnknown"; 224 } 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"; 235 else { 236 return "LargePageUnknown"; 237 } 238 } else { 239 ASSERT(0); 240 return ""; 241 } 242} 243 244UINT32 245MmuEntryGetAttributes ( 246 IN MMU_ENTRY Entry 247 ) 248{ 249 if (Entry.Level == Level1) { 250 if ((Entry.Value & 0x3) == 0) { 251 return 0; 252 } else if ((Entry.Value & 0x3) == 2) { 253 return GET_TT_ATTRIBUTES(Entry.Value); 254 } else { 255 return 0; 256 } 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; 268 else { 269 return 0; 270 } 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); 280 else { 281 return 0; 282 } 283 } else { 284 return 0; 285 } 286} 287 288 289MMU_ENTRY 290DumpMmuLevel ( 291 IN MMU_LEVEL Level, 292 IN UINT32* Table, 293 IN MMU_ENTRY PreviousEntry 294 ) 295{ 296 UINT32 Index = 0, Count; 297 MMU_ENTRY LastEntry, Entry; 298 299 ASSERT((Level == Level1) || (Level == Level2)); 300 301 if (Level == Level1) Count = 4096; 302 else Count = 256; 303 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++); 308 309 LastEntry = MmuEntryCreate(Level,Table,Index); 310 Index++; 311 } else { 312 LastEntry = PreviousEntry; 313 } 314 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)); 324 } 325 LastEntry = Entry; 326 } else { 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)); 332 } 333 LastEntry = Entry; 334 } else { 335 ASSERT(LastEntry.Value != 0); 336 } 337 } 338 PreviousEntry = Entry; 339 } 340 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)); 345 } 346 347 return LastEntry; 348} 349 350 351EFI_STATUS 352EblDumpMmu ( 353 IN UINTN Argc, 354 IN CHAR8 **Argv 355 ) 356{ 357 UINT32 *TTEntry; 358 MMU_ENTRY NoEntry; 359 360 TTEntry = ArmGetTTBR0BaseAddress(); 361 362 AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry); 363 AsciiPrint ("Address Range\t\tAttributes\n"); 364 AsciiPrint ("____________________________________________________\n"); 365 366 NoEntry.Level = (MMU_LEVEL)200; 367 DumpMmuLevel(Level1,TTEntry,NoEntry); 368 369 return EFI_SUCCESS; 370} 371