X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=uefi%2Fmain.asm;h=431a64c9d1267c846c47279630a680b34dff7e69;hb=9e21256a9103dc92035bdef940b342522ea3efb3;hp=aa34ddc9deba4c768e5a3742bc242b3d32c4be12;hpb=df3ce369bb20f34ce81e5c03089dbbe35e4b37df;p=rrq%2Fjonasforth.git diff --git a/uefi/main.asm b/uefi/main.asm index aa34ddc..431a64c 100644 --- a/uefi/main.asm +++ b/uefi/main.asm @@ -1,7 +1,25 @@ +;; vim: syntax=fasm + format pe64 dll efi entry main -;; #region Structs +;; [TODO] We need to provide the following: +;; - [X] Print a string of a given length +;; - [ ] Print a single character +;; - [ ] Terminate the program (? - What should this do?) +;; - [X] Read a single character +;; - This should allow the user to type in a string, and then feed the +;; buffer to us one character at a time. +;; - [ ] We want to show the user's input on the screen while reading +;; - [ ] Read a file that was bundled with the program +;; - It looks like we can use EFI_LOAD_FILE_PROTOCOL.LoadFile() to load +;; a file into a buffer. In order to be able to use this, we need to +;; have some way of interpreting a static buffer instead of reading as +;; we go. + +;; EFI struct definitions {{{ + +EFI_NOT_READY = 0x8000_0000_0000_0000 or 6 ;; Based on https://wiki.osdev.org/Uefi.inc macro struct name { @@ -38,7 +56,21 @@ struc EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL { } struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL -;; #endregion +struc EFI_SIMPLE_TEXT_INPUT_PROTOCOL { + .Reset dq ? ; EFI_INPUT_RESET + .ReadKeyStroke dq ? ; EFI_INPUT_READ_KEY + ; ... +} +struct EFI_SIMPLE_TEXT_INPUT_PROTOCOL + +struc EFI_INPUT_KEY { + .ScanCode dw ? ; UINT16 + .UnicodeChar dw ? ; CHAR16 + align 8 +} +struct EFI_INPUT_KEY + +;; }}} section '.text' code executable readable @@ -46,20 +78,103 @@ main: ; At program startup, RDX contains an EFI_SYSTEM_TABLE*. mov [system_table], rdx + mov rcx, hello_string + mov rdx, hello_string.len + call print_string + + mov rcx, char_buffer + call read_char + + mov rcx, char_buffer + mov rdx, 1 + call print_string + + mov rcx, hello_string + mov rdx, hello_string.len + call print_string + + ret + +;; Print a string of the given length. +;; +;; Inputs: +;; - RCX = String buffer +;; - RDX = String length +print_string: + mov r8, rcx + mov r9, rdx + + mov r10, r9 + add r10, r10 + + ; We take an input string of bytes without any terminator. We need to turn + ; this string into a string of words, terminated by a null character. + mov rcx, 0 + mov rsi, 0 +.copy_byte: + cmp rcx, r10 + je .done + + mov al, byte [r8 + rsi] + lea rdx, [.output_buffer + rcx] + mov byte [rdx], al + inc rcx + inc rsi + + lea rdx, [.output_buffer + rcx] + mov byte [rdx], 0 + inc rcx + + jmp .copy_byte +.done: + lea rdx, [.output_buffer + r10] + mov byte [rdx], 0 + + ; At this point we have our null-terminated word-string at .output_buffer. Now + ; we just need to print it. + + mov rcx, [system_table] ; EFI_SYSTEM_TABLE* rcx + mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* rcx + mov rdx, .output_buffer + mov rbx, [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString] ; EFI_TEXT_STRING rbx + sub rsp, 32 + call rbx + add rsp, 32 + ret + +;; Read a character as an ASCII byte into the given buffer. +;; +;; Inputs: +;; - RCX = Character buffer (1 byte) +read_char: + mov r15, rcx +.read_key: mov rcx, [system_table] ; EFI_SYSTEM_TABLE* rcx - mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* rcx - mov rdx, hello_world_string - ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* rcx, CHAR16* rdx) - mov rbx, [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString] ; EFI_TEXT_STIRNG rbx + mov rcx, [rcx + EFI_SYSTEM_TABLE.ConIn] ; EFI_SIMPLE_TEXT_INPUT_PROTOCOL* rcx + mov rbx, [rcx + EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke] ; EFI_INPUT_READ_KEY rbx + mov rdx, input_key ; EFI_INPUT_KEY* rdx sub rsp, 32 call rbx add rsp, 32 - mov rax, 0 + mov r8, EFI_NOT_READY + cmp rax, r8 + je .read_key + + mov ax, [input_key.UnicodeChar] + mov [r15], al + ret section '.data' readable writable system_table dq ? ; EFI_SYSTEM_TABLE* -hello_world_string du 'Hello world!', 0xC, 0xA, 0 +hello_string db 'Hello, world!', 0xD, 0xA, 'Here is some more text.', 0xD, 0xA +.len = $ - hello_string + +print_string.output_buffer rq 0x400 + +char_buffer db ? + +input_key EFI_INPUT_KEY