test: dropping to 32bit protected mode
[efitest3] / efitest.asm
1 ; vi:ft=nasm:
2         bits 64
3         org 100000h
4
5 start:
6         call get_rip
7 .after_call:
8         sub rax, .after_call - start
9         mov rsi, rax    ; source address
10         mov rdi, start  ; destination
11         mov rcx, end - start
12         shr rcx, 2      ; dwords
13         cld
14         rep movsd       ; copy code to make it absolute
15
16         mov rax, .abs
17         jmp rax
18 .abs:
19         call setup_serial
20
21         ; switch to 32-bit compatibility long mode
22         lgdt [gdtlim]
23         push word 8
24         push qword start32
25         retfq
26
27
28 .hang:  jmp .hang
29
30 get_rip:
31         mov rax, [rsp]
32         ret
33
34
35 UART_DATA               equ 0x3f8
36 UART_DIVLO              equ 0x3f8
37 UART_DIVHI              equ 0x3f9
38 UART_FIFO               equ 0x3fa
39 UART_LCTL               equ 0x3fb
40 UART_MCTL               equ 0x3fc
41 UART_LSTAT              equ 0x3fd
42 DIV_9600                equ 115200 / 9600
43 LCTL_8N1                equ 0x03
44 LCTL_DLAB               equ 0x80
45 FIFO_ENABLE_CLEAR       equ 0x07
46 MCTL_DTR_RTS_OUT2       equ 0x0b
47 LST_TREG_EMPTY          equ 0x20
48
49         ; serial port setup
50 setup_serial:
51         ; set clock divisor
52         mov al, LCTL_DLAB
53         mov dx, UART_LCTL
54         out dx, al
55         mov ax, DIV_9600
56         mov dx, UART_DIVLO
57         out dx, al
58         mov al, ah
59         mov dx, UART_DIVHI
60         out dx, al
61         ; set format 8n1
62         mov al, LCTL_8N1
63         mov dx, UART_LCTL
64         out dx, al
65         ; clear and enable fifo
66         mov al, FIFO_ENABLE_CLEAR
67         mov dx, UART_FIFO
68         out dx, al
69         ; assert RTS and DTR
70         mov al, MCTL_DTR_RTS_OUT2
71         mov dx, UART_MCTL
72         out dx, al
73         ret
74
75 str_hello db 'hello!',13,10,0
76
77         align 4
78 gdtlim  dw 23
79 gdtbase dq gdt
80
81         align 8
82 gdt:    ; 0: null segment
83         dd 0, 0
84         ; 1: code - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
85         dd 0x0000ffff
86         dd 0x00cf9a00
87         ; 2: data - base:0, lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
88         dd 0x0000ffff
89         dd 0x00cf9200
90
91
92         bits 32
93 start32:
94         mov ax, 10h
95         mov ds, ax
96         mov ss, ax
97         mov es, ax
98         mov gs, ax
99         mov fs, ax
100
101         ; disable paging to deactivate long mode
102         mov eax, cr0
103         and eax, 7fffffffh
104         mov cr0, eax
105
106         ; disable long mode (EFER.LME = 0)
107         ; TODO: EFER is MSR c0000080, LME is bit 8
108         mov ecx, 0c0000080h
109         rdmsr
110         and eax, 0fffffeffh
111         wrmsr
112
113         mov esi, str_hello
114         call ser_putstr
115
116 .hang:  hlt
117         jmp .hang
118
119         
120 ser_putchar:
121         mov ah, al
122         ; wait until transmit register is empty
123         mov dx, UART_LSTAT
124 .wait:  in al, dx
125         and al, LST_TREG_EMPTY
126         jz .wait
127         mov dx, UART_DATA
128         mov al, ah
129         out dx, al
130         ret
131
132 ser_putstr:
133         mov al, [esi]
134         test al, al
135         jz .done
136         call ser_putchar
137         inc esi
138         jmp ser_putstr
139 .done:  ret
140
141
142 end: