UEFI的运行阶段
本文的分析只会涉及到DXE之后的阶段,前面的略过。
DXE 阶段
DXE阶段的实现函数在edk2的MdeModulePkg/Core/Dxe/DxeMain
目录中,主入口函数为:
VOID EFIAPI DxeMain ( IN VOID *HobStart )
{
......
gBds->Entry (gBds); //DXE的最后调用BDS的主入口函数
//
// BDS should never return
//
ASSERT (FALSE);
CpuDeadLoop ();
UNREACHABLE ();
}
在该函数中会调用各个DXE driver的入口函数,并且在函数的最后调用BDS的入口函数,进入BDS运行阶段。实际上BDS对于DXE来说也就是一个DXE Driver,它会在Driver初始化时注册BDS Procotol。然后在DXE的最后调用该procotol进入BDS阶段,实际上gBds对应的就是gEfiBdsArchProtocolGuid这个Procotol,这个gBds的定义在 MdeModulePkg/Core/Dxe/DxeMain/DxeProtocolNotify.c
文件中:
EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {
{ &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },
{ &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },
{ &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },
{ &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },
{ &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },
{ &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },
{ &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },
{ &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ NULL, (VOID **)NULL, NULL, NULL, FALSE }
};
BDS阶段
UEFI运行到DXE阶段的最后,会调用BDS Procotol Entry来进入到BDS阶段(boot device select),前面提到BDS也是一个DXE的driver,它的实现是平台相关的,edk2主线分支上的实现有一个:
MdeModulePkg/Universal/BdsDxe
而在高通平台上BDS的实现使用的是如下目录中的:
QcomPkg/Drivers/QcomBds
以它BdsDxe驱动作为例子,它的主要目的是注册一个Procotol到DXECore中,DXECore最后会触发Procotol的Entry操作,而该操作的内容就是执行BDS阶段的任务。
///
/// BDS arch protocol instance initial value.
///
EFI_BDS_ARCH_PROTOCOL gBds = {
BdsEntry
};
EFI_STATUS
EFIAPI
BdsInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
//
// Install protocol interface
//
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiBdsArchProtocolGuid, &gBds,
NULL
);
ASSERT_EFI_ERROR (Status);
DEBUG_CODE (
EFI_EVENT Event;
//
// Register notify function to check deferred images on ReadyToBoot Event.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
CheckDeferredLoadImageOnReadyToBoot,
NULL,
&gEfiEventReadyToBootGuid,
&Event
);
ASSERT_EFI_ERROR (Status);
);
return Status;
}
它会注册一个procotol到DXECore,而具体调用的地方在DXE Main的最后:
gBds->Entry (gBds); //DXE的最后调用BDS的主入口函数
该procotol的Guid为gEfiBdsArchProtocolGuid,进入BDS阶段的入口为BdsEntry,它主要做的任务是:加载和启动kernel。