rdos/kernel/diskio.asm

169 lines
2.8 KiB
NASM

section .bss
disk_buffer:
resb 512
disk_current:
resb 1
lba_supported:
resb 1
disk_chs: ; DL, DH, CL, CH for int 13h CHS functions
resb 4
disk_dap: ; disk access packet for int 13h EBIOS functions
resb 0x10
disk_spc: ; sectors per cylinder = heads * spt
resw 1
disk_spt:
resb 1
part_offset:
resd 1
part_size:
resd 1
; Disk access packet for EBIOS extensions
dapps: equ 0 ; byte packet size
dapnum: equ 2 ; word number of sectors to transfer
dapbuf: equ 4 ; dword transfer buffer
dapsec: equ 8 ; qword absolute sector number
dapsiz: equ 16
section .text
; Convert between drive number and BIOS dl
; Bidirectional mapping
; 0 <-> 0, 1 <-> 1, 2 <-> 0x80, 3 <-> 0x81
dnconv: mov cx, 7
ror dx, 1
rol dl, 1
dncl: rcl dl, 1
rcr dh, 1
loop dncl
xchg dh, dl
ret
; Select a drive for I/O
; IN dl 0=A, 1=B, 2=C, 3=D
select: mov byte [disk_current], 0xFF
mov byte [lba_supported], 0
cmp dl, 0x02
jc select_floppy
; detect EBIOS/LBA extensions
call dnconv
mov byte [disk_chs], dl
mov ah, 0x41
mov bx, 0x55AA
int 0x13
test cx, 1
jz select_hdd
cmp bx, 0xAA55
jnz select_hdd
mov byte [lba_supported], 1
jmp select_hdd
select_floppy:
push dx
call seek_zero
call read
; load disk geometry
mov ax, [disk_buffer+0x0B+bpb_spt]
mov [disk_spt], ax
mul word [disk_buffer+0x0B+bpb_nos]
mov [disk_spc], ax
; set partition size
; we dont rely on the 'total sectors' given in the BPB
; instead, we assume maximum cylinder
; 1023 is the maximum encodable for int 13h
lea di, [part_offset]
xor ax, ax
; partition offset = 0
stosw
stosw
; partition size = 0x00010000 = 32MB
stosw
inc ax
stosw
pop dx
ret
select_hdd:
push dx
; load CHS geometry for drive
mov ah, 0x8
int 0x13
xor ah, ah
mov al, cl
mov [disk_spt], ax
mul byte dh
mov [disk_spc], ax
; load offset and size of first partition
call seek_zero
call read
mov bx, disk_buffer+0x1BE
lea si, [bx+8]
lea di, [part_offset]
mov cx, 4
rep movsw
; read bpb
mov dx, [part_offset+2]
mov ax, [part_offset]
call seek
call read
pop dx
ret
; Set absolute sector number
; IN dx:ax 32-bit sector number
seek: push ax
or ax, dx
pop ax
jz seek_zero
; dx:ax = lba
div word [disk_spc]
xchg ax, dx
; dx = cylinder, ax = head * spt + sector
div byte [disk_spt]
; dx = cylinder, al = head, ah = sector
xchg dl, dh
ror dl, 1
ror dl, 1
or dl, ah
inc dx
; dh bit 0-7: cylinder 0-7
; dl bit 0-5: sector number 0-5
; dl bit 6-7: cylinder 8-9
; store
mov byte [disk_chs+1], al
mov word [disk_chs+2], dx
ret
seek_zero:
; set chs data to first sector
mov byte [disk_chs+1], 0
mov word [disk_chs+2], 1
; set lba data to first sector
lea di, [disk_dap+dapsec]
mov cx, 4
xor ax, ax
rep stosw
ret
; Read a sector into buffer
read: mov ax, 0x0201
mov dx, [disk_chs]
mov cx, [disk_chs+2]
lea bx, [disk_buffer]
push cs
pop es
int 0x13
ret
; Write a sector into buffer
write: stc
ret