/** @file | |
Add custom commands for BeagleBoard development. | |
Copyright (c) 2008-2010, Apple Inc. All rights reserved. | |
All rights reserved. This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include <PiDxe.h> | |
#include <Library/ArmLib.h> | |
#include <Library/CacheMaintenanceLib.h> | |
#include <Library/EblCmdLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/UefiRuntimeServicesTableLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/UefiLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/EfiFileLib.h> | |
#include <Library/ArmDisassemblerLib.h> | |
#include <Library/PeCoffGetEntryPointLib.h> | |
#include <Library/PerformanceLib.h> | |
#include <Library/TimerLib.h> | |
#include <Guid/DebugImageInfoTable.h> | |
#include <Protocol/DebugSupport.h> | |
#include <Protocol/LoadedImage.h> | |
/** | |
Simple arm disassembler via a library | |
Argv[0] - symboltable | |
Argv[1] - Optional qoted format string | |
Argv[2] - Optional flag | |
@param Argc Number of command arguments in Argv | |
@param Argv Array of strings that represent the parsed command line. | |
Argv[0] is the comamnd name | |
@return EFI_SUCCESS | |
**/ | |
EFI_STATUS | |
EblSymbolTable ( | |
IN UINTN Argc, | |
IN CHAR8 **Argv | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageTableHeader = NULL; | |
EFI_DEBUG_IMAGE_INFO *DebugTable; | |
UINTN Entry; | |
CHAR8 *Format; | |
CHAR8 *Pdb; | |
UINT32 PeCoffSizeOfHeaders; | |
UINT32 ImageBase; | |
BOOLEAN Elf; | |
// Need to add lots of error checking on the passed in string | |
// Default string is for RealView debugger | |
Format = (Argc > 1) ? Argv[1] : "load /a /ni /np %a &0x%x"; | |
Elf = (Argc > 2) ? FALSE : TRUE; | |
Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugImageTableHeader); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
DebugTable = DebugImageTableHeader->EfiDebugImageInfoTable; | |
if (DebugTable == NULL) { | |
return EFI_SUCCESS; | |
} | |
for (Entry = 0; Entry < DebugImageTableHeader->TableSize; Entry++, DebugTable++) { | |
if (DebugTable->NormalImage != NULL) { | |
if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { | |
ImageBase = (UINT32)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase; | |
PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageBase); | |
Pdb = PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase); | |
if (Pdb != NULL) { | |
if (Elf) { | |
// ELF and Mach-O images don't include the header so the linked address does not include header | |
ImageBase += PeCoffSizeOfHeaders; | |
} | |
AsciiPrint (Format, Pdb, ImageBase); | |
AsciiPrint ("\n"); | |
} else { | |
} | |
} | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Simple arm disassembler via a library | |
Argv[0] - disasm | |
Argv[1] - Address to start disassembling from | |
ARgv[2] - Number of instructions to disassembly (optional) | |
@param Argc Number of command arguments in Argv | |
@param Argv Array of strings that represent the parsed command line. | |
Argv[0] is the comamnd name | |
@return EFI_SUCCESS | |
**/ | |
EFI_STATUS | |
EblDisassembler ( | |
IN UINTN Argc, | |
IN CHAR8 **Argv | |
) | |
{ | |
UINT8 *Ptr, *CurrentAddress; | |
UINT32 Address; | |
UINT32 Count; | |
CHAR8 Buffer[80]; | |
UINT32 ItBlock; | |
if (Argc < 2) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Address = AsciiStrHexToUintn (Argv[1]); | |
Count = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20; | |
Ptr = (UINT8 *)(UINTN)Address; | |
ItBlock = 0; | |
do { | |
CurrentAddress = Ptr; | |
DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer)); | |
AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer); | |
} while (Count-- > 0); | |
return EFI_SUCCESS; | |
} | |
CHAR8 * | |
ImageHandleToPdbFileName ( | |
IN EFI_HANDLE Handle | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; | |
CHAR8 *Pdb; | |
CHAR8 *StripLeading; | |
Status = gBS->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); | |
if (EFI_ERROR (Status)) { | |
return ""; | |
} | |
Pdb = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); | |
StripLeading = AsciiStrStr (Pdb, "\\ARM\\"); | |
if (StripLeading == NULL) { | |
StripLeading = AsciiStrStr (Pdb, "/ARM/"); | |
if (StripLeading == NULL) { | |
return Pdb; | |
} | |
} | |
// Hopefully we hacked off the unneeded part | |
return (StripLeading + 5); | |
} | |
CHAR8 *mTokenList[] = { | |
"SEC", | |
"PEI", | |
"DXE", | |
"BDS", | |
NULL | |
}; | |
/** | |
Simple arm disassembler via a library | |
Argv[0] - disasm | |
Argv[1] - Address to start disassembling from | |
ARgv[2] - Number of instructions to disassembly (optional) | |
@param Argc Number of command arguments in Argv | |
@param Argv Array of strings that represent the parsed command line. | |
Argv[0] is the comamnd name | |
@return EFI_SUCCESS | |
**/ | |
EFI_STATUS | |
EblPerformance ( | |
IN UINTN Argc, | |
IN CHAR8 **Argv | |
) | |
{ | |
UINTN Key; | |
CONST VOID *Handle; | |
CONST CHAR8 *Token, *Module; | |
UINT64 Start, Stop, TimeStamp; | |
UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds; | |
UINTN Index; | |
TicksPerSecond = GetPerformanceCounterProperties (NULL, NULL); | |
Key = 0; | |
do { | |
Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); | |
if (Key != 0) { | |
if (AsciiStriCmp ("StartImage:", Token) == 0) { | |
if (Stop == 0) { | |
// The entry for EBL is still running so the stop time will be zero. Skip it | |
AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); | |
} else { | |
Delta = Stop - Start; | |
Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL); | |
AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); | |
} | |
} | |
} | |
} while (Key != 0); | |
AsciiPrint ("\n"); | |
TimeStamp = 0; | |
Key = 0; | |
do { | |
Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); | |
if (Key != 0) { | |
for (Index = 0; mTokenList[Index] != NULL; Index++) { | |
if (AsciiStriCmp (mTokenList[Index], Token) == 0) { | |
Delta = Stop - Start; | |
TimeStamp += Delta; | |
Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); | |
AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds); | |
break; | |
} | |
} | |
} | |
} while (Key != 0); | |
AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); | |
return EFI_SUCCESS; | |
} | |
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mLibCmdTemplate[] = | |
{ | |
{ | |
"disasm address [count]", | |
" disassemble count instructions", | |
NULL, | |
EblDisassembler | |
}, | |
{ | |
"performance", | |
" Display boot performance info", | |
NULL, | |
EblPerformance | |
}, | |
{ | |
"symboltable [\"format string\"] [PECOFF]", | |
" show symbol table commands for debugger", | |
NULL, | |
EblSymbolTable | |
} | |
}; | |
VOID | |
EblInitializeExternalCmd ( | |
VOID | |
) | |
{ | |
EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE)); | |
return; | |
} |