Update EBL to have an optional width specifier on commands. So hexdump.4 means use...
[efi/edk2/.git] / edk2 / EmbeddedPkg / Ebl / HwDebug.c
1 /** @file\r
2   Basic command line parser for EBL (Embedded Boot Loader)\r
3 \r
4   Copyright (c) 2007, Intel Corporation<BR>\r
5   Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
6 \r
7   All rights reserved. This program and the accompanying materials\r
8   are licensed and made available under the terms and conditions of the BSD License\r
9   which accompanies this distribution.  The full text of the license may be found at\r
10   http://opensource.org/licenses/bsd-license.php\r
11 \r
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14 \r
15   Module Name:  HwDebug.c\r
16 \r
17   Commands useful for debugging hardware. \r
18 \r
19 **/\r
20 \r
21 #include "Ebl.h"\r
22 \r
23 \r
24 /**\r
25   Dump memory\r
26 \r
27   Argv[0] - "md"[.#] # is optiona width 1, 2, 4, or 8. Default 1\r
28   Argv[1] - Hex Address to dump\r
29   Argv[2] - Number of hex bytes to dump (0x20 is default)\r
30 \r
31   md.4 0x123445678 50 ; Dump 0x50 4 byte quantities starting at 0x123445678\r
32   md   0x123445678 40 ; Dump 0x40 1 byte quantities starting at 0x123445678\r
33   md   0x123445678    ; Dump 0x20 1 byte quantities starting at 0x123445678\r
34 \r
35   @param  Argc   Number of command arguments in Argv\r
36   @param  Argv   Array of strings that represent the parsed command line. \r
37                  Argv[0] is the comamnd name\r
38 \r
39   @return EFI_SUCCESS\r
40 \r
41 **/\r
42 EFI_STATUS\r
43 EblMdCmd (\r
44   IN UINTN  Argc,\r
45   IN CHAR8  **Argv\r
46   )\r
47 {\r
48   STATIC UINT8  *Address = NULL;\r
49   STATIC UINTN  Length   = 0x20;\r
50   STATIC UINTN  Width;\r
51 \r
52   Width = WidthFromCommandName (Argv[0], 1);\r
53 \r
54   switch (Argc) {\r
55     case 3:\r
56       Length = AsciiStrHexToUintn(Argv[2]);\r
57     case 2:\r
58       Address = (UINT8 *)AsciiStrHexToUintn (Argv[1]);\r
59     default:\r
60       break;\r
61   }\r
62 \r
63   OutputData (Address, Length, Width, (UINTN)Address);\r
64 \r
65   Address += Length;\r
66   \r
67   return EFI_SUCCESS;\r
68 }\r
69 \r
70 \r
71 /**\r
72   Fill Memory with data\r
73 \r
74   Argv[0] - "mfill"[.#] # is optiona width 1, 2, 4, or 8. Default 4\r
75   Argv[1] - Hex Address to fill\r
76   Argv[2] - Data to write (0x00 is default)\r
77   Argv[3] - Number of units to dump.\r
78 \r
79   mf.1 0x123445678 aa 100 ; Start at 0x123445678 and write aa (1 byte) to the next 100 bytes\r
80   mf.4 0x123445678 aa 100 ; Start at 0x123445678 and write aa (4 byte) to the next 400 bytes\r
81   mf 0x123445678 aa       ; Start at 0x123445678 and write aa (4 byte) to the next 1 byte\r
82   mf 0x123445678          ; Start at 0x123445678 and write 00 (4 byte) to the next 1 byte\r
83 \r
84   @param  Argc   Number of command arguments in Argv\r
85   @param  Argv   Array of strings that represent the parsed command line. \r
86                  Argv[0] is the comamnd name\r
87 \r
88   @return EFI_SUCCESS\r
89 \r
90 **/\r
91 EFI_STATUS\r
92 EblMfillCmd (\r
93   IN UINTN  Argc,\r
94   IN CHAR8  **Argv\r
95   )\r
96 {\r
97   UINTN   Address;\r
98   UINTN   EndAddress;\r
99   UINT32  Data;\r
100   UINTN   Length;\r
101   UINTN   Width;\r
102 \r
103   if (Argc < 2) {\r
104     return EFI_INVALID_PARAMETER;\r
105   }\r
106 \r
107   Width = WidthFromCommandName (Argv[0], 4);\r
108 \r
109   Address = AsciiStrHexToUintn (Argv[1]);\r
110   Data    = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 0;\r
111   Length  = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 1;\r
112 \r
113   for (EndAddress = Address + (Length * Width); Address < EndAddress; Address += Width) {\r
114     if (Width == 4) {\r
115       MmioWrite32 (Address, Data);\r
116     } else if (Width == 2) {\r
117       MmioWrite32 (Address, (UINT16)Data);\r
118     } else {\r
119       MmioWrite32 (Address, (UINT8)Data);\r
120     }\r
121   }\r
122   \r
123   return EFI_SUCCESS;\r
124 }\r
125 \r
126 \r
127 //\r
128 // Strings for PCI Class code [2]\r
129 //\r
130 CHAR8 *gPciDevClass[] = {\r
131   "Old Device             ",\r
132   "Mass storage           ",\r
133   "Network                ",\r
134   "Display                ",\r
135   "Multimedia             ",\r
136   "Memory controller      ",\r
137   "Bridge device          ",\r
138   "simple communications  ",\r
139   "base system peripherals",\r
140   "Input devices          ",\r
141   "Docking stations       ",\r
142   "Processors             ",\r
143   "serial bus             ",\r
144 };\r
145 \r
146 \r
147 CHAR8 *gPciSerialClassCodes[] = {\r
148   "Mass storage           ",\r
149   "Firewire               ",\r
150   "ACCESS bus             ",\r
151   "SSA                    ",\r
152   "USB                     "\r
153 };\r
154 \r
155 \r
156 /**\r
157   PCI Dump\r
158 \r
159   Argv[0] - "pci"\r
160   Argv[1] - bus\r
161   Argv[2] - dev\r
162   Argv[3] - func\r
163 \r
164   @param  Argc   Number of command arguments in Argv\r
165   @param  Argv   Array of strings that represent the parsed command line. \r
166                  Argv[0] is the comamnd name\r
167 \r
168   @return EFI_SUCCESS\r
169 \r
170 **/\r
171 EFI_STATUS\r
172 EblPciCmd (\r
173   IN UINTN  Argc,\r
174   IN CHAR8  **Argv\r
175   )\r
176 {\r
177   EFI_STATUS                    Status;\r
178   EFI_PCI_IO_PROTOCOL           *Pci;\r
179   UINTN                         HandleCount;\r
180   EFI_HANDLE                    *HandleBuffer;\r
181   UINTN                         Seg;\r
182   UINTN                         Bus;\r
183   UINTN                         Dev;\r
184   UINTN                         Func;\r
185   UINTN                         BusArg;\r
186   UINTN                         DevArg;\r
187   UINTN                         FuncArg;\r
188   UINTN                         Index;\r
189   UINTN                         Count;\r
190   PCI_TYPE_GENERIC              PciHeader;\r
191   PCI_TYPE_GENERIC              *Header;\r
192   PCI_BRIDGE_CONTROL_REGISTER   *Bridge;\r
193   PCI_DEVICE_HEADER_TYPE_REGION *Device;\r
194   PCI_DEVICE_INDEPENDENT_REGION *Hdr;\r
195   CHAR8                         *Str;\r
196   UINTN                         ThisBus;\r
197 \r
198   \r
199   BusArg  = (Argc > 1) ? AsciiStrDecimalToUintn (Argv[1]) : 0;\r
200   DevArg  = (Argc > 2) ? AsciiStrDecimalToUintn (Argv[2]) : 0;\r
201   FuncArg = (Argc > 3) ? AsciiStrDecimalToUintn (Argv[3]) : 0;\r
202 \r
203   Header = &PciHeader;\r
204   \r
205   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
206   if (EFI_ERROR (Status)) {\r
207     AsciiPrint ("No PCI devices found in the system\n");\r
208     return EFI_SUCCESS;\r
209   }\r
210 \r
211   if (Argc == 1) {\r
212     // Dump all PCI devices\r
213     AsciiPrint ("BusDevFun  VendorId DeviceId  Device Class          Sub-Class\n");\r
214     AsciiPrint ("_____________________________________________________________");\r
215     for (ThisBus = 0; ThisBus <= PCI_MAX_BUS; ThisBus++) {\r
216       for (Index = 0; Index < HandleCount; Index++) {\r
217         Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);\r
218         if (!EFI_ERROR (Status)) {\r
219           Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);\r
220           if (ThisBus != Bus) {\r
221             continue;\r
222           }\r
223           AsciiPrint ("\n%03d.%02d.%02d", Bus, Dev, Func);\r
224           Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), &PciHeader);\r
225           if (!EFI_ERROR (Status)) {\r
226             Hdr = &PciHeader.Bridge.Hdr;\r
227             \r
228             if (Hdr->ClassCode[2] < sizeof (gPciDevClass)/sizeof (VOID *)) {\r
229               Str = gPciDevClass[Hdr->ClassCode[2]];\r
230               if (Hdr->ClassCode[2] == PCI_CLASS_SERIAL) {\r
231                 if (Hdr->ClassCode[1] < sizeof (gPciSerialClassCodes)/sizeof (VOID *)) {\r
232                   // print out Firewire or USB inplace of Serial Bus controllers\r
233                   Str = gPciSerialClassCodes[Hdr->ClassCode[1]];\r
234                 }\r
235               }\r
236             } else {\r
237               Str = "Unknown device         ";\r
238             }\r
239             AsciiPrint ("  0x%04x   0x%04x    %a 0x%02x", Hdr->VendorId, Hdr->DeviceId, Str, Hdr->ClassCode[1]);\r
240           }\r
241           if (Seg != 0) {\r
242             // Only print Segment if it is non zero. If you only have one PCI segment it is \r
243             // redundent to print it out\r
244             AsciiPrint (" Seg:%d", Seg);\r
245           }\r
246         }\r
247       }\r
248     }\r
249     AsciiPrint ("\n");\r
250   } else {\r
251     // Dump specific PCI device\r
252     for (Index = 0; Index < HandleCount; Index++) {\r
253       Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);\r
254       if (!EFI_ERROR (Status)) {\r
255         Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);\r
256         if ((Bus == BusArg) && (Dev == DevArg) && (Func == FuncArg)) {\r
257           // Only print Segment if it is non zero. If you only have one PCI segment it is \r
258           // redundent to print it out\r
259           if (Seg != 0) {\r
260             AsciiPrint ("Seg:%d ", Seg);\r
261           }\r
262           AsciiPrint ("Bus:%d Dev:%d Func:%d ", Bus, Dev, Func);\r
263           \r
264           Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), Header);\r
265           if (!EFI_ERROR (Status)) {\r
266             Hdr = &PciHeader.Bridge.Hdr;\r
267             if (IS_PCI_BRIDGE (&PciHeader.Bridge)) {\r
268               Bridge = &PciHeader.Bridge.Bridge;\r
269               AsciiPrint (\r
270                 "PCI Bridge. Bus Primary %d Secondary %d Subordinate %d\n", \r
271                 Bridge->PrimaryBus, Bridge->SecondaryBus, Bridge->SubordinateBus\r
272                 );\r
273               AsciiPrint ("  Bar 0: 0x%08x  Bar 1: 0x%08x\n", Bridge->Bar[0], Bridge->Bar[1]);\r
274             } else {\r
275               Device = &PciHeader.Device.Device;\r
276               AsciiPrint (\r
277                 "VendorId: 0x%04x DeviceId: 0x%04x SubSusVendorId: 0x%04x SubSysDeviceId: 0x%04x\n",\r
278                 Hdr->VendorId, Hdr->DeviceId, Device->SubsystemVendorID, Device->SubsystemID\r
279                 );\r
280               AsciiPrint ("  Class Code: 0x%02x 0x%02x 0x%02x\n", Hdr->ClassCode[2], Hdr->ClassCode[1], Hdr->ClassCode[0]);\r
281               for (Count = 0; Count < 6; Count++) {\r
282                 AsciiPrint ("  Bar %d: 0x%08x\n", Count, Device->Bar[Count]);\r
283               }\r
284             }\r
285           }\r
286           \r
287           AsciiPrint ("\n");\r
288           break;\r
289         }\r
290       }\r
291     }\r
292   }\r
293   \r
294   FreePool (HandleBuffer);\r
295   return EFI_SUCCESS;\r
296 }\r
297 \r
298 \r
299 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdPciDebugTemplate[] = {\r
300   "pci",\r
301   " [bus] [dev] [func]; Dump PCI",\r
302   NULL,\r
303   EblPciCmd\r
304 };\r
305 \r
306 \r
307 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwDebugTemplate[] =\r
308 {\r
309   {\r
310     "md",\r
311     "[.{1|2|4}] [Addr] [Len] [1|2|4]; Memory Dump from Addr Len bytes",\r
312     NULL,\r
313     EblMdCmd\r
314   },\r
315   {\r
316     "mfill",\r
317     "[.{1|2|4}] Addr Len [data] [1|2|4]; Memory Fill Addr Len*(1|2|4) bytes of data(0)",\r
318     NULL,\r
319     EblMfillCmd\r
320   },\r
321 };\r
322 \r
323 \r
324 \r
325 /**\r
326   Initialize the commands in this in this file\r
327 **/\r
328 VOID\r
329 EblInitializemdHwDebugCmds (\r
330   VOID\r
331   )\r
332 {\r
333   if (FeaturePcdGet (PcdEmbeddedHwDebugCmd)) {\r
334     EblAddCommands (mCmdHwDebugTemplate, sizeof (mCmdHwDebugTemplate)/sizeof (EBL_COMMAND_TABLE));\r
335   }\r
336   if (FeaturePcdGet (PcdEmbeddedPciDebugCmd)) {\r
337     EblAddCommands (mCmdPciDebugTemplate, sizeof (mCmdPciDebugTemplate)/sizeof (EBL_COMMAND_TABLE));\r
338   }\r
339 }\r
340 \r