Home | History | Annotate | Download | only in Ebl
      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
     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
     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
    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
    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