switch to 32bit done, changed load address, and fixed the partial code
[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 23
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
132
133         bits 32
134 start32:
135         mov ax, 10h
136         mov ds, ax
137         mov ss, ax
138         mov es, ax
139         mov gs, ax
140         mov fs, ax
141
142         ; disable paging to deactivate long mode
143         mov eax, cr0
144         and eax, 7fffffffh
145         mov cr0, eax
146
147         ; disable long mode (EFER.LME = 0)
148         ; TODO: EFER is MSR c0000080, LME is bit 8
149         mov ecx, 0c0000080h
150         rdmsr
151         and eax, 0fffffeffh
152         wrmsr
153
154         mov edi, 0a0000h
155         mov ecx, 16000
156         mov eax, 00ff0000h
157         rep stosd
158
159         mov esi, str_hello
160         call ser_putstr
161
162 .hang:  hlt
163         jmp .hang
164
165         
166 ser_putchar:
167         mov ah, al
168         ; wait until transmit register is empty
169         mov dx, UART_LSTAT
170 .wait:  in al, dx
171         and al, LST_TREG_EMPTY
172         jz .wait
173         mov dx, UART_DATA
174         mov al, ah
175         out dx, al
176         ret
177
178 ser_putstr:
179         mov al, [esi]
180         test al, al
181         jz .done
182         call ser_putchar
183         inc esi
184         jmp ser_putstr
185 .done:  ret
186
187
188         align 4
189 end: