OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 2:58 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 12:59 pm 
Offline

Joined: Sun Jul 07, 2013 7:29 pm
Posts: 16
Hello, I am implementing a simple UEFI bootloader. Most EFI functions that I tried work me - I can clear Console, print text, successfully read files from system partition, allocate memory pages.

But if I try to read memory map and then call ExitBootServices() QEMU crashes for me:

Quote:
qemu-system-x86_64: Trying to execute code outside RAM or ROM at 0x00000000000b0000



Here is my test-case program that uses GNU-EFI library


Code:
#include "elf.h"
#include <efi.h>
#include <efilib.h>

EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SysTab) {
    InitializeLib(ImageHandle, SysTab);

    uint8_t buffer[4900];
    UINTN msize = sizeof(buffer);
    UINTN mkey = 0, dsize = 0;
    UINT32 dversion;
    SysTab->BootServices->GetMemoryMap(&msize, (EFI_MEMORY_DESCRIPTOR*)buffer, &mkey, &dsize, &dversion);

    EFI_STATUS st = SysTab->BootServices->ExitBootServices(ImageHandle, mkey);
    // QEMU crashes here ^^^^^^^^^^^^^^^^^^^^^^^^^^
    // qemu-system-x86_64: Trying to execute code outside RAM or ROM at 0x00000000000b0000

    Print(L"Press any key: %d\n", st);

    UINTN index;
    EFI_EVENT event = SysTab->ConIn->WaitForKey;
    SysTab->BootServices->WaitForEvent(1, &event, &index);

    return EFI_SUCCESS;
}



Here is a Makefile for it

Code:
ARCH            = x86_64

OBJS            = bootloader.o
TARGET          = bootloader.efi

EFIINC          = /usr/include/efi
EFIINCS         = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
EFILIB          = /usr/lib
EFI_CRT_OBJS    = $(EFILIB)/crt0-efi-$(ARCH).o
EFI_LDS         = $(EFILIB)/elf_$(ARCH)_efi.lds

CFLAGS          = $(EFIINCS) -fno-stack-protector -fPIC -fshort-wchar -mno-red-zone -Wall -std=c11

ifeq ($(ARCH),x86_64)
  CFLAGS += -DHAVE_USE_MS_ABI
endif

LDFLAGS         = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L $(EFILIB) $(EFI_CRT_OBJS)

all: $(TARGET)

bootloader.so: $(OBJS)
   ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi

%.efi: %.so
   objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym  -j .rel -j .rela -j .reloc --target=efi-app-$(ARCH) $^ $@

hda/EFI/BOOT/BOOTX64.EFI: bootloader.efi
   mkdir -p hda/EFI/BOOT/
   cp bootloader.efi hda/EFI/BOOT/BOOTX64.EFI

run: hda/EFI/BOOT/BOOTX64.EFI
   qemu-system-x86_64 --bios OVMF_CODE.fd -hda fat:rw:hda -net none




I think I tried everything: GCC vs clang, compiling/running at Arch vs Debian, tried different OVMF version (from Arch, Debian, Fedora). The crash is still here. I am staring at the code and do not see any problems with it.

Does anybody have a clue what is going here and why ExitBootServices() crashes?


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 1:59 pm 
Offline

Joined: Sun Jul 07, 2013 7:29 pm
Posts: 16
I also tried to use AllocatedPool instead of static array but result is the same:

Code:
#include "elf.h"
#include <efi.h>
#include <efilib.h>

EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SysTab) {
    InitializeLib(ImageHandle, SysTab);

    UINTN mkey = 0, dsize = 0;
    UINT32 dversion = 0;
    UINTN msize = 32768;
    EFI_MEMORY_DESCRIPTOR *mmap = AllocatePool(msize);
    SysTab->BootServices->GetMemoryMap(&msize, mmap, &mkey, &dsize, &dversion);

    EFI_STATUS st = SysTab->BootServices->ExitBootServices(ImageHandle, mkey);
    // QEMU crashes here ^^^^^^^^^^^^^^^^^^^^^^^^^^
    // qemu-system-x86_64: Trying to execute code outside RAM or ROM at 0x00000000000b0000

    FreePool(mmap);
    Print(L"Press any key: %d\n", st);

    UINTN index;
    EFI_EVENT event = SysTab->ConIn->WaitForKey;
    SysTab->BootServices->WaitForEvent(1, &event, &index);

    return EFI_SUCCESS;
}


I also tried to debug this crash and enabled QEMU cpu debugging. It looks like at some point IP jumps to address 0 and start executing it. Begginning of the address space is filled with zeros and x86 emulator executes as valid instructsions ('addl' if I remember).

But the it reaches 0x00000000000b0000 that is some kind of system memory (video?) and value of this memory cell is invalid instruction that crashes QEMU.


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 3:32 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
You cannot use Boot Services after ExitBootServices(). Like here:
Code:
   EFI_STATUS st = SysTab->BootServices->ExitBootServices(ImageHandle, mkey);
    // QEMU crashes here ^^^^^^^^^^^^^^^^^^^^^^^^^^
    // qemu-system-x86_64: Trying to execute code outside RAM or ROM at 0x00000000000b0000

    FreePool(mmap);
    Print(L"Press any key: %d\n", st);

    UINTN index;
    EFI_EVENT event = SysTab->ConIn->WaitForKey;
    SysTab->BootServices->WaitForEvent(1, &event, &index);

_________________
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 3:35 pm 
Offline

Joined: Sun Jul 07, 2013 7:29 pm
Posts: 16
Here is simplified version of the same code. The issue still exists

Code:
#include "elf.h"
#include <efi.h>
#include <efilib.h>

EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SysTab) {
    InitializeLib(ImageHandle, SysTab);

    UINTN mkey = 0, dsize = 0;
    UINT32 dversion = 0;
    UINTN msize = 32768;
    EFI_MEMORY_DESCRIPTOR *mmap = AllocatePool(msize);
    if (!mmap) {
        Print(L"AllocatePool failed\n");
        goto error;
    }

    SysTab->BootServices->GetMemoryMap(&msize, mmap, &mkey, &dsize, &dversion);

    EFI_STATUS st = SysTab->BootServices->ExitBootServices(ImageHandle, mkey);
    // QEMU crashes here ^^^^^^^^^^^^^^^^^^^^^^^^^^
    // qemu-system-x86_64: Trying to execute code outside RAM or ROM at 0x00000000000b0000
error:
    return EFI_SUCCESS;
}


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 3:52 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
Does GetMemoryMap return success?

_________________
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 4:07 pm 
Offline

Joined: Sun Jul 07, 2013 7:29 pm
Posts: 16
zaval wrote:
Does GetMemoryMap return success?


Yes it does. And the memory descriptors info seems fine. Though it does not really matter. In case if GetMemoryMap() is unsuccessfull, subsequent ExitBootServices() should return INVALID_PARAMETER error. But definitely not crash.

I think I tried every possible combination with the code. And now I think the problem either in my CFLAGS/LDFLAGS or something seriously wrong with OVMF firmware. Are there any alternative UEFI firmware blobs that I can try instead of OVMF?


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 4:35 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
anatolik wrote:
zaval wrote:
Does GetMemoryMap return success?


Yes it does. And the memory descriptors info seems fine. Though it does not really matter. In case if GetMemoryMap() is unsuccessfull, subsequent ExitBootServices() should return INVALID_PARAMETER error. But definitely not crash.

I think I tried every possible combination with the code. And now I think the problem either in my CFLAGS/LDFLAGS or something seriously wrong with OVMF firmware. Are there any alternative UEFI firmware blobs that I can try instead of OVMF?

Here, I only can suggest you to report a problem on their mailing list ([email protected]). They answer.

_________________
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Tue Mar 13, 2018 10:00 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

anatolik wrote:
Yes it does. And the memory descriptors info seems fine. Though it does not really matter. In case if GetMemoryMap() is unsuccessfull, subsequent ExitBootServices() should return INVALID_PARAMETER error. But definitely not crash.


Would you mind compiling without "-fno-stack-protector" or "-mno-red-zone" to see if that works?

I'm thinking that maybe something (e.g. the "-fno-stack-protector" or "-mno-red-zone") causes some kind of quirk in GNU's tools that results in the code using calling conventions that are different to what UEFI expects. Note that UEFI expects "Microsoft x64" calling conventions while GNU prefers "System V AMD64 ABI", and I'd assume that the "$(EFIINCS)" takes care of setting up the calling conventions to suit UEFI/Microsoft.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Thu Mar 15, 2018 11:35 am 
Offline

Joined: Sun Jul 07, 2013 7:29 pm
Posts: 16
Alright I think I figured out the problem

Quote:
You cannot use Boot Services after ExitBootServices()

I had to think on it one more time. I also checked the function docs and I see it say

Quote:
On success, several fields of the EFI System Table should be set to NULL.

Setting NULL to a function pointer and later trying to call it sounds exactly like my issue.

But in my simplified example above I did not call any UEFI function after ExitBootServices(), I just returned exit code. Oh wait, what happens *after* I return from efi_main()? What if UEFI Shell tries to use BootServices?

So I added an infinite loop (I cannot use printing for debug purposes) and then attached to the app via GDB and indeed, my app called ExitBootServices() successfully without any crash. Aha, so it is UEFI Shell that crashes. It means once I called ExitBootServices() I cannot do print, I cannot return to shell, I cannot do pretty much anything except just jumping to my OS code. So I added "jmp" and now I see that execution flow reaches my OS startup code correctly.


Top
 Profile  
 
 Post subject: Re: EFI ExitBootServices() function crashes in QEMU
PostPosted: Thu Mar 15, 2018 12:35 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
Quote:
It means once I called ExitBootServices() I cannot do print, I cannot return to shell, I cannot do pretty much anything except just jumping to my OS code. So I added "jmp" and now I see that execution flow reaches my OS startup code correctly.

Yes, it is supposed to be that way - ExitBootServices() is a no return to FW and jump into your OS loader/OS realm. Good to hear you resolved the problem.

Online resources are good, but don't forget - your main source is the freely available UEFI specification. Not that it's the best reading all over the world, but it is the ultimate documentation and is helpful. And it's yet not as bloated as could be! :lol:

_________________
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], DotBot [Bot] and 178 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group