0feb61dcb06a7c5825efb0ebfeb06bdfc27d733c
[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         ; run 16bit video bios test
142         mov ax, 13h
143         int 10h
144
145         ; setup palette
146         mov dx, 3c8h
147         xor al, al
148         out dx, al
149         inc dx
150         xor cl, cl
151 .pal:   mov al, cl
152         out dx, al
153         xor al, al
154         out dx, al
155         mov al, cl
156         not al
157         out dx, al
158         inc cl
159         jnz .pal
160
161         ; fill framebuffer with xor pattern
162         mov ax, 0a000h
163         mov es, ax
164         xor di, di
165         xor cx, cx
166 .yloop: xor dx, dx
167 .xloop: mov ax, dx
168         xor ax, cx
169         stosb
170         inc dx
171         cmp dx, 320
172         jnz .xloop
173         inc cx
174         cmp cx, 200
175         jnz .yloop
176
177         ; halt for ever
178 .hang:  hlt
179         jmp .hang
180
181 print_ivt:
182         xor bx, bx
183 .loop:  mov ax, bx
184         shr ax, 2
185         call printhex8
186         mov al, ' '
187         call ser_putchar
188         mov ax, [bx + 2]        ; segment
189         call printhex16
190         mov al, ':'
191         call ser_putchar
192         mov ax, [bx]            ; offset
193         call printhex16
194         mov al, 13
195         call ser_putchar
196         mov al, 10
197         call ser_putchar
198         add bx, 4
199
200         cmp bx, 64 << 2
201         jnz .loop
202         ret
203
204 hexdig  db '0123456789abcdef'
205
206 printhex8:
207         push bx
208         rol al, 4
209         mov bx, ax
210         and bx, 0fh
211         mov cx, ax
212         mov al, [bx + hexdig]
213         call ser_putchar
214         mov ax, cx
215         rol al, 4
216         mov bx, ax
217         and bx, 0fh
218         mov al, [bx + hexdig]
219         call ser_putchar
220         pop bx
221         ret
222
223 printhex16:
224         push ax
225         mov al, ah
226         call printhex8
227         pop ax
228         call printhex8
229         ret
230
231 ser_putchar:
232         mov ah, al
233         ; wait until transmit register is empty
234         mov dx, UART_LSTAT
235 .wait:  in al, dx
236         and al, LST_TREG_EMPTY
237         jz .wait
238         mov dx, UART_DATA
239         mov al, ah
240         out dx, al
241         ret
242
243 ser_putstr:
244         mov al, [si]
245         test al, al
246         jz .done
247         call ser_putchar
248         inc si
249         jmp ser_putstr
250 .done:  ret
251
252
253 ; ---------- data ------------
254
255         align 8
256 efihandle dq 0
257 systab dq 0
258 ; memory map data
259 mmap_size dq 4096
260 mmap_key dq 0
261 mmap_descsz dq 0
262 mmap_descver dq 0
263
264         align 4096
265 mmapbuf: times 4096 db 0
266
267 str_hello db 'hello!',13,10,0
268
269         align 4
270 gdtlim  dw 31
271 gdtbase dq gdt
272
273         align 8
274 gdt:    ; 0: null segment
275         dd 0, 0
276         ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
277         dd 0x0000ffff
278         dd 0x00cf9a00
279         ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
280         dd 0x0000ffff
281         dd 0x00cf9200
282         ; 3: code16
283         dd 0x0000ffff
284         dd 0x00009a00
285
286
287         align 4
288         ; real mode IDTR pseudo-descriptor pointing to the IVT at addr 0
289         dw 0
290 rmidt:  dw 3ffh
291         dd 0
292
293
294         align 4
295 end:
296 ; vi:ft=nasm: