调用SystemTable函数时UEFI应用挂起或报错的问题排查
UEFI引导加载程序调用SystemTable函数异常问题
开发自定义操作系统及基础UEFI引导加载程序时,遵循OSDev上的GNU-EFI指南,遇到以下问题:
- 调用
SystemTable->ConIn->ReadKeyStroke()时程序挂起,无后续输出 - 调用
SystemTable->BootServices->HandleProtocol()时返回*EFI_INVALID_PARAMETERS(0x02)*错误 - 尝试用
uefi_call_wrapper()替代直接调用,仍会导致程序挂起
代码示例及输出
测试ReadKeyStroke的boot.c
#include <efi.h> #include <efierr.h> #include <efilib.h> EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { InitializeLib(ImageHandle, SystemTable); Print(L"Loading kernel...\n"); EFI_INPUT_KEY Key; SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &Key); Print(L"Pressed key...\n"); return EFI_SUCCESS; }
运行输出:
BdsDxe: loading Boot0001 "UEFI EMU HARDDISK QM00001 * from PciRoot (0x0)/Pci (0x1,0x1) /Ata Primary.Ma ster,0x0) BasDxe: starting Boot0001 "UEFI EMU HARDDISK QM00001 * from PciRoot (0x0) /Pcs (0x1.0x1) /Ata (Primary.M aster,0x0) Loading kernel...
按下任意按键后程序无响应,不会输出Pressed key...
测试HandleProtocol的boot.c
#include <efi.h> #include <efierr.h> #include <efilib.h> EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { InitializeLib(ImageHandle, SystemTable); Print(L"Loading kernel...\n"); EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_STATUS s = 0; s = SystemTable->BootServices->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&LoadedImage); Print(L"ERROR... %d \n", s); EFI_INPUT_KEY Key; SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &Key); Print(L"Pressed key...\n"); return EFI_SUCCESS; }
运行输出:
BdsDxe: loading Boot0001 "UEFI EMU HARDDISK QM00001 * from PciRoot (0x0)/Pci (0x1,0x1) /Ata Primary.Ma ster,0x0) BasDxe: starting Boot0001 "UEFI EMU HARDDISK QM00001 * from PciRoot (0x0) /Pcs (0x1.0x1) /Ata (Primary.M aster,0x0) Loading kernel... ERROR... 2
错误码2对应EFI_INVALID_PARAMETERS
构建使用的Makefile
SRCDIR = src OUTDIR = bin CC = gcc BOOTLOADER_CFLAGS = -I/usr/include/efi -fpic -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -DEFI_FUNCTION_WRAPPER KERNEL_CFLAGS = -ffreestanding -fshort-wchar LD = ld BOOTLOADER_LDFLAGS = -shared -Bsymbolic -Lgnu-efi/ -Tgnu-efi/elf_x86_64_efi.lds gnu-efi/crt0-efi-x86_64.o -lgnuefi -lefi -nostdlib KERNEL_LDFLAGS = -T src/kernel/kernel.ld -shared -Bsymbolic -nostdlib OBJCOPY = objcopy BOOT = bootx64 KERNEL = kernel OSNAME = tinyos KSRCS := $(wildcard $(SRCDIR)/kernel/*.c) OBJS = $(patsubst $(SRCDIR)/kernel/%.c, $(OUTDIR)/kernel/%.o, $(KSRCS)) # Build the kernel source files $(OUTDIR)/kernel/%.o: $(SRCDIR)/kernel/%.c @mkdir -p $(dir $@) $(CC) $(KERNEL_CFLAGS) -c $^ -o $@ # Link the kernel obj files into one elf executable $(KERNEL).elf: $(OBJS) $(LD) $(KERNEL_LDFLAGS) -o $(OUTDIR)/kernel/$(KERNEL).elf $^ # Create the efi application $(BOOT): $(SRCDIR)/boot/*.c $(CC) $(BOOTLOADER_CFLAGS) -c $^ -o $(OUTDIR)/boot/$(BOOT).o $(LD) $(BOOTLOADER_LDFLAGS) $(OUTDIR)/boot/$(BOOT).o -o $(OUTDIR)/boot/$(BOOT).so $(OBJCOPY) -j .text -j .sdata -j .data -j .rodata -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target efi-app-x86_64 --subsystem=10 $(OUTDIR)/boot/$(BOOT).so $(OUTDIR)/boot/$(BOOT).efi # Create the image file and copy the efi application (bootloader) to the efi partition of the image buildimg: $(BOOT) $(KERNEL).elf dd if=/dev/zero of=$(OUTDIR)/$(OSNAME).img bs=512 count=93750 mformat -i $(OUTDIR)/$(OSNAME).img :: mmd -i $(OUTDIR)/$(OSNAME).img ::/efi mmd -i $(OUTDIR)/$(OSNAME).img ::/efi/boot mcopy -i $(OUTDIR)/$(OSNAME).img $(OUTDIR)/boot/$(BOOT).efi ::/efi/boot mcopy -i $(OUTDIR)/$(OSNAME).img $(OUTDIR)/kernel/$(KERNEL).elf :: run: qemu-system-x86_64 -cpu qemu64 -bios /usr/share/edk2-ovmf/x64/OVMF.fd -drive file=$(OUTDIR)/$(OSNAME).img,if=ide
开发环境
- 系统:Arch Linux
- 已安装软件包:最新版qemu、OVMF固件、gnu-efi
内容的提问来源于stack exchange,提问作者kreaon
相关产品推荐
相关产品推荐

