1/** @file 2 Add custom commands for BeagleBoard development. 3 4 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16#include <PiDxe.h> 17#include <Library/ArmLib.h> 18#include <Library/CacheMaintenanceLib.h> 19#include <Library/EblCmdLib.h> 20#include <Library/BaseLib.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 33#include <Guid/DebugImageInfoTable.h> 34 35#include <Protocol/DebugSupport.h> 36#include <Protocol/LoadedImage.h> 37 38/** 39 Simple arm disassembler via a library 40 41 Argv[0] - symboltable 42 Argv[1] - Optional quoted format string 43 Argv[2] - Optional flag 44 45 @param Argc Number of command arguments in Argv 46 @param Argv Array of strings that represent the parsed command line. 47 Argv[0] is the command name 48 49 @return EFI_SUCCESS 50 51**/ 52EFI_STATUS 53EblSymbolTable ( 54 IN UINTN Argc, 55 IN CHAR8 **Argv 56 ) 57{ 58 EFI_STATUS Status; 59 EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageTableHeader = NULL; 60 EFI_DEBUG_IMAGE_INFO *DebugTable; 61 UINTN Entry; 62 CHAR8 *Format; 63 CHAR8 *Pdb; 64 UINT32 PeCoffSizeOfHeaders; 65 UINT32 ImageBase; 66 BOOLEAN Elf; 67 68 // Need to add lots of error checking on the passed in string 69 // Default string is for RealView debugger or gdb depending on toolchain used. 70 if (Argc > 1) { 71 Format = Argv[1]; 72 } else { 73#if __GNUC__ 74 // Assume gdb 75 Format = "add-symbol-file %a 0x%x"; 76#else 77 // Default to RVCT 78 Format = "load /a /ni /np %a &0x%x"; 79#endif 80 } 81 Elf = (Argc > 2) ? FALSE : TRUE; 82 83 Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugImageTableHeader); 84 if (EFI_ERROR (Status)) { 85 return Status; 86 } 87 88 DebugTable = DebugImageTableHeader->EfiDebugImageInfoTable; 89 if (DebugTable == NULL) { 90 return EFI_SUCCESS; 91 } 92 93 for (Entry = 0; Entry < DebugImageTableHeader->TableSize; Entry++, DebugTable++) { 94 if (DebugTable->NormalImage != NULL) { 95 if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { 96 ImageBase = (UINT32)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase; 97 PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageBase); 98 Pdb = PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase); 99 if (Pdb != NULL) { 100 if (Elf) { 101 // ELF and Mach-O images don't include the header so the linked address does not include header 102 ImageBase += PeCoffSizeOfHeaders; 103 } 104 AsciiPrint (Format, Pdb, ImageBase); 105 AsciiPrint ("\n"); 106 } else { 107 } 108 } 109 } 110 } 111 112 return EFI_SUCCESS; 113} 114 115 116/** 117 Simple arm disassembler via a library 118 119 Argv[0] - disasm 120 Argv[1] - Address to start disassembling from 121 ARgv[2] - Number of instructions to disassembly (optional) 122 123 @param Argc Number of command arguments in Argv 124 @param Argv Array of strings that represent the parsed command line. 125 Argv[0] is the command name 126 127 @return EFI_SUCCESS 128 129**/ 130EFI_STATUS 131EblDisassembler ( 132 IN UINTN Argc, 133 IN CHAR8 **Argv 134 ) 135{ 136 UINT8 *Ptr, *CurrentAddress; 137 UINT32 Address; 138 UINT32 Count; 139 CHAR8 Buffer[80]; 140 UINT32 ItBlock; 141 142 if (Argc < 2) { 143 return EFI_INVALID_PARAMETER; 144 } 145 146 Address = AsciiStrHexToUintn (Argv[1]); 147 Count = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20; 148 149 Ptr = (UINT8 *)(UINTN)Address; 150 ItBlock = 0; 151 do { 152 CurrentAddress = Ptr; 153 DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer)); 154 AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer); 155 } while (Count-- > 0); 156 157 158 return EFI_SUCCESS; 159} 160 161 162CHAR8 * 163ImageHandleToPdbFileName ( 164 IN EFI_HANDLE Handle 165 ) 166{ 167 EFI_STATUS Status; 168 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 169 CHAR8 *Pdb; 170 CHAR8 *StripLeading; 171 172 Status = gBS->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); 173 if (EFI_ERROR (Status)) { 174 return ""; 175 } 176 177 Pdb = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); 178 StripLeading = AsciiStrStr (Pdb, "\\ARM\\"); 179 if (StripLeading == NULL) { 180 StripLeading = AsciiStrStr (Pdb, "/ARM/"); 181 if (StripLeading == NULL) { 182 return Pdb; 183 } 184 } 185 // Hopefully we hacked off the unneeded part 186 return (StripLeading + 5); 187} 188 189 190CHAR8 *mTokenList[] = { 191 "SEC", 192 "PEI", 193 "DXE", 194 "BDS", 195 NULL 196}; 197 198/** 199 Simple arm disassembler via a library 200 201 Argv[0] - disasm 202 Argv[1] - Address to start disassembling from 203 ARgv[2] - Number of instructions to disassembly (optional) 204 205 @param Argc Number of command arguments in Argv 206 @param Argv Array of strings that represent the parsed command line. 207 Argv[0] is the command name 208 209 @return EFI_SUCCESS 210 211**/ 212EFI_STATUS 213EblPerformance ( 214 IN UINTN Argc, 215 IN CHAR8 **Argv 216 ) 217{ 218 UINTN Key; 219 CONST VOID *Handle; 220 CONST CHAR8 *Token, *Module; 221 UINT64 Start, Stop, TimeStamp; 222 UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds; 223 UINTN Index; 224 225 TicksPerSecond = GetPerformanceCounterProperties (NULL, NULL); 226 227 Key = 0; 228 do { 229 Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); 230 if (Key != 0) { 231 if (AsciiStriCmp ("StartImage:", Token) == 0) { 232 if (Stop == 0) { 233 // The entry for EBL is still running so the stop time will be zero. Skip it 234 AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); 235 } else { 236 Delta = Stop - Start; 237 Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL); 238 AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); 239 } 240 } 241 } 242 } while (Key != 0); 243 244 AsciiPrint ("\n"); 245 246 TimeStamp = 0; 247 Key = 0; 248 do { 249 Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); 250 if (Key != 0) { 251 for (Index = 0; mTokenList[Index] != NULL; Index++) { 252 if (AsciiStriCmp (mTokenList[Index], Token) == 0) { 253 Delta = Stop - Start; 254 TimeStamp += Delta; 255 Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); 256 AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds); 257 break; 258 } 259 } 260 } 261 } while (Key != 0); 262 263 AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); 264 265 return EFI_SUCCESS; 266} 267 268 269GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mLibCmdTemplate[] = 270{ 271 { 272 "disasm address [count]", 273 " disassemble count instructions", 274 NULL, 275 EblDisassembler 276 }, 277 { 278 "performance", 279 " Display boot performance info", 280 NULL, 281 EblPerformance 282 }, 283 { 284 "symboltable [\"format string\"] [PECOFF]", 285 " show symbol table commands for debugger", 286 NULL, 287 EblSymbolTable 288 } 289}; 290 291 292VOID 293EblInitializeExternalCmd ( 294 VOID 295 ) 296{ 297 EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE)); 298 return; 299} 300