如何获取当前运行镜像在UEFI中的设备路径?

问题描述 投票:0回答:1

作为我正在编写的 UEFI 应用程序的一部分,我希望我的应用程序在与此应用程序相同的文件夹中加载第二个应用程序。 但是,要做到这一点,我需要知道当前运行文件的完整文件路径,并且我无法访问任何固件来包含 SIMPLE_FILE_SYSTEM_PROTOCOL 实例(使用locateHandleBuffer)。

我的解决方案是获取正在运行的应用程序的 LOADED_IMAGE_PROTOCOL,从那里获取设备路径(希望它是文件路径媒体设备路径)并从那里开始。

问题是我的应用程序的每次运行都会提供不同的设备路径。在某些固件上,仅设备路径的长度发生变化,但在其他固件上,设备路径类型会发生变化。此外,在我尝试过的所有固件中,没有一个设备类型是有效的设备类型。

如何获取我尝试加载的文件的设备路径?是这段代码已损坏,还是我处理错误,或者两者兼而有之?

以下是应用程序消息的一些屏幕截图。第一个是 QEMU,第二个是我的笔记本电脑:

这是主程序流程中执行设备路径打印的部分:

;Get the loaded image protocol for this handle
mov rcx, [EFI_HANDLE]
mov rdx, GUID_EFI_LOADED_IMAGE_PROTOCOL
call getProtocolFromHandle

;If getting the protocol failed, exit
cmp rax, [RETURN_SUCCESS]
je print

cmp rax, [RETURN_UNSUPPORTED]
jne error

mov rcx, [CONERR]
mov rdx, protocolNotFound
call printString
jmp printFinalString

print:
;If we have a loaded image protocol, then print information about the device path
add rcx, [OFFSET_LOADED_IMAGE_DEVICE_PATH_PROTOCOL]
mov r8, [rcx]
mov r9, [rcx]
mov r10, [rcx]
and r8, [MASK_FIRST_BYTE]
shr r8, 56
and r9, [MASK_SECOND_BYTE]
shr r9, 48
and r10, [MASK_THIRD_FOURTH_BYTES]
shr r10, 32
mov rcx, [CONOUT]
mov rdx, devicePathOne
call printString
mov rdx, r8
call printNumber
mov rdx, devicePathTwo
call printString
mov rdx, r9
call printNumber
mov rdx, devicePathThree
call printString
mov rdx, r10
call printNumber
mov rdx, newLine
call printString

这是从给定句柄获取协议的代码部分:

;****************************************************
;*** getProtocolFromHandle [BOOT FUNCTION ONLY]   ***
;*** Definition: Gets the address of the protocol ***
;*** of the specified GUID from the image handle  ***
;*** Input: rcx is the image handle               ***
;***        rdx is the protocol's GUID            ***
;*** Output: rcx is a pointer to the protocol     ***
;***         interface installed on that handle   ***
;*****************************************************
getProtocolFromHandle:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    mov r8, ADDRESS_OPEN_PROTOCOL
    mov r9, [EFI_HANDLE]
    mov r10, 0
    mov r11, [CONSTANT_OPEN_PROTOCOL_GET_PROTOCOL]
    push r11 ;Arguments to the stack must be pushed in reverse order
    push r10 
    sub rsp, 0x20
    call [BOOT_SERVICES_OPEN_PROTOCOL]

    ;Restore registers
    add rsp, 0x20
    pop r10
    pop r11
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Prepare return values and return
    mov rcx, [ADDRESS_OPEN_PROTOCOL]
    ret

这是我认为对于理解代码有用的数据副本:

OFFSET_LOADED_IMAGE_DEVICE_PATH_PROTOCOL dq 28
ADDRESS_OPEN_PROTOCOL dq 0
MASK_FIRST_BYTE dq 0xff00000000000000
MASK_SECOND_BYTE dq 0x00ff000000000000
MASK_THIRD_FOURTH_BYTES dq 0x0000ffff00000000

编辑: 在今天运行此应用程序的一个实例中,它在尝试获取值时崩溃了。这表明我的地址完全错误,但我不知道它是如何错误的:

assembly x86-64 nasm uefi
1个回答
0
投票

我发现了这个问题。这里的主要问题是加载的图像设备路径的偏移量需要是 32 而不是 28。 尽管协议以 UINT32(4 个字节)开头,但在 64 位系统上似乎是用零填充来占用 8 个字节。

另外,上面的其余代码将无法工作,因为它有很多错误并且需要进行大量更改,但至少现在您可以获取指向设备路径协议的指针!

这样的事情会起作用:

getImageProtocol:
;Get the loaded image protocol for this handle
mov rcx, [EFI_HANDLE]
mov rdx, GUID_EFI_LOADED_IMAGE_PROTOCOL
call getProtocolFromHandle
cmp rax, [RETURN_SUCCESS]
jne exitWithError
mov [ADDRESS_LOADED_IMAGE], rcx

;Get an instance of the device path utilities protocol
mov rcx, GUID_EFI_DEVICE_PATH_UTILITIES_PROTOCOL
call locateProtocol
cmp rax, [RETURN_SUCCESS]
jne exitWithError
mov [ADDRESS_DEVICE_PATH_UTILITIES_PROTOCOL], rcx
mov rcx, [rcx]
mov [ADDRESS_DEVICE_PATH_UTILITIES_PROTOCOL_GET_DEVICE_PATH_SIZE], rcx

;Print the size of the loaded image device path
mov rcx, [ADDRESS_LOADED_IMAGE]
add rcx, [OFFSET_LOADED_IMAGE_DEVICE_PATH]
mov rcx, [rcx]
call getDevicePathSize
cmp rax, [RETURN_SUCCESS]
jne exitWithError
mov r9, rcx
mov rcx, [ADDRESS_CONOUT]
mov rdx, sizeString
call printString
mov rdx, r9
call printNumber
mov rdx, newLine
call printString

函数看起来像这样(我使用制表符宽度 8,因此某些星号对齐在 SO 中可能看起来很奇怪,因为它的制表符宽度为 4):

;******************************************************************
;*** getProtocolFromHandle [BOOT FUNCTION ONLY]     ***
;*** Definition: Gets an instance of the protocol which is  ***
;***         registered to the given image.     ***
;*** Input: rcx is the image handle             ***
;***        rdx is a pointer to the protocol's GUID     ***
;*** Output: rcx is a pointer to the protocol's interface   ***
;***         installed on that handle.              ***
;******************************************************************
getProtocolFromHandle:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    mov r8, BUFFER_OPENED_PROTOCOL
    mov r9, [EFI_HANDLE]
    mov r10, 0
    mov r11, [CONSTANT_OPEN_PROTOCOL_GET_PROTOCOL]
    push r11 ;Arguments to the stack must be pushed in reverse order
    push r10 
    sub rsp, 0x20
    call [ADDRESS_BOOT_SERVICES_OPEN_PROTOCOL]

    ;Restore registers
    add rsp, 0x20
    pop r10
    pop r11
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Prepare return values and return
    mov rcx, [BUFFER_OPENED_PROTOCOL]
    ret
    
;**************************************************************************
;*** locateProtocol [BOOT FUNCTION ONLY]                ***
;*** Definition: provides an interface to the requested protocol.   ***
;*** Input: rcx is the address of the protocol GUID         ***
;*** Output: rcx holds a pointer to the interface           ***
;**************************************************************************
locateProtocol:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    mov rdx, 0
    mov r8, BUFFER_LOCATED_PROTOCOL
    sub rsp, 0x20
    call [ADDRESS_BOOT_SERVICES_LOCATE_PROTOCOL]

    ;Restore registers
    add rsp, 0x20
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Prepare return values and return
    mov rcx, [BUFFER_LOCATED_PROTOCOL]
    ret

;**************************************************************************
;*** getDevicePathSize                          ***
;*** Definition: gets the total size of all nodes in the device ***
;***         path, including the end-of-path tag            ***
;*** Input: rcx is the address of the device path           ***
;*** Output: rcx is the size of the device path         ***
;**************************************************************************
getDevicePathSize:
    ;Save registers
    push rdx
    push r8
    push r9
    push r10
    push r11
    
    ;Call the function
    sub rsp, 0x20
    call [ADDRESS_DEVICE_PATH_UTILITIES_PROTOCOL_GET_DEVICE_PATH_SIZE] ;My gosh that's a long pointer name!

    ;Restore registers
    add rsp, 0x20
    pop r11
    pop r10
    pop r9
    pop r8
    pop rdx
    
    ;Return
    mov rcx, rax
    cmp rax, 0
    jne GDPSgood
    mov rax, [RETURN_INVALID_ARGUMENT] ;DevicePath is either null or something else, so it's invalid :(
    ret
    
    GDPSgood:
    mov rax, [RETURN_SUCCESS]
    ret
© www.soinside.com 2019 - 2024. All rights reserved.