前面一篇文章提到“提供服务的代码需要常驻内存,一般的 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) —– 内存驻留程序






















