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