从事UEFI开发的人员,对UEFI Device Path的概念都有一定了解,但未必都建立了比较系统而深刻的认识。UEFI Device Path的认知仅限于: 1)它是用来表示系统中设备的路径;2) 在UEFI SPEC中定义了它的数据结构和若干操作它的UEFI Protocol。除此以外, 我对它的相关方面似乎没有更多更深的了解, 包括:
UEFI为什么要提出Device Path的设计?
Device Path可以表示哪些设备? 是如何表示的?
Device Path有哪些实际应用? 最为常见的一个应用就是:进入UEFI Shell后会自动提示如下 Mapping Table, 其中每个FSx或BLKx下面都对应一行Device Path, 如何解读它们呢?
这两天趁着春节的空闲,我重新翻看了UEFI SPEC并下载EDK2 Source Code进行相关编程实验,从理论和实践方面加深了对Device Path的一些认识。这些认识基本围绕上述3个方面来展开,在此汇总成篇。
1.UEFI为什么要提出Device Path的设计?
这里援引UEFI SPEC中关于Device Path用途说明的几个关键句子:
The primary purpose of a Device Path is to allow an application, such as an OS loader, to determine the physical device that the interfaces are abstracting.
A collection of device paths is usually referred to as a name space.
However, the ACPI name space was designed for usage at operating system runtime and does not fit well in platform firmware or OS loaders. Given this, EFI defines its own name space, called a Device Path.
A Device Path is designed to make maximum leverage of the ACPI name space.
对此,我个人的理解和认识是:
Device Path用来在UEFI环境中标识系统中的设备(物理设备或者逻辑设备),类似于在ACPI中用Name Space来标识各个Object。
这就意味:1)Device Path也具有层级结构;2)众多Device Path集合起来构成了1个UEFI环境下的设备命名空间。
OS或者UEFI应用根据Device Path来知道它代表的设备。
举个例子:UEFI SPEC中定义了与Console相关的3个variables:ConIn, ConOut, and ErrOut。每个variable的内容都包含1个Device Path,这个Device Path表示每次开机默认使用的用于该种用途(ConIn,ConOut, ErrOut)的Console Device,UEFI应用可以通过这个Device Path来确定对应的Console Device。
Device Path在设计上充分利用了已有的ACPI Name Space的命名设计。关于这一点参考下面“Device Path与ACPI的联系”一节。
2.Device Path可以表示哪些设备? 是如何表示的?
Device Path的组织结构
Device Path以Device Path Node为基本单位来依次串接而成,其结束标志是End of Hardware Device Path类型的Device Path Node。下图展示了Device Path Node的基本结构:
每个Device Path Node代表某一层级的域/设备或者设备属性(比如MAC地址/IPv4地址/IPv6地址等)。通常来说,它们会按照各自所处的Subsystem的拓扑结构至顶向下来排列形成最终Device Path,从而代表了设备的拓扑路径。下面,以开篇的UEFI Shell下的Device Path为例来说明。
Example 1:Removable USB HDD with MBR partition PciRoot(0x0)/Pci(0x14,0x0)/USB(0x0,0x0)/HD(1,MBR,0x01EDBE02,0x800,0x1004800)
PciRoot(0x0) => 代表Pci Root Bridge扩展出来的Pci总线域,这个是PCI设备的最顶层域,在台式机和笔记本上通常只有1个,其编号为0。
Pci(0x14,0x0) => 代表USB XHCI Controller,其PCI Device=0x14,PCI Function=0x00。PCI Bus因为是会变动的(比如有PCI设备Hot-Plug或者下次启动有PCI设备添加/移除),UEFI SPEC规定其值不纳入Device Path Node,通常结合平台信息可以推断出来PCI Bus的值。
USB(0x0,0x0) => 代表Removable USB HDD, 其接在USB Port 0上。
HD(1,MBR,0x01EDBE02,0x800,0x1004800) => 代表Removable USB HDD上的第1个硬盘分区,为MBR格式。
Example 2:NVMe SSD with GPT partition PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x0)/NVMe(0x1,C3-70-00-00-02-0D-08-00)/HD(1,GPT,425EAA1B-B401-4960-BEFC-5248CA7BCF28,0x800,0x82000)
PciRoot(0x0) => 意义同上。
Pci(0x1C,0x4) => 代表NVMe SSD所在的PCIe Root Port,其PCI Device=0x1C,PCI Function=0x04。
Pci(0x0,0x0) => 代表NVMe SSD Controller, 其PCI Device=0x0,PCI Function=0x0。
NVMe(0x1,C3-70-00-00-02-0D-08-00) => 代表NVMe的Name Space, 用该Name Space来标识NVMe SSD设备。
HD(1,GPT,425EAA1B-B401-4960-BEFC-5248CA7BCF28,0x800,0x82000) => 代表NVMe SSD上的第1个硬盘分区,为GPT格式。
Device Path的类别
UEFI SPEC一共定义了6个大类(Type)的Device Path Node,每个大类下面又分不同的子类(Sub-Type)。大类划分参考下面表格,子类的划分比较繁杂不便一一展开,请直接参考UEFI SPEC。
大类 可表示的典型设备/对象
Hardware Device Path PCI设备,Vendor自定义设备,BMC
ACPI Device Path PCI总线域(如上面的PciRoot(0x0))
显示输出设备,ACPI设备(比如鼠标/键盘等)
Messaging Device Path IDE设备,USB设备,SATA设备,SAS设备,SCSI设备,UART设备,Vendor自定义对象,MAC地址,IPv4/IPv6地址,其他新兴设备
Media Device Path 硬盘分区,CDROM分区,Vendor自定义Media,文件路径,UEFI固件分区,UEFI固件文件,RAM Disk
BIOS Boot Specification Device Path 传统的BIOS启动设备
End of Hardware Device Path Device Path终结符
Device Path的文本表示形式
UEFI定义了相关的Protocol来将Device Path的数据结构转换为可视化的文本形式。下面给出几种常见Devie Path Node类型的文本形式。
EDK2给出了将各种Device Path Node转换成文本形式的实现,具体参考:mUefiDevicePathLibToTextTable[] defined in edk2\MdePkg\Library\UefiDevicePathLib\DevicePathToText.c.
Device Path Node类型 文本格式 示例
PCI设备 Pci(Dev,Func)
Dev-PCI Device NumberFunc-PCI Function Number Pci(0x1C,0x4)
Vendor自定义设备 VenHw(GUID[,Data])
GUID为Vendor GUID,Data为对应的数据(如存在) VenHw(480B3204-C23C-4AE1-BB16-A73FADDA475F)
ACPI设备 - PCI总线域 PciRoot(UID)
UID为PCI总线域编号 PciRoot(0)
ACPI设备 - 通用形式 Acpi(HID,UID)
HID,UID定义参考ACPI SPEC Acpi(PNP0303,0x0)
IDE设备 Ata([PriSec,SlaveMaster,]LUN)
相关参数参考UEFI SPEC说明 Ata(Primary,Master,0)
USB设备 USB(ParentPort,InterfaceNumber)
相关参数参考UEFI SPEC说明 USB(0x5,0x0)
SATA设备 Sata(HBAPort,PortMultiplierPort,LUN)
相关参数参考UEFI SPEC说明 Sata(0x1,0x0,0x0)
NVMe设备 NVMe(NSID,EUI-64)
相关参数参考UEFI SPEC说明 NVMe(0x1,C3-70-00-00-02-0D-08-00)
硬盘分区 HD(PartitionNumber,PartitionFormat,PartitionSig,
PartitionStartLBA,PartitionSize)相关参数参考UEFI SPEC说明 HD(1,MBR,0x01EDBE02,0x800,0x1004800)
HD(1,GPT,425EAA1B-B401-4960-BEFC-5248CA7BCF28,0x800,0x82000)
CD-ROM分区 CDROM(BootEntry[,PartitionStartRBA,PartitionSize])
相关参数参考UEFI SPEC说明
MAC地址 MAC(MACAddr,NICInterface)
相关参数参考UEFI SPEC说明 MAC(54E1AD76ACEB,0x0)
IPv4地址 IPv4(RemoteIPAddr[,Protocol,Static/DHCP,LocalIPAddr,GatewayIPAddr,SubnetMask])
相关参数参考UEFI SPEC说明 IPv4(0.0.0.0)
IPv6地址 IPv6(RemoteIPAddr[,Protocol,IpAddressOrigin,LocalIPAddr,GatewayIPAddr,SubnetMask])
相关参数参考UEFI SPEC说明 IPv6(0000:0000:0000:0000:0000:0000:0000:0000)
UEFI固件分区 Fv(FvGUID)
相关参数参考UEFI SPEC说明 Fv(A881D567-6CB0-4EEE-8435-2E72D33E45B5)
Device Path与ACPI的联系
从上一节可以看到,ACPI Device Path类别的Device Path Node是沿用ACPI命名设计的。在Acpi(HID,UID)形式中,HID是APCI定义的"UUUNNNN"形式的HID字符串,UID也与APCI定义完全相同。
3.如何解读UEFI Shell下Mapping Table中的Device Path?
在“Device Path的组织结构”一节中已经解析过开篇提到的UEFI Shell下的Device Path了,这里补充说一下我对FSx和BLKx是如何进行映射的理解。
具体实现可以参考UEFI Shell在EDK2中的源码:ShellCommandCreateInitialMappingsAndPaths() defined in edk2\ShellPkg\Library\UefiShellCommandLib\UefiShellCommandLib.c.
详细的代码实现逻辑非常复杂,这里只挑几个要点陈述如下:
FSx的映射
1.先找到Support EFI_SIMPLE_FILE_SYSTEM_PROTOCOL的所有Device Handle,每个Device Handle代表1个File System,会被分配1个FSx:。
2.对上述每个Device Handle Locate到其Device Path,转换为Device Path Text,按Text String由小到大的顺序进行排序,对应的Device Handle的FSx从0开始依次编号。
BLKx的映射
1.先找到Support EFI_BLOCK_IO_PROTOCOL的所有Device Handle,每个Device Handle代表1个Block设备,会被分配1个BLKx:。
2.对上述每个Device Handle Locate到其Device Path,转换为Device Path Text, 按Text String由小到大的顺序进行排序,对应的Device Handle的BLKx从0开始依次编号。
3.如上述Device Handle与FSx映射中的Device Handle是同1个,则在对应的FSx:右侧标注对应的BLKx:。