section .bss disk_buffer: resb 512 disk_current: resb 1 lba_supported: resb 1 ; Seek state and geometry info for CHS access disk_chs: ; DL, DH, CL, CH for int 13h CHS functions resb 4 disk_spc: ; sectors per cylinder = heads * spt resw 1 disk_spt: resb 1 ; Partition conf from MBR or dummy for floppies part_offset: resd 1 part_size: resd 1 dap: ; Disk access packet for EBIOS extensions resw 1 dap_sectors: resw 1 dap_buffer: resd 1 dap_sector: resq 1 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 ; This leave the first sector of the partition in the buffer ; IN dl 0=A, 1=B, 2=C, 3=D select: mov byte [disk_current], 0xFF mov byte [lba_supported], 0 call dnconv mov byte [disk_chs], dl cmp dl, 0x80 jc select_floppy ; detect EBIOS/LBA extensions 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 test byte [lba_supported], 1 jnz seek_lba ; 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 xor ax, ax xor dx, dx seek_lba: mov word [dap], 0x10 mov word [dap_sectors], 1 mov word [dap_buffer], disk_buffer mov [dap_buffer+2], cs lea di, [dap_sector] stosw mov ax, dx stosw xor ax, ax stosw stosw ret ; Read a sector into buffer read: test byte [lba_supported], 1 jnz read_lba mov ax, 0x0201 mov dx, [disk_chs] mov cx, [disk_chs+2] lea bx, [disk_buffer] push cs pop es int 0x13 ret read_lba: mov ah, 0x42 mov dl, [disk_chs] lea si, [dap] int 0x13 ret ; Write a sector into buffer write: stc ret