1. Data type for GcdMemoryType and GcdIoType is enumeration type rather than bit field, so we need to use strict equation "==" instead of bit-and "&"; 2. Testing for GcdIoType should use EfiGcdIoType*** constants rather than EfiGcdMemoryType***; 3. As we are going to use strict equation, it is clearer to use switch-case than if-else. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Heyi Guo <heyi.guo@linaro.org> Reviewed-by: Olivier Martin <Olivier.Martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17527 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			474 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			474 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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;
 | |
| }
 |