Page 1 of 1

Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 4:13 pm
by robin1201
Hello everyone,

I am currently in the process of writing a new uefi bootloader, as my old projects somehow became more and more chaotic and I didn't know where anything was anymore. I have psf1 font support so far, can display 32bit bitmaps and am currently loading a 64bit kernel. however, the bootloader then hangs in loader.c under utils/loader.c where I call uefi_call_wrapper. Maybe you can help me to fix this problem?

Best regards

Source: https://github.com/rxbin1201/littleBootV1

Re: Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 5:18 pm
by Rover
Hello!

You call Kernel->GetInfo twice here

Code: Select all

    <...>
    Status = uefi_call_wrapper(
        Kernel->GetInfo,
        4,
        Kernel,
        &gEfiFileInfoGuid,
        &FileInfoSize,
        NULL
    );
    if(EFI_ERROR(Status)) {
        return Status;
    }

    Status = uefi_call_wrapper(
        BS->AllocatePool,
        3,
        EfiLoaderData,
        FileInfoSize,
        (VOID **)&FileInfo
    );
    if(EFI_ERROR(Status)) {
        return Status;
    }

    Status = uefi_call_wrapper(
        Kernel->GetInfo,
        4,
        Kernel,
        &gEfiFileInfoGuid,
        &FileInfoSize,
        (VOID **)&FileInfo
    );
    if(EFI_ERROR(Status)) {
        return Status;
    }
   <...>
Removing the duplicate fixed the issue.
I would also recommend adding --serial file:./Out.log to uefi-run's Qemu arguments so you can see the exceptions UEFI prints out.
You can also print to this file using the gnuefi print function like so:

Code: Select all

Print(L"Test print to serial\n");
Your duplicate code causes a #UD. Maybe someone more experienced with UEFI and #UD exceptions can explain why that is.

You can read more about exceptions and interrupts here (The AMD64 docs have a lot of helpful information you can reference in the future!)
https://www.amd.com/system/files/TechDo ... G14.887970
Hope this helps and have fun!

Re: Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 6:29 pm
by robin1201
Rover wrote:Hello!

You call Kernel->GetInfo twice here

Code: Select all

    <...>
    Status = uefi_call_wrapper(
        Kernel->GetInfo,
        4,
        Kernel,
        &gEfiFileInfoGuid,
        &FileInfoSize,
        NULL
    );
    if(EFI_ERROR(Status)) {
        return Status;
    }

    Status = uefi_call_wrapper(
        BS->AllocatePool,
        3,
        EfiLoaderData,
        FileInfoSize,
        (VOID **)&FileInfo
    );
    if(EFI_ERROR(Status)) {
        return Status;
    }

    Status = uefi_call_wrapper(
        Kernel->GetInfo,
        4,
        Kernel,
        &gEfiFileInfoGuid,
        &FileInfoSize,
        (VOID **)&FileInfo
    );
    if(EFI_ERROR(Status)) {
        return Status;
    }
   <...>
Removing the duplicate fixed the issue.
I would also recommend adding --serial file:./Out.log to uefi-run's Qemu arguments so you can see the exceptions UEFI prints out.
You can also print to this file using the gnuefi print function like so:

Code: Select all

Print(L"Test print to serial\n");
Your duplicate code causes a #UD. Maybe someone more experienced with UEFI and #UD exceptions can explain why that is.

You can read more about exceptions and interrupts here (The AMD64 docs have a lot of helpful information you can reference in the future!)
https://www.amd.com/system/files/TechDo ... G14.887970
Hope this helps and have fun!
Thanks for you help! I removed the duplicate and now in my switch argument it tells me as Status "Error Kernel! Reason: Not Found"

Code: Select all

int pages = (phdr->p_memsz + 0x1000 - 1) / 0x1000;
                Elf64_Addr segment = phdr->p_paddr;
                Status = uefi_call_wrapper(
                    BS->AllocatePages,
                    4,
                    AllocateAddress,
                    EfiLoaderData,
                    pages,
                    &segment
                );
                if(EFI_ERROR(Status)) {
                    return Status;
                }
thats the code where the error came from. I also updated the code on github

Re: Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 7:22 pm
by Rover
Hello!

It seems like your kernel64.elf is being opened.
I also noticed a bug with your Log(); function that causes text to move back to the top of the screen. (Unless that is what you wanted)

Adding Print() statements to your error conditions can help pinpoint the error easier for you and make debugging less guesswork.
For example:

Code: Select all

    Status = uefi_call_wrapper(
        Kernel->GetInfo,
        4,
        Kernel,
        &gEfiFileInfoGuid,
        &FileInfoSize,
        NULL
    );
    if(EFI_ERROR(Status)) {
        Print(L"Failed to GetInfo\n");
        return Status;
    }
This can tell you exactly which call failed.

It seems like AllocatePages is returning an error in your for loop.
Have you tried using gnuefi's AllocatePool(); function? I have found that it works better (and easier) than calling AllocatePages and it doesn't need a uefi_call_wrapper.

Also, imo, it is easier to loop through the ELF and add up the section sizes you need so you only have to call AllocatePool/AllocatePages once for each section and then you can load your kernel code/data to it.
You can see how I do this here. (No guarantee it is bug free)
You don't have to worry about where the kernel is in physical memory (just don't overwrite it) since you can map it anywhere in virtual memory.

P.S
I would recommend changing these

Code: Select all

static const uint16_t ET_NONE = 0;
Into

Code: Select all

#define ET_NONE 0
It is more readable imo.

Re: Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 7:32 pm
by robin1201
Rover wrote:Hello!

It seems like your kernel64.elf is being opened.
I also noticed a bug with your Log(); function that causes text to move back to the top of the screen. (Unless that is what you wanted)

Adding Print() statements to your error conditions can help pinpoint the error easier for you and make debugging less guesswork.
For example:

Code: Select all

    Status = uefi_call_wrapper(
        Kernel->GetInfo,
        4,
        Kernel,
        &gEfiFileInfoGuid,
        &FileInfoSize,
        NULL
    );
    if(EFI_ERROR(Status)) {
        Print(L"Failed to GetInfo\n");
        return Status;
    }
This can tell you exactly which call failed.

It seems like AllocatePages is returning an error in your for loop.
Have you tried using gnuefi's AllocatePool(); function? I have found that it works better (and easier) than calling AllocatePages and it doesn't need a uefi_call_wrapper.

Also, imo, it is easier to loop through the ELF and add up the section sizes you need so you only have to call AllocatePool/AllocatePages once for each section and then you can load your kernel code/data to it.
You can see how I do this here. (No guarantee it is bug free)
You don't have to worry about where the kernel is in physical memory (just don't overwrite it) since you can map it anywhere in virtual memory.

P.S
I would recommend changing these

Code: Select all

static const uint16_t ET_NONE = 0;
Into

Code: Select all

#define ET_NONE 0
It is more readable imo.
Thank you very much. I will try it soon. And with the log function I have also noticed it but I have not found the solution for it yet.

Re: Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 7:58 pm
by Octocontrabass
The first call to GetInfo() is supposed to fail. It needs to fail with the error code EFI_BUFFER_TOO_SMALL so you can allocate the correct buffer to hold whatever info you're requesting. Since the first call doesn't fail, one of the parameters you pass to it must be incorrect, and it's corrupting memory somewhere.

Re: Uefi application hangs up when trying to load the kernel

Posted: Wed Aug 02, 2023 8:07 pm
by Rover
Octocontrabass wrote:The first call to GetInfo() is supposed to fail. It needs to fail with the error code EFI_BUFFER_TOO_SMALL so you can allocate the correct buffer to hold whatever info you're requesting. Since the first call doesn't fail, one of the parameters you pass to it must be incorrect, and it's corrupting memory somewhere.
Oops. I didn’t know that.
I thought I used that uefi call in my code without issues but I actually use LibFileInfo.
They should probably use LibFileInfo() instead of a call wrapper since they use gnuefi. Unless there is something else I am overlooking.