2016-09-09 4 views
1

gnu-efi를 사용하여 Hello World 프로그램을 작성하려고하지만 ExitBootServices 이후에 사용할 수 없기 때문에 부트 서비스가 필요하지 않습니다. ExitBootServices를 호출하기 전에 비디오 메모리에 직접 쓰는 것은 아무 것도 표시하지 않습니다.ExitBootServices (gnu-efi 사용)의 UEFI 간단한 예제

이런 이유로 MapButton이 필요한 ExitBootServices를 호출해야합니다. 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"); 
} 

심지어 QEMU 오류와 충돌 ExitBootServices을 실행하기 전에 :

qemu: fatal: Trying to execute code outside RAM or ROM at 0x00000000000b0000 

사람이 내가 뭐하는 거지에 어떤 문제가 있는지 알 수 있습니까? 감사합니다.

+0

: 여기

는 메모리 맵 종료 부팅 서비스를 얻기의 C의 예입니다? ExitBootServices에서 성공하면 코드에서 예상되는 작업은 무엇입니까? – unixsmurf

+0

ExitBootServices 호출에서 코드를 주석 처리하려고했지만 여전히 동일한 오류가 발생합니다. 코드를 남겨두면 두 개의 오류가 발생합니다 (두 번째는 ExitBootServices의 "EFI_ERROR (status)"에 의해 catch됩니다)). 첫 번째는 qemu를 실행중인 bash 화면입니다. 성공하면 왼쪽 상단 모서리에 "example"문자열과 함께 오류가 없기를 기대합니다. –

+0

그래서 "내가 할 코드가 무엇을 기대합니까?"라고 묻는다면, 일단 함수의 끝 부분에 도달하면 어떻게 될 것으로 예상되는지를 의미합니다. ExitBootServices에 대한 호출에 성공하면 돌아갈 컨텍스트가 없습니다. 이것이 실제 작성한 코드일까요? 그렇다면 컴파일러가 함수의 끝에서 수익을 놓치고 있다는 사실을 알려주지 않는 이유는 무엇입니까? – unixsmurf

답변

1

주된 문제는 GetMemoryMap 호출에 대한 uefi_call_wrapper의 인수 개수를 잊어 버린 것 같습니다 ... 포인터를 전달하면 (큰 숫자 ... 5보다 훨씬 큼) 아마 UEFI 펌웨어 에뮬레이션 및 QEMU. exitBootServices 호출이 같은 이유로 실패하고 인수의 수를 전달하지 않았습니다.

시스템은 메모리 맵에서 16 개 이하의 항목이 있습니다
  1. 귀하의 코드는 불필요한, 아마도 잘못된 가정을

    ... UEFI 펌웨어는 어떤 버전을 반환하는 것입니다

  2. 당신이에 대해 컴파일 EFI_MEMORY_DESCRIPTOR ...

의 GetMemoryMap의 정의 행동은 우리가 문제 하나 해결 할 수 있습니다, 우리는 우리의 코드는 앞으로 UEFI 재치에 합리적인 미래 버전과 호환되는지 확인하기 위해 가능한 모든 것을 할 수 있습니다 새로운 버전의 EFI_MEMORY_DESCRIPTOR. 당신이 ExitBootServices 전에 발생하는 것으로 판단하려면 어떻게

#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; 
}