Home | History | Annotate | Download | only in EblCmdLib
      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