fixed offset in notes
[efitest3] / efitest.asm
1         bits 64
2         org 1000h
3
4 %include "serial.inc"
5
6 BOOT_SERVICES           equ 96
7 BOOT_GET_MEMORY_MAP     equ 56
8 BOOT_EXIT_BOOT_SERVICES equ 232
9
10 start:
11         mov [efihandle], rcx
12         mov [systab], rdx
13
14         ; retrieve memory map
15         ; args: RCX, RDX, R8, and R9.
16         lea rcx, [mmap_size]
17         lea rdx, [mmapbuf]
18         lea r8, [mmap_key]
19         lea r9, [mmap_descsz]
20         lea rax, [mmap_descver]
21         push rax
22         sub rsp, 32
23         mov rax, [systab]
24         mov rbx, [rax + BOOT_SERVICES]
25         call [rbx + BOOT_GET_MEMORY_MAP]
26         add rsp, 40
27         ; exit boot services
28         mov rcx, [efihandle]
29         mov rdx, [mmap_key]
30         mov rax, [systab]
31         mov rbx, [rax + BOOT_SERVICES]
32         call [rbx + BOOT_EXIT_BOOT_SERVICES]
33
34         ; move code to absolute 1000h
35         call get_rip
36 .after_call:
37         sub rax, .after_call - start
38         mov rsi, rax    ; source address
39         mov rdi, start  ; destination
40         mov rcx, end - start
41         shr rcx, 2      ; dwords
42         cld
43         rep movsd       ; copy code to make it absolute
44
45         mov rax, .abs
46         jmp rax
47 .abs:
48         call setup_serial
49
50         ; switch to 32-bit compatibility long mode
51         lgdt [gdtlim]
52         push word 8
53         push qword start32
54         retfq
55
56 get_rip:
57         mov rax, [rsp]
58         ret
59
60         ; serial port setup
61 setup_serial:
62         ; set clock divisor
63         mov al, LCTL_DLAB
64         mov dx, UART_LCTL
65         out dx, al
66         mov ax, DIV_9600
67         mov dx, UART_DIVLO
68         out dx, al
69         mov al, ah
70         mov dx, UART_DIVHI
71         out dx, al
72         ; set format 8n1
73         mov al, LCTL_8N1
74         mov dx, UART_LCTL
75         out dx, al
76         ; clear and enable fifo
77         mov al, FIFO_ENABLE_CLEAR
78         mov dx, UART_FIFO
79         out dx, al
80         ; assert RTS and DTR
81         mov al, MCTL_DTR_RTS_OUT2
82         mov dx, UART_MCTL
83         out dx, al
84         ret
85
86
87 ; ----------- 32bit code ----------
88
89         bits 32
90 start32:
91         mov ax, 10h
92         mov ds, ax
93         mov ss, ax
94         mov es, ax
95         mov gs, ax
96         mov fs, ax
97
98         ; disable paging to deactivate long mode
99         mov eax, cr0
100         and eax, 7fffffffh
101         mov cr0, eax
102
103         ; disable long mode (EFER.LME = 0)
104         ; TODO: EFER is MSR c0000080, LME is bit 8
105         mov ecx, 0c0000080h
106         rdmsr
107         and eax, 0fffffeffh
108         wrmsr
109
110         ; load 16bit IVT descriptor
111         cli     ; just to make sure
112         lidt [rmidt]
113
114         ; load 16bit code segment and jump to 16bit code
115         jmp 0x18:start16
116
117 ; ---------- 16bit real mode code ----------
118
119         bits 16
120 start16:
121         ; disable protection
122         mov eax, cr0
123         and eax, 0fffffffeh
124         mov cr0, eax
125         ; load cs <- 0
126         jmp 0:.loadcs0
127 .loadcs0:
128         ; zero data segments
129         xor ax, ax
130         mov ds, ax
131         mov es, ax
132         mov fs, ax
133         mov gs, ax
134         ; move stack to the top of 640k
135         mov ax, 9000h
136         mov ss, ax
137         xor sp, sp
138
139         call print_ivt
140
141 detect_vbios:
142         ; make sure we have video bios vector installed in 10h
143         mov ax, [10h * 4 + 2]
144         test ax, ax
145         jnz .notnull
146         call init_vbios
147         jnc vbios_present
148         jmp halt
149 .notnull: ; beyond being non-zero, the video bios should really be at c0000h
150         cmp ax, 0c000h
151         jz vbios_present
152         ; unexpected address, make sure it starts with 0aa55h
153         mov es, ax
154         xor bx, bx
155         mov ax, [es:bx]
156         cmp ax, 0aa55h
157         call init_vbios ; seems like garbage, try init
158         jc halt
159
160 vbios_present:
161         mov si, msg_vbios_test
162         call ser_putstr
163
164         ; run 16bit video bios test
165         mov ax, 13h
166         int 10h
167
168         ; setup palette
169         mov dx, 3c8h
170         xor al, al
171         out dx, al
172         inc dx
173         xor cl, cl
174 .pal:   mov al, cl
175         out dx, al
176         xor al, al
177         out dx, al
178         mov al, cl
179         not al
180         out dx, al
181         inc cl
182         jnz .pal
183
184         ; fill framebuffer with xor pattern
185         mov ax, 0a000h
186         mov es, ax
187         xor di, di
188         xor cx, cx
189 .yloop: xor dx, dx
190 .xloop: mov ax, dx
191         xor ax, cx
192         stosb
193         inc dx
194         cmp dx, 320
195         jnz .xloop
196         inc cx
197         cmp cx, 200
198         jnz .yloop
199
200         ; halt for ever
201 halt:   hlt
202         jmp halt
203
204 init_vbios:
205         mov ax, 0c000h
206         mov es, ax
207         xor bx, bx
208         cmp word [es:bx], 0aa55h
209         jz .foundsig
210         mov si, err_vbios_notfound
211         call ser_putstr
212         mov ax, [es:bx]
213         call printhex16
214         mov al, 13
215         call ser_putchar
216         mov al, 10
217         call ser_putchar
218         stc
219         ret
220 .foundsig:
221         mov si, msg_vbios_init
222         call ser_putstr
223         ; don't bother with CRC, just call it
224         push es
225         push word 4
226         mov bp, sp
227         call far [bp]
228         add sp, 4
229         clc
230         ret
231
232 msg_vbios_test db 'running video BIOS test',13,10,0
233 msg_vbios_init db 'attempting to initialize video BIOS',13,10,0
234 err_vbios_notfound db 'failed to initialize video BIOS, sig not found at c0000h: ',0
235
236 print_ivt:
237         xor bx, bx
238 .loop:  mov ax, bx
239         shr ax, 2
240         call printhex8
241         mov al, ' '
242         call ser_putchar
243         mov ax, [bx + 2]        ; segment
244         call printhex16
245         mov al, ':'
246         call ser_putchar
247         mov ax, [bx]            ; offset
248         call printhex16
249         mov al, 13
250         call ser_putchar
251         mov al, 10
252         call ser_putchar
253         add bx, 4
254
255         cmp bx, 33 << 2
256         jnz .loop
257         ret
258
259 hexdig  db '0123456789abcdef'
260
261 printhex8:
262         push bx
263         rol al, 4
264         mov bx, ax
265         and bx, 0fh
266         mov cx, ax
267         mov al, [bx + hexdig]
268         call ser_putchar
269         mov ax, cx
270         rol al, 4
271         mov bx, ax
272         and bx, 0fh
273         mov al, [bx + hexdig]
274         call ser_putchar
275         pop bx
276         ret
277
278 printhex16:
279         push ax
280         mov al, ah
281         call printhex8
282         pop ax
283         call printhex8
284         ret
285
286 ser_putchar:
287         mov ah, al
288         ; wait until transmit register is empty
289         mov dx, UART_LSTAT
290 .wait:  in al, dx
291         and al, LST_TREG_EMPTY
292         jz .wait
293         mov dx, UART_DATA
294         mov al, ah
295         out dx, al
296         ret
297
298 ser_putstr:
299         mov al, [si]
300         test al, al
301         jz .done
302         call ser_putchar
303         inc si
304         jmp ser_putstr
305 .done:  ret
306
307
308 ; ---------- data ------------
309
310         align 8
311 efihandle dq 0
312 systab dq 0
313 ; memory map data
314 mmap_size dq 4096
315 mmap_key dq 0
316 mmap_descsz dq 0
317 mmap_descver dq 0
318
319         align 4096
320 mmapbuf: times 4096 db 0
321
322 str_hello db 'hello!',13,10,0
323
324         align 4
325 gdtlim  dw 31
326 gdtbase dq gdt
327
328         align 8
329 gdt:    ; 0: null segment
330         dd 0, 0
331         ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
332         dd 0x0000ffff
333         dd 0x00cf9a00
334         ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
335         dd 0x0000ffff
336         dd 0x00cf9200
337         ; 3: code16
338         dd 0x0000ffff
339         dd 0x00009a00
340
341
342         align 4
343         ; real mode IDTR pseudo-descriptor pointing to the IVT at addr 0
344         dw 0
345 rmidt:  dw 3ffh
346         dd 0
347
348
349         align 4
350 end:
351 ; vi:ft=nasm: