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