| /** @file | |
| * | |
| * Copyright (c) 2011-2013, ARM Limited. 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/DxeServicesTableLib.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 <Library/BdsLib.h> | |
| #include <Guid/DebugImageInfoTable.h> | |
| #include <Protocol/DebugSupport.h> | |
| #include <Protocol/LoadedImage.h> | |
| #include <Protocol/DevicePathToText.h> | |
| EFI_STATUS | |
| EblDumpMmu ( | |
| IN UINTN Argc, | |
| IN CHAR8 **Argv | |
| ); | |
| EFI_STATUS | |
| EblDumpFdt ( | |
| IN UINTN Argc, | |
| IN CHAR8 **Argv | |
| ); | |
| /** | |
| 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 command 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 | |
| #if (__ARMCC_VERSION < 500000) | |
| Format = (Argc > 1) ? Argv[1] : "load /a /ni /np %a &0x%x"; | |
| #else | |
| Format = (Argc > 1) ? Argv[1] : "add-symbol-file %a 0x%x"; | |
| #endif | |
| 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 = (UINTN)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 command 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); | |
| } | |
| STATIC 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 command 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; | |
| BOOLEAN CountUp; | |
| TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop); | |
| if (Start < Stop) { | |
| CountUp = TRUE; | |
| } else { | |
| CountUp = FALSE; | |
| } | |
| 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 = CountUp?(Stop - Start):(Start - Stop); | |
| 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 = CountUp?(Stop - Start):(Start - Stop); | |
| 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; | |
| } | |
| #define EFI_MEMORY_PORT_IO 0x4000000000000000ULL | |
| EFI_STATUS | |
| EblDumpGcd ( | |
| IN UINTN Argc, | |
| IN CHAR8 **Argv | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN NumberOfDescriptors; | |
| UINTN i; | |
| EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; | |
| EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap; | |
| Status = gDS->GetMemorySpaceMap(&NumberOfDescriptors,&MemorySpaceMap); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| AsciiPrint (" Address Range Image Device Attributes\n"); | |
| AsciiPrint ("__________________________________________________________\n"); | |
| for (i=0; i < NumberOfDescriptors; i++) { | |
| AsciiPrint ("MEM %016lx - %016lx",(UINT64)MemorySpaceMap[i].BaseAddress,MemorySpaceMap[i].BaseAddress+MemorySpaceMap[i].Length-1); | |
| AsciiPrint (" %08x %08x",MemorySpaceMap[i].ImageHandle,MemorySpaceMap[i].DeviceHandle); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_RUNTIME) | |
| AsciiPrint (" RUNTIME"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_PORT_IO) | |
| AsciiPrint (" PORT_IO"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_UC) | |
| AsciiPrint (" MEM_UC"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WC) | |
| AsciiPrint (" MEM_WC"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WT) | |
| AsciiPrint (" MEM_WT"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WB) | |
| AsciiPrint (" MEM_WB"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_UCE) | |
| AsciiPrint (" MEM_UCE"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_WP) | |
| AsciiPrint (" MEM_WP"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_RP) | |
| AsciiPrint (" MEM_RP"); | |
| if (MemorySpaceMap[i].Attributes & EFI_MEMORY_XP) | |
| AsciiPrint (" MEM_XP"); | |
| switch (MemorySpaceMap[i].GcdMemoryType) { | |
| case EfiGcdMemoryTypeNonExistent: | |
| AsciiPrint (" TYPE_NONEXISTENT"); | |
| break; | |
| case EfiGcdMemoryTypeReserved: | |
| AsciiPrint (" TYPE_RESERVED"); | |
| break; | |
| case EfiGcdMemoryTypeSystemMemory: | |
| AsciiPrint (" TYPE_SYSMEM"); | |
| break; | |
| case EfiGcdMemoryTypeMemoryMappedIo: | |
| AsciiPrint (" TYPE_MEMMAP"); | |
| break; | |
| default: | |
| AsciiPrint (" TYPE_UNKNOWN"); | |
| break; | |
| } | |
| AsciiPrint ("\n"); | |
| } | |
| FreePool (MemorySpaceMap); | |
| Status = gDS->GetIoSpaceMap(&NumberOfDescriptors,&IoSpaceMap); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| for (i=0; i < NumberOfDescriptors; i++) { | |
| AsciiPrint ("IO %08lx - %08lx",IoSpaceMap[i].BaseAddress,IoSpaceMap[i].BaseAddress+IoSpaceMap[i].Length); | |
| AsciiPrint ("\t%08x %08x",IoSpaceMap[i].ImageHandle,IoSpaceMap[i].DeviceHandle); | |
| switch (IoSpaceMap[i].GcdIoType) { | |
| case EfiGcdIoTypeNonExistent: | |
| AsciiPrint (" TYPE_NONEXISTENT"); | |
| break; | |
| case EfiGcdIoTypeReserved: | |
| AsciiPrint (" TYPE_RESERVED"); | |
| break; | |
| case EfiGcdIoTypeIo: | |
| AsciiPrint (" TYPE_IO"); | |
| break; | |
| default: | |
| AsciiPrint (" TYPE_UNKNOWN"); | |
| break; | |
| } | |
| AsciiPrint ("\n"); | |
| } | |
| FreePool (IoSpaceMap); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EblDevicePaths ( | |
| IN UINTN Argc, | |
| IN CHAR8 **Argv | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN HandleCount; | |
| EFI_HANDLE *HandleBuffer; | |
| UINTN Index; | |
| CHAR16* String; | |
| EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; | |
| EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; | |
| BdsConnectAllDrivers(); | |
| Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); | |
| if (EFI_ERROR (Status)) { | |
| AsciiPrint ("Did not find the DevicePathToTextProtocol.\n"); | |
| return EFI_SUCCESS; | |
| } | |
| Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleCount, &HandleBuffer); | |
| if (EFI_ERROR (Status)) { | |
| AsciiPrint ("No device path found\n"); | |
| return EFI_SUCCESS; | |
| } | |
| for (Index = 0; Index < HandleCount; Index++) { | |
| Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); | |
| String = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathProtocol,TRUE,TRUE); | |
| Print (L"[0x%X] %s\n",(UINTN)HandleBuffer[Index], String); | |
| } | |
| 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 | |
| }, | |
| { | |
| "dumpgcd", | |
| " dump Global Coherency Domain", | |
| NULL, | |
| EblDumpGcd | |
| }, | |
| { | |
| "dumpmmu", | |
| " dump MMU Table", | |
| NULL, | |
| EblDumpMmu | |
| }, | |
| { | |
| "devicepaths", | |
| " list all the Device Paths", | |
| NULL, | |
| EblDevicePaths | |
| }, | |
| { | |
| "dumpfdt", | |
| " dump the current fdt or the one defined in the arguments", | |
| NULL, | |
| EblDumpFdt | |
| } | |
| }; | |
| VOID | |
| EblInitializeExternalCmd ( | |
| VOID | |
| ) | |
| { | |
| EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE)); | |
| return; | |
| } |