DEADSOFTWARE

boot0: add alternative method to get memory size for older machines
[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, 0x100000
24 # =========================================================================== #
25 # Stage 1
26 # =========================================================================== #
28 _start:
30 .code16
31 stage1:
32 # 1. Setup canonical %cs:%eip, segment registers %ds, %es, %fs, %gs, %ss and stack %sp
33 cli
34 ljmp $0x0, $canonized_label; canonized_label:
35 xor %ax, %ax
36 mov %ax, %ds
37 mov %ax, %es
38 # mov %ax, %fs
39 # mov %ax, %gs
40 mov %ax, %ss
41 mov $STACK1, %sp
43 mov %dx, BootDiskAdr
44 call mapmem
45 sti
47 # 2. Enable A20 gate
48 call enableA20
50 # 3. Reset disk controller (%dl and %dh initialized by bios) and read Kernel into buffer
51 movl $(kernel_code_end - kernel_code_start), KernelSizeAdr
53 stage1__read:
54 mov current_sector, %ax
55 add $1, %ax
56 call lba2chs
58 mov current_sector, %ax
59 shl $5, %ax
60 add $(BUFFER / 16), %ax
61 mov %ax, %es
62 call readsectors
64 mov current_sector, %ax
65 add $READBLOCKS, %ax
66 mov %ax, current_sector
67 cmp $((kernel_code_end - kernel_code_start + 511) / 512), %ax
68 jl stage1__read
70 # 4. Disable interrupts and load GDT
71 mov $msg_protected_mode, %si
72 call print
73 cli
74 lgdt gdt_info
76 # 5. Switch to protected mode
77 mov %cr0, %eax
78 or $1, %al
79 mov %eax, %cr0
80 jmp $8, $stage2
82 # =========================================================================== #
83 # Stage 2
84 # =========================================================================== #
86 .code32
87 stage2:
88 # 6. Setup data segments %ds, %es, %fs, %gs and stack %sp
89 mov $16, %ax
90 mov %ax, %ds
91 mov %ax, %ss
92 mov %ax, %es
93 mov %ax, %fs
94 mov %ax, %gs
95 mov $STACK2, %sp
96 # 7. Copy Kernel from buffer
97 xor %eax, %eax
98 stage2_copy_loop:
99 mov BUFFER(%eax), %bh
100 mov %bh, ImageBase(%eax)
101 inc %eax
102 cmp $(kernel_code_end - kernel_code_start), %eax
103 jne stage2_copy_loop
104 # 8. Exec Kernel
105 jmp ImageBase
108 # =========================================================================== #
109 # Print asciiz string
110 # input: %si = String
111 # =========================================================================== #
113 .code16
114 print:
115 pusha
116 movb $0x0e, %ah
117 print__loop:
118 lodsb
119 orb %al, %al
120 jz print__ret
121 int $0x10
122 jmp print__loop
123 print__ret:
124 popa
125 ret
127 # =========================================================================== #
128 # Make memory map for kernel
129 # =========================================================================== #
131 .code16
132 mapmem:
133 pusha
135 movl $0, MemoryMapAdr
136 xor %ebx, %ebx
137 mov $(MemoryMapAdr + 4), %di
139 mapmem_loop:
140 mov $0xe820, %eax
141 mov $20, %ecx
142 mov $0x0534D4150, %edx
143 int $0x15
144 jc mapmem_method_88
145 cmp %edx, %eax
146 jne mapmem_method_88
147 cmp $0, %ebx
148 je mapmem_done
149 add $20, %di
150 incl MemoryMapAdr
151 jmp mapmem_loop
153 mapmem_method_88:
154 #####
155 ### function:
156 ### int 0x15 + %ah = 0x88
157 ### input:
158 ### none
159 ### output:
160 ### cf clear:
161 ### %ax = available memory starting at 0x100000 in KB
162 ### cf set:
163 ### %ah = error code
164 ### note:
165 ### some bioses do not clear cf, do it manually
166 #####
168 movl $1, (MemoryMapAdr + 0) # num
169 movl $0x100000, (MemoryMapAdr + 4) # base (low)
170 movl $0, (MemoryMapAdr + 8) # base (high)
171 movl $0, (MemoryMapAdr + 12) # len (low)
172 movl $0, (MemoryMapAdr + 16) # len (high)
173 movl $1, (MemoryMapAdr + 20) # type
175 clc
176 mov $0x88, %ah
177 int $0x15
178 jc mapmem_failed
179 test %ax, %ax
180 je mapmem_failed
181 movzx %ax, %eax
182 shl $10, %eax
183 movl %eax, (MemoryMapAdr + 12) # len (low)
184 #jmp mapmem_done
186 mapmem_done:
187 popa
188 ret # <============
190 mapmem_failed:
191 mov $msg_mapmem_failed, %si
192 call print
193 cli
194 hlt
196 # =========================================================================== #
197 # Convert LBA to CHS
198 # input: %ax = LBA %dl = disk
199 # output: %ch = cylider %cl = sector %dh = head %dl = disk
200 # =========================================================================== #
202 .code16
203 lba2chs:
204 # push %es
205 # push %di
206 push %dx
207 push %ax
209 clc
210 mov $0x0, %ax
211 mov %ax, %es
212 mov %ax, %di
213 mov $0x8, %ah
214 int $0x13
215 jnc lba2chs__success
216 mov $msg_chs_error, %si
217 call print
218 cli
219 hlt
220 lba2chs__success:
221 mov %dx, BootDiskDxAdr
222 mov %cx, BootDiskCxAdr
224 # SPT = %cl & 63
225 # HPC = %dh + 1
226 # CYL = LBA / ( HPC * SPT )
227 # TEMP = LBA % ( HPC * SPT )
228 # HEAD = TEMP / SPT
229 # SECT = TEMP % SPT + 1
231 # %ax = FREE %bx = FREE %cx = GSPT %dx = HPC-1
232 and $0x3F, %cl
233 movzx %cl, %cx
235 # %ax = FREE %bx = FREE %cx = SPT %dx = HPC-1
236 movzx %dh, %dx
237 inc %dx
239 # %ax = FREE %bx = FREE %cx = SPT %dx = HPC
240 mov %dx, %ax
241 mul %cx; # overflow in %dx
242 mov %ax, %dx
244 # %ax = FREE %bx = FREE %cx = SPT %dx = (HPC * SPT)
245 pop %ax # LBA
246 mov %dx, %bx
247 xor %dx, %dx
248 div %bx
249 xchg %ax, %dx
251 # %ax = TEMP %bx = FREE %cx = SPT %dx = CYL
252 mov %dx, %bx
253 xor %dx, %dx
254 div %cx
255 inc %dx
257 # %ax = HEAD %bx = CYL %cx = FREE %dx = SECT
258 mov %bl, %ch
259 mov %bh, %cl
260 shl $6, %cl
261 add %dx, %cx
263 # %ax = HEAD %bx = FREE %cx = CYL&SECT %dx = FREE
264 pop %dx
265 mov %al, %dh
267 # %ax = FREE %bx = FREE %cx = CYL&SECT %dx = HEAD&DISK
269 # pop %di
270 # pop %es
271 ret
273 # =========================================================================== #
274 # Read sectors to buffer
275 # input: %cx = Cylider+Sector; %es = 64k buf
276 # =========================================================================== #
278 .code16
279 readsectors:
280 xor %ah, %ah
281 int $0x13
283 xor %bx, %bx
284 mov $0x2, %ah
285 mov $READBLOCKS, %al
286 clc
287 int $0x13
289 jnc readsectors__success
291 /* zero if sectors not readed */
292 or %ah, %ah
293 jnz readsectors__success
295 mov $msg_kernel_read_failed, %si
296 call print
297 cli
298 hlt
300 readsectors__success:
301 ret
303 # =========================================================================== #
304 # Enable A20 Line
305 # =========================================================================== #
307 .code16
309 enableA20:
310 cli
311 xor %cx, %cx
312 enableA20_1:
313 inc %cx
314 jz enableA20_3
315 in $0x64, %al
316 test $0x2, %al
317 jnz enableA20_1
318 mov $0xd1, %al
319 out %al, $0x64
320 enableA20_2:
321 in $0x64, %al
322 test $0x2, %al
323 jnz enableA20_2
324 mov $0xdf, %al
325 out %al, $0x60
326 enableA20_3:
327 sti
328 ret
330 # =========================================================================== #
331 # =========================================================================== #
332 # =========================================================================== #
334 msg_mapmem_failed: .asciz "1"
335 msg_chs_error: .asciz "3"
336 msg_kernel_read_failed: .asciz "4"
337 msg_protected_mode: .asciz ">5"
339 current_sector:
340 .word 0
341 gdt_begin:
342 .byte 0x00, 0x00, 0, 0, 0, 0b00000000, 0b00000000, 0 # null dsc
343 .byte 0xff, 0xff, 0, 0, 0, 0b10011010, 0b11001111, 0 # code dsc
344 .byte 0xff, 0xff, 0, 0, 0, 0b10010010, 0b11001111, 0 # data dsc
345 gdt_info:
346 .word (gdt_info - gdt_begin - 1)
347 .quad (gdt_begin)
349 .fill _start + 510 - .
350 .word 0xaa55
352 kernel_code_start:
353 .incbin "../BlackBox.bin"
354 kernel_code_end:
356 .fill _start + (1440 * 1024) - .