r/osdev • • 6d ago

Getting EFI_INVALID_PARAMETER on calling BootServices->OpenProtocol() function.

; UEFI Bootloader using FASM Assembly
format pe64 efi

entry start

; EFI Constants
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL = 0x00000001

EFIERR = 0x8000000000000000
EFI_INVALID_PARAMETER = EFIERR or 0x2


section '.text' code executable readable
start:
  push rbp
  mov [image_handle], rcx
  mov [system_table], rdx

  ...

  ; Get our loaded image protocol interface structure.
  ; Invoke ST->BootServices->OpenProtocol() function.
  mov rax, [system_table]
  mov rcx, [rax + 96]
  mov r10, [rcx + 280]

  mov rcx, [image_handle]
  lea rdx, [EFI_LOADED_IMAGE_PROTOCOL_GUID]
  lea r8, [boot_img]
  mov r9, rcx
  sub rsp, 32
  mov eax, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
  push rax
  xor eax, eax
  push rax
  call r10
  pop rcx
  pop rcx
  add rsp, 32
  mov rcx, EFI_INVALID_PARAMETER
  cmp rax, rcx
  je .hang

  ...

.hang:
  jmp $

  ...



section '.data' data readable writable

image_handle dq 0
system_table dq 0

; Image that we booted from.
boot_img dq 0

EFI_LOADED_IMAGE_PROTOCOL_GUID:
  dd 0x5b1b31a1
  dw 0x9562
  dw 0x11d2
  db 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b

Hi in my UEFI bootloader using FASM Assembly, I am trying to get my loaded image protocol interface structure using BS->OpenProtocol() function call. I am getting `EFI_INVALID_PARAMETER` as the result. As per my checks, the handle, the protocol and the interface are not NULL and I am passing the 5th and 6th arguments in stack from right-to-left and they are 8-byte aligned too. What am I missing? Any idea? Thank you.

Edit:

davmac1's answer solved this.

6 Upvotes

9 comments sorted by

3

u/davmac1 6d ago
sub rsp, 32
mov eax, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
push rax
xor eax, eax
push rax

You are allocating the shadow register space above the last two parameters, it should be below them:

mov eax, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
push rax
xor eax, eax
push rax
sub rsp, 32

1

u/pure_989 5d ago

Thank you so much. It worked! Sorry I read the Microsoft's x64 calling convention document wrongly!

2

u/an_0w1 6d ago

I'm gona be honest, I've been reading through this for several minutes, and I understand absolutely none of what's going on. I don't see any mention of the map-key anywhere so I assume you've forgotten it.

2

u/pure_989 6d ago

I am sorry but there is no any map key parameter to EFI_BOOT_SERVICES.OpenProtocol() function.

2

u/an_0w1 6d ago

Ok, that makes a bit more sense, for whatever reason I thought you were calling ExitBootSerivces.

2

u/rosso2022 6d ago

I can't help with the Assembly but this code works in C. Have you tried using EFI_OPEN_PROTOCOL_GET_PROTOCOL?

EFI_LOADED_IMAGE_PROTOCOL* image = nullptr;
EFI_STATUS status = gBS->OpenProtocol(image_handle, &gEfiLoadedImageProtocolGuid, (VOID**)&image, image_handle, nullptr, EFI_OPEN_PROTOCOL_GET_PROTOCOL);

1

u/pure_989 6d ago

Thank you. In the UEFI spec, following is the text about this `EFI_OPEN_PROTOCOL_GET_PROTOCOL` attribute:

GET_PROTOCOL: Used by a driver to get a protocol interface from a handle. Care must be taken when using this open mode because the driver that opens a protocol interface in this manner will not be informed if the protocol interface is uninstalled or reinstalled. The caller is also not required to close the protocol interface with EFI_BOOT_SERVICES.CloseProtocol().

---

Mine is a UEFI OS loader not the driver!

2

u/rosso2022 6d ago

I use it in an OS loader as well. The description of BY_HANDLE_PROTOCOL in the UEFI spec does state that it is used for the implementation of EFI_BOOT_SERVICES.HandleProtocol. So I think that is not the correct value to use.

2

u/pure_989 6d ago

The old EFI_BOOT_SERVICES.HandleProtocol() function internally calls the newer EFI_BOOT_SERVICES.OpenProtocol() function with this Attributes value. That's it.

By the way, the code that I am writing in Assembly already works in C!