uefi drivers 是指在inf中将MODULE_TYPE指定为UEFI_DRIVER。例如inf的例子
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = DiskIoDxe
MODULE_UNI_FILE = DiskIoDxe.uni
FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeDiskIo
从这个inf中可以看到这个uefi的driver name为DiskIoDxe,其入口函数为InitializeDiskIo
在uefi driver中一般会用到EFI_DRIVER_BINDING_PROTOCOL/EFI_COMPONENT_NAME_PROTOCOL/EFI_COMPONENT_NAME2_PROTOCOL/EFI_DRIVER_DIAGNOSTICS2_PROTOCOL 这四个protocol.
如下所示:
EFI_STATUS
EFIAPI
InitializeDiskIo (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Install driver model protocol(s).
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gDiskIoDriverBinding,
ImageHandle,
&gDiskIoComponentName,
&gDiskIoComponentName2
);
ASSERT_EFI_ERROR (Status);
return Status;
}
在其入口函数InitializeDiskIo 中通过EfiLibInstallDriverBindingComponentName2 注册driver,
EFI_STATUS
EFIAPI
EfiLibInstallDriverBindingComponentName2 (
IN CONST EFI_HANDLE ImageHandle,
IN CONST EFI_SYSTEM_TABLE *SystemTable,
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
IN EFI_HANDLE DriverBindingHandle,
IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName, OPTIONAL
IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL
)
{
EFI_STATUS Status;
ASSERT (DriverBinding != NULL);
//
// Update the ImageHandle and DriverBindingHandle fields of the Driver Binding Protocol
//
DriverBinding->ImageHandle = ImageHandle;
DriverBinding->DriverBindingHandle = DriverBindingHandle;
if (ComponentName == NULL || FeaturePcdGet(PcdComponentNameDisable)) {
if (ComponentName2 == NULL || FeaturePcdGet(PcdComponentName2Disable)) {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentName2ProtocolGuid, ComponentName2,
NULL
);
}
} else {
if (ComponentName2 == NULL || FeaturePcdGet(PcdComponentName2Disable)) {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentNameProtocolGuid, ComponentName,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentNameProtocolGuid, ComponentName,
&gEfiComponentName2ProtocolGuid, ComponentName2,
NULL
);
}
}
//
// ASSERT if the call to InstallMultipleProtocolInterfaces() failed
//
ASSERT_EFI_ERROR (Status);
return Status;
}
我们这里的ComponentName和ComponentName2 都不是NULL,因此走else的case,即
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentName2ProtocolGuid, ComponentName2,
NULL
);
通过gBS的InstallMultipleProtocolInterfaces,向DriverBinding->DriverBindingHandle注册两个guid。这里的DriverBinding->DriverBindingHandle也是在EfiLibInstallDriverBindingComponentName2 中赋值
DriverBinding->ImageHandle = ImageHandle;
DriverBinding->DriverBindingHandle = DriverBindingHandle;
这里的DriverBindingHandle也就对应InitializeDiskIo中的ImageHandle也就是这个binary本身.
这样当调用 gBS->loadImage将驱动文件加载到内存后,再调用 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);就会call到入口函数
StartImage从是通过 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);调用到入口函数的,针对本例就是调用InitializeDiskIo。
而InitializeDiskIo 最重要的是实现了gDiskIoDriverBinding,
EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
DiskIoDriverBindingSupported,
DiskIoDriverBindingStart,
DiskIoDriverBindingStop,
0xa,
NULL,
NULL
};
gDiskIoDriverBinding 实现了三个函数,DiskIoDriverBindingSupported用与见识是否支持这个driver,如果支持的话,就调用DiskIoDriverBindingStart,在DiskIoDriverBindingStart 中就可以将驱动安装到设备上并启动硬件设备
DiskIoDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
//
// Install protocol interfaces for the Disk IO device.
//
if (Instance->BlockIo2 != NULL) {
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiDiskIoProtocolGuid, &Instance->DiskIo,
&gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiDiskIoProtocolGuid, &Instance->DiskIo,
NULL
);
}
}
在DiskIoDriverBindingStart 中一般会调用InstallMultipleProtocolInterfaces或者InstallProtocolInterfaces来在ControllerHandle 上安装protocol.
后面的其他程序就可以通过gEfiDiskIoProtocolGuid 或者 gEfiDiskIo2ProtocolGuid来得到Instance->DiskIo或者Instance->DiskIo2。
例如下面的例子
Status = gBS->OpenProtocol (
Entry->PartitionHandle,
&gEfiDiskIoProtocolGuid,
(VOID **) &DiskIo,
gImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
ASSERT_EFI_ERROR (Status);
Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
就通过gEfiDiskIoProtocolGuid 来调用DiskIo->WriteDisk
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = DiskIoDxe
MODULE_UNI_FILE = DiskIoDxe.uni
FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeDiskIo
从这个inf中可以看到这个uefi的driver name为DiskIoDxe,其入口函数为InitializeDiskIo
在uefi driver中一般会用到EFI_DRIVER_BINDING_PROTOCOL/EFI_COMPONENT_NAME_PROTOCOL/EFI_COMPONENT_NAME2_PROTOCOL/EFI_DRIVER_DIAGNOSTICS2_PROTOCOL 这四个protocol.
如下所示:
EFI_STATUS
EFIAPI
InitializeDiskIo (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Install driver model protocol(s).
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gDiskIoDriverBinding,
ImageHandle,
&gDiskIoComponentName,
&gDiskIoComponentName2
);
ASSERT_EFI_ERROR (Status);
return Status;
}
在其入口函数InitializeDiskIo 中通过EfiLibInstallDriverBindingComponentName2 注册driver,
EFI_STATUS
EFIAPI
EfiLibInstallDriverBindingComponentName2 (
IN CONST EFI_HANDLE ImageHandle,
IN CONST EFI_SYSTEM_TABLE *SystemTable,
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
IN EFI_HANDLE DriverBindingHandle,
IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName, OPTIONAL
IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL
)
{
EFI_STATUS Status;
ASSERT (DriverBinding != NULL);
//
// Update the ImageHandle and DriverBindingHandle fields of the Driver Binding Protocol
//
DriverBinding->ImageHandle = ImageHandle;
DriverBinding->DriverBindingHandle = DriverBindingHandle;
if (ComponentName == NULL || FeaturePcdGet(PcdComponentNameDisable)) {
if (ComponentName2 == NULL || FeaturePcdGet(PcdComponentName2Disable)) {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentName2ProtocolGuid, ComponentName2,
NULL
);
}
} else {
if (ComponentName2 == NULL || FeaturePcdGet(PcdComponentName2Disable)) {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentNameProtocolGuid, ComponentName,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentNameProtocolGuid, ComponentName,
&gEfiComponentName2ProtocolGuid, ComponentName2,
NULL
);
}
}
//
// ASSERT if the call to InstallMultipleProtocolInterfaces() failed
//
ASSERT_EFI_ERROR (Status);
return Status;
}
我们这里的ComponentName和ComponentName2 都不是NULL,因此走else的case,即
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverBinding->DriverBindingHandle,
&gEfiDriverBindingProtocolGuid, DriverBinding,
&gEfiComponentName2ProtocolGuid, ComponentName2,
NULL
);
通过gBS的InstallMultipleProtocolInterfaces,向DriverBinding->DriverBindingHandle注册两个guid。这里的DriverBinding->DriverBindingHandle也是在EfiLibInstallDriverBindingComponentName2 中赋值
DriverBinding->ImageHandle = ImageHandle;
DriverBinding->DriverBindingHandle = DriverBindingHandle;
这里的DriverBindingHandle也就对应InitializeDiskIo中的ImageHandle也就是这个binary本身.
这样当调用 gBS->loadImage将驱动文件加载到内存后,再调用 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);就会call到入口函数
StartImage从是通过 Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);调用到入口函数的,针对本例就是调用InitializeDiskIo。
而InitializeDiskIo 最重要的是实现了gDiskIoDriverBinding,
EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
DiskIoDriverBindingSupported,
DiskIoDriverBindingStart,
DiskIoDriverBindingStop,
0xa,
NULL,
NULL
};
gDiskIoDriverBinding 实现了三个函数,DiskIoDriverBindingSupported用与见识是否支持这个driver,如果支持的话,就调用DiskIoDriverBindingStart,在DiskIoDriverBindingStart 中就可以将驱动安装到设备上并启动硬件设备
DiskIoDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
//
// Install protocol interfaces for the Disk IO device.
//
if (Instance->BlockIo2 != NULL) {
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiDiskIoProtocolGuid, &Instance->DiskIo,
&gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiDiskIoProtocolGuid, &Instance->DiskIo,
NULL
);
}
}
在DiskIoDriverBindingStart 中一般会调用InstallMultipleProtocolInterfaces或者InstallProtocolInterfaces来在ControllerHandle 上安装protocol.
后面的其他程序就可以通过gEfiDiskIoProtocolGuid 或者 gEfiDiskIo2ProtocolGuid来得到Instance->DiskIo或者Instance->DiskIo2。
例如下面的例子
Status = gBS->OpenProtocol (
Entry->PartitionHandle,
&gEfiDiskIoProtocolGuid,
(VOID **) &DiskIo,
gImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
ASSERT_EFI_ERROR (Status);
Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
就通过gEfiDiskIoProtocolGuid 来调用DiskIo->WriteDisk