【问题标题】:Memory map and Framebuffer after using ExitBootServices使用 ExitBootServices 后的内存映射和帧缓冲区
【发布时间】:2022-07-15 06:24:37
【问题描述】:

我想这个问题本身就很简单。
在 UEFI 中使用 ExitBootServices 后,有什么方法可以检测内存(或获取内存映射)和帧缓冲区(或图形输出协议) 64位模式?如果是这样,那么如何以及是否有任何文档?
我知道使用ExitBootServices之后,你就是整台机器的唯一拥有者。
获取内存映射的方法有很多,但它们都需要引导加载程序的帮助。我想直接从内核获取内存映射。许多网站,如 OSDev 和 github 源代码使用引导加载程序来获取内存映射和帧缓冲区。
使用ExitBootServices 后,我处于 ​​64 位模式,并且 OSDev wiki 上关于获取内存映射的唯一页面适用于 32 位架构。
我没有语言偏好,可能是 C、汇编或其他语言,请不要说它没用、复杂或难做。我只是想要一个答案。

【问题讨论】:

  • 有任何解决方案的人吗?

标签: 64-bit boot osdev


【解决方案1】:

首先,(可能在 (U)EFI 中)U 无法调用引导服务,这是获得所需内容的唯一方法,您可以在 ExitBootServices() 之前获取内存映射和帧缓冲区并将它们传递给内核,您'很幸运,因为我并不总是在这个平台上,我有一个支持 LEGACY BIOS 和 UEFI 的混合启动机制,这里是一个如何做到这一点的例子(我正在研究 EDK2,这是电喷)

这是您从 G.O.P 获取帧缓冲区的方式(已删除 UGA 文档):

FRAME_BUFFER_DESCRIPTOR* GraphicsOutputProtocolInitialize(){

// First, we need to query the firmware of all G.O.P Protocol Instances
// (Each instance may represent a GPU or a monitor, GOP features multiple-screens

// U have asked for a simple implementation so we will use only 1 frame buffer

 EFI_STATUS status = 0;

EFI_HANDLE* HandleBuffer = NULL;
UINTN NumProtocolHandles = 0;

if(EFI_ERROR(gBS->LocateHandleBuffer(
    ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL,
    &NumProtocolHandles, &HandleBuffer
)) || !NumProtocolHandles) return NULL;

// Then u need to create a structure that you can pass to the kernel containing information about frame buffers

FRAME_BUFFER_DESCRIPTOR* FrameBuffer = NULL;
if(EFI_ERROR(gBS->AllocatePool(
    EfiLoaderData, sizeof(FRAME_BUFFER_DESCRIPTOR), (void**)&FrameBuffer
))) ALLOCATION_PROBLEM;

ZeroMemory((void*)FrameBuffer, sizeof(FRAME_BUFFER_DESCRIPTOR));

    EFI_GRAPHICS_OUTPUT_PROTOCOL* gop = NULL;
    status = gBS->OpenProtocol(
        HandleBuffer[0], // Get first Graphics Output Protocol Instance
        &gEfiGraphicsOutputProtocolGuid,
        (void**)&gop,
        NULL,
        NULL,
        EFI_OPEN_PROTOCOL_GET_PROTOCOL
    );
    if(EFI_ERROR(status) || !gop)
    {
        return NULL;
    }

    EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ginfo = NULL;
    UINTN info_size = 0;

    // if mode is not yet set by firmware, then set first mode
    if(status == EFI_NOT_STARTED || !gop->Mode){
        
        status = gop->SetMode(gop, 0);
        if(EFI_ERROR(status) || !gop->Mode->Mode)
        {
            return NULL;
        }
    }

    // Now we will ask firmware for the current Video Mode
    
    status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &ginfo);
    
   
    if(status != EFI_SUCCESS || !ginfo){
        return NULL;
    }
    
    // You can also list availaible video modes
   for(UINTN i = 0;i<gop->Mode->MaxMode;i++) {
      status = gop->QueryMode(gop, i, &info_size, &ginfo);
    
   
    if(status != EFI_SUCCESS || !ginfo){
        return NULL;
    }

    // To set the mode :
    status = gop->SetMode(gop, i);
    if(EFI_ERROR(status))
    {
        return NULL;
    }
   }

    
    FrameBuffer->FrameBufferSize = gop->Mode->FrameBufferSize;
    FrameBuffer->HorizontalResolution = gop->Mode->Info->HorizontalResolution;
    FrameBuffer->VerticalResolution = gop->Mode->Info->VerticalResolution;
    FrameBuffer->FrameBufferBase = (char*)gop->Mode->FrameBufferBase;


    ZeroMemory((void*)FrameBuffer, sizeof(FRAME_BUFFER_DESCRIPTOR));

}




 return FrameBuffer;

 }

这是获取内存映射的方式:

  • 在第一次调用时,您将获得内存映射的大小(状态必须为 EFI_BUFFER_TOO_SMALL)
  • 然后添加 2 * 描述符大小,因为总是有 2 个附加条目,然后为内存映射分配缓冲区
  • 在第二次调用中,您将获得实际的内存映射(状态必须为 EFI_SUCCESS)

然后你就可以正常列出内存映射条目了

这就是你调用 GetMemoryMap() 的方式:

EFI_MEMORY_DESCRIPTOR* memory_map = NULL;
UINTN map_size = 0, map_key = 0, descriptor_size = 0;



// Must return EFI_BUFFER_TOO_SMALL on First Call 
// map_size will contain buffer size needed
EFI_STATUS s = SystemTable->BootServices->GetMemoryMap(&map_size,memory_map,&map_key,&descriptor_size,&descriptor_version);
map_size+=2*descriptor_size; // this padding must be added since there is 2 additionnal entries

但是,您可以随时索取代码示例,(G.O.P) 之前的代码只是复制粘贴和修改以使其更易于理解,它未编译,因此可能包含一些错误。

【讨论】:

    猜你喜欢
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多