e038659aa26a533aff600f4d9705f04a741b8692
[rrq/jonasforth.git] / uefi / main.asm
1 ;; vim: syntax=fasm
2
3 format pe64 dll efi
4 entry main
5
6 ;; [TODO] We need to provide the following:
7 ;; - [X] Print a string of a given length
8 ;; - [ ] Print a single character
9 ;; - [ ] Terminate the program (? - What should this do?)
10 ;; - [ ] Read a single character
11 ;;       - This should allow the user to type in a string, and then feed the
12 ;;         buffer to us one character at a time.
13
14 ;; #region Structs
15
16 ;; Based on https://wiki.osdev.org/Uefi.inc
17 macro struct name {
18   virtual at 0
19     name name
20   end virtual
21 }
22
23 struc EFI_TABLE_HEADER {
24   dq ?
25   dd ?
26   dd ?
27   dd ?
28   dd ?
29 }
30
31 struc EFI_SYSTEM_TABLE {
32   .Hdr EFI_TABLE_HEADER
33   .FirmwareVendor dq ? ; CHAR16*
34   .FirmwareRevision dd ? ; UINT32
35   align 8
36   .ConsoleInHandle dq ? ; EFI_HANDLE
37   .ConIn dq ? ; EFI_SIMPLE_TEXT_INPUT_PROTOCOL*
38   .ConsoleOutHandle dq ? ; EFI_HANDLE
39   .ConOut dq ? ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*
40   ; ...
41 }
42 struct EFI_SYSTEM_TABLE
43
44 struc EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
45   .Reset dq ? ; EFI_TEXT_RESET
46   .OutputString dq ? ; EFI_TEXT_STRING
47   ; ...
48 }
49 struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
50
51 ;; #endregion
52
53 section '.text' code executable readable
54
55 main:
56   ; At program startup, RDX contains an EFI_SYSTEM_TABLE*.
57   mov [system_table], rdx
58
59   mov rcx, hello_string
60   mov rdx, hello_string.len
61   call print_string
62
63   mov rcx, hello_string
64   mov rdx, hello_string.len
65   call print_string
66
67   mov rcx, hello_string
68   mov rdx, hello_string.len
69   call print_string
70
71   ret
72
73 ;; Print a string of the given length.
74 ;;
75 ;; Inputs:
76 ;;  - RCX = String buffer
77 ;;  - RDX = String length
78 print_string:
79   mov r8, rcx
80   mov r9, rdx
81
82   mov r10, r9
83   add r10, r10
84
85   ; We take an input string of bytes without any terminator. We need to turn
86   ; this string into a string of words, terminated by a null character.
87   mov rcx, 0
88   mov rsi, 0
89 .copy_byte:
90   cmp rcx, r10
91   je .done
92
93   mov al, byte [r8 + rsi]
94   lea rdx, [.output_buffer + rcx]
95   mov byte [rdx], al
96   inc rcx
97   inc rsi
98
99   lea rdx, [.output_buffer + rcx]
100   mov byte [rdx], 0
101   inc rcx
102
103   jmp .copy_byte
104 .done:
105   lea rdx, [.output_buffer + r10]
106   mov byte [rdx], 0
107
108   ; At this point we have our null-terminated word-string at .output_buffer. Now
109   ; we just need to print it.
110
111   mov rcx, [system_table]                                       ; EFI_SYSTEM_TABLE* rcx
112   mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut]                      ; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* rcx
113   mov rdx, .output_buffer
114   mov rbx, [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString] ; EFI_TEXT_STRING rbx
115   sub rsp, 32
116   call rbx
117   add rsp, 32
118   ret
119
120 section '.data' readable writable
121
122 system_table dq ?  ; EFI_SYSTEM_TABLE*
123
124 hello_string db 'Hello, world!', 0xD, 0xA, 'Here is some more text.', 0xD, 0xA
125 .len = $ - hello_string
126
127 print_string.output_buffer rq 0x400