Page 1 of 1

UEFI GOP->QueryMode() function doesn't execute the 2nd time

Posted: Tue Nov 10, 2026 4:27 am
by osdev199
Hi, in my UEFI bootloader using FASM Assembly, I am trying to find the video mode code for 1280x1024 resolution. I loop through each value of counter starting from 0 upto the total video modes and on the second iteration, `debug_msg2` doesn't get printed at all and the execution hangs. How can I go about this?

The value of counter at second iteration is 1. Register RCX contains the GOP pointer. What could be wrong here?

Code: Select all

; Video mode code constant
MODE_CODE_INVALID = 100     ; taking an arbitrary higher mode code


section '.text' code executable readable

;
; find_mode_code_for_1280x1024_resolution
;
; This function finds the video mode code for 1280 x 1024 resolution.
;
; Args:
;   @rcx = GOP interface
;   @edx = total number of video modes
;
; Returns:
;   @eax = video mode code
;
find_mode_code_for_1280x1024_resolution:
  push rbp
  mov rbp, rsp

  sub rsp, 32

  total_video_modes equ dword [rbp - 4]
  counter equ dword [rbp - 8]
  gop equ qword [rbp - 14]
  mode_code equ dword [rbp - 18]

  mov gop, rcx
  mov total_video_modes, edx

  mov mode_code, MODE_CODE_INVALID
  mov counter, 0

.loop_start:
  mov eax, total_video_modes
  cmp counter, eax
  jae .loop_end

  ; DEBUG
  uefi_call_wrapper ConOut, OutputString, ConOut, debug_msg1

  mov rcx, gop
  mov edx, counter
  ; invoke EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode() function
  uefi_call_wrapper rcx, QueryMode, rcx, rdx, size_of_info, info

  ; DEBUG
  uefi_call_wrapper ConOut, OutputString, ConOut, debug_msg2

  mov rax, qword [info]
  mov ecx, dword [rax + \
      EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
  cmp ecx, 1280
  jne .free_pool
  mov ecx, dword [rax + \
      EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
  cmp ecx, 1024
  jne .free_pool
  mov ecx, dword [rax + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelFormat]
  cmp ecx, EFI_GRAPHICS_PIXEL_FORMAT_PixelBlueGreenRedReserved8BitPerColor
  jne .free_pool

  mov eax, counter
  mov mode_code, eax
  jmp .loop_end

.free_pool:
  mov rcx, qword [info]
  uefi_call_wrapper BootServices, FreePool, rcx

.loop_next:
  inc counter
  jmp .loop_start

.loop_end:
  mov eax, MODE_CODE_INVALID 
  cmp mode_code, eax
  je .exit

  mov rcx, qword [info]
  uefi_call_wrapper BootServices, FreePool, rcx

.exit:
  mov eax, mode_code

  restore total_video_modes
  restore counter
  restore gop
  restore mode_code

  mov rsp, rbp
  pop rbp
  ret

section '.data' data readable writeable

size_of_info  dq 0
info          dq 0

debug_msg1 du "@Before calling querymode func", 13, 10, 0
debug_msg2 du "@After calling querymode func", 13, 10, 0
Output:

Code: Select all

@Before calling querymode func
@After calling querymode func
@Before calling querymode func
Here is the UEFI library:

Code: Select all

; Invoke a uefi function
macro uefi_call_wrapper interface, function, arg1, arg2, arg3, arg4, arg5 {
  total_arg = 0
  if ~ arg5 eq
    total_arg = total_arg + 1
    if ~ arg5 eq r10
      mov r10, arg5
    end if
  end if
  if ~ arg4 eq
    total_arg = total_arg + 1
    if ~ arg4 eq r9
      mov r9, arg4
    end if
  end if
  if ~ arg3 eq
    total_arg = total_arg + 1
    if ~ arg3 eq r8
      mov r8, arg3
    end if
  end if
  if ~ arg2 eq
    total_arg = total_arg + 1
    if ~ arg2 eq rdx
      mov rdx, arg2
    end if
  end if
  if ~ arg1 eq
    total_arg = total_arg + 1
    if ~ arg1 eq rcx
      if ~ arg1 in <ConsoleInHandle, ConIn, \
              ConsoleOutHandle, ConOut, \
              StandardErrorHandle, StdErr, \
              RuntimeServices, BootServices>
        mov rcx, arg1
      end if
    end if
  end if

  xor rax, rax
  mov al, total_arg
  if interface in <ConsoleInHandle, ConIn, ConsoleOutHandle, ConOut, \
        StandardErrorHandle, StdErr, RuntimeServices, \
        BootServices>
    mov r14, [system_table]
    mov r14, [r14 + EFI_SYSTEM_TABLE.#interface]
  else
    if ~ interface eq r14
      mov r14, interface
    end if
  end if
  if arg1 in <ConsoleInHandle, ConIn, ConsoleOutHandle, ConOut, \
        StandardErrorHandle, StdErr, RuntimeServices, BootServices>
    mov rcx, r14
  end if
  if defined EFI_GRAPHICS_OUTPUT_PROTOCOL.#function
    mov r14, [r14 + EFI_GRAPHICS_OUTPUT_PROTOCOL.#function]
  else if defined EFI_BOOT_SERVICES.#function
    mov r14, [r14 + EFI_BOOT_SERVICES.#function]
  else if defined EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.#function
    mov r14, [r14 + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.#function]
  else if defined EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.#function
    mov r14, [r14 + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.#function]
  else
    mov r14, [r14 + function]
  end if

  call uefi_func
}

;
; Library functions
;

section '.text' code executable readable

;
; uefi_func
;
; Note: See the Microsoft's x64 ABI conventions.
;
uefi_func:
  ; Save stack pointer
  mov qword [uefi_rsptmp], rsp
  ; Set up new aligned stack:
  ; As per the Microsoft's x64 calling convention, the stack pointer
  ; must be 16-byte aligned at the point of any function call.
  and esp, 0FFFFFFF0h
  ; Alignment check on arguments:
  ; if total_arg is less than 5, we don't need any stack pointer
  ; alignment. Reason: we only pass 5th and further arguments via the
  ; stack and it might or might not misalign it.
  cmp eax, 5    ; al contains the total_arg from uefi_call_wrapper macro
  jb .before_call
  bt eax, 0
  jnc @f
  push rax      ; Push dummy rax reg value for stack alignment purpose
  ; Arguments
@@:     cmp al, 5
  jb @f
  push r10
@@:
.before_call:
  ; 32 bytes (shadow) space for
  ; r9
  ; r8
  ; rdx
  ; rcx
  sub rsp, 4*8
  ; call function
  call r14
  ; restore old stack
  mov rsp, qword [uefi_rsptmp]
  ret


section '.data' data readable writeable

image_handle  dq 0
system_table  dq 0

uefi_rsptmp   dq 0

Re: UEFI GOP->QueryMode() function doesn't execute the 2nd time

Posted: Tue Nov 10, 2026 5:51 am
by osdev199
I am sorry. I accidentally calculated 6 bytes instead of 8 for `gop` variable.
The following correction worked!

Code: Select all

gop equ qword [rbp - 16]
mode_code equ dword [rbp - 20]