You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UEFI编程中LocateProtocol返回efi_not_found的问题排查与解决

问题原因及解决方案

可能的原因

  • 启动阶段错误:在ExitBootServices之后调用LocateProtocol,此时Boot Services已关闭,无法访问文件系统协议;或者启动介质未被UEFI识别(比如ESP分区未格式化、未挂载)。
  • GUID定义错误:Pascal代码中EFI_SIMPLE_FILE_SYSTEM_PROTOCOL的GUID与UEFI规范不匹配,导致协议无法被定位。
  • 参数传递错误:LocateProtocol的输出参数类型不匹配,或者传递了无效的指针。
  • 构建环境问题:未使用针对UEFI的编译目标,或者链接了错误的库,导致二进制与UEFI环境不兼容。

Pascal修复方案

1. 修正GUID定义

UEFI规范中EFI_SIMPLE_FILE_SYSTEM_PROTOCOL的GUID为{0x0964E5B2, 0x6459, 0x11D2, {0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B}},确保Pascal中的定义完全一致。

2. 确认调用时机

必须在Boot Services阶段(即EFI_IMAGE_ENTRY_POINT执行期间)调用LocateProtocol,避免在ExitBootServices之后操作。

3. 修复后的Pascal代码示例

program UEFIFileSystemTest;

{$mode objfpc}{$H+}
{$TUEFI}

uses
  uefi;

var
  Status: EFI_STATUS;
  SimpleFileSystem: PEFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
  RootDir: PEFI_FILE_PROTOCOL;
begin
  // 确保Boot Services可用
  if gBS = nil then Exit;

  // 正确的Simple File System Protocol GUID
  const EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID: EFI_GUID = (
    Data1: $0964E5B2;
    Data2: $6459;
    Data3: $11D2;
    Data4: ($8E, $39, $00, $A0, $C9, $69, $72, $3B)
  );

  // 定位协议
  Status := gBS^.LocateProtocol(@EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, nil, @SimpleFileSystem);
  if EFI_ERROR(Status) then
  begin
    gST^.ConOut^.OutputString(gST^.ConOut, 'Failed to locate Simple File System Protocol: ');
    gST^.ConOut^.OutputString(gST^.ConOut, UEFIStatusToString(Status));
    gST^.ConOut^.OutputString(gST^.ConOut, #10#13);
    Exit;
  end;

  // 打开根目录
  Status := SimpleFileSystem^.OpenVolume(SimpleFileSystem, @RootDir);
  if EFI_ERROR(Status) then
  begin
    gST^.ConOut^.OutputString(gST^.ConOut, 'Failed to open root volume'#10#13);
    Exit;
  end;

  gST^.ConOut^.OutputString(gST^.ConOut, 'Successfully accessed file system'#10#13);

  // 释放资源
  RootDir^.Close(RootDir);
end.

4. 修正构建脚本(Free Pascal)

#!/bin/bash
# 编译为64位UEFI应用(若为32位则替换-Px86_64为-Pi386)
fpc -Tuefi -Px86_64 UEFIFileSystemTest.pas
# 将生成的.efi文件复制到ESP分区的EFI/BOOT目录

C语言实现示例

#include <efi.h>
#include <efilib.h>

EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
    EFI_STATUS Status;
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
    EFI_FILE_PROTOCOL *RootDir;

    InitializeLib(ImageHandle, SystemTable);

    // 定位文件系统协议
    Status = uefi_call_wrapper(BS->LocateProtocol, 3,
                               &gEfiSimpleFileSystemProtocolGuid,
                               NULL,
                               (void**)&SimpleFileSystem);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to locate Simple File System Protocol: %r\n", Status);
        return Status;
    }

    // 打开根目录
    Status = uefi_call_wrapper(SimpleFileSystem->OpenVolume, 2,
                               SimpleFileSystem,
                               &RootDir);
    if (EFI_ERROR(Status)) {
        Print(L"Failed to open root volume: %r\n", Status);
        return Status;
    }

    Print(L"Successfully accessed file system\n");

    // 关闭根目录
    uefi_call_wrapper(RootDir->Close, 1, RootDir);

    return EFI_SUCCESS;
}

构建脚本(GCC)

#!/bin/bash
# 编译64位UEFI应用
x86_64-w64-mingw32-gcc -ffreestanding -fshort-wchar -mno-red-zone -m64 -c main.c -o main.o
x86_64-w64-mingw32-ld -nostdlib -Wl,-entry:efi_main -Wl,--subsystem,10 -o main.efi main.o -lefi -lgnuefi

Rust语言实现示例(基于uefi-rs库)

use uefi::{prelude::*, proto::media::file::File, proto::media::fs::SimpleFileSystem};

#[entry]
fn main(_image_handle: Handle, system_table: SystemTable<Boot>) -> Status {
    let stdout = system_table.stdout();
    let boot_services = system_table.boot_services();

    // 定位文件系统协议
    let fs = boot_services.locate_protocol::<SimpleFileSystem>()
        .map_err(|e| {
            let _ = stdout.write_str(format!("Failed to locate Simple File System Protocol: {:?}\n", e).as_str());
            e.status()
        })?;

    // 打开根目录
    let mut root_dir = fs.open_volume()
        .map_err(|e| {
            let _ = stdout.write_str(format!("Failed to open root volume: {:?}\n", e).as_str());
            e.status()
        })?;

    let _ = stdout.write_str("Successfully accessed file system\n");

    // 关闭文件(uefi-rs会自动处理资源,此处可省略)
    let _ = root_dir.close();

    Status::SUCCESS
}

构建脚本(Cargo)

#!/bin/bash
# 确保已安装uefi-rs依赖,编译为64位UEFI应用
cargo build --target x86_64-unknown-uefi --release
# 生成的efi文件路径:target/x86_64-unknown-uefi/release/<项目名>.efi

内容的提问来源于stack exchange,提问作者user24150775

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 13:29:52