1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
|
; asmsyntax=nasm
; hd_io.asm
;
; Interface to BIOS int 0x13 functions
;
; Copyright (C) 2000, Suzhe. See file COPYING for details.
;
%ifndef HAVE_HD_IO
%ifndef MAIN
%include "macros.h"
%include "hd_io.h"
%include "utils.asm"
%endif
%define HAVE_HD_IO
%define RETRY_TIMES 3
bits 16
;==============================================================================
;check_int13ext ---- Check if the extension of int13h is presents for a driver.
;input:
; dl = driver id
;output:
; cf = 0, int13ext is presents
; cl = interface support bitmap.
; cf = 1, int13ext is not presents
;==============================================================================
check_int13ext:
cmp byte [use_int13_ext], 0
jz .not_present
mov bx, 0x55aa
mov ah, INT13H_EXT_INSTCHECK
int 0x13 ; Check if int13h extension is presents
jc .not_present
cmp bx, 0xaa55
jne .not_present
test cl, EXT_SUBSET_FIXED | EXT_SUBSET_EDD
; Check if this drive supports extended
jz .not_present ; read/write
clc
ret
.not_present:
stc
ret
;==============================================================================
;get_drive_info ---- Get drive informations
;input:
; dl = drive id
; es:di -> buffer for drive info (struc struc_driveinfo)
;output:
; cf = 0 ok
; cf = 1 drive is not presents
;==============================================================================
get_drive_info:
pusha
mov [di + struc_driveinfo.id], dl
mov byte [di + struc_driveinfo.flags], 0 ; clear the flags
push dx
call check_int13ext
pop dx
jnc .ext_present
mov ah, INT13H_GETTYPE
push dx
int 0x13
mov [disk_errno], ah
pop dx
jc .drive_not_present
or ah, ah ; ah = drive type, = 0 no such drive
jz .drive_not_present
push es
push di
push ax ; save drive type
mov ah, INT13H_GETINFO
int 0x13
mov [disk_errno], ah
pop ax
pop di
pop es
jc .drive_not_present
push ax ; drive type.
push bx ; floppy type.
movzx ax, cl ;
and al, 0x3f ; get sectors per track
mov [di + struc_driveinfo.sectors], ax ;
xchg ah, ch ;
shl cx, 2 ;
mov cl, ah ; get cylinders
inc cx ;
mov [di + struc_driveinfo.cylinders], cx ;
movzx ax, dh ; get heads
inc ax ;
mov [di + struc_driveinfo.heads], ax ;
pop bx
pop ax
mov dh, DRVFLAG_DRIVEOK
cmp ah, DRV_TYPE_FIXED ; fixed drive.
je .fixed_drive
or dh, DRVFLAG_REMOVABLE
.fixed_drive:
or dh, DRVFLAG_CHSVALID
mov [di + struc_driveinfo.flags], dh
mov word [di + struc_driveinfo.sector_size], 0x200
jmp .endok
.drive_not_present:
popa
stc
ret
.ext_present:
;Int13h ext is presents, use int13h ext to get drive info
mov ah, INT13H_EXT_GETINFO
lea si, [tmp_extparam]
mov word [si + struc_extparam.pack_size], SIZE_OF_EXTPARAM
push dx
int 0x13
mov [disk_errno], ah
pop dx
jc .drive_not_present
mov ax, [si + struc_extparam.cylinders]
mov [di + struc_driveinfo.cylinders], ax
mov ax, [si + struc_extparam.heads]
mov [di + struc_driveinfo.heads], ax
mov ax, [si + struc_extparam.sectors]
mov [di + struc_driveinfo.sectors], ax
mov ax, [si + struc_extparam.bytes_per_sect]
mov [di + struc_driveinfo.sector_size], ax
mov al, [si + struc_extparam.flags] ;
and al, (DRVFLAG_CHSVALID + DRVFLAG_REMOVABLE) ; fill in the
or al, DRVFLAG_EXTOK + DRVFLAG_DRIVEOK ; struc_driveinfo.flags
%ifndef DISABLE_CDBOOT
cmp byte [si + struc_extparam.pack_size], SIZE_OF_EXTPARAM
jb .no_edd30
cmp word [si + struc_extparam.dpi_key], 0xBEDD
jne .no_edd30
cmp byte [si + struc_extparam.dpi_length], 36
jne .no_edd30
cmp dword [si + struc_extparam.interface_type], 'ATAP'
jne .not_cdrom
cmp byte [si + struc_extparam.interface_type+4], 'I'
jne .not_cdrom
or al, DRVFLAG_ISCDROM
.no_edd30:
cmp byte [si + struc_extparam.pack_size], 30
jb .not_cdrom
mov bx, [si + struc_extparam.dpte_addr+2]
cmp bx, 0xffff
je .not_cdrom
mov si, [si + struc_extparam.dpte_addr]
cmp si, 0xffff
je .not_cdrom
push ds
mov ds, bx
test byte [ds:si + struc_dpte.bios_spec], 0x40 ; check if is atapi dev
pop ds
jz .not_cdrom
or al, DRVFLAG_ISCDROM
.not_cdrom:
%endif
mov [di + struc_driveinfo.flags], al
.endok:
popa
clc
ret
;==============================================================================
;get_drive_flags ---- get drive flags
;input:
; dl = drive id
;output:
; cf = 0 ok, al = drive flags
; cf = 1 error, al = 0
;==============================================================================
get_drive_flags:
push di
lea di, [tmp_driveinfo]
call get_drive_info
mov al, [di + struc_driveinfo.flags]
pop di
ret
;;;;;;;;;;;;;;;;;;; perhaps these will be used in future ;;;;;;;;;;;;;;;;;;;
%if 0
;==============================================================================
;init_drives_info ---- get all drives info
;input:
; es:di -> buffer to store the info of each drives
; should have enought space to store 255 drives' info
;output:
; dh = the number of drives (include the floppy)
;==============================================================================
init_drives_info:
push es
push di
mov cx, 256
xor dx, dx
.loop_query:
push cx
push dx
call get_drive_info
pop dx
pop cx
jc .bad_drive
inc dh
.bad_drive:
add di, SIZE_OF_DRIVEINFO
inc dl
loop .loop_query
pop di
pop es
ret
%endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;==============================================================================
;lba2chs ---- lba to chs translation
;input:
; ebx = lba address
; ds : si -> drive info struc
;output:
; cf = 0 success
; ch = low eight bits of cylinder number
; cl = sector number 1-63 (bits 0-5)
; high two bits of cylinder (bits 6-7, hard disk only)
; dh = head number
; cf = 1 error ( cylinder exceed )
;==============================================================================
lba2chs:
push ax
mov eax, ebx
movzx ecx, word [si + struc_driveinfo.sectors] ; calculate sector:
or cx, cx ; sectors per track cannot equal
jz .convert_failed ; to zero.
xor edx, edx
div ecx ; sector = lba % sects_per_track + 1
inc dx ; lba1 = lba / sects_per_track
mov cx, dx ;
; calculate head and cylinder:
; head = lba1 % num_of_heads
movzx ebx, word [si + struc_driveinfo.heads]
; cylinder = lba1 / num_of_heads
or bl, bl ; heads cannot equal to zero.
jz .convert_failed ;
xor edx, edx
div ebx ;
mov dh, dl ; head = dl <= 255
cmp ax, MAX_CYLS ; cylinder = ax
ja .convert_failed ; cylinder is too big.
xchg al, ah ;
shl al, 6 ; fill cylinder and sector into
or cx, ax ; cx
pop ax
clc
ret
.convert_failed:
mov byte [disk_errno], 0xFE ; invalid LBA address
pop ax
stc
ret
;==============================================================================
;disk_access_low ---- read / write sectors on disk
;input:
; ah = function id, ( 02 = read, 03 = write )
; al = number of sectors to be accessed
; ebx = lba address
; ds : si -> drive info struc
; es : di -> buffer to get/store data
;output:
; cf = 0 success
; cf = 1 error
;==============================================================================
disk_access_low:
pusha
mov dh, [si + struc_driveinfo.flags]
test dh, DRVFLAG_DRIVEOK ; check if drive ok
jz .access_error
test dh, DRVFLAG_EXTOK
jz .no_ext
;int13h extension is present, use it
mov dl, [si + struc_driveinfo.id] ; get drive id
add ah, 0x40 ; ext read func id = 0x42
lea si, [tmp_int13ext]
xor ecx, ecx
mov byte [si + struc_int13ext.pack_size], 0x10 ;
mov [si + struc_int13ext.blk_num_high1], ecx ; clear and set
mov [si + struc_int13ext.reserved], cl ; some stuff.
mov [si + struc_int13ext.reserved1], cl ;
mov [si + struc_int13ext.buf_addr_off], di
mov [si + struc_int13ext.buf_addr_seg], es
mov [si + struc_int13ext.blk_num_low1], ebx
.retry_ext_read:
mov [si + struc_int13ext.blk_count], al
push ax
push dx
push si
int 0x13
mov [disk_errno], ah
pop si
pop dx
pop ax
jnc .access_ok
call reset_drive
inc dh
cmp dh, RETRY_TIMES ; retry 3 times
jb .retry_ext_read
jmp short .access_error
;int13h extension is not ok, use old int13h
.no_ext:
call lba2chs
jc .access_error
mov dl, [si + struc_driveinfo.id] ; dl = drive id
mov bx, di ; es : bx -> buffer
xor di, di
.retry_read:
push ax
push dx
push bx
int 0x13
mov [disk_errno], ah
pop bx
pop dx
pop ax
jnc .access_ok
call reset_drive
inc di
cmp di, RETRY_TIMES ; retry 3 times
jb .retry_read
.access_error:
stc
.access_ok:
popa
ret
;==============================================================================
;disk_access ---- read / write sectors on disk
;input:
; ah = function id, ( 02 = read, 03 = write )
; al = number of sectors to be accessed
; ebx = lba address
; dl = drive id
; es : di -> buffer
;output:
; cf = 0 success
; cf = 1 error
;==============================================================================
disk_access:
push si
push di
push ebx
push es
push ds ; ds -> es, tmp_driveinfo is in ds segment.
pop es
lea di, [tmp_driveinfo]
call get_drive_info
pop es
pop ebx
pop di
jc .access_error
lea si, [tmp_driveinfo]
call disk_access_low
.access_error:
pop si
ret
%if 0
;==============================================================================
;get_cdrom_devinfo ---- get the CDROM's device info, e.g. io port
;input: dl = drive id
;output: cf = 0 success, ax = base io port, bx = ctrl port,
; cx = device specification
;==============================================================================
get_cdrom_devinfo:
push si
call get_drive_flags
test al, DRVFLAG_ISCDROM
jz .not_cdrom
mov si, tmp_extparam
mov word [si], SIZE_OF_EXTPARAM
mov ah, 0x48
int 0x13
jc .not_cdrom
cmp byte [si], 30
jb .not_cdrom
mov ax, [si + struc_extparam.dpte_addr + 2]
cmp ax, 0xffff
je .not_cdrom
push es
push di
mov es, ax
mov di, [si + struc_extparam.dpte_addr]
mov ax, [es:di + struc_dpte.base_io]
mov bx, [es:di + struc_dpte.ctrl_io]
pop di
pop es
cmp byte [si], SIZE_OF_EXTPARAM
jb .not_cdrom
mov cx, [si + struc_extparam.device_path]
clc
jmp short .ok
.not_cdrom:
stc
.ok:
pop si
ret
%endif
%ifndef DISABLE_CDBOOT
;==============================================================================
;get_cdrom_boot_catalog ---- get the CDROM's boot catalog
;input:
; dl = drive id
; es:di -> buffer
;output:
; cf =0 success
; cf =1 error
;==============================================================================
get_cdrom_boot_catalog:
pusha
mov si, tmp_cdbc_cmd
mov byte [si], SIZE_OF_CDBC_CMD
mov byte [si+struc_cdbc_cmd.sector_count], 1
mov [si+struc_cdbc_cmd.buf_addr_off], di
mov [si+struc_cdbc_cmd.buf_addr_seg], es
xor bx, bx
mov [si+struc_cdbc_cmd.begnning_sect], bx
mov ax, 0x4d00
int 0x13
mov [disk_errno], ah
popa
ret
%endif
;==============================================================================
;reset_drive ---- reset the drive
;input:
; dl = drive id
;output:
; cf = 0 success
; cf = 1 error
;==============================================================================
reset_drive:
pusha
xor ax, ax
int 0x13
popa
ret
;==============================================================================
;get_drvid_str ---- get driver id string
;input:
; dl = drive id
; es:di -> buffer
;output:
; es:di -> point to the end of the string
;==============================================================================
get_drvid_str:
pusha
%ifdef SHOW_DRV_NAME
call get_drive_flags
cmp dl, MIN_HD_ID
jb .floppy
test al, DRVFLAG_REMOVABLE
jz .harddisk
test al, DRVFLAG_ISCDROM
jnz .cdrom
mov ax, 'RD'
jmp short .show_drv_name
.floppy:
mov ax, 'FD'
jmp short .show_drv_name
.harddisk:
mov ax, 'HD'
jmp short .show_drv_name
.cdrom:
mov ax, 'CD'
.show_drv_name:
stosb
mov al, ah
stosb
movzx ax, dl
and al, 0x0F
mov cl, 1
call htoa
%else
movzx ax, dl ; fill drive id
mov cl, 3 ;
call itoa ;
%endif
popa
add di, 3
ret
use_int13_ext db 1
%ifndef MAIN
%include "tempdata.asm"
%endif
%endif ;End of HAVE_HD_IO
|