调用loadImage返回EFI_NOT_FOUND的原因与解决方法
UEFI应用加载二级镜像时EFI_NOT_FOUND问题排查
问题描述
使用NASM汇编编写UEFI应用,尝试通过绝对文件路径加载二级EFI文件并调用loadImage启动服务运行镜像,但遇到以下问题:
- 设备路径变量非空,但多UEFI系统测试均返回
EFI_NOT_FOUND错误 - 将设备路径设为null时返回无效参数,但UEFI规范仅在设备路径与源缓冲区均为null时才会返回
EFI_NOT_FOUND(已确认设备路径非空)
相关代码
初始loadImage实现
;****************************************************************** ;*** loadImage [BOOT FUNCTION ONLY] *** ;*** Definition: Load an EFI boot driver from a file *** ;*** Input: rcx is a pointer to a device path protocol to load *** ;*** Output: rcx is the EFI handle *** ;****************************************************************** loadImage: ;Save registers push rdx push r8 push r9 push r10 push r11 ;Call the function mov r8, rcx mov rcx, 0 mov rdx, [EFI_HANDLE] mov r8, turtleDevicePathProtocol mov r9, 0 mov r10, 0 mov r11, BUFFER_LOAD_IMAGE push r11 push r10 sub rsp, 0x20 call [ADDRESS_BOOT_SERVICES_LOAD_IMAGE] ;Restore registers add rsp, 0x30 pop r11 pop r10 pop r9 pop r8 pop rdx ;Return mov rcx, [BUFFER_LOAD_IMAGE] ret
初始设备路径定义
;**************************************** ;*** Bootloader device path protocols *** ;**************************************** turtleDevicePathProtocol db 4 ;This is the image I am trying to load db 4 dw 36 db __utf16__ `\\EFI\\turtle.efi\0` db 0x7f db 0xff dw 4 bootloaderDevicePathProtocol db 4 ;This is the loaded image protocol, for reference db 4 dw 48 db __utf16__ `\\EFI\\BOOT\\BOOTX64.efi\0` db 0x7f db 0xff dw 4
编辑后的路径拼接及调用代码
; We need to append two device paths together to load the second image ; First, we need the device path linked to the parent EFI handle ; Second, we need the absolute file path of the image to load ; Third, we append them together ; Finally, we load and start the image at the appended device path ; So, step 1: mov rcx, [ADDRESS_LOADED_IMAGE_DEVICE_HANDLE] mov rdx, GUID_EFI_DEVICE_PATH_PROTOCOL call getProtocolFromHandle cmp rax, [RETURN_SUCCESS] jne exitWithError mov [ADDRESS_DEVICE_PATH], rcx ; Step 2 mov rdx, turtleDevicePathProtocol ; Step 3 call appendDevicePath cmp rax, [RETURN_SUCCESS] jne exitWithError loadDevicePath: mov [ADDRESS_DEVICE_PATH], rcx ; Print the device path if we can. Note that this function uses the optional ; DEVICE_PATH_TO_TEXT_PROTOCOL, so we will just skip this step if we can't find it mov rcx, GUID_EFI_DEVICE_PATH_TO_TEXT_PROTOCOL call locateProtocol cmp rax, [RETURN_SUCCESS] je printImagePath cmp rax, [RETURN_NOT_FOUND] jne exitWithError call warnWithError jmp noPrintDevicePath printImagePath: ; Get the print device path function mov [ADDRESS_DEVICE_PATH_TO_TEXT_PROTOCOL], rcx ;mov rcx, [ADDRESS_DEVICE_PATH_TO_TEXT_PROTOCOL] ;Obviously line is not needed right? add rcx, [OFFSET_DEVICE_PATH_TO_TEXT_CONVERT_PATH] mov rcx, [rcx] mov [ADDRESS_DEVICE_PATH_TO_TEXT_PROTOCOL_CONVERT_PATH_TO_TEXT], rcx ;Print the device path mov rcx, [ADDRESS_DEVICE_PATH] mov rdx, [ADDRESS_CONOUT] call printDevicePath mov rcx, rdx mov rdx, newLine call printString noPrintDevicePath: ;Load turtle image mov rcx, [ADDRESS_DEVICE_PATH] call loadImage cmp rax, [RETURN_SUCCESS] jne exitWithError
输出信息
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/\EFI\turtle.efi Instruction failed with exit code 14. Turtle is stopping!
问题分析及解决方向
1. loadImage函数参数传递错误
初始loadImage实现中存在明显逻辑错误:函数接收的设备路径参数(rcx)先被存入r8,但随后又被硬编码为turtleDevicePathProtocol覆盖,导致传入UEFILoadImage服务的始终是硬编码的错误路径,而非拼接后的正确路径。
修正方案:
保留传入的设备路径参数,不要覆盖r8的值:
;Call the function mov rcx, 0 ; ImageHandle = NULL(加载应用时传NULL) mov rdx, [EFI_HANDLE] ; ParentHandle = 当前应用的Handle mov r8, rcx ; 使用函数输入的设备路径参数 mov r9, 0 ; SourceBuffer = NULL mov r10, 0 ; SourceSize = 0 mov r11, BUFFER_LOAD_IMAGE ; Destination = 输出加载后的Handle的地址 push r11 push r10
2. 设备路径节点长度计算错误
turtleDevicePathProtocol中的文件路径节点长度dw 36不符合实际:
- UTF-16字符串
\\EFI\\turtle.efi\0包含13个字符(含终止null),每个字符占2字节,总字节数为26 - 加上设备路径节点头部的4字节(Type=4, SubType=4, Length=2字节),整个节点的总长度应为
dw 30,而非36
修正方案:
调整turtleDevicePathProtocol的长度字段:
turtleDevicePathProtocol db 4 db 4 dw 30 ; 修正为正确长度 db __utf16__ `\\EFI\\turtle.efi\0` db 0x7f db 0xff dw 4
3. 路径拼接后的内存处理问题
UEFI的AppendDevicePath服务会分配新内存存储拼接后的设备路径,需确认:
appendDevicePath函数是否正确调用UEFI标准服务,返回的拼接路径指针有效- 使用完拼接路径后,调用
FreePool释放内存,避免内存泄漏
4. 存储设备访问问题
从输出路径Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/\EFI\turtle.efi来看,当前应用从Firmware Volume(FV)加载,但turtle.efi可能不在同一FV,或FV为只读无法访问文件系统路径:
- 确认
turtle.efi所在存储设备已被正确枚举,且挂载了文件系统协议 - 尝试基于当前应用
LoadedImage协议的文件路径构建相对路径,而非绝对路径
验证步骤
- 修正
loadImage参数传递错误,确保传入拼接后的正确路径 - 调整设备路径节点的长度值,保证格式合规
- 用
DevicePathToText输出完整路径,确认节点顺序、格式无错误 - 检查
AppendDevicePath返回值,确认内存分配成功 - 手动调用文件系统协议打开
turtle.efi,验证文件可访问性
内容的提问来源于stack exchange,提问作者JD9999
相关产品推荐
相关产品推荐

