rdos/kernel/disk.asm

169 lines
2.5 KiB
NASM

disk_num: equ 0x40 ; BYTE drive number (A=0)
disk_heads: equ 0x41 ; BYTE number of heads/sides
disk_parm: equ 0x42 ; 11 BYTES for int 0x1E
disk_spt: equ 0x46 ; - BYTE
disk_parm_init:
push ax
push si
push di
push ds
; invalidate existing data
mov byte [disk_num], 0xFF
xor ax, ax
mov ds, ax
; if int 0x1E is already pointing to us,
; we have nothing to copy
mov di, disk_parm
lds si, [0x1E*4]
cmp si, di
je .correctparm
; copy bios table into our location
mov cx, 11
rep movsb
; make the interrupt vector point to our address
xor ax, ax
mov ds, ax
mov [0x1E*4], di
mov ax, cs
mov [0x1E*4+2], ax
.correctparm:
pop ds
pop di
pop si
pop ax
ret
disk_load_bpb:
mov ax, 0x0201
mov cx, 0x0001
xor dh, dh
mov bx, diskbuf
stc
int 0x13
jnc .end
; try a second time
mov ax, 0x0201
int 0x13
jnc .end
; try a third time
mov ax, 0x0201
int 0x13
.end:
ret
disk_select:
push ax
push cx
push dx
push bx
cmp byte [disk_num], dl
je .end
mov byte [disk_num], dl
call disk_load_bpb
jc .end
; Validate and apply sector size
mov ax, [diskbuf+fdc_ss]
; test ax, 0xF87F
; jnz .nobpd
call log2
sub al, 7
mov [disk_parm+3], al
; fetch sectors per track
mov al, [diskbuf+fdc_spt]
mov [disk_parm+4], al
; fetch number of sides/heads
mov ax, [diskbuf+fdc_nos]
mov [disk_heads], al
xor ah, ah
int 0x13
.end:
pop bx
pop dx
pop cx
pop ax
ret
; Setup CX, DX and BX for int 13h transfer
; IN BX ptr to 32-bit number
; OUT CL Sector number
; CH Cylinder number
; DL Drive number
; DH Head number
; BX Sector buffer
disk_prepare_chs:
mov ax, word [bx]
mov dx, word [bx+2]
xor bh, bh
mov bl, byte [disk_spt]
div word bx ; ax:temp = (lba / spt)
inc dx ; dx:sector = (lba % spt) + 1
mov cl, dl ; sector number
xor bx, bx
mov bl, byte [disk_heads]
xor dx, dx
div word bx ; ax:cylinder = (temp / nos)
; dx:head = (temp % nos)
mov ch, al ; cylinder number
mov dh, dl ; head number
mov dl, byte [disk_num]
mov bx, diskbuf
ret
; Read a sector into diskbuf
; IN BX ptr to DWORD giving sector number
disk_read:
push ax
push cx
push dx
push bx
call disk_prepare_chs
mov ax, 0x0201
int 0x13
pop bx
pop dx
pop cx
pop ax
ret
; Write a sector from diskbuf
; IN BX ptr to DWORD giving sector number
disk_write:
push ax
push cx
push dx
push bx
call disk_prepare_chs
mov ax, 0x0301
int 0x13
pop bx
pop dx
pop cx
pop ax
ret