2009-12-06 02:57:05 +01:00
|
|
|
/** @file
|
|
|
|
Basic command line parser for EBL (Embedded Boot Loader)
|
|
|
|
|
2010-04-29 14:40:51 +02:00
|
|
|
Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
|
|
|
|
Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
2009-12-06 02:57:05 +01:00
|
|
|
|
2010-04-29 14:40:51 +02:00
|
|
|
This program and the accompanying materials
|
2009-12-06 02:57:05 +01:00
|
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
|
|
|
|
Module Name: HwDebug.c
|
|
|
|
|
|
|
|
Commands useful for debugging hardware.
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "Ebl.h"
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Dump memory
|
|
|
|
|
2010-02-11 00:48:46 +01:00
|
|
|
Argv[0] - "md"[.#] # is optiona width 1, 2, 4, or 8. Default 1
|
2009-12-06 02:57:05 +01:00
|
|
|
Argv[1] - Hex Address to dump
|
|
|
|
Argv[2] - Number of hex bytes to dump (0x20 is default)
|
|
|
|
|
2010-02-11 00:48:46 +01:00
|
|
|
md.4 0x123445678 50 ; Dump 0x50 4 byte quantities starting at 0x123445678
|
|
|
|
md 0x123445678 40 ; Dump 0x40 1 byte quantities starting at 0x123445678
|
|
|
|
md 0x123445678 ; Dump 0x20 1 byte quantities starting at 0x123445678
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
@param Argc Number of command arguments in Argv
|
|
|
|
@param Argv Array of strings that represent the parsed command line.
|
|
|
|
Argv[0] is the comamnd name
|
|
|
|
|
|
|
|
@return EFI_SUCCESS
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EblMdCmd (
|
|
|
|
IN UINTN Argc,
|
|
|
|
IN CHAR8 **Argv
|
|
|
|
)
|
|
|
|
{
|
|
|
|
STATIC UINT8 *Address = NULL;
|
|
|
|
STATIC UINTN Length = 0x20;
|
2010-02-11 00:48:46 +01:00
|
|
|
STATIC UINTN Width;
|
2009-12-06 02:57:05 +01:00
|
|
|
|
2010-02-11 00:48:46 +01:00
|
|
|
Width = WidthFromCommandName (Argv[0], 1);
|
|
|
|
|
|
|
|
switch (Argc) {
|
2009-12-06 02:57:05 +01:00
|
|
|
case 3:
|
|
|
|
Length = AsciiStrHexToUintn(Argv[2]);
|
|
|
|
case 2:
|
2010-02-11 00:48:46 +01:00
|
|
|
Address = (UINT8 *)AsciiStrHexToUintn (Argv[1]);
|
2009-12-06 02:57:05 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-02-11 00:48:46 +01:00
|
|
|
OutputData (Address, Length, Width, (UINTN)Address);
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
Address += Length;
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Fill Memory with data
|
|
|
|
|
2011-08-08 20:29:14 +02:00
|
|
|
Argv[0] - "mfill"[.#] # is optional width 1, 2, 4, or 8. Default 4
|
2009-12-06 02:57:05 +01:00
|
|
|
Argv[1] - Hex Address to fill
|
|
|
|
Argv[2] - Data to write (0x00 is default)
|
|
|
|
Argv[3] - Number of units to dump.
|
|
|
|
|
2010-02-11 00:48:46 +01:00
|
|
|
mf.1 0x123445678 aa 100 ; Start at 0x123445678 and write aa (1 byte) to the next 100 bytes
|
|
|
|
mf.4 0x123445678 aa 100 ; Start at 0x123445678 and write aa (4 byte) to the next 400 bytes
|
2009-12-06 02:57:05 +01:00
|
|
|
mf 0x123445678 aa ; Start at 0x123445678 and write aa (4 byte) to the next 1 byte
|
|
|
|
mf 0x123445678 ; Start at 0x123445678 and write 00 (4 byte) to the next 1 byte
|
|
|
|
|
|
|
|
@param Argc Number of command arguments in Argv
|
|
|
|
@param Argv Array of strings that represent the parsed command line.
|
2011-08-08 20:29:14 +02:00
|
|
|
Argv[0] is the command name
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
@return EFI_SUCCESS
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EblMfillCmd (
|
|
|
|
IN UINTN Argc,
|
|
|
|
IN CHAR8 **Argv
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Address;
|
|
|
|
UINTN EndAddress;
|
|
|
|
UINT32 Data;
|
|
|
|
UINTN Length;
|
|
|
|
UINTN Width;
|
|
|
|
|
|
|
|
if (Argc < 2) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2010-02-11 00:48:46 +01:00
|
|
|
Width = WidthFromCommandName (Argv[0], 4);
|
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
Address = AsciiStrHexToUintn (Argv[1]);
|
|
|
|
Data = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 0;
|
2010-02-11 00:48:46 +01:00
|
|
|
Length = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 1;
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
for (EndAddress = Address + (Length * Width); Address < EndAddress; Address += Width) {
|
|
|
|
if (Width == 4) {
|
|
|
|
MmioWrite32 (Address, Data);
|
|
|
|
} else if (Width == 2) {
|
2010-02-17 00:43:28 +01:00
|
|
|
MmioWrite16 (Address, (UINT16)Data);
|
2009-12-06 02:57:05 +01:00
|
|
|
} else {
|
2010-02-17 00:43:28 +01:00
|
|
|
MmioWrite8 (Address, (UINT8)Data);
|
2009-12-06 02:57:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Strings for PCI Class code [2]
|
|
|
|
//
|
|
|
|
CHAR8 *gPciDevClass[] = {
|
|
|
|
"Old Device ",
|
|
|
|
"Mass storage ",
|
|
|
|
"Network ",
|
|
|
|
"Display ",
|
|
|
|
"Multimedia ",
|
|
|
|
"Memory controller ",
|
|
|
|
"Bridge device ",
|
|
|
|
"simple communications ",
|
|
|
|
"base system peripherals",
|
|
|
|
"Input devices ",
|
|
|
|
"Docking stations ",
|
|
|
|
"Processors ",
|
|
|
|
"serial bus ",
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
CHAR8 *gPciSerialClassCodes[] = {
|
|
|
|
"Mass storage ",
|
|
|
|
"Firewire ",
|
|
|
|
"ACCESS bus ",
|
|
|
|
"SSA ",
|
|
|
|
"USB "
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
PCI Dump
|
|
|
|
|
|
|
|
Argv[0] - "pci"
|
|
|
|
Argv[1] - bus
|
|
|
|
Argv[2] - dev
|
|
|
|
Argv[3] - func
|
|
|
|
|
|
|
|
@param Argc Number of command arguments in Argv
|
|
|
|
@param Argv Array of strings that represent the parsed command line.
|
2011-08-08 20:29:14 +02:00
|
|
|
Argv[0] is the command name
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
@return EFI_SUCCESS
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EblPciCmd (
|
|
|
|
IN UINTN Argc,
|
|
|
|
IN CHAR8 **Argv
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_PCI_IO_PROTOCOL *Pci;
|
|
|
|
UINTN HandleCount;
|
|
|
|
EFI_HANDLE *HandleBuffer;
|
|
|
|
UINTN Seg;
|
|
|
|
UINTN Bus;
|
|
|
|
UINTN Dev;
|
|
|
|
UINTN Func;
|
|
|
|
UINTN BusArg;
|
|
|
|
UINTN DevArg;
|
|
|
|
UINTN FuncArg;
|
|
|
|
UINTN Index;
|
|
|
|
UINTN Count;
|
|
|
|
PCI_TYPE_GENERIC PciHeader;
|
|
|
|
PCI_TYPE_GENERIC *Header;
|
|
|
|
PCI_BRIDGE_CONTROL_REGISTER *Bridge;
|
|
|
|
PCI_DEVICE_HEADER_TYPE_REGION *Device;
|
|
|
|
PCI_DEVICE_INDEPENDENT_REGION *Hdr;
|
|
|
|
CHAR8 *Str;
|
|
|
|
UINTN ThisBus;
|
|
|
|
|
|
|
|
|
|
|
|
BusArg = (Argc > 1) ? AsciiStrDecimalToUintn (Argv[1]) : 0;
|
|
|
|
DevArg = (Argc > 2) ? AsciiStrDecimalToUintn (Argv[2]) : 0;
|
|
|
|
FuncArg = (Argc > 3) ? AsciiStrDecimalToUintn (Argv[3]) : 0;
|
|
|
|
|
|
|
|
Header = &PciHeader;
|
|
|
|
|
|
|
|
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
AsciiPrint ("No PCI devices found in the system\n");
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Argc == 1) {
|
|
|
|
// Dump all PCI devices
|
|
|
|
AsciiPrint ("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
|
|
|
|
AsciiPrint ("_____________________________________________________________");
|
|
|
|
for (ThisBus = 0; ThisBus <= PCI_MAX_BUS; ThisBus++) {
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
|
|
|
|
if (ThisBus != Bus) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
AsciiPrint ("\n%03d.%02d.%02d", Bus, Dev, Func);
|
|
|
|
Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), &PciHeader);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Hdr = &PciHeader.Bridge.Hdr;
|
|
|
|
|
|
|
|
if (Hdr->ClassCode[2] < sizeof (gPciDevClass)/sizeof (VOID *)) {
|
|
|
|
Str = gPciDevClass[Hdr->ClassCode[2]];
|
|
|
|
if (Hdr->ClassCode[2] == PCI_CLASS_SERIAL) {
|
|
|
|
if (Hdr->ClassCode[1] < sizeof (gPciSerialClassCodes)/sizeof (VOID *)) {
|
|
|
|
// print out Firewire or USB inplace of Serial Bus controllers
|
|
|
|
Str = gPciSerialClassCodes[Hdr->ClassCode[1]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Str = "Unknown device ";
|
|
|
|
}
|
|
|
|
AsciiPrint (" 0x%04x 0x%04x %a 0x%02x", Hdr->VendorId, Hdr->DeviceId, Str, Hdr->ClassCode[1]);
|
|
|
|
}
|
|
|
|
if (Seg != 0) {
|
|
|
|
// Only print Segment if it is non zero. If you only have one PCI segment it is
|
|
|
|
// redundent to print it out
|
|
|
|
AsciiPrint (" Seg:%d", Seg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AsciiPrint ("\n");
|
|
|
|
} else {
|
|
|
|
// Dump specific PCI device
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func);
|
|
|
|
if ((Bus == BusArg) && (Dev == DevArg) && (Func == FuncArg)) {
|
|
|
|
// Only print Segment if it is non zero. If you only have one PCI segment it is
|
2011-08-08 20:29:14 +02:00
|
|
|
// redundant to print it out
|
2009-12-06 02:57:05 +01:00
|
|
|
if (Seg != 0) {
|
|
|
|
AsciiPrint ("Seg:%d ", Seg);
|
|
|
|
}
|
|
|
|
AsciiPrint ("Bus:%d Dev:%d Func:%d ", Bus, Dev, Func);
|
|
|
|
|
|
|
|
Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), Header);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Hdr = &PciHeader.Bridge.Hdr;
|
|
|
|
if (IS_PCI_BRIDGE (&PciHeader.Bridge)) {
|
|
|
|
Bridge = &PciHeader.Bridge.Bridge;
|
|
|
|
AsciiPrint (
|
|
|
|
"PCI Bridge. Bus Primary %d Secondary %d Subordinate %d\n",
|
|
|
|
Bridge->PrimaryBus, Bridge->SecondaryBus, Bridge->SubordinateBus
|
|
|
|
);
|
|
|
|
AsciiPrint (" Bar 0: 0x%08x Bar 1: 0x%08x\n", Bridge->Bar[0], Bridge->Bar[1]);
|
|
|
|
} else {
|
|
|
|
Device = &PciHeader.Device.Device;
|
|
|
|
AsciiPrint (
|
|
|
|
"VendorId: 0x%04x DeviceId: 0x%04x SubSusVendorId: 0x%04x SubSysDeviceId: 0x%04x\n",
|
|
|
|
Hdr->VendorId, Hdr->DeviceId, Device->SubsystemVendorID, Device->SubsystemID
|
|
|
|
);
|
|
|
|
AsciiPrint (" Class Code: 0x%02x 0x%02x 0x%02x\n", Hdr->ClassCode[2], Hdr->ClassCode[1], Hdr->ClassCode[0]);
|
|
|
|
for (Count = 0; Count < 6; Count++) {
|
|
|
|
AsciiPrint (" Bar %d: 0x%08x\n", Count, Device->Bar[Count]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AsciiPrint ("\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FreePool (HandleBuffer);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdPciDebugTemplate[] = {
|
|
|
|
"pci",
|
|
|
|
" [bus] [dev] [func]; Dump PCI",
|
|
|
|
NULL,
|
|
|
|
EblPciCmd
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwDebugTemplate[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"md",
|
2010-02-11 00:48:46 +01:00
|
|
|
"[.{1|2|4}] [Addr] [Len] [1|2|4]; Memory Dump from Addr Len bytes",
|
2009-12-06 02:57:05 +01:00
|
|
|
NULL,
|
|
|
|
EblMdCmd
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"mfill",
|
2010-02-12 21:13:55 +01:00
|
|
|
"[.{1|2|4}] Addr Len [data]; Memory Fill Addr Len*(1|2|4) bytes of data(0)",
|
2009-12-06 02:57:05 +01:00
|
|
|
NULL,
|
|
|
|
EblMfillCmd
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Initialize the commands in this in this file
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EblInitializemdHwDebugCmds (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (FeaturePcdGet (PcdEmbeddedHwDebugCmd)) {
|
|
|
|
EblAddCommands (mCmdHwDebugTemplate, sizeof (mCmdHwDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
|
|
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdEmbeddedPciDebugCmd)) {
|
|
|
|
EblAddCommands (mCmdPciDebugTemplate, sizeof (mCmdPciDebugTemplate)/sizeof (EBL_COMMAND_TABLE));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|