本文旨在簡單的介紹一下DXE階段的工作原理:
UDK2015的開源代碼下載:https://github.com/tianocore/tianocore.github.io/wiki/EDK-II
DXE階段是UEFI系統的最主要的組成部分,
1.DXE階段主要由兩部分組成:DXE內核 + 模塊;
2.DXE內核提供了最基本的一些功能,比如Protocol的管理,事件的管理等等(DXE內核提供的基本功能稱為服務);
3.通過加載各種模塊擴展其他的功能;
4.DXE階段的核心概念:Service、Protocol、Handle(Handle和Protocol組成一個二維鏈表,protocol提供的接口類似於內核符號表中的函數;Service類似於linux kernel api);
5.DXE內核在post過程中會加載各種模塊,每個模塊會安裝不同的Protocol(Protocol類似於面向對象編程里面的類),用來擴展系統支持的功能;
內核提供的基本Service:
1 // 2 // DXE Core Module Variables 3 // 4 EFI_BOOT_SERVICES mBootServices = { 5 { 6 EFI_BOOT_SERVICES_SIGNATURE, // Signature 7 EFI_BOOT_SERVICES_REVISION, // Revision 8 sizeof (EFI_BOOT_SERVICES), // HeaderSize 9 0, // CRC32 10 0 // Reserved 11 }, 19 (EFI_CREATE_EVENT) CoreCreateEvent, // CreateEvent 20 (EFI_SET_TIMER) CoreSetTimer, // SetTimer 21 (EFI_WAIT_FOR_EVENT) CoreWaitForEvent, // WaitForEvent 22 (EFI_SIGNAL_EVENT) CoreSignalEvent, // SignalEvent 23 (EFI_CLOSE_EVENT) CoreCloseEvent, // CloseEvent 24 (EFI_CHECK_EVENT) CoreCheckEvent, // CheckEvent 25 (EFI_INSTALL_PROTOCOL_INTERFACE) CoreInstallProtocolInterface, // InstallProtocolInterface 26 (EFI_REINSTALL_PROTOCOL_INTERFACE) CoreReinstallProtocolInterface, // ReinstallProtocolInterface 27 (EFI_UNINSTALL_PROTOCOL_INTERFACE) CoreUninstallProtocolInterface, // UninstallProtocolInterface 28 (EFI_HANDLE_PROTOCOL) CoreHandleProtocol, // HandleProtocol 29 (VOID *) NULL, // Reserved 30 (EFI_REGISTER_PROTOCOL_NOTIFY) CoreRegisterProtocolNotify, // RegisterProtocolNotify 31 .... 56 };
上面是DXE內核提供的功能。
但也有些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 };
以EFI_RUNTIME_SERVICES->ResetSystem()為例,不同的平台(比如x86與ARM),重啟系統的實現方式是不一樣的,所以UDK代碼里面沒有給出具體的實現。在實際項目中,通過平台BSP代碼提供的模塊來安裝這個實現:
// // Hook the runtime service table // SystemTable->RuntimeServices->ResetSystem = Cf9ResetSystem;
1 VOID 2 EFIAPI 3 Cf9ResetSystem ( 4 IN EFI_RESET_TYPE ResetType, 5 IN EFI_STATUS ResetStatus, 6 IN UINTN DataSize, 7 IN CHAR16 *ResetData OPTIONAL 8 ) 9 { 10 //不同平台的具體實現;
11 }
UDK整個系統的代碼框架可描述如下:
1.內核聲明了整個系統必須實現的接口(依據UEFI/PI規范);
2.一部分(最最基本)的接口的實現由內核提供,一部分接口的實現因為跟平台有關,所以由平台代碼提供;
3.通過模塊安裝各種各樣的擴展功能(protocol);
4.整個代碼框架是微內核結構,內核只提供基本的功能,模塊通過安裝protocol來提供其它功能;
5. 內核實現了框架,並提供API,驅動程序調用內核提供的API把自己實現的接口(protocol)安裝到系統中,系統使用統一的接口訪問不同的實現。
6.DXE最后會把控制權交給BDS:
某個DXE driver會安裝下面的protocol,用來提供BDS的入口,DXE到BDS體現了內核通過統一接口訪問不同實現的思想。
模塊舉例:
UDK里面的模塊舉例:(這里的模塊沒有follow UEFI Driver Model)
UEFI Spec里面通過EFI_IMAGE_ENTRY_POINT 這個函數指針類型定義了 UEFI Image的入口點的形式(包括返回值和參數)
Linux里面的模塊舉例: