summaryrefslogtreecommitdiff
path: root/src/bootloader/bios_disk.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/bootloader/bios_disk.asm')
-rw-r--r--src/bootloader/bios_disk.asm149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/bootloader/bios_disk.asm b/src/bootloader/bios_disk.asm
new file mode 100644
index 0000000..5992920
--- /dev/null
+++ b/src/bootloader/bios_disk.asm
@@ -0,0 +1,149 @@
+bios_disk:
+.init:
+mov [boot_device], dl
+mov ah, 0x8
+int 0x13
+;TODO defaults
+
+jc .init_use_defaults
+
+mov [max_head], dh
+mov [max_sector], cl
+and WORD [max_sector], 0x3f
+
+mov [max_cylinder], cl
+shl WORD [max_cylinder], 8
+or [max_cylinder], ch
+and WORD [max_cylinder], 0x3ff
+
+ret
+
+.init_use_defaults:
+mov BYTE [max_sector], 63
+mov WORD [max_head], 15
+mov BYTE [max_cylinder], 1023
+
+ret
+
+; Return:
+; CH = low eight bits of maximum cylinder number
+; CL = maximum sector number (bits 5-0), high two bits of maximum cylinder number (bits 7-6)
+; DH = maximum head number
+
+.load_sectors_v2:
+;AH = 02h
+;AL = number of sectors to read (must be nonzero)
+;CH = low eight bits of cylinder number
+;CL = sector number 1-63 (bits 0-5) high two bits of cylinder (bits 6-7)
+;DH = head number
+;DL = drive number (bit 7 set for hard disk)
+;ES:BX -> data buffer
+
+; I don't understand i8086. The base pointer needs to be above the stack pointer,
+; yet the stack grows down,
+; and we can't address using sp, or by subtraction.
+; it's like it's forcing us to use the whole push/pop thing.
+
+sub sp, 16
+mov bp, sp
+
+; sector: rbp + 0 (uint8_t)
+; head: rbp + 1 (uint8_t)
+; cylinder: rbp + 2 (uint16_t)
+; sector_cnt: rbp + 4 (uint16_t)
+; destination: rbp + 6 (uint32_t)
+
+; set up variables ______________________________________________
+
+;destination to stack
+mov [bp + 6], edi
+
+; find init chs ________________________________________________
+
+; divide sector_start / max_sectors
+; TODO test for overflow
+mov ax, si
+shr esi, 16
+mov dx, si
+
+;find sector
+div DWORD [max_sector]
+inc dx
+mov [bp], edx ; remainder is sector variable
+
+;find head and cylinder
+mov dx, 0
+div DWORD [max_head]
+mov [bp + 1], dx ; head
+mov [bp + 2], ax ; cylinder
+
+.sector_for_loop:
+mov [bp + 4], cx
+
+; do bios call ___________________________________________________
+mov ah, 2
+mov al, 1
+; sets up ch and cl
+mov cx, [bp + 2]
+xchg ch, cl
+shl cl, 6
+or cl, [bp]
+
+mov dh, [bp + 1]
+mov dl, [boot_device]
+mov bx, 0x500 ; where we store the sector temporarily
+
+int 0x13
+jc .read_failed
+
+; mempcy __________________________________________________________
+
+; we move it to the place at edi, which I don't think changes
+mov esi, 0x500
+mov ecx, 512
+a32 rep movsb
+
+; recalc chs ______________________________________________________
+
+; need to test for more overflows I think
+inc WORD [bp]
+mov al, [bp]; increase the sector we're on
+cmp al, [max_sector]
+jbe .continue_loop
+mov WORD [bp], 1
+
+inc WORD [bp + 1]
+mov al, [bp + 1]
+cmp al, [max_head]
+jbe .continue_loop
+mov WORD [bp + 1], 0
+inc DWORD [bp + 2]
+
+; loopin back ____________________________________________________
+.continue_loop:
+mov cx, [bp + 4]
+
+
+loop .sector_for_loop
+add bp, 16
+mov sp, bp
+
+
+ret
+
+
+
+
+.read_failed:
+mov bx, .loadsectors_error
+call bios_print
+cli
+hlt
+
+.loadsectors_error: db "Error loading required sector!", 0
+
+boot_device: db 0
+max_sector: db 0
+max_cylinder: dw 0
+max_head: db 0
+