News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Unified Extensible Firmware Interface (UEFI) Example

Started by LiaoMi, June 29, 2019, 04:04:18 AM

Previous topic - Next topic

LiaoMi

Hi,

cool example, uefi using assembler, the example is written in Nasm, but I think it is easy to convert, this example can be run and tested on qemu  :eusa_boohoo: https://github.com/charlesap/nasm-uefi/archive/master.zip

Quotebare-bones nasm uefi application

build with:

nasm -f bin yo.asm -o yo.efi
sudo mount uefi.iso /mnt
sudo cp yo.efi /mnt/
sudo umount /mnt
Launch QEMU with:

/usr/bin/qemu-system-x86_64 -machine accel=kvm -name guest=uefiguest -machine pc,accel=kvm,usb=off,dump-guest-core=off -smp 2,sockets=2,cores=1,threads=1 -uuid 515645b7-ab3a-4e82-ba62-25751e4b523f -bios ./OVMF.fd -m 1G -vga qxl -spice port=5900,addr=127.0.0.1,disable-ticketing -drive file=uefi.iso
Launch the Spice viewer with:

remote-viewer spice://localhost:5900
In the viewer, at the prompt enter 'fs0:'

Then enter 'yo'

bits 64
org  0x200000
section .header

DOS:
    dd 0x00005a4d       
    times 14 dd 0
    dd 0x00000080
    times 16 dd 0

PECOFF:
        dd `PE\0\0`     ; sig
    dw 0x8664       ; type
    dw 3            ; sections
    dd 0x5cba52f6       ; timestamp
    dq 0            ; * symbol table + # symbols
    dw osize        ; oheader size
    dw 0x202e       ; characteristics

OHEADER:
    dd 0x0000020b       ; oheader + 0000 linker sig
    dd 4096 ;codesize       ; code size
    dd 8192 ;datasize       ; data size
    dd 0            ; uninitialized data size
    dd 4096         ; * entry
    dd 4096         ; * code base
    dq 0x200000        ; * image base
    dd 4096         ; section alignment
    dd 4096         ; file alignment
    dq 0            ; os maj, min, image maj, min
    dq 0            ; subsys maj, min, reserved
    dd 0x4000       ; image size
    dd 4096         ; headers size
    dd 0            ; checksum
    dd 0x0040000A       ; dll characteristics & subsystem
    dq 0x10000      ; stack reserve size
    dq 0x10000      ; stack commit size
    dq 0x10000      ; heap reserve size
    dq 0            ; heap reserve commit
    dd 0            ; loader flags
    dd 0x10         ; rva count

DIRS:
    times 5 dq 0        ; unused
    dd 0x004000        ; virtual address .reloc
    dd 0            ; size .reloc
        times 10 dq 0       ; unused
OEND:
osize equ OEND - OHEADER

SECTS:
.1:
    dq  `.text`     ; name
    dd  4096 ;codesize      ; virtual size
    dd  4096        ; virtual address   
    dd  4096        ; raw data size
    dd  4096        ; * raw data
    dq  0           ; * relocations, * line numbers
    dd  0           ; # relocations, # line numbers
    dd  0x60000020      ; characteristics

.2:
        dq  `.data`
        dd  8192 ;datasize     
        dd  8192
        dd  8192
        dd  8192       
        dq  0
        dd  0
        dd  0xC0000040     


.3:
    dq  `.reloc`
    dd  0   
    dd  0 ;20480
    dd  0
    dd  0 ;20480
    dq  0
    dd  0
    dd  0x02000040

    times 4096 - ($-$$) db 0  ;align the text section on a 4096 byte boundary

section .text follows=.header

EFI_SUCCESS                                 equ 0
EFI_SYSTEM_TABLE_SIGNATURE                  equ 0x5453595320494249
EFI_SYSTEM_TABLE_CONOUT                         equ 64
EFI_SYSTEM_TABLE_RUNTIMESERVICES                equ 88
EFI_SYSTEM_TABLE_BOOTSERVICES                   equ 96

EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_RESET           equ 0
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING        equ 8

EFI_BOOT_SERVICES_GETMEMORYMAP              equ 56
EFI_BOOT_SERVICES_LOCATEHANDLE              equ 176
EFI_BOOT_SERVICES_LOADIMAGE             equ 200
EFI_BOOT_SERVICES_EXIT                  equ 216
EFI_BOOT_SERVICES_EXITBOOTSERVICES          equ 232
EFI_BOOT_SERVICES_LOCATEPROTOCOL            equ 320

EFI_RUNTIME_SERVICES_RESETSYSTEM            equ 104


sub rsp, 6*8   
mov [Handle], rcx         
mov [SystemTable], rdx   

mov rax, [SystemTable]
mov rax, [rax + EFI_SYSTEM_TABLE_BOOTSERVICES]
mov [BS], rax

mov rax, [SystemTable]
mov rax, [rax + EFI_SYSTEM_TABLE_RUNTIMESERVICES]
mov [RTS], rax

lea rdx, [herewego]
mov rcx, [SystemTable]
mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT]
call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING]

; get the memory map
mov qword [memmapsize], 4096
lea rcx, [memmapsize]
lea rdx, [memmap]
lea r8, [memmapkey]
lea r9, [memmapdescsize]
lea r10, [memmapdescver]
mov [STK],rsp
push r10
sub rsp, 4*8
mov rbx, [BS]
call [rbx + EFI_BOOT_SERVICES_GETMEMORYMAP]
add rsp, 4*8
pop r10
mov rsp, [STK]
cmp rax, EFI_SUCCESS
jne oops

; find the interface to GOP
mov rbx, [SystemTable]
mov rbx, [rbx + EFI_SYSTEM_TABLE_BOOTSERVICES]
mov rcx, _EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID
mov rdx, 0
lea r8, [Interface]
call [rbx + EFI_BOOT_SERVICES_LOCATEPROTOCOL]
cmp rax, EFI_SUCCESS
jne oops

mov rcx, [Interface]
mov rcx, [rcx + 0x18 ] ;EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
mov rbx, [rcx + 0x18 ] ;EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE_FRAMEBUFFERBASE
mov [FB], rbx
mov rcx, [rcx + 0x20 ] ;EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE_FRAMEBUFFERSIZE
mov [FBS], rcx
cmp rax, EFI_SUCCESS
jne oops

       mov rbx, [FB]
       push rax
       push rcx
       push rdx
       call printhex
       pop rdx
       pop rcx
       pop rax

       mov rbx, [FBS]
       push rax
       push rcx
       push rdx
       call printhex
       pop rdx
       pop rcx
       pop rax

; exit boot services
mov rcx, [Handle]
mov rdx, [memmapkey]
mov rbx, [SystemTable]
mov rbx, [rbx + EFI_SYSTEM_TABLE_BOOTSERVICES]
call [rbx + EFI_BOOT_SERVICES_EXITBOOTSERVICES]
cmp rax, EFI_SUCCESS
je g5

       mov rbx, [memmapkey]
       push rax
       push rcx
       push rdx
       call printhex
       pop rdx
       pop rcx
       pop rax

; repeat the call to get the memory map
mov qword [memmapsize], 4096
lea rcx, [memmapsize]
lea rdx, [memmap]
lea r8, [memmapkey]
lea r9, [memmapdescsize]
lea r10, [memmapdescver]
mov [STK],rsp
push r10
sub rsp, 4*8
mov rbx, [BS]
call [rbx + EFI_BOOT_SERVICES_GETMEMORYMAP]
add rsp, 4*8
pop r10
mov rsp, [STK]
cmp rax, EFI_SUCCESS
jne oops

       mov rbx, [memmapkey]
       push rax
       push rcx
       push rdx
       call printhex
       pop rdx
       pop rcx
       pop rax

; exit boot services again
mov rcx, [Handle]
mov rdx, [memmapkey]
xor r8, r8
mov rbx, [SystemTable]
mov rbx, [rbx + EFI_SYSTEM_TABLE_BOOTSERVICES]
call [rbx + EFI_BOOT_SERVICES_EXITBOOTSERVICES]
;cmp rax, EFI_SUCCESS
;je g5
;jmp oops

Z:
jmp Z

mov rcx, [FB]
mov rax, [FBS]
Q:
dec rax
mov byte[rcx+rax],255
jnz Q

W:
jmp W

g5:
mov rcx, 2 ;EfiResetShutdown   
mov rdx, EFI_SUCCESS
mov rax, [SystemTable]
mov rax, [rax + EFI_SYSTEM_TABLE_RUNTIMESERVICES]
call [rax + EFI_RUNTIME_SERVICES_RESETSYSTEM]

oops:
lea rdx, [fail]
mov rcx, [SystemTable]
mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT]
call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING]
jmp $-1

printhex:
mov rbp, 16
.loop:
rol rbx, 4
mov rax, rbx
and rax, 0Fh
lea rcx, [_Hex]
mov rax, [rax + rcx]
mov byte [_Num], al
        lea rdx, [_Num]
        mov rcx, [SystemTable]
        mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT]
        call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING]
dec rbp
jnz .loop
lea rdx, [_Nl]
mov rcx, [SystemTable]
mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT]
call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING]

ret

    times 8192-($-$$) db 0 

codesize equ $ - $$

section .data follows=.text

Handle          dq 0
SystemTable     dq 0
Interface       dq 0
BS dq 0
RTS dq 0
STK         dq 0
FB              dq 0
FBS             dq 0
memmapsize      dq 4096
memmapkey       dq 0
memmapdescsize  dq 48
memmapdescver   dq 0

_EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID db 0xde, 0xa9, 0x42, 0x90, 0xdc, 0x23, 0x38, 0x4a
                                  db 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a
fail     db __utf16__ `fail.\r\n\0`
nok      db __utf16__ `Not OK.\r\n\0`
yok      db __utf16__ `OK.\r\n\0`
herewego db __utf16__ `here we go\r\n\0`
_Hex     db '0123456789ABCDEF'
_Num     dw 0,0
_Nl      dw 13,10,0

    times 4096-($-$$) db 0

memmap:
    times 4096 db 0

datasize equ $ - $$


section .reloc follows=.data

johnsa

So I got quite excited about playing with UEFI again.. So for UASM 2.50 release I've created a new custom EFI.INC with all the type/structs hand ported from the C headers.. I will be making a tutorial for it explaining in detail how to setup UEFI and get it booting on real h/w, Virtual BOX etc with a simple build and debug process for creating UEFI apps and boot files.. Just to give you an example of how the header port works in UASM (a lot nicer than NASM ;) )




OPTION WIN64:15
OPTION STACKBASE:RSP
OPTION LITERALS:ON
OPTION ARCH:AVX
OPTION CASEMAP:NONE

include efi.inc

.data

Handle         dq 0
SystemTablePtr dq 0
HelloMsg       dw 'Hello UEFI World!',13,10,0
pConsole       PCONOUT 0
pBootServices  P_BOOT_SERVICES 0

mapSize     UINTN  64*SIZEOF(EFI_MEMORY_DESCRIPTOR)
descriptors EFI_MEMORY_DESCRIPTOR 64 DUP (<?>)
mapKey      UINTN  0
descSize    UINTN  0
descVer     UINT32 0

.code

Main PROC FRAME imageHandle:EFI_HANDLE, SystemTable:PTR_EFI_SYSTEM_TABLE

mov Handle,rcx
mov SystemTablePtr,rdx

;=====================================================================================
; The normal ASM way to make a 64bit FASTCALL.
;=====================================================================================
sub rsp,20h
lea rdx,HelloMsg
mov rcx,SystemTablePtr
mov rcx,[rcx + EFI_SYSTEM_TABLE_CONOUT]
call qword ptr [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING]
add rsp,20h

;=====================================================================================
; The smarter UASM way...
;=====================================================================================
mov rcx,SystemTablePtr
mov rcx,[rcx].EFI_SYSTEM_TABLE.ConOut
mov pConsole,rcx
invoke [rcx].ConOut.OutputString, pConsole, L"Hello Smarter UEFI World!\r\n"

; Or if you have a list of calls to make against the same protocol/interface
ASSUME rcx:PTR ConOut
mov rcx,pConsole
invoke [rcx].OutputString, pConsole, ADDR HelloMsg
ASSUME rcx:NOTHING

;=====================================================================================
; The even smarter ways...
;=====================================================================================
pConsole->OutputString(pConsole, L"Testing\r\n")
; or
mov rax,pConsole
[rax].ConOut->OutputString(pConsole, L"Testing2\r\n")

pConsole->ClearScreen()

;=====================================================================================
; Store pointer to the BOOT SERVICES Interface
;=====================================================================================
mov rax,SystemTablePtr
mov rsi,[rax].EFI_SYSTEM_TABLE.BootServices
mov pBootServices,rsi

; Get Memory Map
[rsi].BOOT_SERVICES->GetMemoryMap(&mapSize, &descriptors, &mapKey, &descSize, &descVer)
.if(rax != EFI_SUCCESS)
pConsole->OutputString(pConsole, L"Failed to get memory map\r\n")
pBootServices->Exit(Handle, EFI_ERROR, 36, L"Memory Map Error\r\n")
.else
pConsole->OutputString(pConsole, L"Got memory map\r\n")
.endif

mov eax,EFI_SUCCESS

ret
Main ENDP

END Main



johnsa

Busy adding in the GOP protocol now, curious to see how raw framebuffer access performs under UEFI as previously I had quite good performance from a VBE frame-buffer in a raw 64bit OS setup as  long as the buffer was mapped write-combining.

johnsa


Hi,

The includes, library examples and guide are now complete and available on the website. Please note this only works with UASM 2.50 which will be available soon as binary packages. In the meantime the 2.50 branch is available in Github.

Please let me know if you have any reports or questions and happy UEFI coding in UASM! :) (I know I have been)

John

aw27

I am not seeing
RAWINTERFACE
ENDRAWINTERFACE
STDFUNC
defined anywhere.


johnsa

My bad, I'd forgotten to push the repo changes. They're in 2.50 branch now along with a few missing return values pointed out by TimoVJL.

I have two more fixes to add and then it should be ready.

TimoVJL

#6
uasm 2.50  :undecided:
\masm32\m32lib\a2wc.asm(14) : Error A2143: Symbol redefinition: memalign
...
May the source be with you

johnsa

memalign is a built-in macro, did that source compile before ?

TimoVJL

May the source be with you

johnsa

An option would be to compile the source using the no macro lib switch ?
The change is possibly that I've added some more case insensitive options to the macrolib IE MEMALIGN vs memalign.

TimoVJL

#10
DELETED
May the source be with you

aw27

; empty line
.x64p
OPTION WIN64:15
OPTION STACKBASE:RSP
OPTION LITERALS:ON
OPTION ARCH:AVX ; <- Builds if removed
OPTION CASEMAP:NONE


johnsa

That's odd, I can't reproduce that error here. Is that the exact hello.asm file from the package ?


aw27

Quote from: johnsa on October 20, 2019, 02:22:07 AM
That's odd, I can't reproduce that error here. Is that the exact hello.asm file from the package ?
It is the UEFI hello.asm from your website. I tested in 2 different computers, in 2 different OSs and with 2 builds of UASM-64 (VS 2019 and the Timo's (Pelles)).

TimoVJL

#14
 :sad:
May the source be with you