我使用EDK-2为UEFI子系统构建驱动程序,在其中我实现了一个自定义协议。为了使用此协议功能,我将此驱动程序加载到内存中,以便稍后查找并使用此协议。除了我的一台UEFI v2.31测试设备(联想ThinkPad(外,它在任何地方都能正常工作。当我试图将我的efi驱动程序加载到内存系统中时。我试着用代码来做,后来我试着从EFIshell将这个EFI映像加载到内存中,但得到了相同的结果。
我在代码中添加了一些调试打印,以找出系统出现问题时的具体步骤。所以,看起来它卡住了这个呼叫
BS->启动图像
以下是加载EFI驱动程序映像的代码示例:
// 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);
}
在这条线上
status = uefi_call_wrapper(BS->StartImage, 3, image_to_execute, NULL, NULL);
系统卡死。
我还尝试将一些调试打印添加到我的自定义驱动程序的入口点,我尝试以这种方式加载这些驱动程序。此处的驾驶员入口点代码示例
EFI_STATUS
EFIAPI
DriverEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
ShellPrintEx(
-1,
-1,
L"1n"
);
Status = EFI_SUCCESS;
//__debugbreak();
initilize_logging();
ShellPrintEx(
-1,
-1,
L"2n"
);
ShellPrintEx(
-1,
-1,
L"3n"
);
// 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"4n"
);
//ASSERT_EFI_ERROR(Status);
ShellPrintEx(
-1,
-1,
L"5n"
);
if(EFI_SUCCESS == Status)
{
ShellPrintEx(
-1,
-1,
L"6n"
);
Status = gBS->InstallProtocolInterface(
&ImageHandle,
&gEfiProtocolGuid,
EFI_NATIVE_INTERFACE,
&gProtocol
);
}
ShellPrintEx(
-1,
-1,
L"7n"
);
return Status;
}
所有这些指纹都在屏幕上曝光了。但是,在那之后,看起来系统停滞了,执行不会返回到调用方(启动驱动程序加载的调用方(,并且在BS->StartImage不会在屏幕上输出。
那么,有人能给我一些想法吗?为什么会发生这种情况,以及如何解决这个问题?
shell可能会因为代码在无限循环中运行而陷入困境。UEFI系统依赖于协同多任务处理,所以如果你的代码被卡住,没有人(除了更高的IRQ(会阻止它。
此外,uefi_call_wrapper
是gnu-uefi的一部分,你确定你在使用EDK2吗?
我根本没有实现驱动程序绑定协议,将其作为EfiLibInstallAllDriverProtocols2方法的参数传递。如@MiSimon所述:EfiLibInstallAllDriverProtocols2方法的DriverBinding参数没有标记为可选,在当前EDK2源中,该函数的开头有一个ASSERT(DriverBinding!=NULL(,传递NULL可能会导致未定义的行为。因此,我必须创建一个伪DriverBinding协议(从Start、Stop、Supported返回EFI_UNSUPPORTED(,并将其传递给EfiLibInstallAllDriverProtocols2。这解决了问题。@米西蒙,谢谢你的帮助!