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