1、创建 gEfiFirmwareVolumeBlockProtocolGuid 类型的 Protocol 实例
在 ./MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c 文件的第 487 行调用了 FwVolBlockDriverInit() 函数,
其定义在 MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c 中:
EFI_STATUS
EFIAPI
FwVolBlockDriverInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
...
//
// Produce an FVB protocol for it
//
ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);
...
}
其中 ProduceFVBProtocolOnBuffer() 定义在 MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c 中:
EFI_STATUS
ProduceFVBProtocolOnBuffer (
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN EFI_HANDLE ParentHandle,
IN UINT32 AuthenticationStatus,
OUT EFI_HANDLE *FvProtocol OPTIONAL
)
{
...
//
//
// Attach FvVolBlock Protocol to new handle
//
Status = CoreInstallMultipleProtocolInterfaces (
&FvbDev->Handle,
&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance,
&gEfiDevicePathProtocolGuid, FvbDev->DevicePath,
NULL
);
...
}
上述 CoreInstallMultipleProtocolInterfaces() 函数创建了gEfiFirmwareVolumeBlockProtocolGuid 类型的 Protocol 实例。
2、创建 gEfiFirmwareVolume2ProtocolGuid 类型的 Protocol 实例
1)注册 gEfiFirmwareVolumeBlockProtocolGuid 实例的通知事件
在 ./MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c 文件中的第 239 行调用了 FwVolDriverInit(),
VOID
EFIAPI
DxeMain (
IN VOID *HobStart
)
{
...
Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
...
}
其中,FwVolDriverInit() 定义在MdeModulePkg/Core/Dxe/FwVol/FwVol.c 文件中:
EFI_STATUS
EFIAPI
FwVolDriverInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
&gEfiFirmwareVolumeBlockProtocolGuid,
TPL_CALLBACK,
NotifyFwVolBlock,
NULL,
&gEfiFwVolBlockNotifyReg
);
return EFI_SUCCESS;
}
它注册了一个针对 gEfiFirmwareVolumeBlockProtocolGuid 类型的 Protocol 实例的通知事件,当这个函数被调用后,将会对系统中已存在的每一个 gEfiFirmwareVolumeBlockProtocolGuid 类型的 Protocol 实例调用 NotifyFwVolBlock(),由于上面已经创建了该类型的实例,所以 NotifyFwVolBlock() 会很快被调用。
其中,NotifyFwVolBlock() 定义在 MdeModulePkg/Core/Dxe/FwVol/FwVol.c
VOID
EFIAPI
NotifyFwVolBlock (
IN EFI_EVENT Event,
IN VOID *Context
)
{
...
//
// Get the FirmwareVolumeBlock protocol on that handle
//
Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
...
//
// Install an New FV protocol on the existing handle
//
Status = CoreInstallProtocolInterface (
&Handle,
&gEfiFirmwareVolume2ProtocolGuid,
EFI_NATIVE_INTERFACE,
&FvDevice->Fv
);
...
}
上述 CoreInstallProtocolInterface() 函数创建了gEfiFirmwareVolume2ProtocolGuid 类型的 Protocol 实例。
2)注册 gEfiFirmwareVolume2ProtocolGuid 类型的 Protocol 实例的通知事件
在 ./MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c 文件中的第 503 行调用了 CoreInitializeDispatcher(),
其定义在 MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c 中:
VOID
CoreInitializeDispatcher (
VOID
)
{
mFwVolEvent = EfiCreateProtocolNotifyEvent (
&gEfiFirmwareVolume2ProtocolGuid,
TPL_CALLBACK,
CoreFwVolEventProtocolNotify,
NULL,
&mFwVolEventRegistration
);
}
它注册了一个针对 gEfiFirmwareVolume2ProtocolGuid 类型的 Protocol 实例的通知事件,当这个函数被调用后,将会对系统中已存在的每一个 gEfiFirmwareVolume2ProtocolGuid 类型的 Protocol 实例调用 CoreFwVolEventProtocolNotify(),由于上面已经创建了该类型的实例,所以 CoreFwVolEventProtocolNotify() 会很快被调用。
其中,CoreFwVolEventProtocolNotify() 定义在 MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c 中:
VOID
EFIAPI
CoreFwVolEventProtocolNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
...
//
// Discover Drivers in FV and add them to the Discovered Driver List.
// Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
// EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
// EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
//
for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
//
// Initialize the search key
//
Key = 0;
do {
Type = mDxeFileTypes[Index];
GetNextFileStatus = Fv->GetNextFile (
Fv,
&Key,
&Type,
&NameGuid,
&Attributes,
&Size
);
...
CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
...
}
上述函数会去查找 FV 中的各个 driver,并通过 CoreAddToDriverList() 将找到的 driver 依次加入到 mDiscoveredList 链表中。
3、加载 driver
在 ./MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c 文件中的第 510 行调用了 CoreDispatcher() 函数
其定义在 MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c 文件中:
EFI_STATUS
EFIAPI
CoreDispatcher (
VOID
)
{
...
do {
//
// Drain the Scheduled Queue
//
while (!IsListEmpty (&mScheduledQueue)) {
DriverEntry = CR (
mScheduledQueue.ForwardLink,
EFI_CORE_DRIVER_ENTRY,
ScheduledLink,
EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
//
// Load the DXE Driver image into memory. If the Driver was transitioned from
// Untrused to Scheduled it would have already been loaded so we may need to
// skip the LoadImage
//
if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) {
DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
Status = CoreLoadImage (
FALSE,
gDxeCoreImageHandle,
DriverEntry->FvFileDevicePath,
NULL,
0,
&DriverEntry->ImageHandle
);
...
//
// Search DriverList for items to place on Scheduled Queue
//
ReadyToRun = FALSE;
for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
...
CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
...
}
上述函数将加载队列 mScheduledQueue 中的驱动,该队列中的元素由 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter() 函数从链表 mDiscoveredList 中取出,再将其放入队列 mScheduledQueue 中。