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