#c #uefi #gnu-efi
#c #uefi #gnu-efi
Вопрос:
Я хочу узнать больше о разработке встроенного ПО. Я уже знаю, как писать программы на ассемблере для старого 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 %un", 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
Ответ №1:
Если вы используете 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
.
Ответ №2:
Я думаю, вы пропустили инициализацию RT.
RT = SystemTable->RuntimeServices;
Ваш код очень похож на один из примеров (приведенный в разделе 4.7.1) Спецификации интерфейса унифицированного расширяемого микропрограммного обеспечения 2.6. Я сомневаюсь, что вы его не читали, но на всякий случай.
https://www.uefi.org/sites/default/files/resources/UEFI Spec 2_6.pdf
Комментарии:
1. Я думал, что InitializeLib() выполнила работу по инициализации RT. Я все равно попробую.