System Table是UEFI软件架构中最重要的一个部分,基本的代码都离不开它。
下面是一个基本的UEFI模块中会包含的Entry Point,它就有一个参数是System Table:
typedef
EFI_STATUS
(EFIAPI *EFI_IMAGE_ENTRY_POINT) (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
以8254Timer这个模块为例,它的inf模块中有以下的代码:
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Timer
MODULE_UNI_FILE = Timer.uni
FILE_GUID = f2765dec-6b41-11d5-8e71-00902707b35e
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = TimerDriverInitialize
其中的ENTRY_POINT就指向了该模块的入口:
/**
Initialize the Timer Architectural Protocol driver
@param ImageHandle ImageHandle of the loaded driver
@param SystemTable Pointer to the System Table
@retval EFI_SUCCESS Timer Architectural Protocol created
@retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
@retval EFI_DEVICE_ERROR A device error occured attempting to initialize the driver.
**/
EFI_STATUS
EFIAPI
TimerDriverInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
后续的代码会使用到SystemTable中包含的内容。
System Table包含了一系列的指针,指向Console设备,指向Runtime Service Table,Boot Service Table、DXE Service Table和Configuration Table,前两张表包含了很多的基础函数,最后一张表包含了ACPI、SMBIOS等表。
System Table的建立是在DXE阶段(所以在这之前的PEI阶段并没有,里面提供的基础函数也不能用),具体的代码在DxeMain.c中,下面列出简单的代码:
EFI_SYSTEM_TABLE mEfiSystemTableTemplate = {
{
EFI_SYSTEM_TABLE_SIGNATURE, // Signature
EFI_SYSTEM_TABLE_REVISION, // Revision
sizeof (EFI_SYSTEM_TABLE), // HeaderSize
0, // CRC32
0 // Reserved
},
NULL, // FirmwareVendor
0, // FirmwareRevision
NULL, // ConsoleInHandle
NULL, // ConIn
NULL, // ConsoleOutHandle
NULL, // ConOut
NULL, // StandardErrorHandle
NULL, // StdErr
NULL, // RuntimeServices
&mBootServices, // BootServices
0, // NumberOfConfigurationTableEntries
NULL // ConfigurationTable
};
//
// Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData
// Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table
//
gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
ASSERT (gDxeCoreST != NULL);
gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
ASSERT (gDxeCoreRT != NULL);
gDxeCoreST->RuntimeServices = gDxeCoreRT;
在System Table中需要特别介绍的就是Boot Service Table和Runtime Service Table,在UEFI开发中一定会用到其中提供的函数。
它主要分为以下的几类:
与事件相关的:
函数名 | 类型 | 函数描述 |
CreateEvent | Boot | Creates a general-purpose event structure |
CreateEventEx | Boot | Creates an event structure as part of an event group |
CloseEvent | Boot | Closes and frees an event structure |
SignalEvent | Boot | Signals an event |
WaitForEvent | Boot | Stops execution until an event is signaled |
CheckEvent | Boot | Checks whether an event is in the signaled state |
SetTimer | Boot | Sets an event to be signaled at a particular time |
RaiseTPL | Boot | Raises the task priority level |
RestoreTPL | Boot | Restores/lowers the task priority level |
与内存相关的:
函数名 | 类型 | 函数描述 |
AllocatePages | Boot | Allocates pages of a particular type. |
FreePages | Boot | Frees allocated pages. |
GetMemoryMap | Boot | Returns the current boot services memory map and memory map key. |
AllocatePool | Boot | Allocates a pool of a particular type. |
FreePool | Boot | Frees allocated pool. |
与Protocol相关的:
函数名 | 类型 | 函数描述 |
InstallProtocolInterface | Boot | Installs a protocol interface on a device handle. |
UninstallProtocolInterface | Boot | Removes a protocol interface from a device handle. |
ReinstallProtocolInterface | Boot | Reinstalls a protocol interface on a device handle. |
RegisterProtocolNotify | Boot | Registers an event that is to be signaled whenever an interface is installed for a specified protocol. |
LocateHandle | Boot | Returns an array of handles that support a specified protocol. |
HandleProtocol | Boot | Queries a handle to determine if it supports a specified protocol. |
LocateDevicePath | Boot | Locates all devices on a device path that support a specified protocol and returns the handle to the device that is closest to the path. |
OpenProtocol | Boot | Adds elements to the list of agents consuming a protocol interface. |
CloseProtocol | Boot | Removes elements from the list of agents consuming a protocol interface. |
OpenProtocolInformation | Boot | Retrieve the list of agents that are currently consuming a protocol interface. |
ConnectController | Boot | Uses a set of precedence rules to find the best set of drivers to manage a controller. |
DisconnectController | Boot | Informs a set of drivers to stop managing a controller. |
ProtocolsPerHandle | Boot | Retrieves the list of protocols installed on a handle. The return buffer is automatically allocated. |
LocateHandleBuffer | Boot | Retrieves the list of handles from the handle database that meet the search criteria. The return buffer is automatically allocated. |
LocateProtocol | Boot | Finds the first handle in the handle database the supports the requested protocol. |
InstallMultipleProtocolInterfaces | Boot | Installs one or more protocol interfaces onto a handle. |
UninstallMultipleProtocolInterfaces | Boot | Uninstalls one or more protocol interfaces from a handle. |
与Image相关的:
函数名 | 类型 | 函数描述 |
LoadImage | Boot | Loads an EFI image into memory. |
StartImage | Boot | Transfers control to a loaded image’s entry point. |
UnloadImage | Boot | Unloads an image. |
EFI_IMAGE_ENTRY_POINT | Boot | Prototype of an EFI Image’s entry point. |
Exit | Boot | Exits the image’s entry point. |
ExitBootServices | Boot | Terminates boot services. |
及其它:
函数名 | 类型 | 函数描述 |
SetWatchDogTimer | Boot | Resets and sets a watchdog timer used during boot services time. |
Stall | Boot | Stalls the processor. |
CopyMem | Boot | Copies the contents of one buffer to another buffer. |
SetMem | Boot | Fills a buffer with a specified value. |
GetNextMonotonicCount | Boot | Returns a monotonically increasing count for the platform. |
InstallConfigurationTable | Boot | Adds, updates, or removes a configuration table from the EFI System Table. |
CalculateCrc32 | Boot | Computes and returns a 32-bit CRC for a data buffer. |
在Boot Service中有一个ExitBootServices,还函数被调用后Boot Serice Table中的函数就不能再使用了,但是Runtime Service Table中的函数仍然可以使用,这些函数在OS中也仍旧可以调用,当然前提是OS支持。
Runtime Serivces有以下几类:
与变量相关的:
函数名 | 类型 | 函数描述 |
GetVariable | Runtime | Returns the value of a variable. |
GetNextVariableName | Runtime | Enumerates the current variable names. |
SetVariable | Runtime | Sets the value of a variable. |
QueryVariableInfo | Runtime | Returns information about the EFI variables |
与时间相关的:
函数名 | 类型 | 函数描述 |
GetTime | Runtime | Returns the current time and date, and the time-keeping capabilities of the platform. |
SetTime | Runtime | Sets the current local time and date information. |
GetWakeupTime | Runtime | Returns the current wakeup alarm clock setting. |
SetWakeupTime | Runtime | Sets the system wakeup alarm clock time. |
与虚拟内存相关的:
函数名 | 类型 | 函数描述 |
SetVirtualAddressMap | Runtime | Used by an OS loader to convert from physical addressing to virtual addressing. |
ConvertPointer | Runtime | Used by EFI components to convert internal pointers when switching to virtual addressing. |
及其它:
函数名 | 类型 | 函数描述 |
GetNextHighMonotonicCount | Runtime | Returns the next high 32 bits of the platform’s monotonic counter. |
ResetSystem | Runtime | Resets the entire platform. |
UpdateCapsule | Runtime | Pass capsules to the firmware. The firmware may process the capsules immediately or return a value to be passed into ResetSystem() that will cause the capsule to be processed by the firmware as part of the reset process. |
QueryCapsuleCapabilities | Runtime | Returns if the capsule can be supported via UpdateCapsule() |
Runtime Service与Boot Service不同,它并不是在DxeMain.c中直接建立好的,它刚开始基本上是一个空的表:
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
};
可以看到很多的CoreEfiNotAvailableYetxx。
Runtime Service需要在DXE阶段运行过程中一个个的填补。
比如关于时间的几个接口的初始化:
/**
This is the declaration of an EFI image entry point. This can be the entry point to an application
written to this specification, an EFI boot service driver, or an EFI runtime driver.
@param ImageHandle Handle that identifies the loaded image.
@param SystemTable System Table for this image.
@retval EFI_SUCCESS The operation completed successfully.
**/
EFI_STATUS
EFIAPI
InitializeRealTimeClock (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
LibRtcInitialize (ImageHandle, SystemTable);
SystemTable->RuntimeServices->GetTime = GetTime;
SystemTable->RuntimeServices->SetTime = SetTime;
SystemTable->RuntimeServices->GetWakeupTime = GetWakeupTime;
SystemTable->RuntimeServices->SetWakeupTime = SetWakeupTime;
Status = gBS->InstallMultipleProtocolInterfaces (
&mHandle,
&gEfiRealTimeClockArchProtocolGuid,
NULL,
NULL
);
return Status;
}
再比如关于变量的几个接口:
EFI_STATUS
EFIAPI
VariableServiceInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT ReadyToBootEvent;
EFI_EVENT EndOfDxeEvent;
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
Status = gBS->InstallMultipleProtocolInterfaces (
&mHandle,
&gEdkiiVariableLockProtocolGuid,
&mVariableLock,
NULL
);
ASSERT_EFI_ERROR (Status);
Status = gBS->InstallMultipleProtocolInterfaces (
&mHandle,
&gEdkiiVarCheckProtocolGuid,
&mVarCheck,
NULL
);
ASSERT_EFI_ERROR (Status);
SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable;
SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable;
SystemTable->RuntimeServices->QueryVariableInfo = VariableServiceQueryVariableInfo;
与Runtime Service类似,Architecture Protocols也是在DXE阶段运行的过程中逐渐填充的。
以下是所有的Architecture Protocols,这些Protocols是UEFI运行所必须的:
//
// DXE Core Global Variables for all of the Architectural Protocols.
// If a protocol is installed mArchProtocols[].Present will be TRUE.
//
// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event
// and mArchProtocols[].Registration as it creates events for every array
// entry.
//
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 }
};
DXE的开始,最后一列都是FALSE的。
DXE阶段各种模块在安装Protocols时会执行一个回调函数,来判断安装的是否是上表中的特定Protocol,如果是的话FALSE就会被设置成TRUE。
从DXE进入BDS之前这些Protocols必须全部被安装,否则就是出错(可以看到进入BDS阶段需要的Protocol也在里面:gEfiBdsArchProtocolGuid)。