- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在 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/
在引导 GRUB2 的 EFI 系统上,我想创建一个只读 EFI 变量。这可能吗? 谢谢,垫子 最佳答案 根据 Uefi Specification 2.7通过不提供 EFI_VARIABLE_NON
我是 UEFI 应用程序开发的新手。 我的要求是, 我需要从我的 UEFI 应用程序 (app.efi) 源代码中运行 UEFI shell 命令。 需要有关如何执行此操作的指导。 例子, cp co
我尝试使用 gnu-efi 编译 uefi 代码。但是我不明白如何编译我的 uefi 应用程序代码。 我得到 gnu-efi 3.0.2,解压并输入 make && make install。我写了
我正在 SoC 设备(Up Board)上编写 EFI 可执行文件,以帮助我们自动执行 BIOS 更新和 PXE 启动,以便在众多设备上安装我们的软件。 我遇到的问题是,似乎规范中的大多数协议(pro
我有一个从 uefi 加载的虚拟机 (Windows7x64)。 我能否将我创建的 UEFI 应用程序\驱动程序添加到 UEFI,以便它在启动时加载它? 另外,我可以更改加载 DXE\UEFI 驱动程
我可以在UEFI环境中build and manually execute一个EFI应用程序。但是,我想让我的应用程序在启动时自动执行。 有没有办法告诉引导加载程序执行此操作,还是需要将我的应用程序提
本题表达方式与What is UEFI's boot sequence?相同,但似乎不是我想要的。我想从指令的角度了解 UEFI 序列。 例如,在 BIOS 引导模式的情况下,以简化的方式, 计算机电
我在研究引导加载程序时正好遇到了 UEFI 一词。我能理解一些关于 UEFI 的事情。但是,具有 UEFI 的系统以什么模式(Real、Protected、Long)启动?如果普通的引导加载程序不能与
我正在考虑开发一个简单的(开始)UEFI 引导加载程序来加载 ELF 镜像,并且想知道是否有人可以很好地进入任何现有项目,或者我可以用来开始的示例和。 此外,我想知道是否有人有任何让 virtual
我写了一个EFI二进制文件来测试UEFI shell下的物理DIMM,过程很简单——先写入一个测试模式到一个物理地址,然后读出并与原始模式进行比较。但是,DIMM 可能会遇到可纠正或不可纠正的错误。通
我正在尝试向 UEFI 中的协议(protocol)添加过滤器驱动程序,这意味着在层次结构中使用该协议(protocol)的每个人最终都会通过我。 我知道我需要将我的驱动程序添加到相关的设备路径 -
有没有办法让线程应用程序在 UEFI 上运行?我只在 UEFI 规范中发现了一些关于线程的提及,但它们并没有真正回答我的问题。 最佳答案 目前 UEFI 中没有线程,但是有一个 MpService p
我是 UEFI 的初学者。我正在尝试从我的 UEFI 应用程序中打开一个文件。文件的路径是 fs1:/myfolder/myfile.txt 代码(借助 this answer ): efiStatu
规范的哪一部分详细说明了如何获取命令行参数? 最佳答案 你需要小心这个。 您可能知道,有一个 UEFI LoadedImage 协议(protocol) - 该协议(protocol)返回一个名为 E
我想在 UEFI 中列出根目录的内容,但我没有找到任何协议(protocol)可以做到这一点;因此我想打印目录文件的内容,但是 EFI_FILE_PROTOCOL 无法读取目录文件。我唯一可以做的另一
我有在操作系统旁边运行一个小服务的想法,但我不确定这是否可能。我试图通过阅读一些文档来弄清楚,但没有走远,所以我的问题来了。 我阅读了有关 UEFI 运行时服务的信息。 是否有可能在固件中有一个小模块
我对 PC 固件编程很感兴趣,我只是在研究 UEFI 规范。令我惊讶的是,它似乎是嵌入在固件中的整个操作系统的规范。您甚至可以编写直接使用 UEFI 引导服务运行的 UEFI“应用程序”,而无需任何其
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
如何在 Debian Jessie 机器上创建 UEFI ISO 镜像? 当我在 Kubuntu 上使用 follow 命令时,一切正常 genisoimage -quiet -V "my-amd64
在 Windows 应用程序中,我有一个 GetFirmwareEnvironmentVariableA 函数来读取固件环境变量。有没有什么办法可以在 uefi 驱动程序的这个变量中写入一些东西,然后
我是一名优秀的程序员,十分优秀!