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