1.http://biosengineer.blogspot.com/2011/09/uefi-screenshot-capture-screen.html UEFI Screenshot (Capture screen)
2.http://kurtqiao.blogspot.com/2013/03/how-to-take-screen-shot-under-uefi-shell.htmlHow to take screen shot under UEFI shell
通常,每个UEFI系统至少有一个 ESP (EFI System Partition)分区,在这个分区上存放启动文件。EFI内置了EFI_SIMPLE_FILE_SYSTEM_PROTOCOL(简称 FileSystemIo)可以用来操作FAT文件系统【参考1】。
相关的介绍:
\MdePkg\Include\Protocol\SimpleFileSystem.h
///
/// The EFI_FILE_PROTOCOL provides file IO access to supported file systems.
/// An EFI_FILE_PROTOCOL provides access to a file's or directory's contents,
/// and is also a reference to a location in the directory tree of the file system
/// in which the file resides. With any given file handle, other files may be opened
/// relative to this file's location, yielding new file handles.
///
struct _EFI_FILE_PROTOCOL {
///
/// The version of the EFI_FILE_PROTOCOL interface. The version specified
/// by this specification is EFI_FILE_PROTOCOL_LATEST_REVISION.
/// Future versions are required to be backward compatible to version 1.0.
///
UINT64 Revision;
EFI_FILE_OPEN Open;
EFI_FILE_CLOSE Close;
EFI_FILE_DELETE Delete;
EFI_FILE_READ Read;
EFI_FILE_WRITE Write;
EFI_FILE_GET_POSITION GetPosition;
EFI_FILE_SET_POSITION SetPosition;
EFI_FILE_GET_INFO GetInfo;
EFI_FILE_SET_INFO SetInfo;
EFI_FILE_FLUSH Flush;
EFI_FILE_OPEN_EX OpenEx;
EFI_FILE_READ_EX ReadEx;
EFI_FILE_WRITE_EX WriteEx;
EFI_FILE_FLUSH_EX FlushEx;
};
/**
Writes data to a file.
@param This A pointer to the EFI_FILE_PROTOCOL instance that is the file
handle to write data to.
@param BufferSize On input, the size of the Buffer. On output, the amount of data
actually written. In both cases, the size is measured in bytes.
@param Buffer The buffer of data to write.
@retval EFI_SUCCESS Data was written.
@retval EFI_UNSUPPORTED Writes to open directory files are not supported.
@retval EFI_NO_MEDIA The device has no medium.
@retval EFI_DEVICE_ERROR The device reported an error.
@retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
@retval EFI_WRITE_PROTECTED The file or medium is write-protected.
@retval EFI_ACCESS_DENIED The file was opened read only.
@retval EFI_VOLUME_FULL The volume is full.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_FILE_WRITE)(
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
);
完整代码:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
#include <Protocol/SimpleFileSystem.h>
extern EFI_BOOT_SERVICES *gBS;
extern EFI_SYSTEM_TABLE *gST;
int
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
EFI_FILE_PROTOCOL *Root;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
UINTN BufSize;
CHAR16 *Textbuf = (CHAR16*) L"www.lab-z.com";
EFI_FILE_PROTOCOL *FileHandle=0;
Status = gBS->LocateProtocol(
&gEfiSimpleFileSystemProtocolGuid,
NULL,
(VOID **)&SimpleFileSystem);
if (EFI_ERROR(Status)) {
Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
return Status;
}
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem,&Root);
if (EFI_ERROR(Status)) {
Print(L"OpenVolume error \r\n");
return Status;
}
Status = Root -> Open(Root,
&FileHandle,
(CHAR16 *) L"atest.txt",
EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
0);
if (EFI_ERROR(Status) || (FileHandle==0)) {
Print(L"Open error \r\n");
return Status;
}
BufSize = StrLen (Textbuf) * 2;
Print(L"[%d]\r\n",BufSize);
Print(L"[%s]\r\n",Textbuf);
Status = FileHandle -> Write(FileHandle, &BufSize, Textbuf);
Print(L"Write Done \r\n");
Status = FileHandle -> Close (FileHandle);
return EFI_SUCCESS;
}
运行结果:
比较有意思的是,我们按照上面的程序写入之后,使用 type 文件名 来显示文件内容和我们的预期有差别,原因是Type命令默认使用 ASCII 来显内容,而我们的文件中写入的是 Unicode。使用 type -u 强制使用 Unicode即可看到我们期望的内容。
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/SimpleFileSystem.h>
extern EFI_HANDLE gImageHandle;
EFI_STATUS
WriteMemoryToFile(
IN EFI_HANDLE ImageHandle,
IN CHAR16 *FileName,
IN VOID *Buffer,
IN UINTN BufferSize
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
EFI_FILE_PROTOCOL *Root;
EFI_FILE_PROTOCOL *File;
EFI_HANDLE *Handles = NULL;
UINTN HandleCount = 0;
// Locate all handles that support the Simple File System Protocol
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
if (EFI_ERROR(Status)) {
Print(L"Failed to locate handles for Simple File System Protocol: %r\n", Status);
return Status;
}
// Open the first Simple File System Protocol
Status = gBS->HandleProtocol(Handles[0], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SimpleFileSystem);
if (EFI_ERROR(Status)) {
Print(L"Failed to open Simple File System Protocol: %r\n", Status);
return Status;
}
// Open the root directory
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root);
if (EFI_ERROR(Status)) {
Print(L"Failed to open root directory: %r\n", Status);
return Status;
}
// Create or open the file
Status = Root->Open(Root, &File, FileName, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
if (EFI_ERROR(Status)) {
Print(L"Failed to open or create file: %r\n", Status);
return Status;
}
// Write the buffer to the file
Status = File->Write(File, &BufferSize, Buffer);
if (EFI_ERROR(Status)) {
Print(L"Failed to write to file: %r\n", Status);
File->Close(File);
return Status;
}
// Close the file
Status = File->Close(File);
if (EFI_ERROR(Status)) {
Print(L"Failed to close file: %r\n", Status);
return Status;
}
Print(L"Memory successfully written to file: %s\n", FileName);
return EFI_SUCCESS;
}
#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
/**
The user Entry Point for Application. The user code starts with this function
as the real entry point for the application.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
Print(L"Hello,World! \r\n");
Print(L"www.lab-z.com \r\n");
Print(L"UefiMain [%X]",(UINTN)UefiMain);
return EFI_SUCCESS;
}
上次介绍了如何在一个程序中直接调用另外的程序,那么在调用过程中是否有机会获得一些加载起来的EFI的信息呢?经过一番搜索,发现EFI_LOADED_IMAGE_PROTOCOL【参考1】。这个protocol的作用就是 “Can be used on any image handle to obtain information about the loaded image.”
从定义上看,我们能够得到加载的Image的一些基本信息。在上次程序的基础上,添加一些代码来实验。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
extern EFI_BOOT_SERVICES *gBS;
extern EFI_SYSTEM_TABLE *gST;
extern EFI_RUNTIME_SERVICES *gRT;
extern EFI_SHELL_PROTOCOL *gEfiShellProtocol;
extern EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
extern EFI_HANDLE gImageHandle;
/**
GET DEVICEPATH
**/
EFI_DEVICE_PATH_PROTOCOL *
EFIAPI
ShellGetDevicePath (
IN CHAR16 * CONST DeviceName OPTIONAL
)
{
//
// Check for UEFI Shell 2.0 protocols
//
if (gEfiShellProtocol != NULL) {
return (gEfiShellProtocol->GetDevicePathFromFilePath(DeviceName));
}
//
// Check for EFI shell
//
if (mEfiShellEnvironment2 != NULL) {
return (mEfiShellEnvironment2->NameToPath(DeviceName));
}
return (NULL);
}
int
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_HANDLE NewHandle;
EFI_STATUS Status;
UINTN ExitDataSizePtr;
CHAR16 *R=L"HelloWorld.efi";
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo = NULL;
Print(L"File [%s]\n",R);
DevicePath=ShellGetDevicePath(R);
//
// Load the image with:
// FALSE - not from boot manager and NULL, 0 being not already in memory
//
Status = gBS->LoadImage(
FALSE,
gImageHandle,
DevicePath,
NULL,
0,
&NewHandle);
if (EFI_ERROR(Status)) {
if (NewHandle != NULL) {
gBS->UnloadImage(NewHandle);
}
Print(L"Error during LoadImage [%X]\n",Status);
return (Status);
}
Status = gBS -> HandleProtocol (
NewHandle,
&gEfiLoadedImageProtocolGuid,
&ImageInfo
);
Print(L"ImageBase [%lX]\n",ImageInfo->ImageBase);
Print(L"ImageSize [%lX]\n",ImageInfo->ImageSize);
//
// now start the image, passing up exit data if the caller requested it
//
Status = gBS->StartImage(
NewHandle,
&ExitDataSizePtr,
NULL
);
if (EFI_ERROR(Status)) {
if (NewHandle != NULL) {
gBS->UnloadImage(NewHandle);
}
Print(L"Error during StartImage [%X]\n",Status);
return (Status);
}
gBS->UnloadImage (NewHandle);
return EFI_SUCCESS;
}
特别注意,我们代码中需要使用这个Protocol的GUID,在INF中添加下面的引用即可。
[Protocols]
gEfiLoadedImageProtocolGuid
运行结果
可以看到显示的ImageSize就是 HelloWorld.efi的大小。
实验调用的代码比较特殊,如果直接调用CLIB编写的程序会导致错误。至于具体的原因,后续再进行研究。
实验的 HelloWorld.EFI 的代码在下面
#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
/**
The user Entry Point for Application. The user code starts with this function
as the real entry point for the application.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
Print(L"Hello,World! \r\n");
Print(L"www.lab-z.com \r\n");
return EFI_SUCCESS;
}
对应的INF
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = HelloWorld
FILE_GUID = 6987936E-ED34-44db-AE97-1FA5E4ED2116
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
HelloWorld.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
PcdLib
[FeaturePcd]
[Pcd]