UEFI基础知识
启动过程
SEC->PEI->DXE->BDS-> TSL->RT->AL
UEFI组成
UEFI提供给操作系统的接口有启动服务(boot services, BS)和运行时服务(Runtime Servcie,RT),以及BS的protocol。
TSL阶段 --BS&RT--> OS Loader(Grub) ->ExitBootServices() -> Runtime 阶段
几个重要Phase
- EndOfPei:在HandOffToDxeCore时被安装
- EndOfDxe
- ReadyToBoot
- ExitBootServices:OS Loader调用
DXE 阶段提供的服务
BootService提供的服务:
事件服务;内存管理;Protocol管理和使用;驱动管理(connect,disconnect); Image 管理;ExitBootService;
BootService
//
39 // DXE Core Module Variables
40 //
41 EFI_BOOT_SERVICES mBootServices = {
42 {
43 EFI_BOOT_SERVICES_SIGNATURE, // Signature
44 EFI_BOOT_SERVICES_REVISION, // Revision
45 sizeof (EFI_BOOT_SERVICES), // HeaderSize
46 0, // CRC32
47 0 // Reserved
48 },
49 (EFI_RAISE_TPL)CoreRaiseTpl, // RaiseTPL
50 (EFI_RESTORE_TPL)CoreRestoreTpl, // RestoreTPL
51 (EFI_ALLOCATE_PAGES)CoreAllocatePages, // AllocatePages
52 (EFI_FREE_PAGES)CoreFreePages, // FreePages
53 (EFI_GET_MEMORY_MAP)CoreGetMemoryMap, // GetMemoryMap
54 (EFI_ALLOCATE_POOL)CoreAllocatePool, // AllocatePool
55 (EFI_FREE_POOL)CoreFreePool, // FreePool
56 (EFI_CREATE_EVENT)CoreCreateEvent, // CreateEvent
57 (EFI_SET_TIMER)CoreSetTimer, // SetTimer
58 (EFI_WAIT_FOR_EVENT)CoreWaitForEvent, // WaitForEvent
59 (EFI_SIGNAL_EVENT)CoreSignalEvent, // SignalEvent
60 (EFI_CLOSE_EVENT)CoreCloseEvent, // CloseEvent
61 (EFI_CHECK_EVENT)CoreCheckEvent, // CheckEvent
62 (EFI_INSTALL_PROTOCOL_INTERFACE)CoreInstallProtocolInterface, // InstallProtocolInterface
63 (EFI_REINSTALL_PROTOCOL_INTERFACE)CoreReinstallProtocolInterface, // ReinstallProtocolInterface
64 (EFI_UNINSTALL_PROTOCOL_INTERFACE)CoreUninstallProtocolInterface, // UninstallProtocolInterface
65 (EFI_HANDLE_PROTOCOL)CoreHandleProtocol, // HandleProtocol
66 (VOID *)NULL, // Reserved
67 (EFI_REGISTER_PROTOCOL_NOTIFY)CoreRegisterProtocolNotify, // RegisterProtocolNotify
68 (EFI_LOCATE_HANDLE)CoreLocateHandle, // LocateHandle
69 (EFI_LOCATE_DEVICE_PATH)CoreLocateDevicePath, // LocateDevicePath
70 (EFI_INSTALL_CONFIGURATION_TABLE)CoreInstallConfigurationTable, // InstallConfigurationTable
71 (EFI_IMAGE_LOAD)CoreLoadImage, // LoadImage
72 (EFI_IMAGE_START)CoreStartImage, // StartImage
73 (EFI_EXIT)CoreExit, // Exit
74 (EFI_IMAGE_UNLOAD)CoreUnloadImage, // UnloadImage
75 (EFI_EXIT_BOOT_SERVICES)CoreExitBootServices, // ExitBootServices
76 (EFI_GET_NEXT_MONOTONIC_COUNT)CoreEfiNotAvailableYetArg1, // GetNextMonotonicCount
77 (EFI_STALL)CoreStall, // Stall
78 (EFI_SET_WATCHDOG_TIMER)CoreSetWatchdogTimer, // SetWatchdogTimer
79 (EFI_CONNECT_CONTROLLER)CoreConnectController, // ConnectController
80 (EFI_DISCONNECT_CONTROLLER)CoreDisconnectController, // DisconnectController
81 (EFI_OPEN_PROTOCOL)CoreOpenProtocol, // OpenProtocol
82 (EFI_CLOSE_PROTOCOL)CoreCloseProtocol, // CloseProtocol
83 (EFI_OPEN_PROTOCOL_INFORMATION)CoreOpenProtocolInformation, // OpenProtocolInformation
84 (EFI_PROTOCOLS_PER_HANDLE)CoreProtocolsPerHandle, // ProtocolsPerHandle
85 (EFI_LOCATE_HANDLE_BUFFER)CoreLocateHandleBuffer, // LocateHandleBuffer
86 (EFI_LOCATE_PROTOCOL)CoreLocateProtocol, // LocateProtocol
87 (EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)CoreInstallMultipleProtocolInterfaces, // InstallMultipleProtocolInterfaces
88 (EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)CoreUninstallMultipleProtocolInterfaces, // UninstallMultipleProtocolInterfaces
89 (EFI_CALCULATE_CRC32)CoreEfiNotAvailableYetArg3, // CalculateCrc32
90 (EFI_COPY_MEM)CopyMem, // CopyMem
91 (EFI_SET_MEM)SetMem, // SetMem
92 (EFI_CREATE_EVENT_EX)CoreCreateEventEx // CreateEventEx
93 };
Runtime阶段提供的服务
Runtime Service:
时间,读写变量,虚拟内存,etc
Runtime Service
EFI_RUNTIME_SERVICES mEfiRuntimeServicesTableTemplate = {
{
EFI_RUNTIME_SERVICES_SIGNATURE, // Signature
EFI_RUNTIME_SERVICES_REVISION, // Revision
sizeof (EFI_RUNTIME_SERVICES), // HeaderSize
0, // CRC32
0 // Reserved
},
(EFI_GET_TIME)CoreEfiNotAvailableYetArg2, // GetTime
(EFI_SET_TIME)CoreEfiNotAvailableYetArg1, // SetTime
(EFI_GET_WAKEUP_TIME)CoreEfiNotAvailableYetArg3, // GetWakeupTime
(EFI_SET_WAKEUP_TIME)CoreEfiNotAvailableYetArg2, // SetWakeupTime
(EFI_SET_VIRTUAL_ADDRESS_MAP)CoreEfiNotAvailableYetArg4, // SetVirtualAddressMap
(EFI_CONVERT_POINTER)CoreEfiNotAvailableYetArg2, // ConvertPointer
(EFI_GET_VARIABLE)CoreEfiNotAvailableYetArg5, // GetVariable
(EFI_GET_NEXT_VARIABLE_NAME)CoreEfiNotAvailableYetArg3, // GetNextVariableName
(EFI_SET_VARIABLE)CoreEfiNotAvailableYetArg5, // SetVariable
(EFI_GET_NEXT_HIGH_MONO_COUNT)CoreEfiNotAvailableYetArg1, // GetNextHighMonotonicCount
(EFI_RESET_SYSTEM)CoreEfiNotAvailableYetArg4, // ResetSystem
(EFI_UPDATE_CAPSULE)CoreEfiNotAvailableYetArg3, // UpdateCapsule
(EFI_QUERY_CAPSULE_CAPABILITIES)CoreEfiNotAvailableYetArg4, // QueryCapsuleCapabilities
(EFI_QUERY_VARIABLE_INFO)CoreEfiNotAvailableYetArg4 // QueryVariableInfo
};
PEI阶段提供的服务
PPI, Pei 阶段读写变量是通过PPI来读写的。
Flags用于描述PPI的类型,常用的有下面几种:
- EFI_PEI_PPI_DESCRIPTOR_PPI,常用于Installppi,此时ppi是该Guid对应的一些函数,通过LocatePpi可以调用这些函数;
- EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,常用于注册Guid对应的callback,此时ppi就是callback函数,一般用于notify。当调用notifyppi时,如果Guid已经被安装了,则直接执行callback,如果对应的Guid没有安装时,在调用Installppi,会自动调用callback函数。
点击查看代码
typedef struct {
///
/// This field is a set of flags describing the characteristics of this imported table entry.
/// All flags are defined as EFI_PEI_PPI_DESCRIPTOR_***, which can also be combined into one.
///
UINTN Flags;
///
/// The address of the EFI_GUID that names the interface.
///
EFI_GUID *Guid;
///
/// A pointer to the PPI. It contains the information necessary to install a service.
///
VOID *Ppi;
} EFI_PEI_PPI_DESCRIPTOR;
///
/// The data structure in a given PEIM that tells the PEI
/// Foundation where to invoke the notification service.
///
struct _EFI_PEI_NOTIFY_DESCRIPTOR {
///
/// Details if the type of notification are callback or dispatch.
///
UINTN Flags;
///
/// The address of the EFI_GUID that names the interface.
///
EFI_GUID *Guid;
///
/// Address of the notification callback function itself within the PEIM.
///
EFI_PEIM_NOTIFY_ENTRY_POINT Notify;
};
///
/// This data structure is the means by which callable services are installed and
/// notifications are registered in the PEI phase.
///
typedef union {
///
/// The typedef structure of the notification descriptor.
///
EFI_PEI_NOTIFY_DESCRIPTOR Notify;
///
/// The typedef structure of the PPI descriptor.
///
EFI_PEI_PPI_DESCRIPTOR Ppi;
} EFI_PEI_DESCRIPTOR;
PPI在PeiCore的全局变量PeiCore Instance中
PeiCore全局变量
PeiCore PrivateData
///
/// Pei Core private data structure instance
///
struct _PEI_CORE_INSTANCE {
UINTN Signature;
///
/// Point to ServiceTableShadow
///
EFI_PEI_SERVICES *Ps;
PEI_PPI_DATABASE PpiData;
///
/// The count of FVs which contains FFS and could be dispatched by PeiCore.
///
UINTN FvCount;
///
/// The max count of FVs which contains FFS and could be dispatched by PeiCore.
///
UINTN MaxFvCount;
///
/// Pointer to the buffer with the MaxFvCount number of entries.
/// Each entry is for one FV which contains FFS and could be dispatched by PeiCore.
///
PEI_CORE_FV_HANDLE *Fv;
///
/// Pointer to the buffer with the MaxUnknownFvInfoCount number of entries.
/// Each entry is for one FV which could not be dispatched by PeiCore.
///
PEI_CORE_UNKNOW_FORMAT_FV_INFO *UnknownFvInfo;
UINTN MaxUnknownFvInfoCount;
UINTN UnknownFvInfoCount;
///
/// Pointer to the buffer FvFileHandlers in PEI_CORE_FV_HANDLE specified by CurrentPeimFvCount.
///
EFI_PEI_FILE_HANDLE *CurrentFvFileHandles;
UINTN AprioriCount;
UINTN CurrentPeimFvCount;
UINTN CurrentPeimCount;
EFI_PEI_FILE_HANDLE CurrentFileHandle;
BOOLEAN PeimNeedingDispatch;
BOOLEAN PeimDispatchOnThisPass;
BOOLEAN PeimDispatcherReenter;
EFI_PEI_HOB_POINTERS HobList;
BOOLEAN SwitchStackSignal;
BOOLEAN PeiMemoryInstalled;
VOID *CpuIo;
EFI_PEI_SECURITY2_PPI *PrivateSecurityPpi;
EFI_PEI_SERVICES ServiceTableShadow;
EFI_PEI_PPI_DESCRIPTOR *XipLoadFile;
EFI_PHYSICAL_ADDRESS PhysicalMemoryBegin;
UINT64 PhysicalMemoryLength;
EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop;
UINTN HeapOffset;
BOOLEAN HeapOffsetPositive;
UINTN StackOffset;
BOOLEAN StackOffsetPositive;
//
// Information for migrating memory pages allocated in pre-memory phase.
//
HOLE_MEMORY_DATA MemoryPages;
PEICORE_FUNCTION_POINTER ShadowedPeiCore;
CACHE_SECTION_DATA CacheSection;
//
// For Loading modules at fixed address feature to cache the top address below which the
// Runtime code, boot time code and PEI memory will be placed. Please note that the offset between this field
// and Ps should not be changed since maybe user could get this top address by using the offset to Ps.
//
EFI_PHYSICAL_ADDRESS LoadModuleAtFixAddressTopAddress;
//
// The field is define for Loading modules at fixed address feature to tracker the PEI code
// memory range usage. It is a bit mapped array in which every bit indicates the corresponding memory page
// available or not.
//
UINT64 *PeiCodeMemoryRangeUsageBitMap;
//
// This field points to the shadowed image read function
//
PE_COFF_LOADER_READ_FILE ShadowedImageRead;
UINTN TempPeimCount;
//
// Pointer to the temp buffer with the TempPeimCount number of entries.
//
EFI_PEI_FILE_HANDLE *TempFileHandles;
//
// Pointer to the temp buffer with the TempPeimCount number of entries.
//
EFI_GUID *TempFileGuid;
//
// Temp Memory Range is not covered by PeiTempMem and Stack.
// Those Memory Range will be migrated into physical memory.
//
HOLE_MEMORY_DATA HoleData[HOLE_MAX_NUMBER];
};
Pei Service
Pei Service
///
/// Pei service instance
///
EFI_PEI_SERVICES gPs = {
{
PEI_SERVICES_SIGNATURE,
PEI_SERVICES_REVISION,
sizeof (EFI_PEI_SERVICES),
0,
0
},
PeiInstallPpi,
PeiReInstallPpi,
PeiLocatePpi,
PeiNotifyPpi,
PeiGetBootMode,
PeiSetBootMode,
PeiGetHobList,
PeiCreateHob,
PeiFfsFindNextVolume,
PeiFfsFindNextFile,
PeiFfsFindSectionData,
PeiInstallPeiMemory,
PeiAllocatePages,
PeiAllocatePool,
(EFI_PEI_COPY_MEM)CopyMem,
(EFI_PEI_SET_MEM)SetMem,
PeiReportStatusCode,
PeiResetSystem,
&gPeiDefaultCpuIoPpi,
&gPeiDefaultPciCfg2Ppi,
PeiFfsFindFileByName,
PeiFfsGetFileInfo,
PeiFfsGetVolumeInfo,
PeiRegisterForShadow,
PeiFfsFindSectionData3,
PeiFfsGetFileInfo2,
PeiResetSystem2,
PeiFreePages,
};
UEFI —— Status Code用法
PEI 阶段用法
是PeiServices中的一个组成。
code: Edk2\MdeModulePkg\Universal\ReportStatusCodeRouter\Pei\ReportStatusCodeRouterPei.c
整体逻辑:
- 调用ReportStatusCode
- 挂在gEfiPeiRscHandlerPpiGuid上的handler都会跑一便
- 执行对应的callback
gEfiPeiRscHandlerPpiGuid 用于注册和卸载handler
gEfiPeiStatusCodePpiGuid 用于当有人调用ReportStatusCode的时候,搜寻并执行gEfiPeiRscHandlerPpiGuid 注册的所有handler
Ppi
EFI_PEI_RSC_HANDLER_PPI mRscHandlerPpi = {
Register,
Unregister
};
EFI_PEI_PROGRESS_CODE_PPI mStatusCodePpi = {
ReportDispatcher
};
EFI_PEI_PPI_DESCRIPTOR mRscHandlerPpiList[] = {
{
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiPeiRscHandlerPpiGuid,
&mRscHandlerPpi
}
};
EFI_PEI_PPI_DESCRIPTOR mStatusCodePpiList[] = {
{
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiPeiStatusCodePpiGuid,
&mStatusCodePpi
}
};
Runtime,DXE阶段
Protocol
EFI_STATUS_CODE_PROTOCOL mStatusCodeProtocol = {
ReportDispatcher
};
EFI_RSC_HANDLER_PROTOCOL mRscHandlerProtocol = {
Register,
Unregister
};
SMM 阶段
Protocol
EFI_MM_STATUS_CODE_PROTOCOL mSmmStatusCodeProtocol = {
ReportDispatcher
};
EFI_MM_RSC_HANDLER_PROTOCOL mSmmRscHandlerProtocol = {
Register,
Unregister
};
Event 的使用方法
ref:Edk2\MdeModulePkg\Core\Dxe\Event\Event.c
-
CreateEvent的用法
a. 如果是EVT_NOTIFY_SIGNAL,就入队gEventSignalQueue点击查看代码
if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) { // // The Event's NotifyFunction must be queued whenever the event is signaled // InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); }
-
SignalEvent&NotifyEvent的用法
a. gEventSignalQueue,以组为单位筛选Event,然后再用gEventQueue筛选Event。
b. gEventQueue,以Tpl为key记录的队列。 -
在CoreInstallProtocolInterface/Reintall中中,类似于PPI,也会notify对应Protocol Guid的event.
代码如下
VOID CoreNotifyProtocolEntry ( IN PROTOCOL_ENTRY *ProtEntry ) { PROTOCOL_NOTIFY *ProtNotify; LIST_ENTRY *Link; ASSERT_LOCKED (&gProtocolDatabaseLock); for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) { ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); CoreSignalEvent (ProtNotify->Event); } }
示例一
先创建一个event,然后把event挂在一个Protocol的GUID上,之后在install protocol时会调用notifyEvent,或者SignalEvent
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
DxeNotifyCallback,
NULL,
&NotifyEvent
);
if (!EFI_ERROR (Status)) {
Status = gBS->RegisterProtocolNotify (
ProtocolGuid,
NotifyEvent,
&Registration
);
示例二
先CreateEvent,然后SignalEvent,最后CloseEvent
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
InternalBdsEmptyCallbackFuntion,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&EndOfDxeEvent
);
ASSERT_EFI_ERROR (Status);
gBS->SignalEvent (EndOfDxeEvent);
gBS->CloseEvent (EndOfDxeEvent);
DEBUG((DEBUG_INFO,"All EndOfDxe callbacks have returned successfully\n"));
示例三
先CreateEvent,然后WaitForEvent
/**
Function waits for a given event to fire, or for an optional timeout to expire.
@param Event The event to wait for
@param Timeout An optional timeout value in 100 ns units.
@retval EFI_SUCCESS Event fired before Timeout expired.
@retval EFI_TIME_OUT Timout expired before Event fired..
**/
EFI_STATUS
BdsWaitForSingleEvent (
IN EFI_EVENT Event,
IN UINT64 Timeout OPTIONAL
)
{
UINTN Index;
EFI_STATUS Status;
EFI_EVENT TimerEvent;
EFI_EVENT WaitList[2];
if (Timeout != 0) {
//
// Create a timer event
//
Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
if (!EFI_ERROR (Status)) {
//
// Set the timer event
//
gBS->SetTimer (
TimerEvent,
TimerRelative,
Timeout
);
//
// Wait for the original event or the timer
//
WaitList[0] = Event;
WaitList[1] = TimerEvent;
Status = gBS->WaitForEvent (2, WaitList, &Index);
ASSERT_EFI_ERROR (Status);
gBS->CloseEvent (TimerEvent);
//
// If the timer expired, change the return to timed out
//
if (Index == 1) {
Status = EFI_TIMEOUT;
}
}
} else {
//
// No timeout... just wait on the event
//
Status = gBS->WaitForEvent (1, &Event, &Index);
ASSERT (!EFI_ERROR (Status));
ASSERT (Index == 0);
}
return Status;
}