PCI device identification and driver binding in Solaris

本文介绍了Solaris系统中PCI设备的识别与驱动绑定过程。文章详细解释了如何通过不同的设备标识符进行驱动匹配,包括vendor-id、device-id、subsystem-vendor-id、subsystem-id等,并探讨了这些标识符在实际应用中的有效性和局限性。

This is a blog article written by Dan Mick, http://blogs.sun.com/dmick/entry/title_pci_device_identification_and

A PCI device has a bunch of device identification numbers associated with it, which generic code can retrieve. I've listed them here in most-specific to least-specific order, by their Solaris property name (shown in the prtconf -pv output, which is why we always always always ask for that when diagnosing driver-binding problems):

  1. revision (not useful on its own)
  2. vendor-id, device-id (the usual lone source of driver binding)
  3. subsystem-vendor-id, subsystem-id (the usual source of the "name" property, and hence the usual source of the /devices node name)
  4. class-code

The revision number is only useful in conjunction with vendor-id, device-id.

Entry 3, the subsystem, is nearly useless for every purpose, as many machines now use the same subsystem ID for every motherboard device, and if not, at least the same subsystem-vendor-id. Sun had originally interpreted subsystem to be more specific than vendor-id, device-id, but that's not how the industry ended up adopting it. (as usual, the spec was unclear as to its intent).

The only things Solaris normally uses for binding device drivers are 2 and 4.

The way Solaris driver binding works is: for every element in the compatible property, in order, a) look for a same-named driver; if it's there, use it; if not, b) look for a same-named device alias, and get the driver field out of it; if it's there, use it. That's it. (Note that I'm specifically talking about Solaris, nothing to do with bootconf or the DCA.)

So most devices are bound through the vendor-id, device-id pair. Some devices and drivers are generic enough so that one driver is able to run an entire class of devices (say, for instance, pci-ide); in that case, the class-code can be used. But for the most part, vendor-id,device-id is what you want in /etc/driver_aliases, and it's always the right thing to talk about when you're trying to describe which device you have to someone else.

The Broadcom device aliases were added with both vendor-id, device-id and subsystem-vendor-id, subsystem-id, the intent being to try to bind the bge device driver only to particular boards and motherboards we had tested explicitly. (Opinions differed as to whether this was a good idea.) Since then, I believe the motion is back to just vendor-id,device-id, but if you see device aliases for bge with four numbers, that's why. They'll still work with two numbers, just not as pickily.

Now obviously this opens up the possibility that more than one alias might match for a particular set of numbers in the PCI device...but that's why we specify what's in the compatible property, not what's in the device. The compatible property is always constructed in a specific order, and as of s10_37, contains the following (intentionally-redundant) elements for PCI devices:

         *   (possibly) node-name       (0)
* pciVVVV,DDDD.SSSS.ssss.RR (1)
* pciVVVV,DDDD.SSSS.ssss (2)
* pciSSSS,ssss (3)
* pciVVVV,DDDD.RR (4)
* pciVVVV,DDDD (5)
* pciclass,CCSSPP (6)
* pciclass,CCSS (7)

(VVVV is vendor-id, DDDD is device-id, SSSS is subsystem-vendor-id, ssss is subsystem-id, RR revision, CC major class number, SS subclass number, PP programming-interface-byte)

Form 0 is there for certain special devices, to "override" the normal matching, mostly older devices. Then, as you can see, we sorta go from most-specific to least-specific, which is the intent of the compatible property on any bus, PCI being no exception. The exception to that order is number 3, which had to be where it is because of the original definition of the compatible property in the original IEEE1275 spec, which all this is based on. But it's OK, because we (as noted above) virtually never use it for binding drivers anyway; we almost-always use 5 or 6/7, and sometimes 2.


<think>好的,用户想了解UEFI EDKII中Driver Binding Protocol的实现原理。首先,我需要回顾一下UEFI驱动模型的基础知识。根据引用[1],Driver Binding Protocol是UEFI驱动模型的核心,用来管理驱动程序的加载和绑定。驱动通过这个协议与设备控制器或总线交互。 接下来,得理清楚Driver Binding Protocol的结构。根据引用[4],它包含三个主要函数:Supported、Start和Stop。Supported函数用于检测驱动是否支持某个设备,Start负责安装协议和服务,Stop则是卸载。这部分需要详细说明每个函数的作用和调用时机。 然后,要考虑驱动和设备的匹配过程。引用[3]提到,UEFI Driver在DXE阶段之后执行,可能涉及多次安装。这里需要解释当控制器被创建时,系统如何遍历已注册的Driver Binding Protocols,调用Supported函数,然后按优先级启动驱动。 还要结合EDKII的源码结构,比如入口函数中如何安装Driver Binding Protocol实例。例如,引用[4]中的例子,入口函数使用InstallProtocolInterface将协议安装到Handle上,这样系统才能发现并调用该驱动。 可能用户还想知道实际应用中的流程,比如控制器的检测、驱动的优先级处理,以及Start函数如何为设备安装其他协议。需要解释每个步骤在代码中的体现,以及这些步骤如何协同工作。 最后,确保回答结构清晰,分点说明实现原理、关键函数、执行流程和源码示例,并附上相关问题帮助用户深入理解。同时,引用相关的资料来支持每个部分的解释,确保准确性。</think>### Driver Binding Protocol 实现原理(UEFI EDKII) 在UEFI EDKII中,`EFI_DRIVER_BINDING_PROTOCOL`是驱动模型的核心组件,其实现原理可分为以下关键点: --- #### 1. **驱动与设备的绑定机制** - **Supported函数** 驱动通过`Supported()`函数检测是否支持特定设备控制器(Controller)。该函数会检查设备是否满足驱动的兼容条件(例如设备类型、协议接口等)。 示例代码片段: ```c EFI_STATUS Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { // 检查ControllerHandle是否包含目标协议(如PCI_IO_PROTOCOL) if (EFI_ERROR(gBS->OpenProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, ...))) { return EFI_UNSUPPORTED; } return EFI_SUCCESS; // 表示支持该设备 } ``` 此函数返回`EFI_SUCCESS`时,系统认为驱动可绑定该设备[^1][^4]。 - **Start函数** 当驱动确认支持设备后,`Start()`会被调用以初始化设备,安装所需协议(如`GRAPHICS_OUTPUT_PROTOCOL`)。例如: ```c EFI_STATUS Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { // 安装设备特定协议 gBS->InstallProtocolInterface(&ControllerHandle, &gEfiGraphicsOutputProtocolGuid, ...); return EFI_SUCCESS; } ``` 此过程可能涉及资源分配、硬件初始化等操作[^3][^4]。 - **Stop函数** 用于卸载驱动或释放资源,通常在设备移除或驱动更新时触发。需确保安全关闭设备并解除协议绑定。 --- #### 2. **驱动注册与执行流程** - **驱动的入口函数** 驱动在入口函数(如`DriverEntry`)中通过`InstallProtocolInterface()`注册`EFI_DRIVER_BINDING_PROTOCOL`实例: ```c EFI_STATUS DriverEntry(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { EFI_DRIVER_BINDING_PROTOCOL DriverBinding = {Supported, Start, Stop, ...}; gBS->InstallProtocolInterface(&ImageHandle, &gEfiDriverBindingProtocolGuid, ...); return EFI_SUCCESS; } ``` 系统通过此协议实例管理驱动的生命周期。 - **控制器的检测与绑定** 当新控制器(如PCI设备)被发现时,UEFI会遍历所有已注册的驱动,按优先级调用`Supported()`和`Start()`。若多个驱动支持同一设备,优先级高的优先加载[^2][^3]。 --- #### 3. **源码结构示例(以EDKII Graphics Driver为例)** - **驱动绑定协议实例化** ```c EFI_DRIVER_BINDING_PROTOCOL gGraphicsDriverBinding = { GraphicsDriverSupported, // Supported函数 GraphicsDriverStart, // Start函数 GraphicsDriverStop, // Stop函数 0x10, // 驱动版本号 NULL, // ImageHandle(由系统填充) NULL DriverBinding附加上下文 }; ``` - **设备协议安装** `Start()`函数中可能调用`InstallMultipleProtocolInterfaces()`为设备安装多个协议接口。 --- #### 4. **关键设计特点** - **动态绑定**:驱动按需加载,仅在检测到兼容设备时激活。 - **协议依赖**:通过协议(如`PCI_IO_PROTOCOL`)解耦驱动与硬件细节。 - **优先级控制**:驱动通过版本号(Version字段)定义加载顺序,高版本优先。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值