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