使用 ExitBootServices 的 UEFI 简单示例(使用 gnu-efi)
UEFI simple example of using ExitBootServices (with gnu-efi)
我正在尝试使用 gnu-efi 编写一个 hello world 类型的程序,但没有启动服务,因为它们在 ExitBootServices 后变得不可用。调用ExitBootServices前直接写入显存不显示任何内容
因此我需要调用 ExitBootServices,它需要一个 Mapkey。 MapKey 由 GetMemoryMap 函数提供。但是当我调用它时,我的应用程序崩溃了(我正在使用 qemu)。
这是我的代码:
#include <efi.h>
#include <efilib.h>
void write_string( int color, const char *string )
{
volatile char *video = (volatile char*)0xB8000;
while( *string != 0 )
{
*video++ = *string++;
*video++ = color;
}
}
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
EFI_LOADED_IMAGE *loaded_image = NULL;
EFI_STATUS status;
InitializeLib(ImageHandle, SystemTable);
status = uefi_call_wrapper(SystemTable->BootServices->HandleProtocol,
3, ImageHandle, &LoadedImageProtocol, (void **)&loaded_image);
if (EFI_ERROR(status)) {
Print(L"handleprotocol: %r\n", status);
return EFI_SUCCESS;
}
/* GetMemoryMap */
UINTN MemoryMapSize = sizeof(EFI_MEMORY_DESCRIPTOR) * 0x10;
EFI_MEMORY_DESCRIPTOR *MemoryMap = AllocatePool (MemoryMapSize);
UINTN MapKey = 0;
UINTN DescriptorSize = 0;
UINT32 DescriptorVersion = 0;
status = uefi_call_wrapper(SystemTable->BootServices->GetMemoryMap,
&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
if (EFI_ERROR(status)) {
Print(L"GetMemoryMap: %r\n", status);
return EFI_SUCCESS;
}
/* ExitBootServices */
status = uefi_call_wrapper(SystemTable->BootServices->ExitBootServices,
ImageHandle, MapKey);
if (EFI_ERROR(status)) {
Print(L"ExitBootServices: %r\n", status);
return EFI_SUCCESS;
}
write_string(0x07, "example");
}
甚至在执行 ExitBootServices 之前,qemu 就崩溃并出现错误:
qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000000b0000
谁能告诉我我在做什么错了?
谢谢。
看起来您的主要问题是您忘记将参数数量传递给 uefi_call_wrapper 以调用 GetMemoryMap...传递指针(大数字...比 5 大得多) 可能会破坏 UEFI 固件仿真和 QEMU。由于同样的原因,您的 ExitBootServices 调用将失败,您没有传入参数数量。
您的代码还进行了一些不必要的、可能不正确的假设...
- 系统在内存映射中将有 16 个或更少的条目...
- UEFI 固件将 return 您编译的任何 EFI_MEMORY_DESCRIPTOR 版本...
GetMemoryMap 的定义行为使我们能够解决问题 1,并且我们可以尽一切可能确保我们的代码与未来对新版本 EFI_MEMORY_DESCRIPTOR 的 UEFI 的合理修订向前兼容。
这里是一个获取内存映射并退出引导服务的 C 示例:
#include <efi.h>
#define ErrorCheck(actual, expected) if(actual != expected) return actual
EFI_STATUS EFIAPI efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable)
{
EFI_STATUS result;
// TODO: Load anything that would change the memory map... (ex: OS kernal executable)
UINTN mapSize = 0, mapKey, descriptorSize;
EFI_MEMORY_DESCRIPTOR *memoryMap = NULL;
UINT32 descriptorVersion;
// Get the required memory pool size for the memory map...
result = uefi_call_wrapper((void *)systemTable->BootServices->GetMemoryMap, 5, &mapSize, &memoryMap, NULL, &descriptorSize, NULL);
ErrorCheck(result, EFI_BUFFER_TOO_SMALL);
// Allocating the pool creates at least one new descriptor... for the chunk of memory changed to EfiLoaderData
// Not sure that UEFI firmware must allocate on a memory type boundry... if not, then two descriptors might be created
mapSize += 2 * descriptorSize;
// Get a pool of memory to hold the map...
result = uefi_call_wrapper((void *)systemTable->BootServices->AllocatePool, 3, EfiLoaderData, mapSize, (void **)&memoryMap);
ErrorCheck(result, EFI_SUCCESS);
// Get the actual memory map...
result = uefi_call_wrapper((void *)systemTable->BootServices->GetMemoryMap, 5, &mapSize, &memoryMap, &mapKey, &descriptorSize, &descriptorVersion);
ErrorCheck(result, EFI_SUCCESS);
result = uefi_call_wrapper((void *)systemTable->BootServices->ExitBootServices, 2, imageHandle, mapKey);
ErrorCheck(result, EFI_SUCCESS);
// TODO: Boot Services no longer available. Do whatever with Runtime Services... (ex: start OS kernal executable)
return EFI_SUCCESS;
}
我正在尝试使用 gnu-efi 编写一个 hello world 类型的程序,但没有启动服务,因为它们在 ExitBootServices 后变得不可用。调用ExitBootServices前直接写入显存不显示任何内容
因此我需要调用 ExitBootServices,它需要一个 Mapkey。 MapKey 由 GetMemoryMap 函数提供。但是当我调用它时,我的应用程序崩溃了(我正在使用 qemu)。
这是我的代码:
#include <efi.h>
#include <efilib.h>
void write_string( int color, const char *string )
{
volatile char *video = (volatile char*)0xB8000;
while( *string != 0 )
{
*video++ = *string++;
*video++ = color;
}
}
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
EFI_LOADED_IMAGE *loaded_image = NULL;
EFI_STATUS status;
InitializeLib(ImageHandle, SystemTable);
status = uefi_call_wrapper(SystemTable->BootServices->HandleProtocol,
3, ImageHandle, &LoadedImageProtocol, (void **)&loaded_image);
if (EFI_ERROR(status)) {
Print(L"handleprotocol: %r\n", status);
return EFI_SUCCESS;
}
/* GetMemoryMap */
UINTN MemoryMapSize = sizeof(EFI_MEMORY_DESCRIPTOR) * 0x10;
EFI_MEMORY_DESCRIPTOR *MemoryMap = AllocatePool (MemoryMapSize);
UINTN MapKey = 0;
UINTN DescriptorSize = 0;
UINT32 DescriptorVersion = 0;
status = uefi_call_wrapper(SystemTable->BootServices->GetMemoryMap,
&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
if (EFI_ERROR(status)) {
Print(L"GetMemoryMap: %r\n", status);
return EFI_SUCCESS;
}
/* ExitBootServices */
status = uefi_call_wrapper(SystemTable->BootServices->ExitBootServices,
ImageHandle, MapKey);
if (EFI_ERROR(status)) {
Print(L"ExitBootServices: %r\n", status);
return EFI_SUCCESS;
}
write_string(0x07, "example");
}
甚至在执行 ExitBootServices 之前,qemu 就崩溃并出现错误:
qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000000b0000
谁能告诉我我在做什么错了? 谢谢。
看起来您的主要问题是您忘记将参数数量传递给 uefi_call_wrapper 以调用 GetMemoryMap...传递指针(大数字...比 5 大得多) 可能会破坏 UEFI 固件仿真和 QEMU。由于同样的原因,您的 ExitBootServices 调用将失败,您没有传入参数数量。
您的代码还进行了一些不必要的、可能不正确的假设...
- 系统在内存映射中将有 16 个或更少的条目...
- UEFI 固件将 return 您编译的任何 EFI_MEMORY_DESCRIPTOR 版本...
GetMemoryMap 的定义行为使我们能够解决问题 1,并且我们可以尽一切可能确保我们的代码与未来对新版本 EFI_MEMORY_DESCRIPTOR 的 UEFI 的合理修订向前兼容。
这里是一个获取内存映射并退出引导服务的 C 示例:
#include <efi.h>
#define ErrorCheck(actual, expected) if(actual != expected) return actual
EFI_STATUS EFIAPI efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable)
{
EFI_STATUS result;
// TODO: Load anything that would change the memory map... (ex: OS kernal executable)
UINTN mapSize = 0, mapKey, descriptorSize;
EFI_MEMORY_DESCRIPTOR *memoryMap = NULL;
UINT32 descriptorVersion;
// Get the required memory pool size for the memory map...
result = uefi_call_wrapper((void *)systemTable->BootServices->GetMemoryMap, 5, &mapSize, &memoryMap, NULL, &descriptorSize, NULL);
ErrorCheck(result, EFI_BUFFER_TOO_SMALL);
// Allocating the pool creates at least one new descriptor... for the chunk of memory changed to EfiLoaderData
// Not sure that UEFI firmware must allocate on a memory type boundry... if not, then two descriptors might be created
mapSize += 2 * descriptorSize;
// Get a pool of memory to hold the map...
result = uefi_call_wrapper((void *)systemTable->BootServices->AllocatePool, 3, EfiLoaderData, mapSize, (void **)&memoryMap);
ErrorCheck(result, EFI_SUCCESS);
// Get the actual memory map...
result = uefi_call_wrapper((void *)systemTable->BootServices->GetMemoryMap, 5, &mapSize, &memoryMap, &mapKey, &descriptorSize, &descriptorVersion);
ErrorCheck(result, EFI_SUCCESS);
result = uefi_call_wrapper((void *)systemTable->BootServices->ExitBootServices, 2, imageHandle, mapKey);
ErrorCheck(result, EFI_SUCCESS);
// TODO: Boot Services no longer available. Do whatever with Runtime Services... (ex: start OS kernal executable)
return EFI_SUCCESS;
}