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