150 lines
2.8 KiB
NASM
150 lines
2.8 KiB
NASM
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
|
|
|