DEADSOFTWARE

Initial Bare Metal BlackBox Prototype
[bmbb.git] / Boot486 / boot0.S
1 .text
2 .global _start
4 /*
5 * Bootloader configuration
6 */
8 .set STACK1, 0x7000
9 .set STACK2, 0xe000
10 .set BUFFER, 0x8000 # 0x80000 - 0x8000 = 480k
11 .set READBLOCKS, 1
13 /*
14 * Kernel configuration (sync with Kernel.odc!)
15 */
17 .set KernelSizeAdr, 0x7e00
18 .set BootDiskAdr, 0x7e04
19 .set BootDiskDxAdr, 0x7e06
20 .set BootDiskCxAdr, 0x7e08
21 .set MemoryMapAdr, 0x7e0A
22 .set ImageBase, 0x1000000
24 # =========================================================================== #
25 # Stage 1
26 # =========================================================================== #
28 .code16
29 _start:
30 stage1:
31 # 1. Setup canonical %cs:%eip, segment registers %ds, %es, %fs, %gs, %ss and stack %sp
32 cli
33 ljmp $0x0, $canonized_label; canonized_label:
34 xor %ax, %ax
35 mov %ax, %ds
36 mov %ax, %es
37 # mov %ax, %fs
38 # mov %ax, %gs
39 mov %ax, %ss
40 mov $STACK1, %sp
42 mov %dx, BootDiskAdr
43 call mapmem
45 # 2. Enable A20 gate
46 call enable_A20
47 sti
49 # 3. Reset disk controller (%dl and %dh initialized by bios) and read Kernel into buffer
50 movl $(kernel_code_end - kernel_code_start), KernelSizeAdr
52 stage1__read:
53 mov current_sector, %ax
54 add $1, %ax
55 call lba2chs
57 mov current_sector, %ax
58 shl $5, %ax
59 add $(BUFFER / 16), %ax
60 mov %ax, %es
61 call readsectors
63 mov current_sector, %ax
64 add $READBLOCKS, %ax
65 mov %ax, current_sector
66 cmp $((kernel_code_end - kernel_code_start + 511) / 512), %ax
67 jl stage1__read
69 # 4. Disable interrupts and load GDT
70 mov $msg_protected_mode, %si
71 call print
72 cli
73 lgdt gdt_info
75 # 5. Switch to protected mode
76 mov %cr0, %eax
77 or $1, %al
78 mov %eax, %cr0
79 jmp $8, $stage2
81 # =========================================================================== #
82 # Stage 2
83 # =========================================================================== #
85 .code32
86 stage2:
87 # 6. Setup data segments %ds, %es, %fs, %gs and stack %sp
88 mov $16, %ax
89 mov %ax, %ds
90 mov %ax, %ss
91 mov %ax, %es
92 mov %ax, %fs
93 mov %ax, %gs
94 mov $STACK2, %sp
95 # 7. Copy Kernel from buffer
96 xor %eax, %eax
97 stage2_copy_loop:
98 mov BUFFER(%eax), %bh
99 mov %bh, ImageBase(%eax)
100 inc %eax
101 cmp $(kernel_code_end - kernel_code_start), %eax
102 jne stage2_copy_loop
103 # 8. Exec Kernel
104 jmp ImageBase
107 # =========================================================================== #
108 # Print asciiz string
109 # input: %si = String
110 # =========================================================================== #
112 .code16
113 print:
114 pusha
115 movb $0x0e, %ah
116 print__loop:
117 lodsb
118 orb %al, %al
119 jz print__ret
120 int $0x10
121 jmp print__loop
122 print__ret:
123 popa
124 ret
126 # =========================================================================== #
127 # Make memory map for kernel
128 # =========================================================================== #
130 .code16
131 mapmem:
132 pusha
133 movl $0, MemoryMapAdr
134 xor %ebx, %ebx
135 mov $(MemoryMapAdr + 4), %di
136 mapmem__loop:
137 mov $0xe820, %eax
138 mov $20, %ecx
139 mov $0x0534D4150, %edx
140 int $0x15
141 jc mapmem__failed
142 cmp %edx, %eax
143 jne mapmem__failed
144 cmp $0, %ebx
145 je mapmem__done
146 add $20, %di
147 incl MemoryMapAdr
148 jmp mapmem__loop
149 mapmem__done:
150 popa
151 ret # <============
152 mapmem__failed:
153 mov $msg_mapmem_failed, %si
154 call print
155 cli
156 hlt
158 # =========================================================================== #
159 # Convert LBA to CHS
160 # input: %ax = LBA %dl = disk
161 # output: %ch = cylider %cl = sector %dh = head %dl = disk
162 # =========================================================================== #
164 .code16
165 lba2chs:
166 # push %es
167 # push %di
168 push %dx
169 push %ax
171 clc
172 mov $0x0, %ax
173 mov %ax, %es
174 mov %ax, %di
175 mov $0x8, %ah
176 int $0x13
177 jnc lba2chs__success
178 mov $msg_chs_error, %si
179 call print
180 cli
181 hlt
182 lba2chs__success:
183 mov %dx, BootDiskDxAdr
184 mov %cx, BootDiskCxAdr
186 # SPT = %cl & 63
187 # HPC = %dh + 1
188 # CYL = LBA / ( HPC * SPT )
189 # TEMP = LBA % ( HPC * SPT )
190 # HEAD = TEMP / SPT
191 # SECT = TEMP % SPT + 1
193 # %ax = FREE %bx = FREE %cx = GSPT %dx = HPC-1
194 and $0x3F, %cl
195 movzx %cl, %cx
197 # %ax = FREE %bx = FREE %cx = SPT %dx = HPC-1
198 movzx %dh, %dx
199 inc %dx
201 # %ax = FREE %bx = FREE %cx = SPT %dx = HPC
202 mov %dx, %ax
203 mul %cx; # overflow in %dx
204 mov %ax, %dx
206 # %ax = FREE %bx = FREE %cx = SPT %dx = (HPC * SPT)
207 pop %ax # LBA
208 mov %dx, %bx
209 xor %dx, %dx
210 div %bx
211 xchg %ax, %dx
213 # %ax = TEMP %bx = FREE %cx = SPT %dx = CYL
214 mov %dx, %bx
215 xor %dx, %dx
216 div %cx
217 inc %dx
219 # %ax = HEAD %bx = CYL %cx = FREE %dx = SECT
220 mov %bl, %ch
221 mov %bh, %cl
222 shl $6, %cl
223 add %dx, %cx
225 # %ax = HEAD %bx = FREE %cx = CYL&SECT %dx = FREE
226 pop %dx
227 mov %al, %dh
229 # %ax = FREE %bx = FREE %cx = CYL&SECT %dx = HEAD&DISK
231 # pop %di
232 # pop %es
233 ret
235 # =========================================================================== #
236 # Read sectors to buffer
237 # input: %cx = Cylider+Sector; %es = 64k buf
238 # =========================================================================== #
240 .code16
241 readsectors:
242 xor %ah, %ah
243 int $0x13
245 xor %bx, %bx
246 mov $0x2, %ah
247 mov $READBLOCKS, %al
248 clc
249 int $0x13
251 jnc readsectors__success
253 /* zero if sectors not readed */
254 or %ah, %ah
255 jnz readsectors__success
257 mov $msg_kernel_read_failed, %si
258 call print
259 cli
260 hlt
262 readsectors__success:
263 ret
265 # =========================================================================== #
266 # Check that A20 Gate is enabled
267 # output: set zero flag if disabled
268 # restore: %ds %es
269 # =========================================================================== #
271 .code16
272 check_A20:
273 push %ds
274 push %es
275 # push %ax
276 # push %di
277 # push %si
279 xor %ax, %ax
280 mov %ax, %es
282 not %ax
283 mov %ax, %ds
285 mov $0x0500, %di
286 mov $0x0510, %si
288 mov %es:0(%di), %al
289 push %ax
291 mov %ds:0(%si), %al
292 push %ax
294 movb $0x00, %es:0(%di)
295 movb $0xff, %ds:0(%si)
297 cmpb $0xff, %es:0(%di)
299 pop %ax
300 mov %es:0(%di), %al
302 pop %ax
303 mov %es:0(%di), %al
305 mov $0, %ax
307 je check_A20__exit
309 mov $1, %ax
311 check_A20__exit:
312 # pop %si
313 # pop %di
314 # pop %ax
315 pop %es
316 pop %ds
317 or %al, %al
318 ret
320 # =========================================================================== #
321 # Enable A20 Gate
322 # =========================================================================== #
324 enable_A20:
325 /* First check */
326 call check_A20
327 jnz enable_A20__success
329 /* BIOS method */
330 mov $0x2401, %ax
331 int $0x15
333 call check_A20
334 jnz enable_A20__success
336 /* Keyboard method 1 */
337 mov $0xd0, %al
338 out %al, $0x64
340 call check_A20
341 jnz enable_A20__success
343 /* Keyboard method 2 */
344 /*
345 # cli
347 call enable_A20__wait1
348 mov $0xad, %al
349 out %al, $0x64
351 call enable_A20__wait1
352 mov $0xd0, %al
353 out %al, $0x64
355 enable_A20__wait2:
356 in $0x64, %al
357 test $1, %al
358 jz enable_A20__wait2
360 in $0x60, %al
361 push %eax
363 call enable_A20__wait1
364 mov $0xd1, %al
365 out %al, $0x64
367 call enable_A20__wait1
368 pop %eax
369 or $2, %al
370 out %al, $0x64
372 call enable_A20__wait1
373 mov $0xae, %al
374 out %al, $0x64
376 call enable_A20__wait1
377 # sti
379 # call check_A20
380 # jnz enable_A20__success
381 */
383 /* Control port A method */
384 mov $1, %al
385 out %al, $0x92
387 call check_A20
388 jnz enable_A20__success
390 /* Fast method */
391 in $0xee, %al
393 call check_A20
394 jnz enable_A20__success
396 mov $msg_a20_failed, %si
397 call print
398 # cli
399 # hlt
401 enable_A20__success:
402 ret
404 /*
405 enable_A20__wait1:
406 in $0x64, %al
407 test $2, %al
408 jnz enable_A20__wait1
409 ret
410 */
412 # =========================================================================== #
413 # =========================================================================== #
414 # =========================================================================== #
416 msg_mapmem_failed: .asciz "1"
417 msg_a20_failed: .asciz "2"
418 msg_chs_error: .asciz "3"
419 msg_kernel_read_failed: .asciz "4"
421 msg_protected_mode: .asciz ">5"
423 current_sector:
424 .word 0
425 gdt_begin:
426 .byte 0x00, 0x00, 0, 0, 0, 0b00000000, 0b00000000, 0 # null dsc
427 .byte 0xff, 0xff, 0, 0, 0, 0b10011010, 0b11001111, 0 # code dsc
428 .byte 0xff, 0xff, 0, 0, 0, 0b10010010, 0b11001111, 0 # data dsc
429 gdt_info:
430 .word (gdt_info - gdt_begin - 1)
431 .quad (gdt_begin)
433 .fill _start + 510 - .
434 .word 0xaa55
436 kernel_code_start:
437 .incbin "../BlackBox.bin"
438 kernel_code_end:
440 .fill _start + (1440 * 1024) - .