首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ExitBootServices的简单示例(使用gnu-efi)

使用ExitBootServices的简单示例(使用gnu-efi)
EN

Stack Overflow用户
提问于 2016-09-09 16:37:27
回答 1查看 3.9K关注 0票数 2

我正试着用gnu-efi写一个hello world类的程序,但是没有启动服务,因为它们在ExitBootServices之后变得不可用。在调用ExitBootServices之前直接写入视频内存不会显示任何内容。

出于这个原因,我需要调用ExitBootServices,它需要一个Mapkey。GetMemoryMap函数提供MapKey。但是当我调用它时,我的应用程序崩溃了(我使用的是qemu)。

这是我的代码:

代码语言:javascript
复制
#include 
#include 

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就会崩溃并出现以下错误:

代码语言:javascript
复制
qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000000b0000

有没有人能说出我的所作所为出了什么问题?谢谢你。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-24 17:48:29

看起来您的主要问题是忘记向uefi传递参数的数量

_

呼叫

_

您对GetMemoryMap的调用的包装器...传入一个指针(大数字...远大于5)可能会通过扩展破坏UEFI固件仿真和QEMU。由于同样的原因,您的ExitBootServices调用也将失败,因为您没有传入数量的参数。

你的代码还做了一些不必要的,可能是不正确的假设...

系统在内存映射中将有16个或更少的条目...

UEFI固件将返回任何版本的EFI

_

内存

_

您编译所依据的描述符...

定义的GetMemoryMap行为允许我们解决问题1,我们可以做任何可能的事情来确保我们的代码与新版本的UEFI的合理的未来修订版是向前兼容的

_

内存

_

描述符。

下面是一个获取内存映射并退出引导服务的C语言示例:

代码语言:javascript
复制
#include 

#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;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39407280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档