initial commit
[com32] / src / loader.asm
1         section .loader
2
3         extern startup
4         extern tmpsegbase
5
6         [bits 16]
7         global _start
8 _start:
9         cli
10         mov ax, cs
11         mov ds, ax
12         mov es, ax
13         mov fs, ax      ; this will store the original real mode segment
14         mov ss, ax
15         ; modify the return to real mode jump segment
16         mov [.jmpcs16 + 3], ax
17
18         xor ax, ax
19         mov sp, ax
20
21
22         call enable_a20
23
24         ; calculate GDT linear address
25         xor eax, eax
26         mov ax, cs
27         shl eax, 4
28         mov [tmpsegbase], eax   ; save segment base
29         add eax, gdt
30         mov [gdt_base], eax
31
32         ; set tmp segment bases to match the linear address of our current seg
33         xor eax, eax
34         mov ax, cs
35         shl eax, 4
36         mov word [gdt + 18h + 2], ax    ; tmp pm code base
37         mov word [gdt + 20h + 2], ax    ; tmp pm data base
38         mov word [gdt + 28h + 2], ax    ; ret-to-realmode code
39         shr eax, 16
40         mov byte [gdt + 18h + 4], al
41         mov byte [gdt + 20h + 4], al
42         mov byte [gdt + 28h + 4], al
43
44         mov si, str_enterpm
45         call printstr
46
47         lgdt [gdt_lim]
48
49         mov eax, cr0
50         or eax, 1
51         mov cr0, eax
52
53         jmp 18h:.pm
54
55         [bits 32]
56 .pm:    mov ax, 20h     ; tmp data selector
57         mov ds, ax
58         mov ss, ax
59         mov ax, 10h     ; dest data selector
60         mov es, ax
61
62         mov esp, 200000h
63
64         call startup
65
66         ; return to real mode
67         jmp 28h:.rm
68
69         [bits 16]
70 .rm:    mov eax, cr0
71         and ax, 0xfffe
72         mov cr0, eax
73 .jmpcs16:
74         jmp 42h:.loadcs16       ; 42 seg is modifed at the start (TODO)
75 .loadcs16:
76         mov ax, fs
77         mov ds, ax
78         mov es, ax
79         mov ss, ax
80
81         mov ax, 4c00h
82         int 21h
83
84 str_enterpm db 'Entering 32bit protected mode ...',10,0
85
86 enable_a20:
87         call test_a20
88         jnc .ret
89
90         mov si, .infomsg
91         call printstr           ; print "Enable A20 line ... "
92
93         call enable_a20_kbd
94         call test_a20
95         jnc .done
96         call enable_a20_fast
97         call test_a20
98         jnc .done
99         mov si, .failstr
100         call printstr
101         mov ax, 4c00h
102         int 21h
103 .done:  mov si, .okstr
104         call printstr
105 .ret:   ret
106
107 .infomsg db 'Enable A20 line:',0
108 .failstr db ' failed.',10,0
109 .okstr  db ' success.',10,0
110
111         ; CF = 1 if A20 test fails (not enabled)
112 test_a20:
113         push ds
114         push es
115         xor ax, ax
116         mov ds, ax
117         not ax
118         mov es, ax
119         mov si, 420h
120         mov di, 430h
121         mov dl, [ds:si]
122         mov dh, [es:di]
123         mov [ds:si], al
124         not ax
125         mov [es:di], al
126         cmp al, [ds:si]
127         clc
128         jnz .done
129         stc
130 .done:  mov [ds:si], dl
131         mov [es:di], dh
132         pop es
133         pop ds
134         ret
135
136 enable_a20_fast:
137         mov si, .info
138         call printstr
139         in al, 92h
140         or al, 2
141         out 92h, al
142         ret
143 .info db ' fast ...',0
144
145 KBC_DATA_PORT equ 0x60
146 KBC_CMD_PORT equ 0x64
147 KBC_STATUS_PORT equ 0x64
148 KBC_CMD_WR_OUTPORT equ 0xd1
149
150 KBC_STAT_IN_FULL equ 2
151
152 enable_a20_kbd:
153         mov si, .info
154         call printstr
155         call kbc_wait_write
156         mov al, KBC_CMD_WR_OUTPORT
157         out KBC_CMD_PORT, al
158         call kbc_wait_write
159         mov al, 0xdf
160         out KBC_DATA_PORT, al
161         ret
162 .info db ' kbd ...',0
163
164 kbc_wait_write:
165         in al, KBC_STATUS_PORT
166         and al, KBC_STAT_IN_FULL
167         jnz kbc_wait_write
168         ret
169
170 printstr:
171         lodsb
172         test al, al
173         jz .end
174         cmp al, 10      ; check for line-feed and insert CR before it
175         jnz .nolf
176         push ax
177         mov dl, 13
178         mov ah, 2
179         int 21h
180         pop ax
181 .nolf:  mov ah, 2
182         mov dl, al
183         int 21h
184         jmp printstr
185 .end:   ret
186
187         
188         align 4
189 enterpm dd 0xbad00d     ; space for linear address for far jump to pmode
190 enterpm_sel dw 8        ; selector for far jump to protected mode
191         align 4
192 gdt_lim dw 47           ; GDT limit
193 gdt_base dd 0xbadf00d   ; space for GDT linear address
194
195         align 8
196 gdt:    ; 0: null segment
197         dd 0
198         dd 0
199         ; 1: code - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:code/non-conf/rd
200         dd 0000ffffh
201         dd 00cf9a00h
202         ; 2: data - 0/lim:4g, G:4k, 32bit, avl, pres|app, dpl:0, type:data/rw
203         dd 0000ffffh
204         dd 00cf9200h
205         ; 3: tmp code (will set base before entering pmode)
206         dd 0000ffffh
207         dd 00cf9a00h
208         ; 4: tmp data (will set base before entering pmode)
209         dd 0000ffffh
210         dd 00cf9200h
211         ; 5: return to real-mode 16bit code segment
212         dd 0000ffffh
213         dd 00009a00h
214
215
216 ; vi:set ts=8 sts=8 sw=8 ft=nasm: