;
; Hello.asm
; Hello UEFI in assembly
; Flat Assembler v1.71.54
; 2016 MrFox
;

; Symbols and structures

; The UEFI favorite data type: Unsigned Integer Native width
; (32-bit width in 32-bit systems, 64-bit in 64-bit systems)
; I use 32-bit width because my EFI is 32-bit (rd)
; Data alignment must be same as width
; (all UEFI data stuff must be native aligned)
struc UINTN {
  align 4
  . rd 1
}

; Error codes

EFI_SUCCESS				= 0
EFIERR				    = 0x80000000
EFI_LOAD_ERROR			= EFIERR or 1
EFI_INVALID_PARAMETER	= EFIERR or 2
EFI_UNSUPPORTED 		= EFIERR or 3
; Etc (more error codes in EFI spec)


; Our program on entry gets two pointers as arguments:
; ImageHandle and SystemTable (see below at the beginning of code)
; ImageHandle is just like an ID of our running app
; SystemTable is just a table somewhere in memory
; which contains pointers to all functionality of UEFI
; (without it our program is blind and can't contact with UEFI
; functions just because it doesn't know where they are)


; SystemTable structure
virtual at 0
EFI_SYSTEM_TABLE:
 ; Table header
 .Signature				rq	1
 .Revision				UINTN
 .HeaderSize			UINTN
 .CRC32					UINTN
 .Reserved				UINTN
 
 ; Rest of the table
 .FirmwareVendor		UINTN
 .FirmwareRevision		UINTN
 .ConsoleInHandle		UINTN
 .ConIn					UINTN
 .ConsoleOutHandle		UINTN
 .ConOut				UINTN	; We need this one to handle screen output
 .StandardErrorHandle	UINTN
 .StdErr				UINTN
 .RuntimeServices		UINTN
 .BootServices			UINTN
 .NumberOfTableEntries	UINTN
 .ConfigurationTable	UINTN
end virtual

; Simple Text Output is a Protocol (like just a set of functions).
; The ConOut pointer in SystemTable (above) points to the memory address
; where the table described just below is located.
; The table itself contains memory addresses to 'call'
; if we want to use a specific UIFI function

virtual at 0
SIMPLE_TEXT_OUTPUT:
 .Reset 				UINTN
 .OutputString			UINTN	; Calling this address will run this function
 .TestString			UINTN
 .QueryMode				UINTN
 .SetMode				UINTN
 .SetAttribute			UINTN
 .ClearScreen			UINTN
 .SetCursorPosition		UINTN
 .EnableCursor			UINTN
 .Mode					UINTN
end virtual

; Some initial format settings for the linker regarding
; the executable file format used by UEFI
format pe dll efi
entry main
section '.text' code executable readable

; Program entry point

main:
	push ebp

	; get args (ImageHandle and SystemTable pointers)
	mov		eax, [esp+8]
	mov		[ImageHandle], eax

	mov		ebx, [esp+12]
	mov		[SystemTable], ebx

	; Call OutputString function of SIMPLE_TEXT_OUTPUT protocol
	; Function OutputString when entered, looks for two args in the stack:
	; 1. The address of the zero-ended UCS2 string to print
	; 2. The address of the Simple Text Output interface (aka *This in C language)
	; so we 'push' them before calling the function and then
	; restore the stack pointer (add esp,8) when the function returns
	; 8 is the total size of our two args of type UINTN
	; More info is in UEFI spec, page 474 (UEFI Specification Version 2.6)
	; http://www.uefi.org/specifications
	; Pay attention to the reversed order of the arguments pushed on stack
	
	lea		eax, [Text]	
	push	eax			; This is out text address
	mov		eax, [SystemTable]
	mov		ebx, [eax+EFI_SYSTEM_TABLE.ConOut]
	push	ebx			; push ConOut address and call one of its functions
	call	[ebx+SIMPLE_TEXT_OUTPUT.OutputString]
	add		esp, 8		; restore stack pointer (UEFI uses C calling convention)
						; so restoring stack pointer is caller's responsibility
	;	Exit program
	mov		eax, EFI_SUCCESS
	pop		ebp
	ret

section '.data' data readable writeable

ImageHandle		dd		?
SystemTable		dd		?
Text			du 		'Hello UEFI',13,10,0	; 13 and 10 are Line Feed and Form Feed characters

section '.reloc' fixups data discardable
