ae804dd74e5f87eb9c4101610b560935fc4bc576
[efitest3] / efitest.asm
1 ; vi:ft=nasm:
2         bits 64
3         org 1000h
4
5 BOOT_SERVICES           equ 96
6 BOOT_GET_MEMORY_MAP     equ 56
7 BOOT_EXIT_BOOT_SERVICES equ 232
8
9 start:
10         mov [efihandle], rcx
11         mov [systab], rdx
12
13         ; retrieve memory map
14         ; args: RCX, RDX, R8, and R9.
15         lea rcx, [mmap_size]
16         lea rdx, [mmapbuf]
17         lea r8, [mmap_key]
18         lea r9, [mmap_descsz]
19         lea rax, [mmap_descver]
20         push rax
21         sub rsp, 32
22         mov rax, [systab]
23         mov rbx, [rax + BOOT_SERVICES]
24         call [rbx + BOOT_GET_MEMORY_MAP]
25         add rsp, 40
26         ; exit boot services
27         mov rcx, [efihandle]
28         mov rdx, [mmap_key]
29         mov rax, [systab]
30         mov rbx, [rax + BOOT_SERVICES]
31         call [rbx + BOOT_EXIT_BOOT_SERVICES]
32
33         ; move code to absolute 1000h
34         call get_rip
35 .after_call:
36         sub rax, .after_call - start
37         mov rsi, rax    ; source address
38         mov rdi, start  ; destination
39         mov rcx, end - start
40         shr rcx, 2      ; dwords
41         cld
42         rep movsd       ; copy code to make it absolute
43
44         mov rax, .abs
45         jmp rax
46 .abs:
47         call setup_serial
48
49         ; switch to 32-bit compatibility long mode
50         lgdt [gdtlim]
51         push word 8
52         push qword start32
53         retfq
54
55
56 .hang:  jmp .hang
57
58 get_rip:
59         mov rax, [rsp]
60         ret
61
62
63 UART_DATA               equ 0x3f8
64 UART_DIVLO              equ 0x3f8
65 UART_DIVHI              equ 0x3f9
66 UART_FIFO               equ 0x3fa
67 UART_LCTL               equ 0x3fb
68 UART_MCTL               equ 0x3fc
69 UART_LSTAT              equ 0x3fd
70 DIV_9600                equ 115200 / 9600
71 LCTL_8N1                equ 0x03
72 LCTL_DLAB               equ 0x80
73 FIFO_ENABLE_CLEAR       equ 0x07
74 MCTL_DTR_RTS_OUT2       equ 0x0b
75 LST_TREG_EMPTY          equ 0x20
76
77         ; serial port setup
78 setup_serial:
79         ; set clock divisor
80         mov al, LCTL_DLAB
81         mov dx, UART_LCTL
82         out dx, al
83         mov ax, DIV_9600
84         mov dx, UART_DIVLO
85         out dx, al
86         mov al, ah
87         mov dx, UART_DIVHI
88         out dx, al
89         ; set format 8n1
90         mov al, LCTL_8N1
91         mov dx, UART_LCTL
92         out dx, al
93         ; clear and enable fifo
94         mov al, FIFO_ENABLE_CLEAR
95         mov dx, UART_FIFO
96         out dx, al
97         ; assert RTS and DTR
98         mov al, MCTL_DTR_RTS_OUT2
99         mov dx, UART_MCTL
100         out dx, al
101         ret
102
103
104         align 8
105 efihandle dq 0
106 systab dq 0
107 ; memory map data
108 mmap_size dq 4096
109 mmap_key dq 0
110 mmap_descsz dq 0
111 mmap_descver dq 0
112
113         align 4096
114 mmapbuf: times 4096 db 0
115
116 str_hello db 'hello!',13,10,0
117
118         align 4
119 gdtlim  dw 31
120 gdtbase dq gdt
121
122         align 8
123 gdt:    ; 0: null segment
124         dd 0, 0
125         ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
126         dd 0x0000ffff
127         dd 0x00cf9a00
128         ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
129         dd 0x0000ffff
130         dd 0x00cf9200
131         ; 3: code16
132         dd 0x0000ffff
133         dd 0x00009a00
134
135         bits 32
136 start32:
137         mov ax, 10h
138         mov ds, ax
139         mov ss, ax
140         mov es, ax
141         mov gs, ax
142         mov fs, ax
143
144         ; disable paging to deactivate long mode
145         mov eax, cr0
146         and eax, 7fffffffh
147         mov cr0, eax
148
149         ; disable long mode (EFER.LME = 0)
150         ; TODO: EFER is MSR c0000080, LME is bit 8
151         mov ecx, 0c0000080h
152         rdmsr
153         and eax, 0fffffeffh
154         wrmsr
155
156         ; load 16bit code segment and jump to 16bit code
157         jmp 0x18:start16
158
159 .hang:  hlt
160         jmp .hang
161
162         
163 ser_putchar:
164         mov ah, al
165         ; wait until transmit register is empty
166         mov dx, UART_LSTAT
167 .wait:  in al, dx
168         and al, LST_TREG_EMPTY
169         jz .wait
170         mov dx, UART_DATA
171         mov al, ah
172         out dx, al
173         ret
174
175 ser_putstr:
176         mov al, [esi]
177         test al, al
178         jz .done
179         call ser_putchar
180         inc esi
181         jmp ser_putstr
182 .done:  ret
183
184
185         align 4
186         ; real mode IDTR pseudo-descriptor pointing to the IVT at addr 0
187         dw 0
188 rmidt:  dw 3ffh
189         dd 0
190
191         bits 16
192 start16:
193         ; disable protection
194         mov eax, cr0
195         and eax, 0fffffffeh
196         mov cr0, eax
197         ; load cs <- 0
198         jmp 0:.loadcs0
199 .loadcs0:
200         ; zero data segments
201         xor ax, ax
202         mov ds, ax
203         mov es, ax
204         mov fs, ax
205         mov gs, ax
206         ; move stack to the top of 640k
207         mov ax, 9000h
208         mov ss, ax
209         xor sp, sp
210
211         ; run 16bit video bios test
212         mov ax, 13h
213         ;int 10h
214
215         mov ax, 0a000h
216         mov es, ax
217         xor di, di
218         mov cx, 32000
219         mov ax, 6767h
220         rep stosw
221
222 .hang:  hlt
223         jmp .hang
224
225         align 4
226 end: