如何使用 UEFI 运行时服务?
How can I use UEFI Runtime Services?
我想了解更多关于固件开发的知识。我已经知道如何为旧的 BIOS 编写汇编程序,现在我想从 UEFI 开始。我设法编译并模拟了一个 Hello World 程序,现在我正尝试编写一个程序,使用运行时服务 GetTime() 在屏幕上显示当前时间。但是,当我使用此功能时,程序挂起,就好像它没有在 PI 期间安装一样。
这是代码:
#include <efi.h>
#include <efilib.h>
#include <efiapi.h>
//gBS: SystemTable->BootServices;
//gRS: SystemTable->RuntimeServices;
EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE* systab)
{
EFI_TIME* time;
InitializeLib(image, systab);
RT->GetTime(time, NULL);
Print(L"Time %u\n", time->Hour);
return EFI_SUCCESS;
}
你知道我做错了什么吗?
这是我用来编译和模拟的代码,以备您需要:
gcc -I/usr/include/efi -I/usr/include/efi/x86_64/ -fpic -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -c main.c -o main.o
ld -shared -Bsymbolic -L/usr/lib -T/usr/lib/elf_x86_64_efi.lds /usr/lib/crt0-efi-x86_64.o main.o -o main.so -lgnuefi -lefi
objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target efi-app-x86_64 --subsystem=10 main.so main.efi
uefi-run -b /usr/share/edk2-ovmf/x64/OVMF.fd -q /usr/bin/qemu-system-x86_64 main.efi
我想你错过了初始化 RT。
RT = SystemTable->RuntimeServices;
您的代码与统一可扩展固件接口规范 2.6 的示例之一(第 4.7.1 节中的示例)非常相似。我怀疑你没看过,但以防万一
https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
如果您使用的是 gnu-efi,请使用 uefi_call_wrapper()
调用 UEFI 函数。
RT->GetTime(time, NULL); // Program hangs
uefi_call_wrapper(RT->GetTime, 2, time, NULL); // Okay
原因是 UEFI(使用 Microsoft x64 调用约定)和 Linux(使用 System V amd64 ABI)之间的调用约定不同。默认情况下,gcc 会生成 Linux 格式的代码,所以我们需要明确告诉它生成 UEFI 格式的代码。
您可以通过执行 objdump
.
来查看差异
我想了解更多关于固件开发的知识。我已经知道如何为旧的 BIOS 编写汇编程序,现在我想从 UEFI 开始。我设法编译并模拟了一个 Hello World 程序,现在我正尝试编写一个程序,使用运行时服务 GetTime() 在屏幕上显示当前时间。但是,当我使用此功能时,程序挂起,就好像它没有在 PI 期间安装一样。 这是代码:
#include <efi.h>
#include <efilib.h>
#include <efiapi.h>
//gBS: SystemTable->BootServices;
//gRS: SystemTable->RuntimeServices;
EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE* systab)
{
EFI_TIME* time;
InitializeLib(image, systab);
RT->GetTime(time, NULL);
Print(L"Time %u\n", time->Hour);
return EFI_SUCCESS;
}
你知道我做错了什么吗?
这是我用来编译和模拟的代码,以备您需要:
gcc -I/usr/include/efi -I/usr/include/efi/x86_64/ -fpic -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -c main.c -o main.o
ld -shared -Bsymbolic -L/usr/lib -T/usr/lib/elf_x86_64_efi.lds /usr/lib/crt0-efi-x86_64.o main.o -o main.so -lgnuefi -lefi
objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target efi-app-x86_64 --subsystem=10 main.so main.efi
uefi-run -b /usr/share/edk2-ovmf/x64/OVMF.fd -q /usr/bin/qemu-system-x86_64 main.efi
我想你错过了初始化 RT。
RT = SystemTable->RuntimeServices;
您的代码与统一可扩展固件接口规范 2.6 的示例之一(第 4.7.1 节中的示例)非常相似。我怀疑你没看过,但以防万一
https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
如果您使用的是 gnu-efi,请使用 uefi_call_wrapper()
调用 UEFI 函数。
RT->GetTime(time, NULL); // Program hangs
uefi_call_wrapper(RT->GetTime, 2, time, NULL); // Okay
原因是 UEFI(使用 Microsoft x64 调用约定)和 Linux(使用 System V amd64 ABI)之间的调用约定不同。默认情况下,gcc 会生成 Linux 格式的代码,所以我们需要明确告诉它生成 UEFI 格式的代码。
您可以通过执行 objdump
.