Skip to main content

Retrieving Disk Information in UEFI Using Disk Protocols

·796 words·4 mins
UEFI EDK2 Disk Firmware
Table of Contents

This article explores how to retrieve disk-related information in a UEFI environment by leveraging standard firmware protocols. The focus is on identifying physical disks and extracting metadata such as model name, serial number, firmware interface type, and capacity.

🧭 Introduction
#

UEFI provides several protocols for interacting with storage devices at different abstraction levels. The three most relevant protocols for disk enumeration and identification are:

  • EFI_BLOCK_IO_PROTOCOL – Provides block-level access to storage devices.
  • EFI_DISK_IO_PROTOCOL – Enables byte-level disk access.
  • EFI_DISK_INFO_PROTOCOL – Exposes hardware-specific disk information.

The first two protocols are defined in the UEFI Specification, while EFI_DISK_INFO_PROTOCOL is part of the PI (Platform Initialization) Specification.

🧱 BlockIo vs. DiskIo
#

Both BlockIo and DiskIo are used to access storage devices, but they differ in purpose and abstraction:

  • BlockIo operates at the block level and is commonly used for reading or writing logical blocks.
  • DiskIo provides lower-level, byte-granular access to the disk media.

In practice, BlockIo is useful for enumerating devices and determining media properties, while DiskIo helps confirm whether a handle represents a physical disk rather than a logical partition.

💽 DiskInfo Protocol Overview
#

The primary role of the DiskInfo protocol is to expose standardized, hardware-specific disk metadata. This information typically includes:

  • Disk interface type (IDE, AHCI, etc.)
  • Manufacturer and model name
  • Serial number
  • Firmware or identify data

This protocol is essential when you need to retrieve descriptive information rather than raw data blocks.

🧪 Practical Example
#

Objective
#

Enumerate all physical disks and print the following details:

  • Model name
  • Serial number (SN)
  • Disk interface type
  • Total capacity

Approach
#

  1. Use BlockIo to locate all block device handles.
  2. Filter out removable media and logical partitions.
  3. Use DiskIo to confirm access to physical disks.
  4. Query DiskInfo and call Identify() to retrieve raw identify data.
  5. Parse the identify data based on the disk interface type.
  6. Calculate disk capacity using media block information.

🧩 Code Implementation
#

/**
 * @file DiskInfo.c
 * @version 0.2
 * @date 2024-09-09
 */

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PrintLib.h>

#include <Protocol/BlockIo.h>
#include <Protocol/DiskIo.h>
#include <Protocol/DiskInfo.h>
#include <Protocol/IdeControllerInit.h>

VOID HexDump (UINT8 *Buffer, UINT8 RowNum)
{
  UINT8 Cols, Rows;

  for (Rows = 0; Rows < RowNum; Rows++) {
    for (Cols = 0; Cols < 16; Cols++) {
      Print(L"%2X ", Buffer[Cols + Rows * 16]);
    }
    Print(L"  ");
    for (Cols = 0; Cols < 16; Cols++) {
      if ((Buffer[Cols + Rows * 16] >= '0' && Buffer[Cols + Rows * 16] <= '9') ||
          (Buffer[Cols + Rows * 16] >= 'a' && Buffer[Cols + Rows * 16] <= 'z') ||
          (Buffer[Cols + Rows * 16] >= 'A' && Buffer[Cols + Rows * 16] <= 'Z')) {
        Print(L"%c", Buffer[Cols + Rows * 16]);
      } else {
        Print(L".");
      }
    }
    Print(L"\n\r");
  }
  Print(L"\n\r");
}

VOID BmEliminateExtraSpaces (IN CHAR16 *Str)
{
  UINTN Index, ActualIndex;

  for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
    if ((Str[Index] != L' ') ||
        ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
      Str[ActualIndex++] = Str[Index];
    }
  }
  Str[ActualIndex] = L'\0';
}

EFI_STATUS EFIAPI GetDiskIdentifyData (EFI_HANDLE Handle)
{
  EFI_STATUS Status;
  EFI_DISK_INFO_PROTOCOL *DiskInfo;
  EFI_ATAPI_IDENTIFY_DATA IdentifyData;
  UINT32 IdentifyDataSize;
  CHAR16 *ModelName;
  CHAR16 *SerialNo;
  UINTN Index;

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

  if (CompareGuid(&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
      CompareGuid(&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {

    IdentifyDataSize = sizeof(EFI_ATAPI_IDENTIFY_DATA);
    Status = DiskInfo->Identify(DiskInfo, &IdentifyData, &IdentifyDataSize);
    if (EFI_ERROR(Status)) {
      return Status;
    }

    ModelName = AllocatePool(sizeof(CHAR16) * 40);
    SerialNo  = AllocatePool(sizeof(CHAR16) * 20);

    for (Index = 0; Index + 1 < 40; Index += 2) {
      ModelName[Index]     = (CHAR16)IdentifyData.ModelName[Index + 1];
      ModelName[Index + 1] = (CHAR16)IdentifyData.ModelName[Index];
    }

    for (Index = 0; Index + 1 < 20; Index += 2) {
      SerialNo[Index]     = (CHAR16)IdentifyData.SerialNo[Index + 1];
      SerialNo[Index + 1] = (CHAR16)IdentifyData.SerialNo[Index];
    }

    BmEliminateExtraSpaces(ModelName);
    BmEliminateExtraSpaces(SerialNo);

    Print(L"Model Name: %s\n\r", ModelName);
    Print(L"Serial No : %s\n\r", SerialNo);
    Print(L"Disk Type : %g\n\r", DiskInfo->Interface);
  }

  return EFI_SUCCESS;
}

🧠 Parsing Logic Explained
#

According to the ATA specification, fields such as Model Name and Serial Number are stored as arrays of 16-bit words. Each word is encoded in little-endian format, meaning the least significant byte appears first. As a result, each pair of bytes must be swapped to produce readable strings.

for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
  ModelName[Index]     = (CHAR16) IdentifyData.ModelName[Index + 1];
  ModelName[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
}

Without this byte swap, the extracted strings would appear garbled or reversed.

📌 Limitations and Notes
#

  • The default EDK2 implementation only includes parsing definitions for IDE and AHCI devices.
  • NVMe and SD card parsing logic is not natively provided in UefiBootManagerLib and must be implemented separately.
  • The example logic is derived from BmGetDescriptionFromDiskInfo in MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c.

By combining BlockIo, DiskIo, and DiskInfo, firmware applications can reliably enumerate physical disks and extract meaningful hardware metadata in UEFI environments.

Related

14 High-Performance CSV Processing Techniques in Python (2025)
·639 words·3 mins
Python Data Engineering CSV Performance ETL
Architect’s Guide to Generative AI Tech Stack
·604 words·3 mins
GenAI AI Architecture Data Lake MLOps
The Lifespan of a Data Center GPU is Only 3 Years
·443 words·3 mins
Google GPU H100