.text .global _start /* * Bootloader configuration */ .set STACK1, 0x7000 .set STACK2, 0xe000 .set BUFFER, 0x8000 # 0x80000 - 0x8000 = 480k .set READBLOCKS, 1 /* * Kernel configuration (sync with Kernel.odc!) */ .set KernelSizeAdr, 0x7e00 .set BootDiskAdr, 0x7e04 .set BootDiskDxAdr, 0x7e06 .set BootDiskCxAdr, 0x7e08 .set MemoryMapAdr, 0x7e0A .set ImageBase, 0x100000 _start: # =========================================================================== # # Setup canonical %cs:%eip, segment registers %ds, %es, %fs, %gs, %ss and # stack %sp # =========================================================================== # .code16 cli ljmp $0x0, $canonized_label; canonized_label: xor %ax, %ax mov %ax, %ds mov %ax, %es # mov %ax, %fs # mov %ax, %gs mov %ax, %ss mov $STACK1, %sp mov %dx, BootDiskAdr # =========================================================================== # # Make memory map for kernel # =========================================================================== # pusha movl $0, MemoryMapAdr xor %ebx, %ebx mov $(MemoryMapAdr + 4), %di mapmem_loop: mov $0xe820, %eax mov $20, %ecx mov $0x0534D4150, %edx int $0x15 jc mapmem_method_88 cmp %edx, %eax jne mapmem_method_88 cmp $0, %ebx je mapmem_done add $20, %di incl MemoryMapAdr jmp mapmem_loop mapmem_method_88: ##### ### function: ### int 0x15 + %ah = 0x88 ### input: ### none ### output: ### cf clear: ### %ax = available memory starting at 0x100000 in KB ### cf set: ### %ah = error code ### note: ### some bioses do not clear cf, do it manually ##### movl $3, (MemoryMapAdr + 0) # num xor %eax, %eax mov $1, %ebx # free low memory movl %eax, (MemoryMapAdr + 4) # base (low) movl %eax, (MemoryMapAdr + 8) # base (high) movl $0x080000, (MemoryMapAdr + 12) # len (low) movl %eax, (MemoryMapAdr + 16) # len (high) movl %ebx, (MemoryMapAdr + 20) # type # reserved harware memory movl $0x080000, (MemoryMapAdr + 24) # base (low) movl %eax, (MemoryMapAdr + 28) # base (high) movl $0x080000, (MemoryMapAdr + 32) # len (low) movl %eax, (MemoryMapAdr + 36) # len (high) movl %eax, (MemoryMapAdr + 40) # type # free high memory movl $0x100000, (MemoryMapAdr + 44) # base (low) movl %eax, (MemoryMapAdr + 48) # base (high) #movl $0x700000, (MemoryMapAdr + 52) # len (low) movl %eax, (MemoryMapAdr + 56) # len (high) movl %ebx, (MemoryMapAdr + 60) # type clc mov $0x88, %ah int $0x15 jc mapmem_failed test %ax, %ax je mapmem_failed movzx %ax, %eax shl $10, %eax movl %eax, (MemoryMapAdr + 52) # len (low) jmp mapmem_done mapmem_failed: mov $msg_mapmem_failed, %si call print hlt mapmem_done: popa # =========================================================================== # # Enable A20 Line # =========================================================================== # enableA20: xor %cx, %cx enableA20_1: inc %cx jz enableA20_3 in $0x64, %al test $0x2, %al jnz enableA20_1 mov $0xd1, %al out %al, $0x64 enableA20_2: in $0x64, %al test $0x2, %al jnz enableA20_2 mov $0xdf, %al out %al, $0x60 enableA20_3: # =========================================================================== # # Reset disk controller (%dl and %dh initialized by bios) and read Kernel # into buffer # =========================================================================== # sti movl $(kernel_code_end - kernel_code_start), KernelSizeAdr stage1__read: mov current_sector, %ax add $1, %ax call lba2chs mov current_sector, %ax shl $5, %ax add $(BUFFER / 16), %ax mov %ax, %es readsectors: # %cx = Cylider+Sector; %es = 64k buf xor %ah, %ah int $0x13 xor %bx, %bx mov $0x2, %ah mov $READBLOCKS, %al clc int $0x13 jnc readsectors__success /* zero if sectors not readed */ or %ah, %ah jnz readsectors__success mov $msg_kernel_read_failed, %si call print #cli hlt readsectors__success: mov current_sector, %ax add $READBLOCKS, %ax mov %ax, current_sector cmp $((kernel_code_end - kernel_code_start + 511) / 512), %ax jl stage1__read cli # =========================================================================== # # Load GDT # =========================================================================== # mov $msg_protected_mode, %si call print lgdt gdt_info # =========================================================================== # # Switch to protected mode # =========================================================================== # mov %cr0, %eax or $1, %al mov %eax, %cr0 jmp $8, $stage2 # =========================================================================== # # 32 bit stage begins # =========================================================================== # .code32 stage2: # =========================================================================== # # Setup data segments %ds, %es, %fs, %gs and stack %sp # =========================================================================== # mov $16, %ax mov %ax, %ds mov %ax, %ss mov %ax, %es mov %ax, %fs mov %ax, %gs mov $STACK2, %sp # =========================================================================== # # Copy Kernel from buffer # =========================================================================== # xor %eax, %eax stage2_copy_loop: mov BUFFER(%eax), %bh mov %bh, ImageBase(%eax) inc %eax cmp $(kernel_code_end - kernel_code_start), %eax jne stage2_copy_loop # =========================================================================== # # Jump to Kernel code (never returns) # =========================================================================== # jmp ImageBase # =========================================================================== # # ================================ routines ================================= # # =========================================================================== # # =========================================================================== # # Print asciiz string # input: %si = String # =========================================================================== # .code16 print: pusha movb $0x0e, %ah print__loop: lodsb orb %al, %al jz print__ret int $0x10 jmp print__loop print__ret: popa ret # =========================================================================== # # Convert LBA to CHS # input: %ax = LBA %dl = disk # output: %ch = cylider %cl = sector %dh = head %dl = disk # =========================================================================== # .code16 lba2chs: # push %es # push %di push %dx push %ax clc mov $0x0, %ax mov %ax, %es mov %ax, %di mov $0x8, %ah int $0x13 jnc lba2chs__success mov $msg_chs_error, %si call print hlt lba2chs__success: mov %dx, BootDiskDxAdr mov %cx, BootDiskCxAdr # SPT = %cl & 63 # HPC = %dh + 1 # CYL = LBA / ( HPC * SPT ) # TEMP = LBA % ( HPC * SPT ) # HEAD = TEMP / SPT # SECT = TEMP % SPT + 1 # %ax = FREE %bx = FREE %cx = GSPT %dx = HPC-1 and $0x3F, %cl movzx %cl, %cx # %ax = FREE %bx = FREE %cx = SPT %dx = HPC-1 movzx %dh, %dx inc %dx # %ax = FREE %bx = FREE %cx = SPT %dx = HPC mov %dx, %ax mul %cx; # overflow in %dx mov %ax, %dx # %ax = FREE %bx = FREE %cx = SPT %dx = (HPC * SPT) pop %ax # LBA mov %dx, %bx xor %dx, %dx div %bx xchg %ax, %dx # %ax = TEMP %bx = FREE %cx = SPT %dx = CYL mov %dx, %bx xor %dx, %dx div %cx inc %dx # %ax = HEAD %bx = CYL %cx = FREE %dx = SECT mov %bl, %ch mov %bh, %cl shl $6, %cl add %dx, %cx # %ax = HEAD %bx = FREE %cx = CYL&SECT %dx = FREE pop %dx mov %al, %dh # %ax = FREE %bx = FREE %cx = CYL&SECT %dx = HEAD&DISK # pop %di # pop %es ret # =========================================================================== # # =========================================================================== # # =========================================================================== # msg_mapmem_failed: .asciz "1" msg_chs_error: .asciz "3" msg_kernel_read_failed: .asciz "4" msg_protected_mode: .asciz ">5" current_sector: .word 0 gdt_begin: .byte 0x00, 0x00, 0, 0, 0, 0b00000000, 0b00000000, 0 # null dsc .byte 0xff, 0xff, 0, 0, 0, 0b10011010, 0b11001111, 0 # code dsc .byte 0xff, 0xff, 0, 0, 0, 0b10010010, 0b11001111, 0 # data dsc gdt_info: .word (gdt_info - gdt_begin - 1) .quad (gdt_begin) .fill _start + 510 - . .word 0xaa55 kernel_code_start: .incbin "../BlackBox.bin" kernel_code_end: .fill _start + (1440 * 1024) - .