1 /** @file 2 * 3 * Copyright (c) 2011-2013, 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/ArmLib.h> 17 #include <Library/CacheMaintenanceLib.h> 18 #include <Library/EblCmdLib.h> 19 #include <Library/BaseLib.h> 20 #include <Library/DxeServicesTableLib.h> 21 #include <Library/DebugLib.h> 22 #include <Library/UefiBootServicesTableLib.h> 23 #include <Library/UefiRuntimeServicesTableLib.h> 24 #include <Library/MemoryAllocationLib.h> 25 #include <Library/UefiLib.h> 26 #include <Library/PcdLib.h> 27 #include <Library/EfiFileLib.h> 28 #include <Library/ArmDisassemblerLib.h> 29 #include <Library/PeCoffGetEntryPointLib.h> 30 #include <Library/PerformanceLib.h> 31 #include <Library/TimerLib.h> 32 #include <Library/BdsLib.h> 33 34 #include <Guid/DebugImageInfoTable.h> 35 36 #include <Protocol/DebugSupport.h> 37 #include <Protocol/LoadedImage.h> 38 #include <Protocol/DevicePathToText.h> 39 40 EFI_STATUS 41 EblDumpMmu ( 42 IN UINTN Argc, 43 IN CHAR8 **Argv 44 ); 45 46 EFI_STATUS 47 EblDumpFdt ( 48 IN UINTN Argc, 49 IN CHAR8 **Argv 50 ); 51 52 /** 53 Simple arm disassembler via a library 54 55 Argv[0] - symboltable 56 Argv[1] - Optional qoted format string 57 Argv[2] - Optional flag 58 59 @param Argc Number of command arguments in Argv 60 @param Argv Array of strings that represent the parsed command line. 61 Argv[0] is the command name 62 63 @return EFI_SUCCESS 64 65 **/ 66 EFI_STATUS 67 EblSymbolTable ( 68 IN UINTN Argc, 69 IN CHAR8 **Argv 70 ) 71 { 72 EFI_STATUS Status; 73 EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageTableHeader = NULL; 74 EFI_DEBUG_IMAGE_INFO *DebugTable; 75 UINTN Entry; 76 CHAR8 *Format; 77 CHAR8 *Pdb; 78 UINT32 PeCoffSizeOfHeaders; 79 UINT32 ImageBase; 80 BOOLEAN Elf; 81 82 // Need to add lots of error checking on the passed in string 83 // Default string is for RealView debugger 84 #if (__ARMCC_VERSION < 500000) 85 Format = (Argc > 1) ? Argv[1] : "load /a /ni /np %a &0x%x"; 86 #else 87 Format = (Argc > 1) ? Argv[1] : "add-symbol-file %a 0x%x"; 88 #endif 89 Elf = (Argc > 2) ? FALSE : TRUE; 90 91 Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugImageTableHeader); 92 if (EFI_ERROR (Status)) { 93 return Status; 94 } 95 96 DebugTable = DebugImageTableHeader->EfiDebugImageInfoTable; 97 if (DebugTable == NULL) { 98 return EFI_SUCCESS; 99 } 100 101 for (Entry = 0; Entry < DebugImageTableHeader->TableSize; Entry++, DebugTable++) { 102 if (DebugTable->NormalImage != NULL) { 103 if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { 104 ImageBase = (UINTN)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase; 105 PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageBase); 106 Pdb = PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase); 107 if (Pdb != NULL) { 108 if (Elf) { 109 // ELF and Mach-O images don't include the header so the linked address does not include header 110 ImageBase += PeCoffSizeOfHeaders; 111 } 112 AsciiPrint (Format, Pdb, ImageBase); 113 AsciiPrint ("\n"); 114 } else { 115 } 116 } 117 } 118 } 119 120 return EFI_SUCCESS; 121 } 122 123 124 /** 125 Simple arm disassembler via a library 126 127 Argv[0] - disasm 128 Argv[1] - Address to start disassembling from 129 ARgv[2] - Number of instructions to disassembly (optional) 130 131 @param Argc Number of command arguments in Argv 132 @param Argv Array of strings that represent the parsed command line. 133 Argv[0] is the command name 134 135 @return EFI_SUCCESS 136 137 **/ 138 EFI_STATUS 139 EblDisassembler ( 140 IN UINTN Argc, 141 IN CHAR8 **Argv 142 ) 143 { 144 UINT8 *Ptr, *CurrentAddress; 145 UINT32 Address; 146 UINT32 Count; 147 CHAR8 Buffer[80]; 148 UINT32 ItBlock; 149 150 if (Argc < 2) { 151 return EFI_INVALID_PARAMETER; 152 } 153 154 Address = AsciiStrHexToUintn (Argv[1]); 155 Count = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20; 156 157 Ptr = (UINT8 *)(UINTN)Address; 158 ItBlock = 0; 159 do { 160 CurrentAddress = Ptr; 161 DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer)); 162 AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer); 163 } while (Count-- > 0); 164 165 166 return EFI_SUCCESS; 167 } 168 169 170 CHAR8 * 171 ImageHandleToPdbFileName ( 172 IN EFI_HANDLE Handle 173 ) 174 { 175 EFI_STATUS Status; 176 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 177 CHAR8 *Pdb; 178 CHAR8 *StripLeading; 179 180 Status = gBS->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); 181 if (EFI_ERROR (Status)) { 182 return ""; 183 } 184 185 Pdb = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); 186 StripLeading = AsciiStrStr (Pdb, "\\ARM\\"); 187 if (StripLeading == NULL) { 188 StripLeading = AsciiStrStr (Pdb, "/ARM/"); 189 if (StripLeading == NULL) { 190 return Pdb; 191 } 192 } 193 // Hopefully we hacked off the unneeded part 194 return (StripLeading + 5); 195 } 196 197 198 STATIC CHAR8 *mTokenList[] = { 199 /*"SEC",*/ 200 "PEI", 201 "DXE", 202 /*"BDS",*/ 203 NULL 204 }; 205 206 /** 207 Simple arm disassembler via a library 208 209 Argv[0] - disasm 210 Argv[1] - Address to start disassembling from 211 ARgv[2] - Number of instructions to disassembly (optional) 212 213 @param Argc Number of command arguments in Argv 214 @param Argv Array of strings that represent the parsed command line. 215 Argv[0] is the command name 216 217 @return EFI_SUCCESS 218 219 **/ 220 EFI_STATUS 221 EblPerformance ( 222 IN UINTN Argc, 223 IN CHAR8 **Argv 224 ) 225 { 226 UINTN Key; 227 CONST VOID *Handle; 228 CONST CHAR8 *Token, *Module; 229 UINT64 Start, Stop, TimeStamp; 230 UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds; 231 UINTN Index; 232 BOOLEAN CountUp; 233 234 TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop); 235 if (Start < Stop) { 236 CountUp = TRUE; 237 } else { 238 CountUp = FALSE; 239 } 240 241 Key = 0; 242 do { 243 Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); 244 if (Key != 0) { 245 if (AsciiStriCmp ("StartImage:", Token) == 0) { 246 if (Stop == 0) { 247 // The entry for EBL is still running so the stop time will be zero. Skip it 248 AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); 249 } else { 250 Delta = CountUp?(Stop - Start):(Start - Stop); 251 Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL); 252 AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); 253 } 254 } 255 } 256 } while (Key != 0); 257 258 AsciiPrint ("\n"); 259 260 TimeStamp = 0; 261 Key = 0; 262 do { 263 Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); 264 if (Key != 0) { 265 for (Index = 0; mTokenList[Index] != NULL; Index++) { 266 if (AsciiStriCmp (mTokenList[Index], Token) == 0) { 267 Delta = CountUp?(Stop - Start):(Start - Stop); 268 TimeStamp += Delta; 269 Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); 270 AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds); 271 break; 272 } 273 } 274 } 275 } while (Key != 0); 276 277 AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); 278 279 return EFI_SUCCESS; 280 } 281 282 #define EFI_MEMORY_PORT_IO 0x4000000000000000ULL 283 284 EFI_STATUS 285 EblDumpGcd ( 286 IN UINTN Argc, 287 IN CHAR8 **Argv 288 ) 289 { 290 EFI_STATUS Status; 291 UINTN NumberOfDescriptors; 292 UINTN i; 293 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; 294 EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap; 295 296 Status = gDS->GetMemorySpaceMap(&NumberOfDescriptors,&MemorySpaceMap); 297 if (EFI_ERROR (Status)) { 298 return Status; 299 } 300 AsciiPrint (" Address Range Image Device Attributes\n"); 301 AsciiPrint ("__________________________________________________________\n"); 302 for (i=0; i < NumberOfDescriptors; i++) { 303 AsciiPrint ("MEM %016lx - %016lx",(UINT64)MemorySpaceMap[i].BaseAddress,MemorySpaceMap[i].BaseAddress+MemorySpaceMap[i].Length-1); 304 AsciiPrint (" %08x %08x",MemorySpaceMap[i].ImageHandle,MemorySpaceMap[i].DeviceHandle); 305 306 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_RUNTIME) 307 AsciiPrint (" RUNTIME"); 308 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_PORT_IO) 309 AsciiPrint (" PORT_IO"); 310 311 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_UC) 312 AsciiPrint (" MEM_UC"); 313 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WC) 314 AsciiPrint (" MEM_WC"); 315 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WT) 316 AsciiPrint (" MEM_WT"); 317 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WB) 318 AsciiPrint (" MEM_WB"); 319 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_UCE) 320 AsciiPrint (" MEM_UCE"); 321 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WP) 322 AsciiPrint (" MEM_WP"); 323 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_RP) 324 AsciiPrint (" MEM_RP"); 325 if (MemorySpaceMap[i].Attributes & EFI_MEMORY_XP) 326 AsciiPrint (" MEM_XP"); 327 328 switch (MemorySpaceMap[i].GcdMemoryType) { 329 case EfiGcdMemoryTypeNonExistent: 330 AsciiPrint (" TYPE_NONEXISTENT"); 331 break; 332 case EfiGcdMemoryTypeReserved: 333 AsciiPrint (" TYPE_RESERVED"); 334 break; 335 case EfiGcdMemoryTypeSystemMemory: 336 AsciiPrint (" TYPE_SYSMEM"); 337 break; 338 case EfiGcdMemoryTypeMemoryMappedIo: 339 AsciiPrint (" TYPE_MEMMAP"); 340 break; 341 default: 342 AsciiPrint (" TYPE_UNKNOWN"); 343 break; 344 } 345 346 AsciiPrint ("\n"); 347 } 348 349 FreePool (MemorySpaceMap); 350 351 Status = gDS->GetIoSpaceMap(&NumberOfDescriptors,&IoSpaceMap); 352 if (EFI_ERROR (Status)) { 353 return Status; 354 } 355 for (i=0; i < NumberOfDescriptors; i++) { 356 AsciiPrint ("IO %08lx - %08lx",IoSpaceMap[i].BaseAddress,IoSpaceMap[i].BaseAddress+IoSpaceMap[i].Length); 357 AsciiPrint ("\t%08x %08x",IoSpaceMap[i].ImageHandle,IoSpaceMap[i].DeviceHandle); 358 359 switch (IoSpaceMap[i].GcdIoType) { 360 case EfiGcdIoTypeNonExistent: 361 AsciiPrint (" TYPE_NONEXISTENT"); 362 break; 363 case EfiGcdIoTypeReserved: 364 AsciiPrint (" TYPE_RESERVED"); 365 break; 366 case EfiGcdIoTypeIo: 367 AsciiPrint (" TYPE_IO"); 368 break; 369 default: 370 AsciiPrint (" TYPE_UNKNOWN"); 371 break; 372 } 373 374 AsciiPrint ("\n"); 375 } 376 377 FreePool (IoSpaceMap); 378 379 return EFI_SUCCESS; 380 } 381 382 EFI_STATUS 383 EblDevicePaths ( 384 IN UINTN Argc, 385 IN CHAR8 **Argv 386 ) 387 { 388 EFI_STATUS Status; 389 UINTN HandleCount; 390 EFI_HANDLE *HandleBuffer; 391 UINTN Index; 392 CHAR16* String; 393 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; 394 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; 395 396 BdsConnectAllDrivers(); 397 398 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); 399 if (EFI_ERROR (Status)) { 400 AsciiPrint ("Did not find the DevicePathToTextProtocol.\n"); 401 return EFI_SUCCESS; 402 } 403 404 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleCount, &HandleBuffer); 405 if (EFI_ERROR (Status)) { 406 AsciiPrint ("No device path found\n"); 407 return EFI_SUCCESS; 408 } 409 410 for (Index = 0; Index < HandleCount; Index++) { 411 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); 412 String = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathProtocol,TRUE,TRUE); 413 Print (L"[0x%X] %s\n",(UINTN)HandleBuffer[Index], String); 414 } 415 416 return EFI_SUCCESS; 417 } 418 419 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mLibCmdTemplate[] = 420 { 421 { 422 "disasm address [count]", 423 " disassemble count instructions", 424 NULL, 425 EblDisassembler 426 }, 427 { 428 "performance", 429 " Display boot performance info", 430 NULL, 431 EblPerformance 432 }, 433 { 434 "symboltable [\"format string\"] [PECOFF]", 435 " show symbol table commands for debugger", 436 NULL, 437 EblSymbolTable 438 }, 439 { 440 "dumpgcd", 441 " dump Global Coherency Domain", 442 NULL, 443 EblDumpGcd 444 }, 445 { 446 "dumpmmu", 447 " dump MMU Table", 448 NULL, 449 EblDumpMmu 450 }, 451 { 452 "devicepaths", 453 " list all the Device Paths", 454 NULL, 455 EblDevicePaths 456 }, 457 { 458 "dumpfdt", 459 " dump the current fdt or the one defined in the arguments", 460 NULL, 461 EblDumpFdt 462 } 463 }; 464 465 466 VOID 467 EblInitializeExternalCmd ( 468 VOID 469 ) 470 { 471 EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE)); 472 return; 473 } 474