前面一篇文章提到“提供服务的代码需要常驻内存,一般的 Application 是不会常驻内存的,而驱动直接可以常驻内存”。普通的Application 不能常驻内存,但是可以做个特殊的Application 来完成这个功能,之前的文章【参考1】我们尝试过写一个能够一直在 Shell 右上角显示当前时间的程序。结合前面的Protocol安装的驱动代码,我们做一个安装Protocol的Application。
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellCEntryLib.h> #include <stdio.h> #include <stdlib.h> #include <wchar.h> #include <time.h> #include <Protocol/EfiShell.h> #include <Library/ShellLib.h> #include <Library/PrintLib.h> #include <Protocol/SimpleFileSystem.h> #include <Protocol/BlockIo.h> #include <Library/DevicePathLib.h> #include <Library/HandleParsingLib.h> #include <Library/SortLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/BaseMemoryLib.h> #include <Library/DebugLib.h> #include <Protocol/LoadedImage.h> #include "Print9.h" extern EFI_BOOT_SERVICES *gBS; extern EFI_SYSTEM_TABLE *gST; extern EFI_RUNTIME_SERVICES *gRT; extern EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; extern EFI_HANDLE gImageHandle; typedef struct { UINTN Signature; /// Image handle EFI_HANDLE Handle; /// Image type UINTN Type; /// If entrypoint has been called BOOLEAN Started; /// The image's entry point EFI_IMAGE_ENTRY_POINT EntryPoint; /// loaded image protocol EFI_LOADED_IMAGE_PROTOCOL Info; } LOADED_IMAGE_PRIVATE_DATA_TEMP; EFI_GUID gEfiPrint9ProtocolGuid= { 0xf05976ef, 0x83f1, 0x4f3d, { 0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x61 } }; #define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) #define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ _CR(a, LOADED_IMAGE_PRIVATE_DATA_TEMP, Info) CONST EFI_PRINT9_PROTOCOL mPrint9Protocol = { UnicodeBSPrint, UnicodeSPrint, UnicodeBSPrintAsciiFormat, UnicodeSPrintAsciiFormat, UnicodeValueToString, AsciiBSPrint, AsciiSPrint, AsciiBSPrintUnicodeFormat, AsciiSPrintUnicodeFormat, AsciiValueToString }; EFI_LOADED_IMAGE_PROTOCOL *ImageInfo = NULL; typedef void (*Fun)(); void function() { EFI_STATUS Status; Status = gBS->InstallMultipleProtocolInterfaces ( &gImageHandle, &gEfiPrint9ProtocolGuid, &mPrint9Protocol, NULL ); ASSERT_EFI_ERROR (Status); } int EFIAPI main ( IN int Argc, IN char **Argv ) { EFI_STATUS Status = EFI_SUCCESS; EFI_HANDLE Handle = 0; EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; LOADED_IMAGE_PRIVATE_DATA_TEMP *private = NULL; Fun fun; UINTN FunOffset; UINTN FunAddr; Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo); // function offset in the old image FunOffset = (UINTN)function - (UINTN)ImageInfo->ImageBase; // load the image in memory again Status = gBS->LoadImage(FALSE, gImageHandle, NULL, ImageInfo->ImageBase, (UINTN)ImageInfo->ImageSize, &Handle); // get the newer imageinfo Status = gBS->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, &ImageInfo); private = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(ImageInfo); FunAddr = (UINTN)FunOffset + (UINTN)ImageInfo->ImageBase; fun = (Fun)((UINTN)FunOffset + (UINTN)ImageInfo->ImageBase); // called the newer function in new image,the new image will be always in memory because it will not be free fun(); return EFI_SUCCESS; }
完整的代码下载:
appprotocol
参考:
1. http://www.lab-z.com/49str/ Step to UEFI (49) —– 内存驻留程序