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
EblSymbolTable(IN UINTN Argc,IN CHAR8 ** Argv)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
EblDisassembler(IN UINTN Argc,IN CHAR8 ** Argv)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 *
ImageHandleToPdbFileName(IN EFI_HANDLE Handle)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
EblPerformance(IN UINTN Argc,IN CHAR8 ** Argv)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
EblDumpGcd(IN UINTN Argc,IN CHAR8 ** Argv)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
EblDevicePaths(IN UINTN Argc,IN CHAR8 ** Argv)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
EblInitializeExternalCmd(VOID)467 EblInitializeExternalCmd (
468   VOID
469   )
470 {
471   EblAddCommands (mLibCmdTemplate, sizeof (mLibCmdTemplate)/sizeof (EBL_COMMAND_TABLE));
472   return;
473 }
474