这次介绍一下用来取得系统上硬盘信息的 Protocol: EFI_DISK_INFO_PROTOCOL。
在\MdePkg\Include\Protocol\DiskInfo.h 有他的原型:
/// /// Forward declaration for EFI_DISK_INFO_PROTOCOL /// typedef struct _EFI_DISK_INFO_PROTOCOL EFI_DISK_INFO_PROTOCOL; /// /// The EFI_DISK_INFO_PROTOCOL provides controller specific information. /// struct _EFI_DISK_INFO_PROTOCOL { /// /// A GUID that defines the format of buffers for the other member functions /// of this protocol. /// EFI_GUID Interface; /// /// Return the results of the Inquiry command to a drive in InquiryData. Data /// format of Inquiry data is defined by the Interface GUID. /// EFI_DISK_INFO_INQUIRY Inquiry; /// /// Return the results of the Identify command to a drive in IdentifyData. Data /// format of Identify data is defined by the Interface GUID. /// EFI_DISK_INFO_IDENTIFY Identify; /// /// Return the results of the Request Sense command to a drive in SenseData. Data /// format of Sense data is defined by the Interface GUID. /// EFI_DISK_INFO_SENSE_DATA SenseData; /// /// Specific controller. /// EFI_DISK_INFO_WHICH_IDE WhichIde; };
更详细的介绍可以在 PI Specification 1.4 上找到。
对于不同类型的设备,比如 IDE 和 USB ,返回的数据格式是不同的。枚举到这个 PROTOCOL 之后需要检查EFI_GUID Interface 通过不同的GUID得知当前设备的类型。
下面先编写一个简单的 Demo,检查 GUID ,判断当前设备的类型:
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellCEntryLib.h> #include <Library/ShellCEntryLib.h> #include <Protocol/DiskInfo.h> #include <Library/BaseMemoryLib.h> extern EFI_BOOT_SERVICES *gBS; extern EFI_HANDLE gImageHandle; EFI_GUID gEfiDiskInfoProtocolGuid = { 0xD432A67F, 0x14DC, 0x484B, { 0xB3, 0xBB, 0x3F, 0x02, 0x91, 0x84, 0x93, 0x27 }}; EFI_GUID gEfiDiskInfoIdeInterfaceGuid = { 0x5E948FE3, 0x26D3, 0x42B5, { 0xAF, 0x17, 0x61, 0x02, 0x87, 0x18, 0x8D, 0xEC }}; EFI_GUID gEfiDiskInfoScsiInterfaceGuid = { 0x08F74BAA, 0xEA36, 0x41D9, { 0x95, 0x21, 0x21, 0xA7, 0x0F, 0x87, 0x80, 0xBC }}; EFI_GUID gEfiDiskInfoUsbInterfaceGuid = { 0xCB871572, 0xC11A, 0x47B5, { 0xB4, 0x92, 0x67, 0x5E, 0xAF, 0xA7, 0x77, 0x27 }}; EFI_GUID gEfiDiskInfoAhciInterfaceGuid = { 0x9e498932, 0x4abc, 0x45af, { 0xa3, 0x4d, 0x02, 0x47, 0x78, 0x7b, 0xe7, 0xc6 }}; EFI_GUID gEfiDiskInfoNvmeInterfaceGuid = { 0x3ab14680, 0x5d3f, 0x4a4d, { 0xbc, 0xdc, 0xcc, 0x38, 0x0, 0x18, 0xc7, 0xf7 }}; EFI_GUID gEfiDiskInfoUfsInterfaceGuid = { 0x4b3029cc, 0x6b98, 0x47fb, { 0xbc, 0x96, 0x76, 0xdc, 0xb8, 0x4, 0x41, 0xf0 }}; int EFIAPI main ( IN int Argc, IN CHAR16 **Argv ) { EFI_STATUS Status; UINTN HandleIndex, NumHandles; EFI_HANDLE *ControllerHandle = NULL; EFI_DISK_INFO_PROTOCOL *DiskInfoProtocol; Status = gBS->LocateHandleBuffer( ByProtocol, &gEfiDiskInfoProtocolGuid, NULL, &NumHandles, &ControllerHandle); for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) { Status = gBS->OpenProtocol( ControllerHandle[HandleIndex], &gEfiDiskInfoProtocolGuid, (VOID**)&DiskInfoProtocol, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR(Status)) { continue; } Print(L"Device[%d] GUID: %g", HandleIndex, DiskInfoProtocol->Interface); if (CompareGuid ( &DiskInfoProtocol->Interface, &gEfiDiskInfoIdeInterfaceGuid)) { Print(L" IDE HDD\n"); } if (CompareGuid ( &DiskInfoProtocol->Interface, &gEfiDiskInfoScsiInterfaceGuid)) { Print(L" Scsi HDD\n"); } if (CompareGuid ( &DiskInfoProtocol->Interface, &gEfiDiskInfoUsbInterfaceGuid)) { Print(L" USB HDD\n"); } if (CompareGuid ( &DiskInfoProtocol->Interface, &gEfiDiskInfoAhciInterfaceGuid)) { Print(L" AHCI HDD\n"); } if (CompareGuid ( &DiskInfoProtocol->Interface, &gEfiDiskInfoNvmeInterfaceGuid)) { Print(L" NVME HDD\n"); } if (CompareGuid ( &DiskInfoProtocol->Interface, &gEfiDiskInfoUfsInterfaceGuid)) { Print(L" Ufs HDD\n"); } } return EFI_SUCCESS; }
上述代码在UDK2014中编译通过,但是无法在 NT32环境下运行。于是在实体机KabyLake HDK 上实验, 板子上挂载了一个 SATA HDD 一个eMMC和两个USB Disk。运行结果如下:
可以看出,当前的SATA 是AHCI 模式。此外, eMMC 设备是无法被识别出来的,也许后面会扩展到这种设备吧。
完整的代码下载:
博主,您好,我使用DiskIo这个Protocol时,读出来的数据和RU读出来的不一样,我的设备一共就两个,USB和AHCI HDD,我怀疑我写的代码是读到了USB,要怎么确定自己的代码读到的硬盘是哪个呢?
针对你的情况,可以检查当前 Device 上是否还有 USBIO 这个Protocol ,如果有的话,那就是 USB Disk。另外,还可以尝试检查硬盘大小,一般来说 AHCI HDD 容量是大于 U盘的。
好的,谢谢,我去读出来所有的device并打印出来,然后对照发现读的确实是USB,另外,我还想问问博主,要读IDE也就是identify要怎么去读呢?万分感谢
这个我没研究过,隐约记得好像有一个 pass through 的 Protocol 你可以参考一下。