gpt4 book ai didi

uefi - 大多数 UEFI 协议(protocol)报告为 "unsupported"

转载 作者:行者123 更新时间:2023-12-02 01:02:14 35 4
gpt4 key购买 nike

我正在 SoC 设备(Up Board)上编写 EFI 可执行文件,以帮助我们自动执行 BIOS 更新和 PXE 启动,以便在众多设备上安装我们的软件。

我遇到的问题是,似乎规范中的大多数协议(protocol)在这个平台上都是“不受支持的”,甚至是基本的文件系统任务。我唯一成功使用的是 LOADED_IMAGE_PROTOCOL。我正在使用 gnu-efi 编译代码,将我的代码基于此示例 https://mjg59.dreamwidth.org/18773.html .是我做错了什么,还是固件完全没有实现任何协议(protocol)?

American Megatrends 实用程序“AfuEfix64.efi”能够检索 BIOS 信息,SoC BIOS 更新是使用 Intel 的 EFI 可执行文件完成的。不幸的是,两者都是封闭源代码。我最初的想法是编写一个脚本来解析这些可执行文件的输出,但我认为 EFI shell 没有太多用于此类任务的功能,所以我继续编写 EFI 可执行文件来执行此操作。

显示此内容的最少代码:

#include <efi.h>
#include <efilib.h>
#include <x86_64/efibind.h>

// gnu-efi does not currently define firmware management
// https://raw.githubusercontent.com/tianocore/edk2/master/MdePkg/Include/Protocol/FirmwareManagement.h
#include "efifirmware.h"

// gnu-efi does not currently define this
#define EFI_LOAD_FILE2_PROTOCOL_GUID \
{ 0x4006c0c1, 0xfcb3, 0x403e, \
{ 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }}
typedef EFI_LOAD_FILE_PROTOCOL EFI_LOAD_FILE2_PROTOCOL;

void tryProtocol(EFI_GUID proto_guid, void** out, const CHAR16* name,
EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {

EFI_STATUS status;
status = uefi_call_wrapper(systemTable->BootServices->HandleProtocol, 3,
imageHandle, &proto_guid, out);

if (EFI_ERROR(status)) {
Print(L"HandleProtocol error for %s: %r\n", name, status);
} else {
Print(L"Protocol %s is supported\n", name);
}
}

void tryProtocols(EFI_HANDLE imgh, EFI_SYSTEM_TABLE* syst) {
EFI_LOADED_IMAGE* loaded_image = NULL;
EFI_GUID guid_imgprot = LOADED_IMAGE_PROTOCOL;
tryProtocol(guid_imgprot, (void**)&loaded_image,
L"LOADED_IMAGE_PROTOCOL", imgh, syst);

Print(L"Image base: %lx\n", loaded_image->ImageBase);
Print(L"Image size: %lx\n", loaded_image->ImageSize);
Print(L"Image file: %s\n", DevicePathToStr(loaded_image->FilePath));

EFI_FIRMWARE_MANAGEMENT_PROTOCOL* fw_manage = NULL;
EFI_GUID guid_fwman_prot = EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
tryProtocol(guid_fwman_prot, (void**)&fw_manage,
L"FIRMWARE_MANAGEMENT_PROTOCOL", imgh, syst);

EFI_LOAD_FILE_PROTOCOL* load_file = NULL;
EFI_GUID guid_loadf_prot = EFI_LOAD_FILE_PROTOCOL_GUID;
tryProtocol(guid_loadf_prot, (void**)&load_file,
L"LOAD_FILE_PROTOCOL", imgh, syst);

EFI_LOAD_FILE2_PROTOCOL* load_file2 = NULL;
EFI_GUID guid_loadf2_prot = EFI_LOAD_FILE2_PROTOCOL_GUID;
tryProtocol(guid_loadf2_prot, (void**)&load_file2,
L"LOAD_FILE2_PROTOCOL", imgh, syst);

EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* simple_fs = NULL;
EFI_GUID guid_simple_fs_prot = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
tryProtocol(guid_simple_fs_prot, (void**)&simple_fs,
L"SIMPLE_FILE_SYSTEM_PROTOCOL", imgh, syst);

EFI_DISK_IO_PROTOCOL* disk = NULL;
EFI_GUID guid_disk_io_prot = EFI_DISK_IO_PROTOCOL_GUID;
tryProtocol(guid_disk_io_prot, (void**)&disk,
L"DISK_IO_PROTOCOL", imgh, syst);

EFI_BLOCK_IO_PROTOCOL* block = NULL;
EFI_GUID guid_block_io_prot = EFI_BLOCK_IO_PROTOCOL_GUID;
tryProtocol(guid_block_io_prot, (void**)&block,
L"BLOCK_IO_PROTOCOL", imgh, syst);
}

EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {
InitializeLib(imageHandle, systemTable);
Print(L"Image loaded\n");

tryProtocols(imageHandle, systemTable);

return EFI_SUCCESS;
}

这是运行它的输出:

EFI Shell version 2.40 [5.11]
Current running mode 1.1.2
Device mapping table
fs0 :HardDisk - Alias hd6b blk0
PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)/HD(1,GPT,2DCDDADD-8F3A-4A77-94A9-010A8C700BB8,0x800,0x100000)
fs1 :Removable HardDisk - Alias hd9g0a0b blk1
PciRoot(0x0)/Pci(0x14,0x0)/USB(0x6,0x0)/USB(0x0,0x0)/HD(1,MBR,0x528E6A1F,0x800,0x1CDE800)
blk0 :HardDisk - Alias hd6b fs0
PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)/HD(1,GPT,2DCDDADD-8F3A-4A77-94A9-010A8C700BB8,0x800,0x100000)
blk1 :Removable HardDisk - Alias hd9g0a0b fs1
PciRoot(0x0)/Pci(0x14,0x0)/USB(0x6,0x0)/USB(0x0,0x0)/HD(1,MBR,0x528E6A1F,0x800,0x1CDE800)
blk2 :HardDisk - Alias (null)
PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)/HD(2,GPT,8AC0F94E-3CA2-4C03-BE00-3A69721CC391,0x100800,0x1C1F7DF)
blk3 :BlockDevice - Alias (null)
PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)
blk4 :BlockDevice - Alias (null)
PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x1)
blk5 :BlockDevice - Alias (null)
PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x2)
blk6 :Removable BlockDevice - Alias (null)
PciRoot(0x0)/Pci(0x14,0x0)/USB(0x6,0x0)/USB(0x0,0x0)

Press ESC in 4 seconds to skip startup.nsh, any other key to continue.

fs1:\> tryprotocols.efi
Image loaded
Protocol LOADED_IMAGE_PROTOCOL is supported
Image base: 55BA6000
Image size: F000
Image file: \/tryprotocols.efi
HandleProtocol error for FIRMWARE_MANAGEMENT_PROTOCOL: Unsupported
HandleProtocol error for LOAD_FILE_PROTOCOL: Unsupported
HandleProtocol error for LOAD_FILE2_PROTOCOL: Unsupported
HandleProtocol error for SIMPLE_FILE_SYSTEM_PROTOCOL: Unsupported
HandleProtocol error for DISK_IO_PROTOCOL: Unsupported
HandleProtocol error for BLOCK_IO_PROTOCOL: Unsupported

fs1:\>

这是我用来编译它的 Makefile:

ARCH=x86_64
OBJS=tryprotocols.o
TARGET=tryprotocols.efi
TARGET_SO=$(TARGET:.efi=.so)
GNUEFIDIR=/home/gekko/gnu-efi-3.0.8
EFIINC=$(GNUEFIDIR)/inc
EFIINCS=-I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
LIB=$(GNUEFIDIR)/$(ARCH)/lib
EFILIB=$(GNUEFIDIR)/gnuefi
EFI_CRT_OBJS=$(GNUEFIDIR)/$(ARCH)/gnuefi/crt0-efi-$(ARCH).o
EFI_LDS=$(EFILIB)/elf_$(ARCH)_efi.lds

CFLAGS=$(EFIINCS) -fno-stack-protector -fpic \
-fshort-wchar -mno-red-zone -Wall

ifeq ($(ARCH),x86_64)
CFLAGS += -DEFI_FUNCTION_WRAPPER
endif

LDFLAGS=-nostdlib -znocombreloc -T $(EFI_LDS) -shared \
-Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS)

all: $(TARGET)

$(TARGET_SO): $(OBJS)
ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi

%.efi: %.so
objcopy -j .text -j .sdata -j .data -j .dynamic \
-j .dynsym -j .rel -j .rela -j .reloc \
--target=efi-app-$(ARCH) $^ $@

clean:
rm -f *.o
rm -f $(TARGET)
rm -f $(TARGET_SO)

编辑:正确使用 LocateProtocol() 查找协议(protocol)并使用它们打开和关闭文件的修改版本。

#include <efi.h>
#include <efilib.h>
#include <x86_64/efibind.h>

BOOLEAN tryProtocol(EFI_GUID proto_guid, void** out, const CHAR16* name,
EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {

*out = NULL;
EFI_STATUS status;
EFI_HANDLE interface = NULL;

status = uefi_call_wrapper(systemTable->BootServices->LocateProtocol, 3,
&proto_guid, NULL, &interface);

if (EFI_ERROR(status)) {
Print(L"LocateProtocol error for %s: %r\n", name, status);
return FALSE;
}

Print(L"Locate protocol address: %s, %x\n", name, interface);
*out = interface;

return TRUE;
}
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {
InitializeLib(imageHandle, systemTable);
Print(L"Image loaded\n");

EFI_LOADED_IMAGE* loaded_image = NULL;
EFI_GUID guid_imgprot = LOADED_IMAGE_PROTOCOL;

if (tryProtocol(guid_imgprot, (void**)&loaded_image,
L"LOADED_IMAGE_PROTOCOL", imageHandle, systemTable) != TRUE) {
Print(L"Missing required protocol. Aborting\n");
return EFI_SUCCESS;
}

Print(L"Image base: %lx\n", loaded_image->ImageBase);
Print(L"Image size: %lx\n", loaded_image->ImageSize);
Print(L"Image file: %s\n", DevicePathToStr(loaded_image->FilePath));

EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* simple_fs = NULL;
EFI_GUID guid_simple_fs_prot = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;

if (tryProtocol(guid_simple_fs_prot, (void**)&simple_fs,
L"EFI_SIMPLE_FILE_SYSTEM_PROTOCOL", imageHandle, systemTable) != TRUE) {
Print(L"Missing required protocol. Aborting\n");
return EFI_SUCCESS;
}

EFI_FILE_PROTOCOL* vol_proto = NULL;
EFI_STATUS status;

Print(L"dereffing\n");
Print(L"address of OpenVolume: %x\n", simple_fs->OpenVolume);

status = uefi_call_wrapper(simple_fs->OpenVolume, 2, simple_fs, &vol_proto);

if (EFI_ERROR(status)) {
Print(L"Error opening volume: %r\n", status);
return EFI_SUCCESS;
}

Print(L"SIMPLE_FILE_SYSTEM volume opened\n");

EFI_FILE_PROTOCOL* f;
CHAR16 fname[10] = L"foo.txt\0";
UINT64 openmode = EFI_FILE_MODE_READ;
UINT64 attr = 0;
status = uefi_call_wrapper(vol_proto->Open, 5, vol_proto, &f, fname, openmode, attr);

if (EFI_ERROR(status)) {
Print(L"Error opening file: %r\n", status);
return EFI_SUCCESS;
}

Print(L"opened file %s\n", fname);

// Spec says can only return EFI_SUCCESS
status = uefi_call_wrapper(vol_proto->Close, 1, f);

Print(L"Closed file\n");

return EFI_SUCCESS;
}

最佳答案

UEFI 规范并未静态定义访问特定协议(protocol)的位置和方式,而是需要在运行时发现的内容。虽然有点费力,但它可以编写可移植到完全符合规范的完全不同的 UEFI 实现的应用程序/驱动程序。

因此,在使用 HandleProtocol() 之前,您需要在您打算使用的每个协议(protocol)上找到 LocateProtocol()。您可以使用 LOADED_IMAGE_PROTOCOL,因为它是用您的 ImageHandle 初始化的,引用当前正在执行的图像(您的程序)的实例。

这在 Matthew 的帖子部分介绍了这一点,该部分介绍了如何使用附加到图像句柄的协议(protocol)。附加到其他句柄的协议(protocol)怎么样?

关于uefi - 大多数 UEFI 协议(protocol)报告为 "unsupported",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49793563/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com