Search code examples
cuefiedk2

System stucks on attempt to load EFI driver image


I build driver for UEFI subsystem using EDK-2 in which I implement one my custom protocol. To use this protocol functionality I load this driver into memory to find and use this protocol later. It works fine everywhere except one my test device(Lenovo ThinkPad) with UEFI v2.31. When I try to load my efi driver into memory system stucks. I tried to do it by code, later I tried to load this EFI image into memory from EFI shell, but got the same result.

I added some debug prints to my code to find out concrete step, when system stucks. So, it looks like it stucks on this call

BS->StartImage

Here is sample of code to load EFI driver image:

// try to generate path and load image from this path
// if absolute path was passed (start with "\EFI\")
// it (path) will not be changed
status = generate_path(loaded_image_info, image_path, &path_name);

PrintLineWithCLI("7");

if (status != EFI_SUCCESS)
    return status;

PrintLineWithCLI("8");

devpath = FileDevicePath(loaded_image_info->DeviceHandle, path_name);

PrintLineWithCLI("9");

status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image_handle, devpath, NULL, 0, &image_to_execute);

PrintLineWithCLI("10");

if (status == EFI_SUCCESS)
{
    PrintLineWithCLI("11");

    // before start image we must add load options (if exist) to loaded image
    if (load_options != NULL && load_options_size > 0)
    {
        PrintLineWithCLI("12");

        // obtain information for image to execute (that we try to execute)
        status = uefi_call_wrapper(BS->HandleProtocol, 3, image_to_execute, &gEfiLoadedImageProtocolGuid, (void **)&loaded_image_info);

        PrintLineWithCLI("13");

        if (status == EFI_SUCCESS)
        {
            PrintLineWithCLI("14");

            // aas where and when we must free this memory?
            loaded_image_info->LoadOptions = AllocateZeroPool(load_options_size);
            loaded_image_info->LoadOptionsSize = load_options_size;
            CopyMem(loaded_image_info->LoadOptions, load_options, load_options_size);
        }
    }

    PrintLineWithCLI("15");

    status = uefi_call_wrapper(BS->StartImage, 3, image_to_execute, NULL, NULL);

    PrintLineWithCLI("16");

    // do not unload image here - through this code we load drivers and drivers not have to be unloaded
    //uefi_call_wrapper(BS->UnloadImage, 1, image_to_execute);
}

And on this line

status = uefi_call_wrapper(BS->StartImage, 3, image_to_execute, NULL, NULL);

system stucks.

I tried to add also some debug prints to entry point of my custom driver which I try to load in this way. Sample of driver entry point code here

EFI_STATUS
EFIAPI
DriverEntryPoint(
IN EFI_HANDLE        ImageHandle,
IN EFI_SYSTEM_TABLE  *SystemTable
)
{
EFI_STATUS  Status;

ShellPrintEx(
    -1,
    -1,
    L"1\n"
);

Status = EFI_SUCCESS;

//__debugbreak();

initilize_logging();

ShellPrintEx(
    -1,
    -1,
    L"2\n"
);

ShellPrintEx(
    -1,
    -1,
    L"3\n"
);

// Install UEFI Driver Model protocol(s).
//
Status = EfiLibInstallAllDriverProtocols2(
    ImageHandle,
    SystemTable,
    NULL,
    NULL, // pass NULL to always create new HANDLE for this driver - it's necessary for SECURE BOOT
    &gComponentName,
    &gComponentName2,
    NULL,
    NULL,
    NULL,
    NULL
);

ShellPrintEx(
    -1,
    -1,
    L"4\n"
);

//ASSERT_EFI_ERROR(Status);

ShellPrintEx(
    -1,
    -1,
    L"5\n"
);

if(EFI_SUCCESS == Status)
{
    ShellPrintEx(
        -1,
        -1,
        L"6\n"
    );

    Status = gBS->InstallProtocolInterface(
        &ImageHandle,
        &gEfiProtocolGuid,
        EFI_NATIVE_INTERFACE,
        &gProtocol
    );
}

ShellPrintEx(
    -1,
    -1,
    L"7\n"
);

return Status;
}

All of these prints were outed on a screen. But, after that it looks like systems stucks and execution doesn't return to the caller (who initiated driver loading) and next print after BS->StartImage is not outputed on a screen.

So, can somebody give me any ideas, why it happens and how to solve this problem?


Solution

  • I haven't implemented Driver Binding protocol at all to pass it as a parameter for the EfiLibInstallAllDriverProtocols2 method. As described @MiSimon: the DriverBinding parameter for the EfiLibInstallAllDriverProtocols2 method is not marked as optional, in the current EDK2 sources there is an ASSERT (DriverBinding != NULL) at the start of this function, passing NULL may result in undefined behaviour. So I had to create a dummy DriverBinding protocol (return EFI_UNSUPPORTED from Start, Stop, Supported) and pass it to EfiLibInstallAllDriverProtocols2. That resolved the problem. @MiSimon, thank you for your help!