Translate

Archives

Using PCI.IDS Database to Show PCI Vendor and Device Information in UEFI Shell

The UEFI Shell has a built-in command called pci for enumerating PCI (Peripheral Component Interconnect) devices. Here is what is outputted for a Lenovo T450 using this command:

fs1:> pci
   Seg  Bus  Dev  Func
   ---  ---  ---  ----
    00   00   00    00 ==> Bridge Device - Host/PCI bridge
             Vendor 8086 Device 1604 Prog Interface 0
    00   00   02    00 ==> Display Controller - VGA/8514 controller
             Vendor 8086 Device 1616 Prog Interface 0
    00   00   03    00 ==> Multimedia Device - Mixed mode device
             Vendor 8086 Device 160C Prog Interface 0
    00   00   14    00 ==> Serial Bus Controllers - USB
             Vendor 8086 Device 9CB1 Prog Interface 30
    00   00   16    00 ==> Simple Communications Controllers - Other communication device
             Vendor 8086 Device 9CBA Prog Interface 0
    00   00   19    00 ==> Network Controller - Ethernet controller
             Vendor 8086 Device 15A2 Prog Interface 0
    00   00   1B    00 ==> Multimedia Device - Mixed mode device
             Vendor 8086 Device 9CA0 Prog Interface 0
    00   00   1C    00 ==> Bridge Device - PCI/PCI bridge
             Vendor 8086 Device 9C9A Prog Interface 0
    00   00   1C    01 ==> Bridge Device - PCI/PCI bridge
             Vendor 8086 Device 9C94 Prog Interface 0
    00   00   1D    00 ==> Serial Bus Controllers - USB
             Vendor 8086 Device 9CA6 Prog Interface 20
    00   00   1F    00 ==> Bridge Device - PCI/ISA bridge
             Vendor 8086 Device 9CC3 Prog Interface 0
    00   00   1F    02 ==> Mass Storage Controller - Serial ATA controller
             Vendor 8086 Device 9C83 Prog Interface 1
    00   00   1F    03 ==> Serial Bus Controllers - System Management Bus
             Vendor 8086 Device 9CA2 Prog Interface 0
    00   00   1F    06 ==> Data Acquisition & Signal Processing Controllers - Other DAQ & SP controllers
             Vendor 8086 Device 9CA4 Prog Interface 0
    00   02   00    00 ==> Device does not fit in any defined classes - 
             Vendor 10EC Device 5227 Prog Interface 0
    00   03   00    00 ==> Network Controller - Other network controller
             Vendor 8086 Device 095B Prog Interface 0


As you can see the command returns, amongst other information, the Vendor ID (VID) and the Device ID (DID) together with a simple generic description of the device.

On Linux distributions, the utility lspci is typically used to view PCI information. This utility uses the pci.ids text-based database to provide descriptions of vendors, devices, and subvendors. It is not a perfect list but it is relatively complete.

Here is an excerpt from pci.ids which details where to get the file and the layout of the file, together with a number of entries:

#
#	List of PCI ID's
#
#	Version: 2016.01.02
#	Date:    2016-01-02 03:15:02
#
#	Maintained by Albert Pool, Martin Mares, and other volunteers from
#	the PCI ID Project at http://pci-ids.ucw.cz/.
#
#	New data are always welcome, especially if they are accurate. If you have
#	anything to contribute, please follow the instructions at the web site.
#
#	This file can be distributed under either the GNU General Public License
#	(version 2 or higher) or the 3-clause BSD License.
#

# Vendors, devices and subsystems. Please keep sorted.

# Syntax:
# vendor  vendor_name
#	device  device_name				< -- single tab
#		subvendor subdevice  subsystem_name	<-- two tabs

0001  SafeNet (wrong ID)
0010  Allied Telesis, Inc (Wrong ID)
# This is a relabelled RTL-8139
	8139  AT-2500TX V3 Ethernet
001c  PEAK-System Technik GmbH
	0001  PCAN-PCI CAN-Bus controller
		001c 0004  2 Channel CAN Bus SJC1000
		001c 0005  2 Channel CAN Bus SJC1000 (Optically Isolated)
003d  Lockheed Martin-Marietta Corp
# Real TJN ID is e159, but they got it wrong several times --mj
0059  Tiger Jet Network Inc. (Wrong ID)
0070  Hauppauge computer works Inc.
	7801  WinTV HVR-1800 MCE
0071  Nebula Electronics Ltd.
0095  Silicon Image, Inc. (Wrong ID)
	0680  Ultra ATA/133 IDE RAID CONTROLLER CARD
# Wrong ID used in subsystem ID of the TELES.S0/PCI 2.x ISDN adapter
00a7  Teles AG (Wrong ID)
0100  Ncipher Corp Ltd
0123  General Dynamics
# 018a is not LevelOne but there is a board misprogrammed
018a  LevelOne
	0106  FPC-0106TX misprogrammed [RTL81xx]
# 021b is not Compaq but there is a board misprogrammed
021b  Compaq Computer Corporation
	8139  HNE-300 (RealTek RTL8139c) [iPaq Networking]
0270  Hauppauge computer works Inc. (Wrong ID)
# SpeedStream is Efficient Networks, Inc, a Siemens Company
02ac  SpeedStream
	1012  1012 PCMCIA 10/100 Ethernet Card [RTL81xx]
0303  Hewlett-Packard Company (Wrong ID)
0308  ZyXEL Communications Corporation (Wrong ID)
0315  SK-Electronics Co., Ltd.
0357  TTTech Computertechnik AG (Wrong ID)
	000a  TTP-Monitoring Card V2.0
0432  SCM Microsystems, Inc.
	0001  Pluto2 DVB-T Receiver for PCMCIA [EasyWatch MobilSet]
0675  Dynalink
	1700  IS64PH ISDN Adapter
	1702  IS64PH ISDN Adapter
	1703  ISDN Adapter (PCI Bus, DV, W)
	1704  ISDN Adapter (PCI Bus, D, C)
0721  Sapphire, Inc.
0777  Ubiquiti Networks, Inc.
0795  Wired Inc.
	6663  Butane II (MPEG2 encoder board)
	6666  MediaPress (MPEG2 encoder board)
07d1  D-Link System Inc
0925  VIA Technologies, Inc. (Wrong ID)
0a89  BREA Technologies Inc


I decided to try and produce a “better” PCI utility for the UEFI shell – a utility that would use pci.ids to retrieve and display a description for both the VID and the DID of each device found. This blog post details my experiment.

Before you read any further, if you are unfamiliar with the PCI configuration space, you might wish to read this Wikipedia article. A good reference source for Vendor IDs and Device IDs is pcidatabase.com. It is more complete than the data in pci.ids.

The 16-bit VID and DID registers together identify the device (such as a networking chip), and are commonly called the PCI IDs. The VID is allocated by the PCI-SIG. The DID is assigned by the vendor.

The Subsystem Vendor ID (SVID) and the Subsystem ID (SSID) are used to differentiate between the original equipment manufacturer and the implementation manufacturer. If implemented correctly, the VID/DID/SVID/SSID combination provides a 4 tuple that is unique.

A example is useful here. Suppose Kane Security Devices Limited manufactures a PCI-based security board which uses a Intel LAN on Motherboard (LOM). The company is a member of PCI-SIG and has an assigned DID of 0xEEAA (SVIDs come from the DID namespace). Their DID would go into the SVID register in our example. What goes into the Subvendor Device ID field? Well, it can be anything you like. Some people just start at 1 (0 evidently causes problems) and increment the number for each new design.

Here is the source code for my utility (which I called ShowPCIx):

//
//  Copyright (c) 2017  Finnbarr P. Murphy.   All rights reserved.
//
//  Show PCI devices using PCI.IDS text-based database
//
//  License: UDK2015 license applies to code from UDK2015 source, 
//           BSD 2 cluase license applies to all other code.
//


#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/ShellLib.h>
#include <Library/ShellCommandLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PrintLib.h>

#include <Protocol/EfiShell.h>
#include <Protocol/PciEnumerationComplete.h>
#include <Protocol/PciRootBridgeIo.h>

#include <IndustryStandard/Pci.h>

#define CALC_EFI_PCI_ADDRESS(Bus, Dev, Func, Reg) \
    ((UINT64) ((((UINTN) Bus) << 24) + (((UINTN) Dev) << 16) + (((UINTN) Func) << 8) + ((UINTN) Reg)))

// all typedefs from UDK2015 sources
#pragma pack(1)
typedef struct {
   UINT16  VendorId;
   UINT16  DeviceId;
   UINT16  Command;
   UINT16  Status;
   UINT8   RevisionId;
   UINT8   ClassCode[3];
   UINT8   CacheLineSize;
   UINT8   PrimaryLatencyTimer;
   UINT8   HeaderType;
   UINT8   Bist;
} PCI_COMMON_HEADER;

typedef struct {
   UINT32  Bar[6];               // Base Address Registers
   UINT32  CardBusCISPtr;        // CardBus CIS Pointer
   UINT16  SubVendorId;          // Subsystem Vendor ID
   UINT16  SubSystemId;          // Subsystem ID
   UINT32  ROMBar;               // Expansion ROM Base Address
   UINT8   CapabilitiesPtr;      // Capabilities Pointer
   UINT8   Reserved[3];
   UINT32  Reserved1;
   UINT8   InterruptLine;        // Interrupt Line
   UINT8   InterruptPin;         // Interrupt Pin
   UINT8   MinGnt;               // Min_Gnt
   UINT8   MaxLat;               // Max_Lat
} PCI_DEVICE_HEADER;

typedef struct {
   UINT32  CardBusSocketReg;     // Cardus Socket/ExCA Base Address Register
   UINT8   CapabilitiesPtr;      // 14h in pci-cardbus bridge.
   UINT8   Reserved;
   UINT16  SecondaryStatus;      // Secondary Status
   UINT8   PciBusNumber;         // PCI Bus Number
   UINT8   CardBusBusNumber;     // CardBus Bus Number
   UINT8   SubordinateBusNumber; // Subordinate Bus Number
   UINT8   CardBusLatencyTimer;  // CardBus Latency Timer
   UINT32  MemoryBase0;          // Memory Base Register 0
   UINT32  MemoryLimit0;         // Memory Limit Register 0
   UINT32  MemoryBase1;
   UINT32  MemoryLimit1;
   UINT32  IoBase0;
   UINT32  IoLimit0;             // I/O Base Register 0
   UINT32  IoBase1;              // I/O Limit Register 0
   UINT32  IoLimit1;
   UINT8   InterruptLine;        // Interrupt Line
   UINT8   InterruptPin;         // Interrupt Pin
   UINT16  BridgeControl;        // Bridge Control
} PCI_CARDBUS_HEADER;

typedef union {
   PCI_DEVICE_HEADER   Device;
   PCI_CARDBUS_HEADER  CardBus;
} NON_COMMON_UNION;

typedef struct {
   PCI_COMMON_HEADER Common;
   NON_COMMON_UNION  NonCommon;
   UINT32            Data[48];
} PCI_CONFIG_SPACE;
#pragma pack()

#define UTILITY_VERSION L"0.8"
#define LINE_MAX  1024

#define EFI_PCI_EMUMERATION_COMPLETE_GUID \
    { 0x30cfe3e7, 0x3de1, 0x4586, {0xbe, 0x20, 0xde, 0xab, 0xa1, 0xb3, 0xb7, 0x93}}


CHAR16 *
GetDeviceDesc( CHAR16 *Line)
{
    CHAR16 *s = Line;
    static CHAR16 DeviceDesc[LINE_MAX];
    CHAR16 *d = DeviceDesc;

    s++;
    while (*s++) {
        if (*s == L' ' || *s == L'\t')
           break;
    }

    while (*s++) {
        if (*s != L' ' && *s != L'\t')
           break;
    }

    while (*s) {
        *(d++) = *(s++);
    }
    *d = 0;

    return DeviceDesc;
}


CHAR16 *
GetVendorDesc( CHAR16 *Line)
{
    CHAR16 *s = Line;
    static CHAR16 VendorDesc[LINE_MAX];
    CHAR16 *d = VendorDesc;

    while (*s++) {
        if (*s == L' ' || *s == L'\t')
            break;
    }

    while (*s++) {
        if (*s != L' ' && *s != L'\t')
            break;
    }

    while (*s) {
        *(d++) = *(s++);
    }
    *d = 0;

    return VendorDesc;
}


//
// Copied from UDK2015 Source.
//
EFI_STATUS
PciGetNextBusRange( EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
                    UINT16 *MinBus,
                    UINT16 *MaxBus,
                    BOOLEAN *IsEnd)
{
    *IsEnd = FALSE;

    if ((*Descriptors) == NULL) {
        *MinBus = 0;
        *MaxBus = PCI_MAX_BUS;
        return EFI_SUCCESS;
    }

    while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
        if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
            *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
            *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
            (*Descriptors)++;
            return (EFI_SUCCESS);
        }

        (*Descriptors)++;
    }

    if ((*Descriptors)->Desc == ACPI_END_TAG_DESCRIPTOR) {
        *IsEnd = TRUE;
    }

    return EFI_SUCCESS;
}


//
// Copied from UDK2015 Source. 
//
EFI_STATUS
PciGetProtocolAndResource( EFI_HANDLE Handle,
                           EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **IoDev,
                           EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors)
{
    EFI_STATUS Status;

    Status = gBS->HandleProtocol( Handle,
                                  &gEfiPciRootBridgeIoProtocolGuid,
                                  (VOID**)IoDev);
    if (EFI_ERROR (Status)) {
        return Status;
    }

    Status = (*IoDev)->Configuration (*IoDev, (VOID**)Descriptors);
    if (Status == EFI_UNSUPPORTED) {
        *Descriptors = NULL;
        return EFI_SUCCESS;
    }

    return Status;
}


VOID
LowerCaseStr( CHAR16 *Str)
{
    for (int i = 0; Str[i] != L'\0'; i++) {
        if (Str[i] >= L'A' && Str[i] <= L'Z') {
            Str[i] -= (CHAR16)(L'A' - L'a');
        }
    }
}


BOOLEAN
SearchPciData( SHELL_FILE_HANDLE FileHandle,
               CHAR16 *ReadLine,
               UINTN VendorID, 
               UINTN DeviceID)
{

    EFI_STATUS Status = EFI_SUCCESS;
    BOOLEAN Found = FALSE;
    BOOLEAN VendorFound = FALSE;
    BOOLEAN Ascii = TRUE;
    UINTN   Size = LINE_MAX;
    CHAR16  Vendor[5];
    CHAR16  Device[5];

    UnicodeSPrint(Vendor, sizeof(Vendor), L"%04x", VendorID);
    LowerCaseStr(Vendor);
    UnicodeSPrint(Device, sizeof(Device), L"%04x", DeviceID);
    LowerCaseStr(Device);

    ShellSetFilePosition(FileHandle, 0);

    // read file line by line
    for (;!ShellFileHandleEof(FileHandle); Size = 1024) {
        Status = ShellFileHandleReadLine(FileHandle, ReadLine, &Size, TRUE, &Ascii);
        if (Status == EFI_BUFFER_TOO_SMALL) {
            Status = EFI_SUCCESS;
        } else if (EFI_ERROR(Status)) {
            break;
        }

        // Skip comment and empty lines
        if (ReadLine[0] == L'#' || ReadLine[0] == L' ' || 
            ReadLine[0] == L'\n' || ReadLine[0] == L'\r') {
            continue;
        }
 
        if (StrnCmp(ReadLine, Vendor, 4) == 0) {
            Print(L"     %s", GetVendorDesc(ReadLine));
            VendorFound = TRUE;
        } else if (VendorFound && StrnCmp(&ReadLine[1], Device, 4) == 0) {
            Print(L", %s", GetDeviceDesc(ReadLine));
            Found = TRUE;
            break;
        } else if (VendorFound && (StrnCmp(ReadLine, L"\t", 1) != 0) && 
                  (StrnCmp(ReadLine, L"\t\t", 2) != 0)) {
            break;
        }
    }

    return Found;
} 


VOID
Usage( CHAR16 *Str)
{
    Print(L"Usage: %s [ -v | --verbose ]\n", Str);
    Print(L"       %s [ -h | --help | -V | --version ]\n", Str);
}


INTN
EFIAPI
ShellAppMain(UINTN Argc, CHAR16 **Argv)
{
    EFI_GUID gEfiPciEnumerationCompleteProtocolGuid = EFI_PCI_EMUMERATION_COMPLETE_GUID;  
    EFI_STATUS Status = EFI_SUCCESS;
    EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev;
    EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
    SHELL_FILE_HANDLE InFileHandle = (SHELL_FILE_HANDLE)NULL;
    PCI_COMMON_HEADER PciHeader;
    PCI_CONFIG_SPACE ConfigSpace;
    PCI_DEVICE_HEADER *DeviceHeader;
    CHAR16 FileName[] = L"pci.ids";
    CHAR16 *FullFileName = (CHAR16 *)NULL;
    CHAR16 *ReadLine = (CHAR16 *)NULL;
    VOID *Interface;
    EFI_HANDLE *HandleBuf;
    UINTN HandleBufSize;
    UINTN HandleCount;
    UINTN Size = LINE_MAX;
    UINT16 MinBus, MaxBus;
    UINT64 Address;
    BOOLEAN IsEnd; 
    BOOLEAN Verbose = FALSE;
  
    for (int i = 1; i < Argc; i++) {
        if (!StrCmp(Argv[i], L"--version") ||
            !StrCmp(Argv[i], L"-V")) {
            Print(L"Version: %s\n", UTILITY_VERSION);
            return Status;
        } else if (!StrCmp(Argv[i], L"--verbose") ||
            !StrCmp(Argv[i], L"-v")) {
            Verbose = TRUE;
        } else if (!StrCmp(Argv[i], L"--help") ||
            !StrCmp(Argv[i], L"-h") ||
            !StrCmp(Argv[i], L"-?")) {
            Usage(Argv[0]);
            return Status;
        } else {
            Print(L"ERROR: Unknown option.\n");
            Usage(Argv[0]);
            return Status;
        }
    }


    Status = gBS->LocateProtocol( &gEfiPciEnumerationCompleteProtocolGuid,
                                  NULL,
                                  &Interface);
    if (EFI_ERROR(Status)) {
        Print(L"ERROR: Could not find an enumerated PCI database\n");
        return Status;
    }

    HandleBufSize = sizeof(EFI_HANDLE);
    HandleBuf = (EFI_HANDLE *) AllocateZeroPool( HandleBufSize);
    if (HandleBuf == NULL) {
        Print(L"ERROR: Out of memory resources\n");
        goto Done;
    }

    Status = gBS->LocateHandle( ByProtocol,
                                &gEfiPciRootBridgeIoProtocolGuid,
                                NULL,
                                &HandleBufSize,
                                HandleBuf);

    if (Status == EFI_BUFFER_TOO_SMALL) {
        HandleBuf = ReallocatePool (sizeof (EFI_HANDLE), HandleBufSize, HandleBuf);
        if (HandleBuf == NULL) {
            Print(L"ERROR: Out of memory resources\n");
            goto Done;
        }

        Status = gBS->LocateHandle( ByProtocol,
                                    &gEfiPciRootBridgeIoProtocolGuid,
                                    NULL,
                                    &HandleBufSize,
                                    HandleBuf);
    }

    if (EFI_ERROR (Status)) {
        Print(L"ERROR: Failed to find any PCI handles\n");
        goto Done;
    }

    if (Verbose) {
        FullFileName = ShellFindFilePath(FileName);
        if (FullFileName == NULL) {
            Print(L"ERROR: Could not find %s\n", FileName);
            Status = EFI_NOT_FOUND;
            goto Done;
        }

        // open the file
        Status = ShellOpenFileByName(FullFileName, &InFileHandle, EFI_FILE_MODE_READ, 0);
        if (EFI_ERROR(Status)) {
            Print(L"ERROR: Could not open %s\n", FileName);
            goto Done;
        }

        // allocate a buffer to read lines into
        ReadLine = AllocateZeroPool(Size);
        if (ReadLine == NULL) {
            Print(L"ERROR: Could not allocate memory\n");
            Status = EFI_OUT_OF_RESOURCES;
            goto Done;
        }
    }

    HandleCount = HandleBufSize / sizeof (EFI_HANDLE);

    for (UINT16 Index = 0; Index < HandleCount; Index++) {
        Status = PciGetProtocolAndResource( HandleBuf[Index],
                                            &IoDev,
                                            &Descriptors);
        if (EFI_ERROR(Status)) {
            Print(L"ERROR: PciGetProtocolAndResource [%d]\n, Status");
            goto Done;
        }
  
        while(1) {
            Status = PciGetNextBusRange( &Descriptors, &MinBus, &MaxBus, &IsEnd);
            if (EFI_ERROR(Status)) {
                Print(L"ERROR: Retrieving PCI bus range [%d]\n", Status);
                goto Done;
            }

            if (IsEnd) {
                break;
            }

            Print(L"\n");
            Print(L"Bus    Vendor   Device  Subvendor SVDevice\n");
            Print(L"\n");

            for (UINT16 Bus = MinBus; Bus <= MaxBus; Bus++) {
                for (UINT16 Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
                    for (UINT16 Func = 0; Func <= PCI_MAX_FUNC; Func++) {
                         Address = CALC_EFI_PCI_ADDRESS (Bus, Device, Func, 0);

                         Status = IoDev->Pci.Read( IoDev,
                                                   EfiPciWidthUint8,
                                                   Address,
                                                   sizeof(ConfigSpace),
                                                   &ConfigSpace);

                         DeviceHeader = (PCI_DEVICE_HEADER *) &(ConfigSpace.NonCommon.Device);

                         Status = IoDev->Pci.Read( IoDev,
                                                   EfiPciWidthUint16,
                                                   Address,
                                                   1,
                                                   &PciHeader.VendorId);

                         if (PciHeader.VendorId == 0xffff && Func == 0) {
                             break;
                         }

                         if (PciHeader.VendorId != 0xffff) {
                             Status = IoDev->Pci.Read( IoDev,
                                                       EfiPciWidthUint32,
                                                       Address,
                                                       sizeof(PciHeader)/sizeof(UINT32),
                                                       &PciHeader);

                             Print(L" %02d     %04x     %04x     %04x     %04x", 
                                   Bus, PciHeader.VendorId, PciHeader.DeviceId, 
                                   DeviceHeader->SubVendorId, DeviceHeader->SubSystemId);

                             if (Verbose) {
                                 SearchPciData( InFileHandle, 
                                                ReadLine, 
                                                PciHeader.VendorId, 
                                                PciHeader.DeviceId);
                             }

                             Print(L"\n");

                             if (Func == 0 && 
                                ((PciHeader.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00)) {
                                break;
                             }
                         }
                     }
                 }
             }

            if (Descriptors == NULL) {
                break;
            }
        }
    }

    Print(L"\n");

Done:
    if (HandleBuf != NULL) {
        FreePool(HandleBuf);
    }
    if (Verbose) {
        if (ReadLine != NULL) {
            FreePool(ReadLine);
        }
        if (FullFileName != NULL) {
            FreePool(FullFileName);
        }
        if (InFileHandle != NULL) {
            ShellCloseFile(&InFileHandle);
        }
    }

    return Status;
}


As usual, it is assumed that you are familiar with the various UEFI specifications and UDK2015 if you are reading this blog post. The above source code is not production quality code and still needs some work to make it more robust. Currently it has no support for displaying SubVendor ID descriptions but the required code to do so can easily be added.

Note that 0xFFFF is the value that is returned on read accesses to PCI configuration space registers of non-existent devices. Hence the test for this value in the above code.

I could also have listed the PCI class code and description for each device but I do not think it adds much value to the output. There are standard classes for every sort of PCI device; for example the class code for a SCSI device is 0x0100.

Here is the UDK2015 build file that I used:

[Defines]
  INF_VERSION                    = 0x00010006
  BASE_NAME                      = ShowPCIx
  FILE_GUID                      = 4ea87c51-7491-4dfd-0055-767013f3ce51
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 0.1
  ENTRY_POINT                    = ShellCEntryLib
  VALID_ARCHITECTURES            = X64

[Sources]
  ShowPCIx.c

[Packages]
  MdePkg/MdePkg.dec
  ShellPkg/ShellPkg.dec 
 
[LibraryClasses]
  ShellCEntryLib   
  ShellLib
  ShellCommandLib
  BaseLib
  BaseMemoryLib
  UefiLib
  
[Protocols]
  gEfiPciRootBridgeIoProtocolGuid             ## CONSUMES
  
[BuildOptions]

[Pcd]


Note that the code has only been built and tested on Intel X64 platforms so there may be architecture-related issues on other platforms.

Use the same laptop, here is the output from my utility:

fs1> ShowPCIx --help
Usage: FS1:\ShowPCI.efi [ -v | --verbose ]
       FS1:\ShowPCI.efi [ -h | --help | -V | --version ]

fs1> ShowPCIx

Bus    Vendor   Device  Subvendor SVDevice

 00     8086     1604     17AA     5034
 00     8086     1616     17AA     5034
 00     8086     160C     17AA     5034
 00     8086     9CB1     17AA     5034
 00     8086     9CBA     17AA     5034
 00     8086     15A2     17AA     2226
 00     8086     9CA0     17AA     5034
 00     8086     9C9A     0000     0000
 00     8086     9C94     0000     0000
 00     8086     9CA6     17AA     5034
 00     8086     9CC3     17AA     5034
 00     8086     9C83     17AA     5034
 00     8086     9CA2     17AA     5034
 00     8086     9CA4     17AA     5034
 02     10EC     5227     17AA     5034
 03     8086     095B     8086     5210

fs1> ShowPCIx --verbose

Bus    Vendor   Device  Subvendor SVDevice

 00     8086     1604     17AA     5034     Intel Corporation, Broadwell-U Host Bridge -OPI
 00     8086     1616     17AA     5034     Intel Corporation, Broadwell-U Integrated Graphics
 00     8086     160C     17AA     5034     Intel Corporation, Broadwell-U Audio Controller
 00     8086     9CB1     17AA     5034     Intel Corporation, Wildcat Point-LP USB xHCI Controller
 00     8086     9CBA     17AA     5034     Intel Corporation, Wildcat Point-LP MEI Controller #1
 00     8086     15A2     17AA     2226     Intel Corporation, Ethernet Connection (3) I218-LM
 00     8086     9CA0     17AA     5034     Intel Corporation, Wildcat Point-LP High Definition Audio Controller
 00     8086     9C9A     0000     0000     Intel Corporation, Wildcat Point-LP PCI Express Root Port #6
 00     8086     9C94     0000     0000     Intel Corporation, Wildcat Point-LP PCI Express Root Port #3
 00     8086     9CA6     17AA     5034     Intel Corporation, Wildcat Point-LP USB EHCI Controller
 00     8086     9CC3     17AA     5034     Intel Corporation, Wildcat Point-LP LPC Controller
 00     8086     9C83     17AA     5034     Intel Corporation, Wildcat Point-LP SATA Controller [AHCI Mode]
 00     8086     9CA2     17AA     5034     Intel Corporation, Wildcat Point-LP SMBus Controller
 00     8086     9CA4     17AA     5034     Intel Corporation, Wildcat Point-LP Thermal Management Controller
 02     10EC     5227     17AA     5034     Realtek Semiconductor Co., Ltd., RTS5227 PCI Express Card Reader
 03     8086     095B     8086     5210     Intel Corporation, Wireless 7265

fs1>


As you can see, the output is more useful due to the additional of VID and DID descriptions.

Hopefully the developers of the UEFI reference implementation will consider adding support for pci.ids, or a similar database, to a future version of the UEFI shell.

Enjoy!

1 comment to Using PCI.IDS Database to Show PCI Vendor and Device Information in UEFI Shell

  • ER

    I hope I can ask a question regarding your article on converting MBR to GPT. I have followed your steps and everything completes without error. When I reboot Fedora 16 I only get GRUB_ with a flashing underscore but no GRUB boot menu. I have hammered on this for a week and this is where I am. SDA1 is flagged bios boot, SDA2 has the Linux OS and SDA3 is storage.

    The original install uses MBR and works fine with a 2TB limit. I am trying to move to GPT to expand the drive to 4TB.

    I have captured all of the terminal process to text.

    How can I recover the GRUB boot menu?