基于UEFI的BIOS怎么识别不同设备(SataHdd、SataCdrom、USB、BMC)
参考:UEFI_SPEC
第一种方法:
SATA设备根据EFI_ATA_DEVICE_TYPE类型来细分
ATAPI接口是SCSI和IDE总线的结合产物。该接口使用IDE接口和协议机型ATA和SCSI总线命令传输,允许使用ATAPI控制所连接的SCSI设备。
1、EFI_ATA_PASS_THRU_PROTOCOL
提供允许将ATA命令发送到附加到ATA控制器上的ATA设备的服务。基于包的命令只能通过扩展SCSI协议发送到ATAPI设备。当ATA_PASS_THRU向ATA公开一个接口,EXT_SCSI_PASS_THRU负责为同一ATA控制器上的ATAPI设备公开基于数据包的命令接口。
Status =gBS->LocateHandleBuffer (
ByProtocol,
&gEfiAtaPassThruProtocolGuid,
NULL,
&NumberHandles,
&AtaPassHandles
);
用LocateHandleBuffer 定位支持gEfiAtaPassThruProtocolGuid的句柄。
2、循环遍历获得的句柄,获得支持gEfiAtaPassThruProtocolGuid的接口AtaPassProtocol
for (Index = 0; Index < NumberHandles; Index++) {
Status = gBS->HandleProtocol (
AtaPassHandles[Index],
&gEfiAtaPassThruProtocolGuid,
(VOID **) &AtaPassProtocol
);
if (Status == EFI_SUCCESS) {
Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (AtaPassProtocol);
Node = GetFirstNode (&Instance->DeviceList);
while (!IsNull (&Instance->DeviceList, Node)) {
ATADeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);
Node = GetNextNode (&Instance->DeviceList, Node);
}
}
3、判断条件:区分SataHdd和SataCdrom:
SataHdd:ATADeviceInfo->Type == EfiIdeHarddisk
SataCdrom:ATADeviceInfo->Type == EfiIdeCdrom;
typedef enum {
EfiIdeCdrom, /* ATAPI CDROM /
EfiIdeHarddisk, / Hard Disk /
EfiPortMultiplier, / Port Multiplier */
EfiIdeUnknown
} EFI_ATA_DEVICE_TYPE;
EFI_ATA_DEVICE_TYPE对SATA的设备类型进行细分,Cdrom,和Harddisk都接的SATA口,使用ATA类型可以进一步划分。
第二种方法:分析设备路径类型
设备路径的区分通过EFI_DEVICE_PATH_PROTOCOL的Type和SubType的值进行区分
1、EFI_DEVICE_PATH_PROTOCOL.
设备路径用于定义指向设备的编程路径。设备路径的主要目的是允许一个应用程序,例如操作系统加载程序,来确定接口正在抽象的物理设备。
可用于任何设备句柄,以获取有关物理设备或逻辑设备的通用路径/位置信息。如果句柄在逻辑上没有映射到物理设备,则该句柄可能不一定支持设备路径协议。设备路径描述了该手柄所对应的设备的位置。设备路径的大小可以由组成设备路径的结构来确定。
typedef struct {
UINT8 Type; ///< 0x01 Hardware Device Path.
///< 0x02 ACPI Device Path.
///< 0x03 Messaging Device Path.
///< 0x04 Media Device Path.
///< 0x05 BIOS Boot Specification Device Path.
///< 0x7F End of Hardware Device Path.
UINT8 SubType; ///< Varies by Type
///< 0xFF End Entire Device Path, or
///< 0x01 End This Instance of a Device Path and start a new
///< Device Path.
UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define
///< type of data. Size of data is included in Length.
} EFI_DEVICE_PATH_PROTOCOL;
0x01 Hardware Device Path:硬盘设备路径。
0x02 ACPI Device Path. ACPI设备路径,
0x03 Messaging Device Path. SCSI设备路径:
0x04 Media Device Path. 硬盘上的分区路径
0x05 BIOS Boot Specification Device Path. 指向引导旧的操作系统的设备路径
0x7F End of Hardware Device Path. 硬件设备路径的结束。
2、主要几种设备的类型举例
需要更多类型,应查看UEFI SPEC
2.1、PCI Device Path
Mnemonic | ByteOffset | Byte Length | Description |
---|---|---|---|
type | 0 | 1 | Type 1 – Hardware Device Path |
Sub-Type | 1 | 1 | Sub-Type 1 – PCI |
Length | 2 | 2 | Length of this structure is 6 bytes |
2.2、BMC Device Path | |||
Mnemonic | ByteOffset | Byte Length | Description |
-------- | ----- | ----- | ----- |
type | 0 | 1 | Type 1 – Hardware Device Path |
Sub-Type | 1 | 1 | Sub-Type 6 – BMC |
Length | 2 | 2 | Length of this structure in bytes. Length is 13 bytes |
2.3、ATAPI Device Path | |||
Mnemonic | ByteOffset | Byte Length | Description |
-------- | ----- | ----- | ----- |
type | 0 | 1 | Type 3 – Messaging Device Path |
Sub-Type | 1 | 1 | Sub-Type 6 – Sub-Type 1 – ATAPI |
Length | 2 | 2 | Length of this structure in bytes. Length is 13 bytes |
2.4、SCSI Device Path | |||
Mnemonic | ByteOffset | Byte Length | Description |
-------- | ----- | ----- | ----- |
type | 0 | 1 | Type 3 – Messaging Device Path |
Sub-Type | 1 | 1 | Sub-Type 6 – Sub-Type 2– SCSI |
Length | 2 | 2 | Length of this structure in bytes. Length is 8 bytes |
2.5、USB Device Paths | |||
Mnemonic | ByteOffset | Byte Length | Description |
-------- | ----- | ----- | ----- |
type | 0 | 1 | Type 3 – Messaging Device Path |
Sub-Type | 1 | 1 | Sub-Type 6 – Sub-Type 5– USB |
Length | 2 | 2 | Length of this structure in bytes. Length is 6 bytes |
2.6、 MAC Address Device Path | |||
Mnemonic | ByteOffset | Byte Length | Description |
-------- | ----- | ----- | ----- |
type | 0 | 1 | Type 3 – Messaging Device Path |
Sub-Type | 1 | 1 | Sub-Type 11 – MAC Address for a network interface |
Length | 2 | 2 | Length of this structure in bytes. Length is 37 bytes |
3、判断ClassCode的值
Status = gBS->LocateHandleBuffer(
ByProtocol,
&gEfiPciIoProtocolGuid,
NULL,
&HandleArrayCount,
&HandleArray
);
if (EFI_ERROR(Status)) {
return OCPPortNum;
}
for (Index2=0; Index2<HandleArrayCount; Index2++){
Status = gBS->HandleProtocol(
HandleArray[Index2],
&gEfiPciIoProtocolGuid,
(VOID **)&PciIo
);
Status = PciIo->Pci.Read(
PciIo,
EfiPciIoWidthUint8,
0x0B, //PCI_CLASSCODE_OFFSET
1,
&BaseClass
);
Status = PciIo->Pci.Read(
PciIo,
EfiPciIoWidthUint8,
0x0A, //PCI_CLASSCODE_OFFSET
1,
&SubClass
);
}
if(BaseClass == 0x02){
// 网卡
}
if((BaseClass == 0x01)&&((SubClass == 0x07)||(SubClass == 0x04)){
// raid卡
}