; Program to demonstrate INT 13h AH=4xh LBA disk read functions ; Reads and dumps master boot record (MBR; partition table) of hard drive, ; then reads and dumps bootsectors of primary partitions. ORG 100h ; DOS .COM file ; set up registers and disk address packet for INT 13h AH=42h mov dl,80h ; first hard drive mov [disk_adr_pkt.seg],ds mov si,disk_adr_pkt mov di,lba_msg call cputs ; check for LBA extensions to INT 13h BIOS mov ah,41h mov bx,55AAh int 13h jc no_lba cmp bx,0AA55h je lba_ok no_lba: mov di,lba_err_msg msg: call cputs exit: mov ax,4C01h ; exit to DOS with ERRORLEVEL 1 int 21h lba_ok: mov di,mbr_msg call cputs mov ah,42h int 13h mov di,err_msg jc msg cmp ah,0 jne msg mov bx,mbr + 446 ; dump the partition table mov cx,64 call dump mov word [disk_adr_pkt.off],boot jmp short foo bar: add bx,16 foo: cmp bx,mbr + 510 jae exit cmp byte [bx + 4],0 ; does this partition exist? je bar mov ax,[bx + 8] ; yes, get LBA partition start mov [disk_adr_pkt.lba + 0],ax push dx push bx mov dx,[bx + 10] mov [disk_adr_pkt.lba + 2],dx mov di,boot_msg call cputs mov bx,10 call wrnum mov di,boot2_msg call cputs pop bx pop dx mov ah,42h ; read partition start (bootsector) int 13h mov di,err_msg jc msg cmp ah,0 jne msg push bx mov bx,boot ; dump the bootsector mov cx,64 call dump pop bx jmp short bar ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; name: putch ; action: writes one character to screen ; in: ASCII character in AL ; out: (nothing) ; modifies: (nothing) ; minimum CPU: 8088 ; notes: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GLOBAL putch putch: push bx push ax mov ah,0Eh ; INT 10h: teletype output xor bx,bx ; video page 0 int 10h pop ax pop bx ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; name: cputs ; action: writes ASCIZ string to text screen ; in: 0-terminated string at DS:DI ; out: (nothing) ; modifies: (nothing) ; minimum CPU: 8088 ; notes: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GLOBAL cputs cputs: push di push ax jmp cputs2 cputs1: call putch cputs2: mov al,[di] inc di or al,al jne cputs1 pop ax pop di ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; name: wrnum ; action: writes 32-bit value to text screen ; in: 32-bit unsigned value in DX:AX, radix in BX ; out: (nothing) ; modifies: (nothing) ; minimum CPU: 8088 ; notes: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GLOBAL wrnum wrnum: push di push dx push cx push ax mov di,num_buf ; extended precision division from section 9.3.5 ; of Randall Hyde's "Art of Assembly" ; start: DX=dividend MSW, AX=dividend LSW, BX=divisor wrnum1: push ax mov ax,dx xor dx,dx ; before div: DX=0, AX=dividend MSW, BX=divisor ; after div: AX=quotient MSW, DX=intermediate remainder div bx mov cx,ax pop ax ; before div: DX=intermediate remainder, AX=dividend LSW, BX=divisor ; after div: AX=quotient LSW, DX=remainder div bx ; end: DX=quotient MSW, AX=quotient LSW, CX=remainder xchg dx,cx add cl,'0' cmp cl,'9' jbe wrnum2 add cl,('A'-('9'+1)) wrnum2: dec di mov [di],cl mov cx,ax or cx,dx jne wrnum1 call cputs pop ax pop cx pop dx pop di ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; name: dump ; action: displays hex and ASCII dump ; in: CX=byte count, BX->address ; out: (nothing) ; modifies: (nothing) ; minimum CPU: 8088 ; notes: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dump: push di push si push dx push cx push bx push ax dump_1: xor di,di dump_2: or cx,cx je dump_5 xor dx,dx xor ah,ah mov al,[bx + di] ; don't use wrnum because we want the field width fixed at 2 characters shr al,1 shr al,1 shr al,1 shr al,1 add al,'0' cmp al,'9' jbe dump_3 add al,('A'-('9'+1)) dump_3: call putch mov al,[bx + di] and al,0Fh add al,'0' cmp al,'9' jbe dump_4 add al,('A'-('9'+1)) dump_4: call putch mov al,' ' call putch dec cx inc di cmp di,16 jb dump_2 dump_5: mov al,' ' ; xxx - printf("\t"); call putch mov dx,di xor di,di dump_6: mov al,[bx + di] cmp al,' ' jae dump_7 mov al,'.' dump_7: call putch inc di cmp di,dx jb dump_6 mov di,crlf_msg call cputs add bx,16 or cx,cx jne dump_1 pop ax pop bx pop cx pop dx pop si pop di ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; lba_msg: db "Checking for LBA extensions to INT 13h BIOS...", 13, 10, 0 lba_err_msg: db "Sorry, the INT 13h BIOS in this PC does not support LBA", 13, 10 db "Try running this program in a Windows DOS box", 13, 10, 0 ; run it in a Windows DOS box because Windows will virtualize INT 13h AH=4xh ; (it will emulate these functions even if the BIOS doesn't support them) mbr_msg: db "Reading master boot record/partition table (sector 0 of disk)..." db 13, 10, 0 err_msg: db "Error from INT 13h AH=42h (LBA disk read)", 13, 10, 0 boot_msg: db 13, 10, "Reading boot sector (sector 0 of partition, sector ", 0 boot2_msg: db " of disk)", 13, 10, 0 crlf_msg: db 13, 10, 0 disk_adr_pkt: db disk_adr_pkt_len ; packet size (16 bytes) db 0 ; reserved ;dw 1 db 1 ; number of sectors to transfer db 0 ; reserved ; Note: if far address of sector buffer = FFFF:FFFF, the 64-bit ; linear address of the sector buffer is stored at offset 10h ; instead (disk_adr_pkt_len must be set to 18h) ; ; xxx - I tried this; it doesn't work with Windows95 emulated LBA ; .off: dw mbr ; far address of sector buffer .seg: dw 0 .lba: dd 0, 0 ; 64-bit starting sector number disk_adr_pkt_len equ $ - disk_adr_pkt mbr: ; partition table/MBR (sector 0 of drive) times 512 db 0 boot: ; bootsector (sector 0 of partition) times 512 db 0 times 40 db 0 num_buf: db 0