Obsah - Organizace dat na disku

IO Disku v Assembleru

[bits 32]

Floppy Disk

FD_COMMAND_SEEK = 0Fh
FD_COMMAND_WRITESECTOR = 45h
FD_COMMAND_READSECTOR = 46h
FD_COMMAND_READID = 4Ah
FD_COMMAND_FORMATTRACK = 4Dh

// Reset controller
// DESTROY: ax, dx
h_fd_p_reset:
mov al, 0
mov dx, 3F2h
out dx, al
ret

// Start motor
// IN: al = fdnumber
// DESTROY: ax, cx, dx
h_fd_p_start_motor:
and al, 3
mov cl, al
mov al, 10h
shl al, cl
or al, 8 + 4
or al, cl
mov dx, 3F2h
out dx, al
ret

// Stop motor
// DESTROY: ax, dx
h_fd_p_stop_motor:
mov al, 8 + 4
mov dx, 3F2h
out dx, al
ret

// Wait0
// DESTROY: ax, dx
h_fd_p_wait0:
mov dx, 3F4h
l_h_fd_p_wait0_1:
 //...
 in al, dx
 and al, 0C0h
 cmp al, 80h
 jnz l_h_fd_p_wait0_1
ret

// Wait1
// DESTROY: ax, dx
h_fd_p_wait1:
mov dx, 3F4h
l_h_fd_p_wait1_1:
 //...
 in al, dx
 and al, 0C0h
 cmp al, 0C0h
 jnz l_h_fd_p_wait1_1
ret

// BEFORE: wait0, motor started
// IN: fdt_diskn, bh = head, cl = cylinder
// DESTROY: ax, dx
h_fd_p_seek:
mov dx, 3F5h
mov al, FD_COMMAND_SEEK
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov ah, fdt_diskn
mov al, bh
and al, 1
shl al, 2
or al, ah
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, cl
out dx, al
ret

// BEFORE: wait0, motor started
// IN: al = command, cl = cylinder, bh = head, bl = sector, fdt_diskn, fd_tracklen, fd_gap3
// OUT: al = 0 | errorcode
// DESTROY: ax, cx, dx, esi
h_fd_p_iocommand:
mov dx, 3F5h
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov ah, fdt_diskn
mov al, bh
and al, 1
shl al, 2
or al, ah
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, cl
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, bh
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, bl
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, 2
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, fd_tracklen
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, fd_gap3
out dx, al

call h_fd_p_wait0
mov dx, 3F5h
mov al, 0FFh
out dx, al

// Wait, read result
call h_fd_p_wait1
mov dx, 3F5h
in al, dx
mov ah, al

call h_fd_p_wait1
mov dx, 3F5h
in al, dx
mov cl, al

call h_fd_p_wait1
mov dx, 3F5h
in al, dx
mov ch, al

call h_fd_p_wait1
mov dx, 3F5h
in al, dx

call h_fd_p_wait1
mov dx, 3F5h
in al, dx

call h_fd_p_wait1
mov dx, 3F5h
in al, dx

call h_fd_p_wait1
mov dx, 3F5h
in al, dx

//... Project ah, cl, ch -> al
mov al, 0

ret

// BEFORE: wait0, motor started
// IN: fdt_diskn, cl = cylinder, bh = head, bl = sector, edi = target DMA, fd_*
// OUT: al = 0 | errorcode
// DESTROY: ax, cx, dx, esi
h_fd_p_read0:
// Prepare DMA
push ebx
 push ecx
  mov al, 2
  mov ah, DMA_MODE_SINGLE | DMA_MODE_READ
  mov ebx, edi
  mov ecx, 512
  call h_dma_read
 pop ecx
pop ebx
test al, al
jz l_h_fd_p_read0_3
ret

l_h_fd_p_read0_3:
// Read sector
mov al, FD_COMMAND_READSECTOR
jmp h_fd_p_iocommand


// BEFORE: wait0, motor started
// IN: fdt_diskn, cl = cylinder, bh = head, bl = sector, edi = source DMA, fd_*
// OUT: al = 0 | errorcode
// DESTROY: ax, cx, dx, esi
h_fd_p_write0:
// Prepare DMA
push ebx
 push ecx
  mov al, 2
  mov ah, DMA_MODE_SINGLE | DMA_MODE_WRITE
  mov ebx, edi
  mov ecx, 512
  call h_dma_write
 pop ecx
pop ebx
test al, al
jz l_h_fd_p_write0_3
ret

l_h_fd_p_write0_3:
// Write sector
mov al, FD_COMMAND_WRITESECTOR
jmp h_fd_p_iocommand


Hard Disk

HD_PORT_DATA = 0x1F0
HD_PORT_FEATURES = 0x1F1
HD_PORT_ERROR = 0x1F1
HD_PORT_COUNT = 0x1F2
HD_PORT_SECTOR = 0x1F3
HD_PORT_CYLLOW = 0x1F4
HD_PORT_CYLHIGH = 0x1F5
HD_PORT_DRIVEHEAD = 0x1F6
HD_PORT_COMMAND = 0x1F7
HD_PORT_STATUS = 0x1F7

HD_STATUS_BUSY = 0x80
HD_STATUS_DATAREADY = 8
HD_STATUS_ERROR = 1
HD_STATUS_FAULT = 0x20

ATA_CMD_READ = 0x20
ATA_CMD_WRITE = 0x30
ATA_CMD_EXT_READ = 0x24
ATA_CMD_EXT_WRITE = 0x34
ATA_CMD_DMA_EXT_READ = 0x25
ATA_CMD_DMA_EXT_WRITE = 0x35
ATA_CMD_FLUSH = 0xE7
ATA_CMD_IDENTIFY = 0xEC

ERC_HARDWARE = 2

uns1 hdt_slave_bit
uns2 hdt_port_base


// IN: al = physical disk number (0..3)
// OUT: hdt_slave_bit, hdt_port_base
h_hd_prepare_port_slave:
push eax
  and al, 1
  shl al, 4
  mov hdt_slave_bit, al // hdt_slave_bit = (pdn & 1) << 4
pop eax
test al, 2
jz l_h_hd_prepare_port_slave_2
  mov hdt_port_base, 170h
  jmp short l_h_hd_prepare_port_slave_3

l_h_hd_prepare_port_slave_2:
  mov hdt_port_base, 1F0h

l_h_hd_prepare_port_slave_3:
ret


// IN: edx:ebx = sector, ecx = count, hdt_slave_bit, hdt_port_base
// OUT: al = command_base, dx = port_base, hdt_count_remain
// DESTROY: eax, ecx, edx, hdt_high
h_hd_p_mklba:
test edx, edx
jnz l_h_hd_p_mklba_48
cmp ebx, 0x10000000
jnb l_h_hd_p_mklba_48

// 28
mov eax, ebx
shr eax, 24
and al, 15
or al, hdt_slave_bit
or al, 0xE0
mov dx, hdt_port_base
or dl, 6 // dx = HD_PORT_DRIVEHEAD (6)
out dx, al

mov eax, ecx
cmp eax, 256
jb l_h_hd_p_mklba_281
 mov eax, 255
l_h_hd_p_mklba_281:
sub ecx, eax
mov hdt_count_remain, ecx
mov ecx, eax
sub dl, 4 // dx = HD_PORT_COUNT (2)
out dx, al

mov al, bl
inc dl // dx = HD_PORT_SECTOR (3) / LBA low
out dx, al

mov al, bh
inc dl // dx = HD_PORT_CYLLOW (4) / LBA mid
out dx, al

mov eax, ebx
shr eax, 16
inc dl // dx = HD_PORT_CYLHIGH (5) / LBA high
out dx, al

sub dl, 5 // dx = PORT_BASE (0)
mov al, 0
ret

// 48
l_h_hd_p_mklba_48:
mov eax, ebx
shr eax, 24
shl edx, 8
or eax, edx
mov hdt_high, eax

mov al, 0xE0
or al, hdt_slave_bit
mov dx, hdt_port_base
or dl, 6 // dx = HD_PORT_DRIVEHEAD (6)
out dx, al

mov eax, ecx
cmp eax, 65536
jb l_h_hd_p_mklba_481
 mov eax, 65535
l_h_hd_p_mklba_481:
sub ecx, eax
mov hdt_count_remain, ecx
mov ecx, eax
mov al, ah
sub dl, 4 // dx = HD_PORT_COUNT (2)
out dx, al

mov eax, hdt_high
inc dl // dx = HD_PORT_SECTOR (3) / LBA low
out dx, al
shr eax, 8
inc dl // dx = HD_PORT_CYLLOW (4) / LBA mid
out dx, al
mov al, ah
inc dl // dx = HD_PORT_CYLHIGH (5) / LBA high
out dx, al

mov al, cl
sub dl, 3 // dx = HD_PORT_COUNT (2)
out dx, al

mov eax, ebx
inc dl // dx = HD_PORT_SECTOR (3)
out dx, al
shr eax, 8
inc dl // dx = HD_PORT_CYLLOW (4)
out dx, al
mov al, ah
inc dl // dx = HD_PORT_CYLHIGH (5)
out dx, al

sub dl, 5 // dx = PORT_BASE (0)
mov al, 4
ret


// IN: edx:ebx = sector, ecx = count, es:edi -> buffer, hdt_slave_bit, hdt_port_base
h_hd_read:
call h_hd_p_mklba
or al, ATA_CMD_READ
or dl, 7 // dx = HD_PORT_COMMAND (7)
out dx, al
l_h_hd_read5:
 or dl, 7 // dx = HD_PORT_STATUS (7)
 in al, dx
 test al, HD_STATUS_BUSY
 jz l_h_hd_read6
  //... noop
  jmp l_h_hd_read5
 l_h_hd_read6:
 test al, HD_STATUS_ERROR | HD_STATUS_FAULT
 jnz l_h_hd_error

 push ecx
  and dl, 0F8h // dx = HD_PORT_DATA (0)
  mov ecx, 512/4
  cld
  rep insd
 pop ecx
 dec ecx
 test ecx, ecx
 jnz l_h_hd_read5
xor eax, eax
ret

l_h_hd_error:
mov dx, hdt_port_base
or dl, 1 // dx = HD_PORT_ERROR (1)
in al, dx
mov ah, al
mov al, ERC_HARDWARE
ret


// IN: edx:ebx = sector, ecx = count, es:edi -> buffer, hdt_slave_bit, hdt_port_base
h_hd_write:
call h_hd_p_mklba
or al, ATA_CMD_WRITE
or dl, 7 // dx = HD_PORT_COMMAND (7)
out dx, al
push ds
 push esi
  mov ax, es
  mov esi, edi
  mov ds, ax
  l_h_hd_write5:
   or dl, 7 // dx = HD_PORT_STATUS (7)
   in al, dx
   test al, HD_STATUS_BUSY
   jz l_h_hd_write6
    //... noop
    jmp l_h_hd_write5
   l_h_hd_write6:
   test al, HD_STATUS_ERROR | HD_STATUS_FAULT
   jnz l_h_hd_write_error

   push ecx
    and dl, 0F8h // dx = HD_PORT_DATA (0)
    mov ecx, 512/4
    cld
    l_h_hd_write71:
     outsd
     jmp short l_h_hd_write76
     l_h_hd_write76:
     loop l_h_hd_write71
   pop ecx
   dec ecx
   test ecx, ecx
   jnz l_h_hd_write5
  mov edi, esi
 pop esi
pop ds
xor eax, eax
ret

l_h_hd_write_error:
 pop esi
pop ds
jmp l_h_hd_error


CD/DVD

ATA_CMD_PACKET = 0xA0
SCSI_COMMAND_READ10 = 28h

byte cd_packet[12], cd_buffer[2048]

// IN: ebx = sector number, hdt_port_base, hdt_slave_bit
// hdt_slave_bit: 0 (master) || 10h (slave)
// hdt_port_base: 1F0h (primary) || 170h (secondary)
// KEEP: ebx, ecx, edi
h_cd_p_read:
mov word ptr cd_packet[0], SCSI_COMMAND_READ10

mov eax, ebx
shr eax, 16
mov byte ptr cd_packet[2], ah
mov byte ptr cd_packet[3], al
mov byte ptr cd_packet[4], bh
mov byte ptr cd_packet[5], bl

mov byte ptr cd_packet[6], 0

mov byte ptr cd_packet[7], 1 / 256
mov byte ptr cd_packet[8], 1 & 255

mov byte ptr cd_packet[9], 0
mov word ptr cd_packet[10], 0

push ebx
 push ecx

  mov dx, hdt_port_base

  mov al, hdt_slave_bit
  or dl, 6 // dx = HD_PORT_DRIVEHEAD (6)
  out dx, al

  sub dl, 5 // dx = 1
  mov al, 0 // 0: PIO, 1:DMA
  out dx, al

  add dl, 3 // dx = 4
  mov al, 2048 & 255
  out dx, al
  inc dl // dx = 5
  mov al, 2048 >> 8
  out dx, al

  mov al, ATA_CMD_PACKET
  or dl, 7 // dx = HD_PORT_COMMAND (7)
  out dx, al

  l_h_cd_p_read_5:
   or dl, 7 // dx = HD_PORT_STATUS (7)
   in al, dx
   test al, HD_STATUS_BUSY
   jz l_h_cd_p_read_6
    //... noop
    jmp l_h_cd_p_read_5

  l_h_cd_p_read_6:
  test al, HD_STATUS_ERROR | HD_STATUS_FAULT
  jnz l_h_cd_p_read_error

  // write packet
  and dl, 0F8h // dx = HD_PORT_DATA (0)
  mov esi, offset cd_packet
  mov ecx, 6
  cld
  rep outsw

  // wait
  l_h_cd_p_read_7:
   or dl, 7 // dx = HD_PORT_STATUS (7)
   in al, dx
   test al, HD_STATUS_BUSY
   jz l_h_cd_p_read_8
    //... noop
    jmp l_h_cd_p_read_7

  l_h_cd_p_read_8:
  test al, HD_STATUS_ERROR | HD_STATUS_FAULT
  jnz l_h_cd_p_read_error

  // read byte count
  and dl, 0F8h
  add dl, 4 // dx = HD_PORT_CYLLOW (4) / LBA mid
  in al, dx
  mov cl, al
  inc dl // dx = HD_PORT_CYLHIGH (5) / LBA high
  in al, dx
  mov ch, al
  movzx ecx, cx // assert ecx = 2048
  cmp ecx, 800h
  jz l_h_cd_p_read_85
   mov al, ERC_UNKNOWN_GEOMETRY

 pop ecx
pop ebx

jmp short l_h_cd_p_read_9

  l_h_cd_p_read_85:

  // read data
  push edi
   and dl, 0F8h // dx = HD_PORT_DATA (0)
   mov edi, offset cd_buffer // es:edi
   shr ecx, 2
   rep insd
  pop edi

 pop ecx
pop ebx

mov al, 0

l_h_cd_p_read_9:
ret

l_h_cd_p_read_error:
 pop ecx
pop ebx
jmp l_h_hd_error