Add notes about loading files from disk
[rrq/jonasforth.git] / uefi / main.asm
index aa34ddc9deba4c768e5a3742bc242b3d32c4be12..431a64c9d1267c846c47279630a680b34dff7e69 100644 (file)
@@ -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