194 lines
5.8 KiB
NASM
194 lines
5.8 KiB
NASM
format pe64 dll efi
|
|
entry main
|
|
|
|
; The UEFI calling convention is, as told in the documentation, the same
|
|
; as the standard cdecl but for convenience (because it looks like cdecl
|
|
; isn't that much standardized) here it is (in C-like notation):
|
|
;
|
|
; rax func(rcx, rdx, r8, r9, rsp+32, rsp+64, ...)
|
|
;
|
|
; basically the rest of arguments is passed through the stack with 32bit
|
|
; offset as it was designed for variadic functions
|
|
|
|
; Also important fact about uefi is that uefi apps are called images.
|
|
; for further reading I think I recommend the official uefi documentation
|
|
; I'm not sure because maybe there might be better source
|
|
|
|
; macro that saves the most important registers and calls the function
|
|
macro call_safe func
|
|
{
|
|
push rcx
|
|
push rbx
|
|
call func
|
|
pop rbx
|
|
pop rcx
|
|
}
|
|
|
|
|
|
section '.text' code executable readable
|
|
|
|
include 'uefi.inc'
|
|
|
|
main:
|
|
; storing the args that the main function is called with
|
|
; main(*ImageHandle, *SystemTable)
|
|
mov [ImgHdl], rcx
|
|
mov [SysTbl], rdx
|
|
|
|
sub rsp, 6*8+8
|
|
|
|
; storing the most used structures for faster use
|
|
mov rax, [rdx + EFI_SYSTEM_TABLE.BootServices]
|
|
mov [BootSrvc], rax
|
|
mov rax, [rdx + EFI_SYSTEM_TABLE.ConOut]
|
|
mov [Output], rax
|
|
|
|
; preparing args and calling
|
|
; ConOut.SetAttribute(Output, BG_CLR | FG_CLR)
|
|
mov rax, EFI_BACKGROUND_BLACK or EFI_GREEN
|
|
|
|
mov rcx, [Output]
|
|
call_safe [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.SetAttribute]
|
|
|
|
; clearing the screen
|
|
; ConOut.ClearScreen(ConOut)
|
|
mov rcx, [Output]
|
|
call_safe [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen]
|
|
|
|
; printing the initial message to indicate
|
|
; that the bootloader started successfully
|
|
mov rdx, BootMsg
|
|
call print
|
|
|
|
.GetGOP:
|
|
mov rcx, EFI_GRAPHICS_OUTPUT_UUID
|
|
mov rdx, 3
|
|
mov r8, Video
|
|
|
|
mov rax, [BootSrvc]
|
|
call_safe [rax + EFI_BOOT_SERVICES_TABLE.LocateProtocol]
|
|
|
|
cmp rax, EFI_SUCCES
|
|
jne .error
|
|
|
|
mov rax, [Video]
|
|
mov rbx, [rax + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.MaxMode]
|
|
|
|
jmp .
|
|
; TODO: Get and store framebuffer
|
|
|
|
; Getting the memory map is kind of harder (not in this case), normally
|
|
; you would need to call the function two times to get the buffer size
|
|
; then allocate it (+ some padding because it will expand because of the
|
|
; allocation) and then call it again, but as I'm storing it somewhere
|
|
; in memory, I'm not using for now, I can just call it two times without
|
|
; the allocation.
|
|
; BootServices.GetMemoryMap(
|
|
; *MemMapSize,
|
|
; *MemMapBuffer,
|
|
; *MemMapKey,
|
|
; *MemMapDescSize,
|
|
; *MemMapDescVer)
|
|
.GetMemMap:
|
|
mov rax, [BootSrvc]
|
|
|
|
mov rcx, MemMapSize
|
|
mov rdx, [MemMapBuff]
|
|
mov r8, MemMapKey
|
|
mov r9, MemMapDescSize
|
|
; notice the last argument is moved to r10 and then "pushed" to the stack
|
|
; with 32bit offset
|
|
mov r10, 0
|
|
mov [rsp+32], r10
|
|
|
|
call [rax + EFI_BOOT_SERVICES_TABLE.GetMemoryMap]
|
|
|
|
; if it returns buffer too small run the function again as it filled out
|
|
; the needed buffer length
|
|
cmp al, EFI_BUFFER_TOO_SMALL
|
|
pushf
|
|
|
|
; preparing args and calling
|
|
; BootServices.ExitBootServices(*ImegeHandle, *MemMapKey)
|
|
mov rcx, [ImgHdl]
|
|
mov rdx, [MemMapKey]
|
|
|
|
mov rax, [BootSrvc]
|
|
call_safe [rax + EFI_BOOT_SERVICES_TABLE.ExitBootServices]
|
|
|
|
cmp rax, EFI_SUCCESS
|
|
je .after
|
|
|
|
mov rdx, ErrMsg
|
|
call print
|
|
|
|
popf
|
|
je .GetMemMap
|
|
|
|
.after:
|
|
mov rdx, OKMsg
|
|
call print
|
|
|
|
mov eax, EFI_SUCCESS
|
|
jmp .exit
|
|
|
|
; if it returned something else it maybe a problem possible TODO: proper
|
|
; error handling for now it just puts out error and exits with non-zero code
|
|
; cmp rax, EFI_SUCCESS
|
|
; jne .error
|
|
|
|
; print a message saying that we didn't f**k up yet...
|
|
;mov rdx, OKMsg
|
|
;call print
|
|
|
|
; preparing args and calling
|
|
; BootServices.ExitBootServices(*ImegeHandle, *MemMapKey)
|
|
; mov rcx, [ImgHdl]
|
|
; mov rdx, [MemMapKey]
|
|
|
|
; mov rax, [BootSrvc]
|
|
; call_safe [rax + EFI_BOOT_SERVICES_TABLE.ExitBootServices]
|
|
|
|
; cmp rax, EFI_SUCCESS
|
|
; jne .error
|
|
|
|
; mov eax, EFI_SUCCESS
|
|
; jmp .exit
|
|
|
|
.error:
|
|
mov rdx, ErrMsg
|
|
call print
|
|
mov eax, 1
|
|
|
|
.exit:
|
|
ret
|
|
|
|
; print the string in rdx
|
|
print:
|
|
mov rcx, [Output]
|
|
call_safe [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString]
|
|
ret
|
|
|
|
; Should not be reachable
|
|
hlt
|
|
jmp $
|
|
|
|
section '.data' data readable writeable
|
|
|
|
ImgHdl dq ?
|
|
SysTbl dq ?
|
|
BootSrvc dq ?
|
|
Output dq ?
|
|
Video dq ?
|
|
|
|
MemMapSize dq 32768
|
|
MemMapKey dq ?
|
|
MemMapDescSize dq ?
|
|
MemMapDescVer dq ?
|
|
MemMapBuff dq 0x220000
|
|
|
|
BootMsg du '[BOOT]: Booting the system...',13,10,0
|
|
ErrMsg du '[BOOT]: There was an error :(',13,10,0
|
|
OKMsg du '[BOOT]: Everything is OK :), for now...',13,10,0
|
|
|
|
section '.reloc' fixups data discardable
|