; ============================================================================= ; ; Litos8 BIOS disk (physical disk) ; ; ============================================================================= ; Limitations: Sector size must be 512 bytes. Max. 2 floppy and 4 hard disks. ; ; Format of floppy disks is preset and cannot be changed: ; drive 360 KB: double side, 40 cylinders, 9 sectors per track ; drive 720 KB: double side, 80 cylinders, 9 sectors per track ; drive 1.2 MB: double side, 80 cylinders, 15 sectors per track ; drive 1.44 MB: double side, 80 cylinders, 18 sectors per track ; drive 2.88 MB: double side, 80 cylinders, 36 sectors per track ; ----------------------------------------------------------------------------- ; Exported user functions (15): ; BDiskGetNum - get number of BIOS disks ; BDiskGetDesc - get BIOS disk descriptor ; BDiskGetDescBIOS - get BIOS disk descriptor by BIOS disk number ; BDiskGetType - get BIOS disk type TEXT ; BDiskGetInfo - get BIOS disk info TEXT ; BDiskGetAllInfo - get BIOS all disks info TEXT ; LBAToCHS - translate absolute sector to CHS ; BDiskRead - read sectors ; BDiskWrite - write sectors (without verify) ; BDiskWriteV - write sectors with verify ; BDiskVerify - verify sectors ; BDiskReadSect - read cached sector (into sector buffer) ; BDiskWriteSect - write cached sector (from sector buffer) ; HDDCheck - check hard disk ; FDDCheck - check floppy disk ; ----------------------------------------------------------------------------- CODEINIT_SECTION ; ----------------------------------------------------------------------------- ; INIT: Initialize BIOS disk driver ; ----------------------------------------------------------------------------- ; ------------- invalid sector buffer BDiskInit: and word [OldSectBDD],byte 0 ; invalid sector buffer ; ------------- save current disk parameter table push ds ; push DS mov cl,1eh ; CL <- INT 1eh call SysGetInt32 ; get INT 1Eh address -> DX:AX mov ds,dx ; DS <- INT 1Eh segment xchg ax,si ; SI <- INT 1Eh offset mov di,FloppyDPT ; DI <- new INT 1Eh table mov cx,DPT_size ; CX <- DPT size push di ; push DI rep movsb ; copy old INT 1Eh DPT table pop di ; pop DI pop ds ; pop DS ; ------------- correct DPT table mov byte [di+DPT_Settle],15 ; head-settle time mov byte [di+DPT_LastSect],50 ; set last sector ; ------------- set new disk parameter table mov dx,ds ; DX <- INT 1Eh segment xchg ax,di ; AX <- INT 1Eh offset mov cl,1eh ; CL <- INT 1Eh call SysSetInt32 ; set new INT 1Eh address ; ------------- get number of floppy disks -> SI (max. 2) mov di,BDDTab ; DI <- descriptors test byte [Equipment],B0 ; any floppy disk? jz short BDiskInit3 ; no floppy disk mov al,[Equipment] ; AL <- equipment mov cl,6 ; CL <- number of rotations shr al,cl ; AL <- number of floppy disks - 1 inc ax ; AL <- number of floppy disks cmp al,2 ; max. 2 disks jb short BDiskInit0 ; number of disks is OK mov al,2 ; AL <- limit to 2 disks BDiskInit0: mov ah,0 ; AX = number of floppy disks xchg ax,si ; SI <- number of floppy disks ; ------------- get floppy disk type xor dx,dx ; DL <- 0, disk number BDiskInit1: push dx ; push DX (disk number) mov ah,8 ; AH <- function code mov bl,BDDF_Floppy360 ; preset to 360 KB call Int13 ; get disk parameters pop dx ; pop DX (disk number) ; ------------- initialize floppy descriptors mov [di+BDD_Disk],dl ; set disk number mov al,BDDiskNameFD2-BDDiskNameFD1 ; length of name mul dl ; AX <- offset of device name add ax,BDDiskNameFD1 ; AX <- device name mov [di+BDD_DevName],ax ; device name cmp bl,BDDF_FloppyLast ; check floppy type jbe short BDiskInit2 ; valid floppy type mov bl,BDDF_Floppy288 ; BL <- floppy is 2.88 MB or more BDiskInit2: or bl,BDDF_Removable ; BL <- flags mov [di+BDD_Flags],bl ; set flags and bx,byte BDDF_TypeMask ; BX <- type mov ah,[bx+FloppyCyl] ; AL <- number of cylinders mov [di+BDD_Cylinders],ah ; set cylinders mov al,[bx+FloppySect] ; AL <- sectors per track mov [di+BDD_SectTrack],al ; set sectors per track shl al,1 ; AL <- sectors per cylinder mov [di+BDD_SectCyl],al ; set sectors per cylinder mov byte [di+BDD_Heads],2 ; set number of heads mul ah ; AX <- total sectors mov [di+BDD_SectNum],ax ; set total sectors inc byte [FloppyNum] ; increase number of floppy disks inc byte [BDDNum] ; increase number of disks ; ------------- next floppy disk lea di,[di+BDD_size]; DI <- next descriptor inc dx ; increase disk number dec si ; counter of floppy disks jnz short BDiskInit1 ; initialize next floppy ; ------------- get number of hard disks -> SI (max. 4) BDiskInit3: mov dl,80h ; DL <- first hard disk mov ah,8 ; AH <- function code call Int13 ; get number of hard didks jnc short BDiskInit4 BDiskInit32: ret ; no hard disk BDiskInit4: and dl,7fh ; DL <- number of hard disks jz short BDiskInit32 ; no hard disk cmp dl,4 ; max. hard disks jb short BDiskInit5 ; number of hard disks is OK mov dl,4 ; DL <- limit number of hard disks BDiskInit5: mov dh,0 ; DX = number of hard disks mov si,dx ; SI <- number of hard disks ; ------------- get hard disk parameters mov dl,80h ; DL <- 80h, disk number BDiskInit6: push dx ; push DX (disk number) mov ah,8 ; AH <- function code call Int13 ; get disk parameters mov al,dh ; AL <- last head pop dx ; pop DX (disk number) ; ------------- initialize hard disk descriptors mov ah,0 ; AX = last head inc ax ; AX <- number of heads mov [di+BDD_Heads],ax ; set number of heads mov al,dl ; AL <- disk number (80h...) and al,7fh ; AL <- disk number relative mov al,BDDiskNameHD2-BDDiskNameHD1 ; length of name mul ah ; AX <- offset of device name add ax,BDDiskNameHD1 ; AX <- device name mov [di+BDD_DevName],ax ; device name mov al,ch ; AL <- max. cylinder LOW mov ah,cl ; AL <- max. cylinder HIGH rol ah,1 rol ah,1 ; rotate bits 6,7 to 0,1 and ah,B0+B1 ; AX = max. cylinder inc ax ; AX <- number of cylinders mov [di+BDD_Cylinders],ax ; set number of cylinders and cl,3fh ; CL <- max. sector mov [di+BDD_SectTrack],cl ; set sectors per track mov [di+BDD_Disk],dl ; set disk number mov byte [di+BDD_Flags],BDDF_HardDisk; set flags push dx ; push DX (disk number) mov ax,[di+BDD_SectTrack] ; AX <- sectors per track mul word [di+BDD_Heads] ; AX <- sectors per cylinder mov [di+BDD_SectCyl],ax ; set sectors per cylinder mul word [di+BDD_Cylinders] ; DX:AX <- total sectors mov [di+BDD_SectNum],ax ; set total sectors LOW mov [di+BDD_SectNum+2],dx ; set total sectors HIGH pop dx ; pop DX (disk number) inc byte [HardNum] ; increase number of hard disks inc byte [BDDNum] ; increase number of disks ; ------------- check LBA extension push dx ; push DX (disk number) mov ah,41h ; AH <- function code mov bx,55aah ; BX <- magic call Int13 ; check LBA extension pop dx ; pop DX (disk number) jc short BDiskInit7 ; no LBA extension cmp bx,0aa55h ; check magic jne short BDiskInit7 ; no LBA extension ; ------------- get drive extended parameters push dx ; push DX (disk number) push si ; push SI (disk counter) mov ah,48h ; AH <- function code mov si,BDD_Res ; SI <- result buffer mov word [si],BDD_RES_SIZE ; set size of buffer call Int13 ; get drive parameters mov bx,si ; BX <- result buffer pop si ; pop SI (disk counter) pop dx ; pop DX (disk number) jc short BDiskInit7 ; invalid LBA extension ; ------------- initialize LBA extended parameters cmp word [bx+24],SECTSIZE ; check sector size jne short BDiskInit7 ; invalid sector size or byte [di+BDD_Flags],BDDF_UseLBA ; use LBA extension push dx ; push DX mov ax,[bx+16] ; AX <- number of sectors LOW mov dx,[bx+18] ; DX <- number of sectors HIGH cmp word [bx+20],byte 0 ; overflow? ( > 2000 GB) je BDiskInit62 ; size is OK xor ax,ax ; AX <- 0 dec ax ; AX <- -1 mov dx,ax ; DX:AX <- limit disk size BDiskInit62: mov [di+BDD_SectNum],ax ; set total sectors LOW mov [di+BDD_SectNum+2],dx ; set total sectors HIGH or word [di+BDD_Cylinders],byte -1 ; limit cylinders cmp dx,[di+BDD_SectCyl] ; check sectors per cylinder jae BDiskInit64 ; overflow should came up div word [di+BDD_SectCyl] ; AX <- new number of cylinders mov [di+BDD_Cylinders],ax ; set new number of cylinders BDiskInit64: pop dx ; pop DX ; ------------- next hard disk BDiskInit7: lea di,[di+BDD_size]; DI <- next descriptor BDiskInit8: inc dx ; increase disk number dec si ; counter of hard disks jz short BDiskInit9 ; it was last disk jmp BDiskInit6 ; initialize next hard disk BDiskInit9: ret CODE_SECTION ; ----------------------------------------------------------------------------- ; Get number of BIOS disks ; ----------------------------------------------------------------------------- ; OUTPUT: AL = number of disks ; CL = number of floppy disks ; CH = number of hard disks ; ----------------------------------------------------------------------------- BDiskGetNum: mov al,[BDDNum] mov cx,[FloppyHardNum] ret ; ----------------------------------------------------------------------------- ; Get BIOS disk descriptor ; ----------------------------------------------------------------------------- ; INPUT: AL = disk number (0...) ; OUTPUT: BX = pointer to BDD descriptor (or NULL on CY error) ; CY = error, invalid disk number (returns BX = NULL) ; ----------------------------------------------------------------------------- ; ------------- check disk BDiskGetDesc: xor bx,bx ; BX <- 0 cmp al,[BDDNum] ; check disk number cmc ; CY = error jc short BDiskGetDesc8 ; error, invalid disk ; ------------- get BDD address -> BX (clears CF) xchg ax,bx ; BL <- disk number mov al,BDD_size ; AL <- descriptor size mul bl ; AX <- offset of descriptor add ax,BDDTab ; AX <- BDD address xchg ax,bx ; BX <- BDD address, AL <- disk number BDiskGetDesc8: ret ; ----------------------------------------------------------------------------- ; Get BIOS disk descriptor by BIOS disk number ; ----------------------------------------------------------------------------- ; INPUT: AL = BIOS disk number (0=fd1, ... 80h=hd1, ... 0C0h=rd1, ...) ; OUTPUT: BX = pointer to BDD descriptor (or NULL on CY error) ; CY = error, invalid disk number (returns BX = NULL) ; ----------------------------------------------------------------------------- BDiskGetDescBIOS: push cx ; push CX mov bx,BDDTab ; BX <- BDD tables mov cx,[BDDNum] ; CX <- number of BIOS disks jcxz BDiskGetDescB3 ; no BIOS disk BDiskGetDescB2: cmp al,[bx+BDD_Disk] ; check BIOS disk je short BDiskGetDescB4 ; found BIOS disk add bx,byte BDD_size ; BX <- shift pointer loop BDiskGetDescB2 ; next BIOS disk BDiskGetDescB3: xor bx,bx ; BX <- 0, invalid disk stc ; set error flag BDiskGetDescB4: pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Get BIOS disk type TEXT ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to BDD descriptor ; OUTPUT: SI = pointer to CTEXT disk type name ; ----------------------------------------------------------------------------- BDiskGetType: mov si,[bx+BDD_Flags] ; SI <- type and si,byte BDDF_TypeMask ; SI <- disk type shl si,1 ; SI <- offset in table mov si,[si+BDTypeTab] ; SI <- pointer to type name ret ; ----------------------------------------------------------------------------- ; Get BIOS disk info TEXT ; ----------------------------------------------------------------------------- ; INPUT: AL = disk number (0...) ; OUTPUT: BX = pointer to TEXT structure (NULL on memory error) ; CY = disk or memory error (BX = NULL) ; NOTES: Returned text should be destroyed using TextFree. ; ----------------------------------------------------------------------------- ; ------------- push registers BDiskGetInfo: push ax ; push AX push cx ; push CX push dx ; push DX push si ; push SI push di ; push DI ; ------------- get BIOS disk descriptor -> DI call BDiskGetDesc ; get disk descriptor jnc short BDiskGetInfo0 BDiskGetInfo99: jmp BDiskGetInfo9 ; invalid disk BDiskGetInfo0: mov di,bx ; DI <- disk descriptor call BDiskGetType ; get disk type -> SI ; ------------- create TEXT xchg ax,bx ; BL <- disk call TextNewEmpty ; create new text xchg bx,ax ; BX <- TEXT structure, AL <- disk jc short BDiskGetInfo99 ; memory error ; ------------- disk number mov ax,[di+BDD_DevName] ; AX <- device name call TextAddText ; add device name mov al,":" call TextAddChar ; add char ":" call TextAddSpc ; add space ; ------------- BIOS disk number mov al,"(" call TextAddChar ; add "(" char mov al,[di+BDD_Disk] ; AL <- BIOS disk call TextAddHByte ; add BIOS disk number mov ax,BDTextH ; text "h) " call TextAddText ; add "h) " text ; ------------- disk type xchg ax,si ; AX <- type name call TextAddText ; add type name ; ------------- disk size in MB (not removable media) ; Sector: 9 bits, 1 MB: 20 bits, conversion: 20-9 = 11 shifts test byte [di+BDD_Flags],BDDF_Removable ; removable? jnz short BDiskGetInfo2 ; removable call TextAddSpc ; add space mov ax,[di+BDD_SectNum] ; AX <- number of sectors LOW mov dx,[di+BDD_SectNum+2] ; DX <- number of sectors HIGH call TextAddDiskSize ; add disk size jmp short BDiskGetInfo3 ; ------------- flags BDiskGetInfo2: mov ax,BDFlagsTextRem ; AX <- text Removable call TextAddText ; add flag Removable BDiskGetInfo3: test byte [di+BDD_Flags],BDDF_UseLBA ; LBA? jz short BDiskGetInfo4 ; not LBA mov ax,BDFlagsTextLBA ; AX <- text LBA call TextAddText ; add flag LBA ; ------------- cylinders BDiskGetInfo4: mov ax,BDTextCyl ; AX <- text "cyl=" call TextAddText ; add text "cyl=" mov ax,[di+BDD_Cylinders] ; AX <- cylinders call TextAddWord ; add cylinders ; ------------- heads mov ax,BDTextHead ; AX <- text "heads=" call TextAddText ; add text "heads=" mov ax,[di+BDD_Heads] ; AX <- heads call TextAddWord ; add heads ; ------------- sectors per track mov ax,BDTextSTrk ; AX <- text "sectrk=" call TextAddText ; add text "sectrk=" mov ax,[di+BDD_SectTrack] ; AX <- sectors per track call TextAddWord ; add sectors per track ; ------------- total sectors mov ax,BDTextTotal ; AX <- text "total" call TextAddText ; add text "total=" mov ax,[di+BDD_SectNum] ; AX <- total sectors LOW mov dx,[di+BDD_SectNum+2] ; DX <- total sectors HIGH call TextAddDWord ; add total sectors ; ------------- pop registers clc ; clear error flag BDiskGetInfo9: pop di ; pop DI pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Get BIOS all disks info TEXT ; ----------------------------------------------------------------------------- ; OUTPUT: BX = pointer to TEXT structure (NULL on memory error) ; CY = memory error (BX = NULL) ; NOTES: Returned text should be destroyed using TextFree. ; ----------------------------------------------------------------------------- ; ------------- push registers BDiskGetAllInfo:push ax ; push AX push dx ; push DX ; ------------- create TEXT call TextNewEmpty ; create new text xchg bx,ax ; BX <- TEXT structure jc short BDiskGetAllInf9 ; memory error ; ------------- total number of disks mov ax,BDTextDiskNum ; AX <- text "Physical drives=" call TextAddText ; add text "Physical drives=" mov al,[BDDNum] ; AL <- total number of disks call TextAddByte ; add total number of disks ; ------------- number of floppy disks mov ax,BDTextFlopNum ; AX <- text "Floppy drives count=" call TextAddText ; add text "Floppy drives count=" mov al,[FloppyNum] ; AL <- number of floppy disks call TextAddByte ; add number of floppy disks ; ------------- number of hard disks mov ax,BDTextHardNum ; AX <- text "Hard drives count=" call TextAddText ; add text "Hard drives count=" mov al,[HardNum] ; AL <- number of hard disks call TextAddByte ; add number of hard disks call TextAddNewLine ; add new line ; ------------- add disc descriptors mov al,0 ; AL <- disk index mov ah,[BDDNum] ; AH <- number of disks or ah,ah ; any disk? jz short BDiskGetAllInf9 ; no disk BDiskGetAllInf2:push ax ; push AX mov dx,bx ; DX <- TEXT descriptor call BDiskGetInfo ; get disk info xchg ax,bx ; AX <- disk TEXT mov bx,dx ; BX <- TEXT descriptor jc short BDiskGetAllInf6 ; error call TextAddText ; add text xchg ax,bx ; AX <- TEXT, BX <- disk TEXT call TextFree ; free disk TEXT xchg ax,bx ; BX <- TEXT call TextAddNewLine ; add new line BDiskGetAllInf6:pop ax ; pop AX inc ax ; increase disk index dec ah ; decrease disk counter jnz short BDiskGetAllInf2 ; get next disk ; ------------- pop registers clc ; clear error flag BDiskGetAllInf9:pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Translate absolute sector to CHS ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0...) ; BX = pointer to BDD descriptor ; OUTPUT: CL = bit 0..5: sector number (1..63) ; bit 6..7: cylinder number HIGH (bits 8..9) ; CH = cylinder number LOW (bits 0..7) ; DH = head number (0..255) ; or bit 0..5 head number (0..63) ; bit 6,7: cylinder bits 10..11 ; DESTROYS: DL ; ----------------------------------------------------------------------------- ; Requirements: sector: 1..63, head: 0..255 (or 0..63), ; cylinder: 0..1023 (or 0..4095) ; ------------- push registers LBAToCHS: push ax ; push AX ; ------------- get cylinder number -> AX, and sector in cylinder -> DX div word [bx+BDD_SectCyl] ; AX <- cylinder, DX <- sector ; ------------- prepare cylinder number -> CX, AH xchg al,ah ; AH <- cylinder LOW, AL <- HIGH ror al,1 ror al,1 ; AL <- shift HIGH to bits 6..7 mov ch,al ; CH <- cylinder number HIGH ror ch,1 ror ch,1 ; CH <- bits 10..11 to bits 6..7 and al,B6+B7 ; mask bits 6..7 (cylinder 8..9) and ch,B6+B7 ; mask bits 6..7 (cylinder 10..11) xchg ax,cx ; CX <- cylinder, AH <- HIGH ; ------------- prepare head -> DH, and sector -> CL xchg ax,dx ; AX <- sector in cylinder, DH <- cyl. div byte [bx+BDD_SectTrack] ; AL <- head, AH <- sector inc ah ; AH <- sector + 1 or cl,ah ; CL <- cylinder HIGH + sector or dh,al ; DH <- head number + cylinder 10..11 ; ------------- pop registers pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Read/write sectors ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0..) ; BX = pointer to BDD descriptor ; CH = command (BCMD_READ, BCMD_WRITE, BCMD_VERIFY) ; CL = number of sectors (1..127) ; DI = data buffer ; OUTPUT: CY = operation error ; DX:AX = new sector ; CL = 0 ; DI = new data buffer ; DESTROY: CH ; NOTES: Verify after write is performed automatically. ; ----------------------------------------------------------------------------- ; ------------- push registers BDiskRW: push bp ; push BP BDiskRW0: mov bp,2 ; BP <- number of tries on error BDiskRW1: push ax ; push AX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- command correction cmp ch,BCMD_WRITEV ; write with verify? jne BDiskRW12 ; no mov ch,BCMD_WRITE ; CH <- change to Write command BDiskRW12: cmp ch,BCMD_VERIFYW ; verify after write? jne BDiskRW14 ; no mov ch,BCMD_VERIFY ; CH <- change to Verify command ; ------------- use LBA BDiskRW14: test byte [bx+BDD_Flags],BDDF_UseLBA ; use LBA mode? jz short BDiskRW2 ; not using LBA ; ------------- prepare DAP structure mov si,BDD_DAP ; SI <- LBA descriptor mov word [si+DAP_len],DAP_size ; size of structure mov [si+DAP_num],cl ; number of sectors mov [si+DAP_buff],di ; buffer LOW mov [si+DAP_buff+2],ds ; buffer HIGH mov [si+DAP_start],ax ; sector LOW mov [si+DAP_start+2],dx ; sector HIGH xor ax,ax ; AX <- 0 mov [si+DAP_res2],al ; reserved mov [si+DAP_start+4],ax ; sector 3 mov [si+DAP_start+6],ax ; sector 4 xchg ax,cx ; AH<-command, AL<-number of sectors add ah,40h ; AH <- command push ax ; push AX (number of sectors) mov al,0 ; AL <- flags, verify off jmp short BDiskRW4 ; ------------- translate absolute sector DX:AX to CHS -> CX, DX BDiskRW2: mov si,cx ; SI <- command and number of sectors call LBAToCHS ; translate sector to CHS xchg ax,si ; AH <- command, AL <- number of sectors ; ------------- limit number of sectors -> AL mov si,bx ; SI <- pointer to BDD descriptor mov bl,cl ; BL <- sector number and cylinder and bl,3fh ; BL <- mask sector number (1..63) dec bx ; BL <- sector number (0..62) mov bh,[si+BDD_SectTrack] ; BH <- sectors per track sub bh,bl ; BH <- remaining sectors cmp al,bh ; check number of sectors jb short BDiskRW3 ; number of sectors is OK mov al,bh ; AL <- limit number of sectors BDiskRW3: mov bx,si ; BX <- pointer to BDD descriptor ; ------------- perform required operation push ax ; push AX (number of sectors) BDiskRW4: xchg bx,di ; BX <- data buffer, DI <- BDD descr. mov dl,[di+BDD_Disk] ; DL <- disk number cmp dl,RAMDISK ; RAM disk? jne short BDiskRW5 ; no call RAMDiskRW ; RAM disk read/write jmp short BDiskRW56 BDiskRW5: cmp dl,MEMDISK ; memory disk? jne short BDiskRW52 ; no call MEMDiskRW ; memory disk read/write jmp short BDiskRW56 BDiskRW52: call Int13All ; call required operation BDiskRW56: xchg bx,di ; DI <- data buffer, BX <- BDD descr. pop ax ; pop AX (number of required sectors) ; ------------- pop registers (without AX and BP) pop si ; pop SI pop dx ; pop DX pop cx ; pop CX ; ------------- repeat on error jnc short BDiskRW6 ; operation OK dec bp ; BP <- error counter jz short BDiskRW9 ; no next attempt ; ------------- reset disk and try again push dx ; push DX mov ah,0 ; AH <- function code mov dl,[bx+BDD_Disk] ; DL <- disk number call Int13All ; disk reset pop dx ; pop DX pop ax ; pop AX jmp BDiskRW1 ; next attempt ; ------------- verify after write BDiskRW6: mov ah,0 ; AX <- number of sectors xchg ax,bp ; BP <- number of sectors pop ax ; pop AX cmp ch,BCMD_WRITEV ; write before verify? jne short BDiskRW8 ; no mov ch,BCMD_VERIFYW ; CH <- change to verify after write BDiskRW7: jmp BDiskRW0 ; verify sectors ; ------------- shift registers BDiskRW8: add ax,bp ; AX <- shift sector LOW adc dx,byte 0 ; DX <- shift sector HIGH xchg ax,bp ; AX <- number of sectors sub cl,al ; CL <- decrease number of sectors xchg ax,bp ; BP <- number of sectors push ax ; push AX push dx ; push DX mov ax,SECTSIZE ; AX <- sector size mul bp ; AX <- data size add di,ax ; DI <- shift data buffer pop dx ; pop DX pop ax ; pop AX ; ------------- change from verify to write cmp ch,BCMD_VERIFYW ; verify after write? jne short BDiskRW84 ; no mov ch,BCMD_WRITEV ; change to write before verify ; ------------- next group of sectors BDiskRW84: or cl,cl ; all sectors are transfered? jnz short BDiskRW7 ; next group of sectors push ax ; push AX ; ------------- pop rest of registers BDiskRW9: pop ax ; pop AX pop bp ; pop BP ret ; ----------------------------------------------------------------------------- ; Read sectors ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0..) ; BX = pointer to BDD descriptor ; CL = number of sectors (1..127) ; DI = data buffer ; OUTPUT: CY = operation error ; DX:AX = new sector ; DI = new data buffer ; ----------------------------------------------------------------------------- BDiskRead: push cx ; push CX mov ch,BCMD_READ ; CH <- command jmp short BDiskWrite4 ; ----------------------------------------------------------------------------- ; Write sectors (without verify) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0..) ; BX = pointer to BDD descriptor ; CL = number of sectors (1..127) ; DI = data buffer ; OUTPUT: CY = operation error ; DX:AX = new sector ; DI = new data buffer ; ----------------------------------------------------------------------------- BDiskWrite: push cx ; push CX mov ch,BCMD_WRITE ; CH <- command BDiskWrite4: call BDiskRW ; write sectors pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Write sectors with verify ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0..) ; BX = pointer to BDD descriptor ; CL = number of sectors (1..127) ; DI = data buffer ; OUTPUT: CY = operation error ; DX:AX = new sector ; DI = new data buffer ; ----------------------------------------------------------------------------- BDiskWriteV: push cx ; push CX mov ch,BCMD_WRITEV ; CH <- command jmp short BDiskWrite4 ; ----------------------------------------------------------------------------- ; Verify sectors ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0..) ; BX = pointer to BDD descriptor ; CL = number of sectors (1..127) ; OUTPUT: CY = operation error ; DX:AX = new sector ; ----------------------------------------------------------------------------- BDiskVerify: push cx ; push CX push di ; push DI mov ch,BCMD_VERIFY ; CH <- command xor di,di ; DI <- buffer call BDiskRW ; verify sectors pop di ; pop DI pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Read cached sector (into SectBuf) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = absolute sector (0..) ; BX = pointer to BDD descriptor ; OUTPUT: SI = sector buffer SectBuf ; CY = operation error ; ----------------------------------------------------------------------------- BDiskReadSect: mov si,SectBuf ; SI <- sector buffer ; ------------- check parameters cmp bx,[OldSectBDD] ; check BDD descriptor jne short BDiskReadSect2 ; invalid sector cmp ax,[OldSect] ; check sector index LOW jne short BDiskReadSect2 ; invalid sector cmp dx,[OldSect+2] ; check sector index HIGH je short BDiskReadSect8 ; sector is OK ; ------------- set parameters BDiskReadSect2: mov [OldSectBDD],bx ; set BDD descriptor mov [OldSect],ax ; set sector index LOW mov [OldSect+2],dx ; set sector index HIGH ; ------------- push registers push ax ; push AX push cx ; push CX push dx ; push DX push di ; push DI ; ------------- read sector mov cl,1 ; CL <- read 1 sector mov di,si ; DI <- sector buffer call BDiskRead ; read sector ; ------------- destroy buffer on error jnc short BDiskReadSect4 ; sector readed OK mov word [OldSectBDD],0 ; invalid sector buffer ; ------------- pop registers BDiskReadSect4: pop di ; pop DI pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX BDiskReadSect8: ret ; ----------------------------------------------------------------------------- ; Write cached sector (from SectBuf, with verify) ; ----------------------------------------------------------------------------- ; OUTPUT: CY = operation error ; NOTES: Valid parameters must be set in OldSectBDD and OldSect. ; ----------------------------------------------------------------------------- ; ------------- push registers BDiskWriteSect: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push di ; push DI ; ------------- get sector parameters mov bx,[OldSectBDD] ; BX <- BDD descriptor mov ax,[OldSect], ; AX <- sector index LOW mov dx,[OldSect+2] ; DX <- sector index HIGH ; ------------- read sector mov cl,1 ; CL <- read 1 sector mov di,SectBuf ; DI <- sector buffer call BDiskWriteV ; write sector with verify ; ------------- pop registers pop di ; pop DI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Call INT 13h service, saving some registers ; ----------------------------------------------------------------------------- ; DESTROY: AX, BX, CX, DX ; ----------------------------------------------------------------------------- ; ------------- push registers Int13: push si ; push SI push di ; push DI push bp ; push BP push ds ; push DS push es ; push ES ; ------------- protect writes to hard disk %ifdef PROTECT cmp ah,3 ; write sectors je short Int132 cmp ah,5 ; format track je short Int132 cmp ah,6 ; format track set bad sectors je short Int132 cmp ah,7 ; format track set bad sectors je short Int132 cmp ah,43h ; extended write sectors jne short Int136 Int132: or dl,dl ; hard disk? jns short Int136 ; no push cs pop ds push cs pop es cld call DispClear ; clear display mov bx,BDiskWProtErr ; BX <- text "panic" call DispConTextStr ; display error text Int134: jmp short Int134 ; system halt Int136: %endif ; ------------- call INT 13h stc ; preset error (due to some BIOSes) int 13h ; call Int 13h sti ; reenable interrupt (some BIOSes) cld ; set direction UP ; ------------- pop registers pop es ; pop ES pop ds ; pop DS pop bp ; pop BP pop di ; pop DI pop si ; pop SI ret ; ----------------------------------------------------------------------------- ; Call INT 13h service, saving (almost) all registers ; ----------------------------------------------------------------------------- ; DESTROYS: AX ; ----------------------------------------------------------------------------- ; ------------- push registers Int13All: push bx ; push BX push cx ; push CX push dx ; push DX ; ------------- call INT 13h call Int13 ; call Int 13h with saving registers ; ------------- pop registers pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Check hard disk ; ----------------------------------------------------------------------------- ; INPUT: BL = hard disk (0..) ; OUTPUT: CY = invalid hard disk ; ----------------------------------------------------------------------------- HDDCheck: push bx ; push BX add bl,80h ; add hard disk base jmp short FDDCheck2 ; check disk ; ----------------------------------------------------------------------------- ; Check memory disk ; ----------------------------------------------------------------------------- ; INPUT: BL = memory disk (0..) ; OUTPUT: CY = invalid memory disk ; ----------------------------------------------------------------------------- RAMCheck: push bx ; push BX add bl,MEMDISK ; add memory disk base jmp short FDDCheck2 ; check disk ; ----------------------------------------------------------------------------- ; Check RAM disk ; ----------------------------------------------------------------------------- ; INPUT: BL = RAM disk (0..) ; OUTPUT: CY = invalid RAM disk ; ----------------------------------------------------------------------------- RDDCheck: push bx ; push BX add bl,RAMDISK ; add RAM disk base jmp short FDDCheck2 ; check disk ; ----------------------------------------------------------------------------- ; Check floppy disk ; ----------------------------------------------------------------------------- ; INPUT: BL = floppy disk (0..) ; OUTPUT: CY = invalid floppy disk ; ----------------------------------------------------------------------------- FDDCheck: push bx ; push BX FDDCheck2: push ax ; push AX xchg ax,bx ; AL <- BIOS disk number call BDiskGetDescBIOS ; get BDD descriptor pop ax ; pop AX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Hard disk size ; ----------------------------------------------------------------------------- ; INPUT: BL = hard disk (0..) ; OUTPUT: DX:AX = media size (0 on error) ; CY = invalid hard disk (DX:AX = 0) ; ----------------------------------------------------------------------------- HDDSize: push bx ; push BX add bl,80h ; add hard disk base jmp short FDDSize2 ; disk size ; ----------------------------------------------------------------------------- ; Memory disk size ; ----------------------------------------------------------------------------- ; INPUT: BL = memory disk (0..) ; OUTPUT: DX:AX = media size (0 on error) ; CY = invalid memory disk (DX:AX = 0) ; ----------------------------------------------------------------------------- RAMSize: push bx ; push BX add bl,MEMDISK ; add memory disk base jmp short FDDSize2 ; disk size ; ----------------------------------------------------------------------------- ; RAM disk size ; ----------------------------------------------------------------------------- ; INPUT: BL = RAM disk (0..) ; OUTPUT: DX:AX = media size (0 on error) ; CY = invalid RAM disk (DX:AX = 0) ; ----------------------------------------------------------------------------- RDDSize: push bx ; push BX add bl,RAMDISK ; add RAM disk base jmp short FDDSize2 ; disk size ; ----------------------------------------------------------------------------- ; Floppy disk size ; ----------------------------------------------------------------------------- ; INPUT: BL = floppy disk (0..) ; OUTPUT: DX:AX = media size (0 on error) ; CY = invalid floppy disk (DX:AX = 0) ; ----------------------------------------------------------------------------- FDDSize: push bx ; push BX FDDSize2: xchg ax,bx ; AL <- BIOS disk number xor dx,dx ; DX <- 0 call BDiskGetDescBIOS ; get BDD descriptor mov ax,dx ; AX <- 0 jc short FDDSize4 ; error, invalid disk mov ah,[bx+BDD_SectNum] ; AX <- number of sectors * 256 mov dx,[bx+BDD_SectNum+1] ; DX <- number of sectors HIGH shl ax,1 ; AX <- size LOW rcl dx,1 ; DX <- size HIGH clc ; clear error flag FDDSize4: pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Read from hard disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = hard disk (0..1) ; CX = number of sectors ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- HDDRead: push bx ; push BX add bl,80h ; add hard disk base jmp short FDDRead2 ; read from disk ; ----------------------------------------------------------------------------- ; Read from memory disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = memory disk (0..1) ; CX = number of sectors ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- RAMRead: push bx ; push BX add bl,MEMDISK ; add memory disk base jmp short FDDRead2 ; read from disk ; ----------------------------------------------------------------------------- ; Read from RAM disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = RAM disk (0..1) ; CX = number of sectors ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- RDDRead: push bx ; push BX add bl,RAMDISK ; add RAM disk base jmp short FDDRead2 ; read from disk ; ----------------------------------------------------------------------------- ; Read from floppy disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = floppy disk (0..1) ; CX = number of sectors ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- ; ------------- push registers 1 FDDRead: push bx ; push BX ; ------------- get BDD descriptor -> BX FDDRead2: push ax ; push AX xchg ax,bx ; AL <- BIOS disk number call BDiskGetDescBIOS ; get BDD descriptor pop ax ; pop AX jc short FDDRead9 ; invalid disk ; ------------- push registers 2 push ax ; push AX push dx ; push DX push di ; push DI ; ------------- read data from disk call BDiskRead ; read sectors jc short FDDRead6 ; error xor cx,cx ; CX <- 0, data OK ; ------------- pop registers FDDRead6: pop di ; pop DI pop dx ; pop DX pop ax ; pop AX FDDRead9: pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Write to hard disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = hard disk (0..1) ; CX = number of sectors ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- HDDWrite: push bx ; push BX add bl,80h ; add hard disk base jmp short FDDWrite2 ; write to disk ; ----------------------------------------------------------------------------- ; Write to memory disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = memory disk (0..1) ; CX = number of sectors ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- RAMWrite: push bx ; push BX add bl,MEMDISK ; add memory disk base jmp short FDDWrite2 ; write to disk ; ----------------------------------------------------------------------------- ; Write to RAM disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = RAM disk (0..1) ; CX = number of sectors ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- RDDWrite: push bx ; push BX add bl,RAMDISK ; add RAM disk base jmp short FDDWrite2 ; write to disk ; ----------------------------------------------------------------------------- ; Write to floppy disk device ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = current sector offset ; BL = floppy disk (0..1) ; CX = number of sectors ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining sectors (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- ; ------------- push registers 1 FDDWrite: push bx ; push BX ; ------------- get BDD descriptor -> BX FDDWrite2: push ax ; push AX xchg ax,bx ; AL <- BIOS disk number call BDiskGetDescBIOS ; get BDD descriptor pop ax ; pop AX jc short FDDWrite9 ; invalid disk ; ------------- push registers 2 push ax ; push AX push dx ; push DX push di ; push DI ; ------------- write data to disk call BDiskWriteV ; write sectors (with verify) jc short FDDWrite6 ; error xor cx,cx ; CX <- 0, data OK ; ------------- pop registers FDDWrite6: pop di ; pop DI pop dx ; pop DX pop ax ; pop AX FDDWrite9: pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Constant data ; ----------------------------------------------------------------------------- CONST_SECTION align 2, db 0 ; ------------- floppy disk cylinders and sectors (2.88M,360K,1.2M,720K,1.44M) FloppyCyl: db 80,40,80,80,80 ; number of cylinders FloppySect: db 36,9,15,9,18 ; number of sectors per track ; ------------- floppy disk type name BDType288: CTEXT "floppy_2.88M" BDType360: CTEXT "floppy_360K" BDType12: CTEXT "floppy_1.2M" BDType720: CTEXT "floppy_720K" BDType144: CTEXT "floppy_1.44M" BDTypeHD: CTEXT "harddisk" BDTypeMEM: CTEXT "memory" BDTypeRAMDISK: CTEXT "RAMdisk" BDTypeTab: dw BDType288 dw BDType360 dw BDType12 dw BDType720 dw BDType144 dw BDTypeHD dw BDTypeMEM dw BDTypeRAMDISK BDTextH: CTEXT "h) " BDFlagsTextRem: CTEXT " removable" BDFlagsTextLBA: CTEXT " LBA" BDTextCyl: CTEXT " C=" BDTextHead: CTEXT " H=" BDTextSTrk: CTEXT " S=" BDTextTotal: CTEXT " total=" BDTextDiskNum: CTEXT "Physical drives=" BDTextFlopNum: CTEXT ", fdd=" BDTextHardNum: CTEXT ", hdd=" ; ------------- BIOS disk device names BDDiskNameFD1: CTEXT "fd1" ; floppy disk 1 BDDiskNameFD2: CTEXT "fd2" ; floppy disk 2 BDDiskNameHD1: CTEXT "hd1" ; hard disk 80h BDDiskNameHD2: CTEXT "hd2" ; hard disk 81h BDDiskNameHD3: CTEXT "hd3" ; hard disk 82h BDDiskNameHD4: CTEXT "hd4" ; hard disk 83h ; ------------- protect writes to hard disk %ifdef PROTECT BDiskWProtErr: CTEXT "PANIC: Unauthorized write to hard disk!",13,10 %endif ; ----------------------------------------------------------------------------- ; Uninitialised data ; ----------------------------------------------------------------------------- DATA_SECTION ; ------------- BIOS disks descriptors align 4, resb 1 BDDTab: resb BDD_size * BDISK_MAX ; disk descriptors BDDNum: resw 1 ; number of BIOS disks (word or byte) FloppyHardNum: FloppyNum: resb 1 ; number of floppy disks HardNum: resb 1 ; number of hard disks ; ------------- Disk Address Packet DAP (for LBA) BDD_DAP: ; resb DAP_size ; LBA descriptor (common with BDD_Res) BDD_Res: resb BDD_RES_SIZE ; LBA result buffer ; ------------- sector buffer align 4, resb 1 SectBuf: resb SECTSIZE ; sector buffer align 4, resb 1 OldSect: resd 1 ; old sector index OldSectBDD: resw 1 ; old sector BDD descriptor ; ------------- diskette parameter table (INT 1Eh) align 4, resb 1 FloppyDPT: resb DPT_size ; diskette parameter table