Advertisement
Guest User

ata.asm

a guest
Oct 1st, 2013
323
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;********************************************
  2. ;   ATA Hard Disk Routines
  3. ;
  4. ;   Can read/write ATA/PATA disks on Primary or secondary bus
  5. ;********************************************
  6.  
  7.  
  8. %ifndef __ATA__
  9. %define __ATA__
  10.  
  11. %include "pit.inc"
  12.  
  13. ; register-offsets (Primary bus: 0x1F0- ; for secondary: 0x170- )
  14. %define ATA_PORT_DATA       0
  15. %define ATA_PORT_ERROR      1
  16. %define ATA_PORT_SECT_COUNT 2
  17. %define ATA_PORT_SECT_NUM   3
  18. %define ATA_PORT_CYL_LOW    4
  19. %define ATA_PORT_CYL_HIGH   5
  20. %define ATA_PORT_DRV_HEAD   6
  21. %define ATA_PORT_STATUS     7
  22. %define ATA_PORT_COMMAND    7
  23.  
  24.  
  25. ata_port_ctrl dw    0   ; 0x3F6 ; Device Control Register (secondary: 0x376)
  26. ata_port_base dw    0   ; can be 0x1F0 (primary bus) or 0x170 (secondary)
  27.  
  28. ; status-reg's bits
  29. %define ATA_ST_ERR  0x01
  30. %define ATA_ST_IDX  0x02
  31. %define ATA_ST_DDRC 0x04
  32. %define ATA_ST_DRQ  0x08
  33. %define ATA_ST_SRV  0x10
  34. %define ATA_ST_DF   0x20
  35. %define ATA_ST_RDY  0x40
  36. %define ATA_ST_BSY  0x80
  37.  
  38. ; drive-head-reg's bits  (also used for selecting HD)
  39. ;   bits 3-0:   head number
  40. ;   bit4:       HD0(=0), HD1(=1)
  41. ;   bits 7-5:   101b for master (0xA0) or 1011b (0xB0) for slave. ORed  (0xE0 and 0xF0 for LBA28; 0x40 and 0x50 for LBA48)
  42.  
  43. ; Device Control Register (0x3F6)
  44. ;   bit 1:  nIEN    Disable IRQ sending
  45. ;   bit 2:  SRST    Software Reset if 1 on all ATA drives on a bus
  46. ;   bit 7:  HOB     Set this to read back the high-order-byte of the last LBA48 value sent to an I/O port.
  47. ;   all other bits are reserved and should always be clear.
  48. %define ATA_DCR_NIEN    0x02
  49. %define ATA_DCR_SRST    0x04
  50. %define ATA_DCR_HOB     0x80
  51.  
  52. ; HD ids
  53. %define ATA_CHS_MASTER      0xA0        ;(0xB0 is slave; i.e. 0xA0 | slave_bit)  
  54. %define ATA_LBA28_MASTER    0xE0        ;(0xF0 is slave)
  55. %define ATA_LBA48_MASTER    0x40        ;(0x50 is slave)
  56.  
  57. ata_slave_bit   db  0   ; change this to 1 if not the master but the slave drive need to be used on the bus
  58.  
  59. ; HD commands
  60. %define ATA_CMD_NOP             0x0
  61. %define ATA_CMD_READ            0x20
  62. %define ATA_CMD_READ_EXT        0x24    ; LBA48
  63. %define ATA_CMD_WRITE           0x30
  64. %define ATA_CMD_WRITE_EXT       0x34    ; LBA48
  65. %define ATA_CMD_READ_VRFY       0x40    ; sectors
  66. %define ATA_CMD_DIAG            0x90    ; execute device diagnostics
  67. %define ATA_CMD_STANDBY_IMM     0xE0
  68. %define ATA_CMD_IDLE_IMM        0xE1
  69. %define ATA_CMD_STANDBY         0xE2
  70. %define ATA_CMD_IDLE            0xE3
  71. %define ATA_CMD_CHK_PWR_MODE    0xE5
  72. %define ATA_CMD_SLEEP           0xE6
  73. %define ATA_CMD_FLUSH_CACHE     0xE7
  74. %define ATA_CMD_FLUSH_CACHE_EXT 0xEA
  75. %define ATA_CMD_IDENTIFY        0xEC
  76. ; there are many DMA-related cmds in the spec too!
  77.  
  78.  
  79. ata_id_arr dd 0x92000   ; Pointer to 512byte memory for IDENTIFY (just temporary memory)
  80.  
  81. ; cmd results
  82. %define ATA_OK          0
  83. %define ATA_NO_DRIVE    1
  84. %define ATA_ERR         2
  85. %define ATA_TIMEOUT     3
  86.  
  87. ; IDENTIFY data
  88. ; SerialNum word10-19 (20bytes). Words are big endian ("abcdefg" is stored as "badcfe g") (chars)
  89. ata_iden_sn times 20 db 0
  90. SerialNumtxt db "Serial number: ", 0
  91. ; Firmware version  word23-26 (chars)
  92. ata_iden_fv times 8 db 0
  93. FirmwareVertxt db "Firmware version: ", 0
  94. ; ModelNumber word 27-46 (40bytes). (chars)
  95. ata_iden_mn times 40 db 0
  96. ModelNumtxt db "Model number: ", 0
  97. Supportedtxt db "Supported: ", 0
  98. ; ATA?  word0, bit15 0: ATA
  99. ata_iden_ata    db 0    ; 1 is ATA          ; do we need this?
  100. ATAtxt db "ATA device", 0
  101. ; LBA?  word49 bit9 (1 if LBA supported)
  102. ata_iden_lba    db 0
  103. LBAtxt db "LBA ", 0
  104. ; LBA48 word83 bit10
  105. ata_iden_lba48  db 0
  106. LBA48txt db "LBA48 ", 0
  107. ; LBA28 word60-61 max 28-bit-LBA num (if nonzero: supports LBA28)
  108. ata_iden_maxlba28   dd 0
  109. MaxLBA28txt db "MaxLBA28: ", 0
  110. ; LBA48 word100-103 max 48-bit-LBA num
  111. ata_iden_maxlba48   times 8 db 0
  112. ata_iden_maxlba48tmp    times 8 db 0
  113. MaxLBA48txt db "MaxLBA48: ", 0
  114. ; DMA?  word49 bit8 (1 if DMA supported)
  115. ata_iden_dma    db 0
  116. DMAtxt db "DMA ", 0
  117. ; MDMA  word63  (supported MultiDMA modes)  bit2-0
  118. ata_iden_mdma   db 0
  119. ; UDMA  word88  (supported UDMA modes)  bit6-0
  120. ata_iden_udma   db 0
  121. ; MaxLogicalSectorNumPerRead/WriteMultipleCmds word47 bit7-0
  122. ata_iden_maxlsn db 0
  123. MaxNumSectPerMultiCmdtxt db "Max number of logical sectors per r/w multiple cmds: ", 0
  124. ; Current number of logicals sectors/DRQblock on R/W Multiple cmds. word59 bits7-0
  125. ata_iden_currlsn db 0
  126. ; PhysicalSectorSize/LogicalSectorSize word106 see bits
  127. ;   if bit14=1 and bit15=0 then info is valid in this word
  128. ;   if bit13 is set then info in bits3-0 is valid (number of logsects/physsects)
  129. ;   if bit12 is set, then this device has been formatted with logical sector size larger than 256 (see words117-118)
  130. ata_iden_logperphys db 0
  131. LogSectsPerPhysSecttxt db "Logical sectors per physical sector: ", 0
  132. ; LogicalSectorSize word117-118 (value is valid if bit12 of word106 is set) >256
  133. ata_iden_logsectsize dd 0
  134. LogicalSectorSizetxt db "Logical sectorsize: ", 0
  135. Capacitytxt db "Capacity: ", 0
  136. CapacityUnittxt db " Gb", 0
  137. ata_capacity dd 0 ; in Gb
  138.  
  139. ata_identify_res db 0   ; result of IDENTIFY
  140.  
  141. PrimaryBustxt   db "Primary bus, ", 0
  142. SecondaryBustxt db "Secondary bus, ", 0
  143. Mastertxt       db "Master", 0
  144. Slavetxt        db "Slave", 0
  145.  
  146.  
  147. ata_mem_addr dd 0   ; for R/W
  148.  
  149. ata_lba48   times 8 db 0        ; for R/W LBA48
  150.  
  151. ; identifies HD
  152. ; OUT: AL
  153. ata_identify:
  154.             xor eax, eax
  155.             ;send 0xA0 to 0x1F6  (This is CHS-mode. LBA28 and 48 ?)
  156.             mov al, ATA_CHS_MASTER
  157.             mov bl, [ata_slave_bit]
  158.             shl bl, 4
  159.             or  al, bl
  160.             mov dx, [ata_port_base]
  161.             add dx, ATA_PORT_DRV_HEAD
  162.             out dx, al
  163.             ;set 0 to 0x1F2 to 0x1F5
  164.             mov al, 0
  165.             mov dx, [ata_port_base]
  166.             add dx, ATA_PORT_SECT_COUNT
  167.             out dx, al
  168.             mov dx, [ata_port_base]
  169.             add dx, ATA_PORT_SECT_NUM
  170.             out dx, al
  171.             mov dx, [ata_port_base]
  172.             add dx, ATA_PORT_CYL_LOW
  173.             out dx, al
  174.             mov dx, [ata_port_base]
  175.             add dx, ATA_PORT_CYL_HIGH
  176.             out dx, al
  177.             ;send 0xEC to 0x1F7
  178.             mov al, ATA_CMD_IDENTIFY
  179.             mov dx, [ata_port_base]
  180.             add dx, ATA_PORT_COMMAND
  181.             out dx, al
  182.             ;read 0x1F7 (Status) if it is 0 then the drive doesn't exist
  183.             in al, dx
  184.             cmp al, ATA_NO_DRIVE
  185.             jz  .Back
  186.             ;If not 0:
  187.             ; poll 0x1F7 (STATUS) until bit7 clears (0x80) and bit3 sets: OK
  188.             ; or
  189.             ; bit0 sets or bit5 sets: ERR
  190.             mov DWORD [pit_ticks], 0
  191. .Poll       mov dx, [ata_port_base]         ; Timeout should be added
  192.             add dx, ATA_PORT_STATUS
  193.             in al, dx
  194.             mov bl, al
  195.             and al, ATA_ST_BSY+ATA_ST_DRQ
  196.             cmp al, ATA_ST_DRQ
  197.             jz  .Read
  198.             and bl, ATA_ST_ERR+ATA_ST_DF
  199.             cmp bl, 0
  200.             jz  .ChkTimOut
  201.             mov al, ATA_ERR
  202.             jmp .Back
  203. .ChkTimOut  cmp DWORD [pit_ticks], 2000 ; 2sec timeout
  204.             jna .Poll
  205.             mov al, ATA_TIMEOUT
  206.             jmp .Back
  207.             ; Read 256 words from ATA_PORT_DATA
  208. .Read       push edi
  209.             mov edi, DWORD [ata_id_arr]
  210.             mov dx, [ata_port_base]
  211.             add dx, ATA_PORT_DATA
  212.             mov ecx, 256
  213.             rep insw
  214.             push esi
  215.             ; copy data
  216.             mov ecx, 10
  217.             mov esi, DWORD [ata_id_arr]
  218.             add esi, 2*10
  219.             mov edi, ata_iden_sn
  220.             rep movsw
  221.             mov ecx, 4
  222.             mov esi, DWORD [ata_id_arr]
  223.             add esi, 2*23
  224.             mov edi, ata_iden_fv
  225.             rep movsw
  226.             mov ecx, 20
  227.             mov esi, DWORD [ata_id_arr]
  228.             add esi, 2*27
  229.             mov edi, ata_iden_mn
  230.             rep movsw
  231.             mov esi, DWORD [ata_id_arr]
  232.             test WORD [esi], 0x8000
  233.             jz  .SetATA
  234.             mov BYTE [ata_iden_ata], 0
  235.             jmp .ChkLBA
  236. .SetATA     mov BYTE [ata_iden_ata], 1
  237. .ChkLBA     mov esi, DWORD [ata_id_arr]
  238.             add esi, 2*49
  239.             test WORD [esi], 0x0200
  240.             jnz .SetLBA
  241.             mov BYTE [ata_iden_lba], 0
  242.             ; here should cmd 0x91 executes and then read words54-56 for CHS
  243.             ; also should calculate MAXLBA here from CHS
  244.             jmp .ChkDMA
  245. .SetLBA     mov BYTE [ata_iden_lba], 1
  246. .ChkLBA48   mov esi, DWORD [ata_id_arr]
  247.             add esi, 2*83
  248.             test WORD [esi], 0x0400
  249.             jnz .SetLBA48
  250.             mov BYTE [ata_iden_lba48], 0
  251.             jmp .MaxLBA28
  252. .SetLBA48   mov BYTE [ata_iden_lba48], 1
  253. .MaxLBA28   mov ecx, 2
  254.             mov esi, DWORD [ata_id_arr]
  255.             add esi, 2*60
  256.             mov edi, ata_iden_maxlba28
  257.             rep movsw
  258.             mov ecx, 4                      ; data of LBA48 will be copied even if LBA48 is not set!
  259.             mov esi, DWORD [ata_id_arr]
  260.             add esi, 2*100
  261.             mov edi, ata_iden_maxlba48
  262.             rep movsw
  263.             ; DMA
  264. .ChkDMA     mov esi, DWORD [ata_id_arr]
  265.             add esi, 2*49
  266.             test WORD [esi], 0x0100
  267.             jnz .SetDMA
  268.             mov BYTE [ata_iden_dma], 0
  269.             jmp .SetMDMA
  270. .SetDMA     mov BYTE [ata_iden_dma], 1
  271. .SetMDMA    mov esi, DWORD [ata_id_arr]
  272.             add esi, 2*63
  273.             mov cx, WORD [esi]
  274.             and cx, 0x0007
  275.             mov [ata_iden_mdma], cl
  276.             mov esi, DWORD [ata_id_arr]
  277.             add esi, 2*88
  278.             mov cx, WORD [esi]
  279.             and cx, 0x007F
  280.             mov [ata_iden_udma], cl
  281.             mov esi, DWORD [ata_id_arr]
  282.             add esi, 2*47
  283.             mov cx, WORD [esi]
  284.             and cx, 0x007F
  285.             mov [ata_iden_maxlsn], cl
  286.             mov esi, DWORD [ata_id_arr]
  287.             add esi, 2*59
  288.             mov cx, WORD [esi]
  289.             and cx, 0x007F
  290.             mov [ata_iden_currlsn], cl
  291.             mov esi, DWORD [ata_id_arr]
  292.             add esi, 2*106
  293.             mov cx, WORD [esi]
  294.             mov ax, cx
  295.             and ax, 0xC000
  296.             cmp ax, 0x4000
  297.             jz  .Valid
  298.             jmp .Sect512
  299. .Valid      mov esi, DWORD [ata_id_arr]
  300.             add esi, 2*106
  301.             test WORD [esi], 0x2000
  302.             jz  .LogSectS
  303.             and cl, 0x0F
  304.             mov [ata_iden_logperphys], cl
  305. .LogSectS   test WORD [esi], 0x1000
  306.             jz  .Sect512
  307.             mov esi, DWORD [ata_id_arr]
  308.             add esi, 2*117
  309.             mov ecx, [esi]
  310.             mov DWORD [ata_iden_logsectsize], ecx
  311.             jmp .Capacity
  312. .Sect512    mov ecx, 512
  313.             mov DWORD [ata_iden_logsectsize], ecx
  314.             ; Capacity computation (Gb)
  315. .Capacity   mov ecx, 21 ; if sector=512 byte then shift 2^11 to get Gb
  316.             cmp DWORD [ata_iden_logsectsize], 1024
  317.             jnz .Chk2048
  318.             mov ecx, 20
  319.             jmp .GetLBA
  320. .Chk2048    cmp DWORD [ata_iden_logsectsize], 2048
  321.             jnz .Chk4096
  322.             mov ecx, 19
  323.             jmp .GetLBA
  324. .Chk4096    cmp DWORD [ata_iden_logsectsize], 4096
  325.             jnz .GetLBA
  326.             mov ecx, 18
  327. .GetLBA     cmp BYTE [ata_iden_lba48], 1
  328.             jz  .GetLBA48
  329.             mov edx, [ata_iden_maxlba28]
  330.             shr edx, cl
  331.             mov [ata_capacity], edx
  332.             jmp .Ok
  333. .GetLBA48   push ecx
  334.             mov ecx, 8
  335.             mov esi, ata_iden_maxlba48
  336.             mov edi, ata_iden_maxlba48tmp
  337.             rep movsb
  338.             pop ecx
  339.             mov edx, DWORD [ata_iden_maxlba48tmp]
  340.             shr edx, cl
  341.             mov [ata_capacity], edx
  342. .Ok         mov al, ATA_OK
  343.             pop esi
  344.             pop edi
  345. .Back       mov [ata_identify_res], al
  346.             ret
  347.  
  348.  
  349. ata_info:
  350.             push esi
  351.             ; serial number
  352.             mov ebx, SerialNumtxt
  353.             call stdio_puts
  354.             mov ecx, 10
  355.             mov esi, ata_iden_sn
  356. .NextSN     mov ax, WORD [esi]         
  357.             mov bl, ah
  358.             call stdio_put_ch
  359.             mov bl, al
  360.             call stdio_put_ch
  361.             add esi, 2
  362.             loop .NextSN
  363.             call stdio_new_line
  364.             ; firmware version
  365.             mov ebx, FirmwareVertxt
  366.             call stdio_puts
  367.             mov ecx, 4
  368.             mov esi, ata_iden_fv
  369. .NextFV     mov ax, WORD [esi]
  370.             mov bl, ah
  371.             call stdio_put_ch
  372.             mov bl, al
  373.             call stdio_put_ch
  374.             add esi, 2
  375.             loop .NextFV
  376.             call stdio_new_line
  377.             ; model number
  378.             mov ebx, ModelNumtxt
  379.             call stdio_puts
  380.             mov ecx, 20
  381.             mov esi, ata_iden_mn
  382. .NextMN     mov ax, WORD [esi]         
  383.             mov bl, ah
  384.             call stdio_put_ch
  385.             mov bl, al
  386.             call stdio_put_ch
  387.             add esi, 2
  388.             loop .NextMN
  389.             call stdio_new_line
  390.             ; ATA?
  391.             cmp BYTE [ata_iden_ata], 1
  392.             jnz .PrLBA
  393.             mov ebx, ATAtxt
  394.             call stdio_puts
  395.             call stdio_new_line
  396.             mov ebx, Supportedtxt
  397.             call stdio_puts
  398.             ; LBA?
  399. .PrLBA      cmp BYTE [ata_iden_lba], 1
  400.             jnz .PrLBA48
  401.             mov ebx, LBAtxt
  402.             call stdio_puts
  403.             ; LBA48?
  404. .PrLBA48    cmp BYTE [ata_iden_lba48], 1
  405.             jnz .PrDMA
  406.             mov ebx, LBA48txt
  407.             call stdio_puts
  408.             ; DMA?
  409. .PrDMA      cmp BYTE [ata_iden_dma], 1
  410.             jnz .PrMaxLBA28
  411.             mov ebx, DMAtxt
  412.             call stdio_puts
  413.             ; Max sector-number of LBA28
  414. .PrMaxLBA28 call stdio_new_line
  415.             cmp BYTE [ata_iden_lba], 1
  416.             jnz .PrMaxSctPW
  417.             mov ebx, MaxLBA28txt
  418.             call stdio_puts
  419.             mov eax, [ata_iden_maxlba28]
  420.             call stdio_put_dec
  421.             call stdio_new_line
  422.             ; Max sector-number of LBA48
  423.             cmp BYTE [ata_iden_lba48], 1
  424.             jnz .PrMaxSctPW
  425.             mov ebx, MaxLBA48txt
  426.             call stdio_puts
  427.             mov eax, DWORD [ata_iden_maxlba48]          ;;;;;;
  428.             mov edx, DWORD [ata_iden_maxlba48+4]
  429.             call stdio_put_dec64
  430.             call stdio_new_line
  431.             ; Max number of Logical Sectors per Read/Write Multiple Commands
  432. .PrMaxSctPW mov ebx, MaxNumSectPerMultiCmdtxt
  433.             call stdio_puts
  434.             xor eax, eax
  435.             mov al, BYTE [ata_iden_maxlsn]
  436.             call stdio_put_dec
  437.             call stdio_new_line
  438.             cmp BYTE [ata_iden_logperphys], 0
  439.             jz  .PrLogSctSi
  440.             mov ebx, LogSectsPerPhysSecttxt
  441.             call stdio_puts
  442.             xor eax, eax
  443.             mov al, BYTE [ata_iden_logperphys]
  444.             call stdio_put_dec
  445.             call stdio_new_line
  446. .PrLogSctSi mov ebx, LogicalSectorSizetxt
  447.             call stdio_puts
  448.             mov eax, DWORD [ata_iden_logsectsize]
  449.             call stdio_put_dec
  450.             call stdio_new_line
  451.             ; Capacity
  452.             mov ebx, Capacitytxt
  453.             call stdio_puts
  454.             mov eax, [ata_capacity]
  455.             call stdio_put_dec
  456.             mov ebx, CapacityUnittxt
  457.             call stdio_puts    
  458.             call stdio_new_line
  459.             ; Primary or Secondary Bus, Master or Slave
  460.             cmp WORD [ata_port_base], 0x1F0
  461.             jnz .SecondaryB
  462.             mov ebx, PrimaryBustxt
  463.             call stdio_puts
  464.             jmp .MasterSl
  465. .SecondaryB cmp WORD [ata_port_base], 0x170
  466.             jnz .MasterSl
  467.             mov ebx, SecondaryBustxt
  468.             call stdio_puts
  469. .MasterSl   cmp WORD [ata_slave_bit], 0
  470.             jnz .Slave
  471.             mov ebx, Mastertxt
  472.             call stdio_puts
  473.             call stdio_new_line
  474.             jmp .End
  475. .Slave      mov ebx, Slavetxt
  476.             call stdio_puts
  477.             call stdio_new_line
  478. .End        pop esi
  479.             ret
  480.  
  481.  
  482. ata_reset:
  483.             mov dx, WORD [ata_port_ctrl]        ; does a reset on the bus
  484.             mov al, ATA_DCR_SRST
  485.             out dx, al          ; do a "software reset" on the bus
  486.             xor eax, eax
  487.             out dx, al          ; reset the bus to normal operation
  488.             in al, dx           ; it might take 4 tries for status bits to reset
  489.             in al, dx           ; ie. do a 400ns delay
  490.             in al, dx
  491.             in al, dx           ; do we really need these 4 in-s ?
  492.             mov dx, [ata_port_base]
  493.             add dx, ATA_PORT_STATUS
  494. .rdylp:
  495.             in al, dx
  496.             and al, ATA_ST_BSY+ATA_ST_RDY       ; check BSY and RDY
  497.             cmp al, ATA_ST_RDY          ; want BSY clear and RDY set
  498.             jne short .rdylp
  499.             ret
  500.  
  501.  
  502. ; IN:
  503. ;   ECX: lbaLo, EBP: lbaHi, EBX: sectorcnt, EAX: memaddr
  504. ; OUT: AL (0 indicates success)
  505. ata_rw:
  506.             cmp BYTE [ata_iden_lba], 1
  507.             jnz .Err                        ; if not LBA-drive then error
  508.             mov [ata_mem_addr], eax
  509.             cmp BYTE [ata_iden_lba48], 1
  510.             jz  .LBA48
  511.             call ata_rw_lba28
  512.             jmp .Back
  513. .LBA48      mov [ata_lba48], ecx
  514.             mov [ata_lba48+4], ebp
  515.             call ata_rw_lba48
  516.             jmp .Back
  517. .Err        mov al, ATA_ERR
  518. .Back       ret
  519.  
  520.  
  521. ; IN: 28-bit LBA in ECX; sector-count in BL; memory-address in ata_mem_addr; R/W (read=0) in DL
  522. ; OUT: AL 0 is ok
  523. ; sector-count of 0 means 256 sectors (128Kb) !?
  524. ata_rw_lba28:
  525.             ; send 0xE0 for the master or 0xF0 for the slave ORed with the highest 4 bits of the LBA to port DRV_HEAD
  526.             push edx
  527.             push ecx
  528.             push ebx
  529.             mov al, ATA_LBA28_MASTER
  530.             mov bl, [ata_slave_bit]
  531.             shl bl, 4
  532.             or  al, bl
  533.             pop ebx
  534.             shr ecx, 24
  535.             and cl, 0x0F
  536.             or al, cl
  537.             mov dx, [ata_port_base]
  538.             add dx, ATA_PORT_DRV_HEAD
  539.             out dx, al
  540.             ; send a NULL byte to port ERROR, if you like (it's ignored)
  541.             mov al, 0
  542.             mov dx, [ata_port_base]
  543.             add dx, ATA_PORT_ERROR
  544.             out dx, al
  545.             ; send sectorcount to port SECT_COUNT
  546.             mov al, bl
  547.             mov dx, [ata_port_base]
  548.             add dx, ATA_PORT_SECT_COUNT
  549.             out dx, al
  550.             ; send the low 8 bits of the LBA to port SECT_NUM
  551.             pop eax             ; pop ecx in eax
  552.             push eax
  553.             mov dx, [ata_port_base]
  554.             add dx, ATA_PORT_SECT_NUM
  555.             out dx, al
  556.             ; send the next low 8 bits of the LBA to port CYL_LOW
  557.             pop eax
  558.             push eax
  559.             shr ax, 8
  560.             mov dx, [ata_port_base]
  561.             add dx, ATA_PORT_CYL_LOW
  562.             out dx, al
  563.             ; send the next low 8 bits of the LBA to port CYL_HIGH
  564.             pop eax
  565.             shr eax, 16
  566.             mov dx, [ata_port_base]
  567.             add dx, ATA_PORT_CYL_HIGH
  568.             out dx, al
  569.             ; check if read or write
  570.             pop edx
  571.             cmp dl, 1
  572.             jz  .Write
  573.             ; Read
  574.             ; send r/w cmd to port COMMAND
  575.             mov al, ATA_CMD_READ
  576.             mov dx, [ata_port_base]
  577.             add dx, ATA_PORT_COMMAND
  578.             out dx, al
  579.             ; poll
  580.             mov DWORD [pit_ticks], 0
  581. .Poll       mov dx, [ata_port_base]     ; Timeout should be added
  582.             add dx, ATA_PORT_STATUS
  583.             in al, dx
  584.             mov bl, al
  585.             and al, ATA_ST_BSY+ATA_ST_DRQ
  586.             cmp al, ATA_ST_DRQ
  587.             jz  .Read
  588.             and bl, ATA_ST_ERR+ATA_ST_DF
  589.             cmp bl, 0
  590.             jz  .ChkTimOut
  591.             xor eax, eax
  592.             mov al, ATA_ERR
  593.             jmp .Back
  594. .ChkTimOut  cmp DWORD [pit_ticks], 2000 ; 2sec timeout
  595.             jna .Poll
  596.             xor eax, eax
  597.             mov al, ATA_TIMEOUT
  598.             jmp .Back
  599.             ; sect_count times
  600.             ; Read SectSize/2 words from PORT_DATA
  601. .Read       mov eax, DWORD [ata_iden_logsectsize]
  602.             shr eax, 1                  ; to get word instead of byte (divide by 2)
  603.             mul ebx
  604.             mov ecx, eax                ; EDX not important
  605.             push edi
  606.             mov edi, DWORD [ata_mem_addr]
  607.             mov dx, [ata_port_base]
  608.             add dx, ATA_PORT_DATA
  609.             rep insw
  610.             pop edi
  611.             xor eax, eax
  612.             mov al, ATA_OK
  613.             jmp .Back
  614.             ; Write
  615.             ; send r/w cmd to port COMMAND
  616. .Write      mov al, ATA_CMD_WRITE
  617.             mov dx, [ata_port_base]
  618.             add dx, ATA_PORT_COMMAND
  619.             out dx, al
  620.             ; poll
  621.             mov DWORD [pit_ticks], 0
  622. .PollWr     mov dx, [ata_port_base]     ; Timeout should be added
  623.             add dx, ATA_PORT_STATUS
  624.             in al, dx
  625.             mov bl, al
  626.             and al, ATA_ST_BSY+ATA_ST_DRQ
  627.             cmp al, ATA_ST_DRQ
  628.             jz  .Write2
  629.             and bl, ATA_ST_ERR+ATA_ST_DF
  630.             cmp bl, 0
  631.             jz  .ChkTimOutW
  632.             xor eax, eax
  633.             mov al, ATA_ERR
  634.             jmp .Back
  635. .ChkTimOutW cmp DWORD [pit_ticks], 2000 ; 2sec timeout
  636.             jna .PollWr
  637.             xor eax, eax
  638.             mov al, ATA_TIMEOUT
  639.             jmp .Back
  640.             ; sect_count times
  641.             ; Write SectSize/2 words to PORT_DATA
  642. .Write2     mov eax, DWORD [ata_iden_logsectsize]
  643.             shr eax, 1                  ; to get word instead of byte (divide by 2)
  644.             mul ebx
  645.             mov ecx, eax                ; EDX not important
  646.             push esi
  647.             mov esi, DWORD [ata_mem_addr]
  648.             mov dx, [ata_port_base]
  649.             add dx, ATA_PORT_DATA       ; Don't use rep outsw, because it's too fast!
  650. .NextR      outsw
  651.             nop                         ; delay
  652.             nop
  653.             nop
  654.             nop
  655.             loop .NextR
  656.             pop esi
  657.             ; flush (0xE7) after each write (maybe in the loop after every cycle!?)
  658.             mov al, ATA_CMD_FLUSH_CACHE
  659.             mov dx, [ata_port_base]
  660.             add dx, ATA_PORT_COMMAND
  661.             out dx, al
  662.             xor eax, eax
  663.             mov al, ATA_OK
  664. .Back       ret
  665.  
  666.  
  667. ; IN: 48-bit LBA in [ata_lba48]; sector-count in BX; memory-address in ata_mem_addr; R/W (read=0) in DL
  668. ; OUT: AL 0 is ok
  669. ; sector-count of 0 means 65536 sectors (32Mb) !?
  670. ; Since FOS is a 32-bit OS, 48-bit LBA cannot be entered in the command line!? (with LO and HI 32-bits on pstack it is possible).
  671. ata_rw_lba48:
  672.             ; send 0x40 for the master or 0x50 for the slave
  673.             push edx
  674.             push ebx
  675.             mov al, ATA_LBA48_MASTER
  676.             mov bl, [ata_slave_bit]
  677.             shl bl, 4
  678.             or  al, bl
  679.             pop ebx
  680.             mov dx, [ata_port_base]
  681.             add dx, ATA_PORT_DRV_HEAD
  682.             out dx, al
  683.             ; send sectorcount high-byte to port SECT_COUNT
  684.             mov al, bh
  685.             mov dx, [ata_port_base]
  686.             add dx, ATA_PORT_SECT_COUNT
  687.             out dx, al
  688.             ; send LBA4 to port SECT_NUM
  689.             mov al, [ata_lba48+3]
  690.             mov dx, [ata_port_base]
  691.             add dx, ATA_PORT_SECT_NUM
  692.             out dx, al
  693.             ; send LBA5 to port CYL_LOW
  694.             mov al, [ata_lba48+4]
  695.             mov dx, [ata_port_base]
  696.             add dx, ATA_PORT_CYL_LOW
  697.             out dx, al
  698.             ; send LBA6 to port CYL_HI
  699.             mov al, [ata_lba48+5]
  700.             mov dx, [ata_port_base]
  701.             add dx, ATA_PORT_CYL_HIGH
  702.             out dx, al
  703.             ; send sectorcount low-byte to port SECT_COUNT
  704.             mov al, bl
  705.             mov dx, [ata_port_base]
  706.             add dx, ATA_PORT_SECT_COUNT
  707.             out dx, al
  708.             ; send LBA1 to port SECT_NUM
  709.             mov al, [ata_lba48]
  710.             mov dx, [ata_port_base]
  711.             add dx, ATA_PORT_SECT_NUM
  712.             out dx, al
  713.             ; send LBA2 to port CYL_LOW
  714.             mov al, [ata_lba48+1]
  715.             mov dx, [ata_port_base]
  716.             add dx, ATA_PORT_CYL_LOW
  717.             out dx, al
  718.             ; send LBA3 to port CYL_HI
  719.             mov al, [ata_lba48+2]
  720.             mov dx, [ata_port_base]
  721.             add dx, ATA_PORT_CYL_HIGH
  722.             out dx, al
  723.             ; check if read or write
  724.             pop edx
  725.             cmp dl, 1
  726.             jz  .Write
  727.             ; Read
  728.             ; send r/w cmd to port COMMAND
  729.             mov al, ATA_CMD_READ_EXT
  730.             mov dx, [ata_port_base]
  731.             add dx, ATA_PORT_COMMAND
  732.             out dx, al
  733.             ; poll
  734.             mov DWORD [pit_ticks], 0
  735. .Poll       mov dx, [ata_port_base]     ; Timeout should be added
  736.             add dx, ATA_PORT_STATUS
  737.             in al, dx
  738.             mov bl, al
  739.             and al, ATA_ST_BSY+ATA_ST_DRQ
  740.             cmp al, ATA_ST_DRQ
  741.             jz  .Read
  742.             and bl, ATA_ST_ERR+ATA_ST_DF
  743.             cmp bl, 0
  744.             jz  .ChkTimOut
  745.             xor eax, eax
  746.             mov al, ATA_ERR
  747.             jmp .Back
  748. .ChkTimOut  cmp DWORD [pit_ticks], 2000 ; 2sec timeout
  749.             jna .Poll
  750.             xor eax, eax
  751.             mov al, ATA_TIMEOUT
  752.             jmp .Back
  753.             ; sect_count times
  754.             ; Read SectSize/2 words from PORT_DATA
  755. .Read       mov eax, DWORD [ata_iden_logsectsize]
  756.             shr eax, 1                  ; to get word instead of byte (divide by 2)
  757.             mul ebx
  758.             mov ecx, eax                ; EDX not important
  759.             push edi
  760.             mov edi, DWORD [ata_mem_addr]
  761.             mov dx, [ata_port_base]
  762.             add dx, ATA_PORT_DATA
  763.             rep insw
  764.             pop edi
  765.             xor eax, eax
  766.             mov al, ATA_OK
  767.             jmp .Back
  768.             ; Write
  769.             ; send r/w cmd to port COMMAND
  770. .Write      mov al, ATA_CMD_WRITE_EXT
  771.             mov dx, [ata_port_base]
  772.             add dx, ATA_PORT_COMMAND
  773.             out dx, al
  774.             ; poll
  775.             mov DWORD [pit_ticks], 0
  776. .PollWr     mov dx, [ata_port_base]     ; Timeout should be added
  777.             add dx, ATA_PORT_STATUS
  778.             in al, dx
  779.             mov bl, al
  780.             and al, ATA_ST_BSY+ATA_ST_DRQ
  781.             cmp al, ATA_ST_DRQ
  782.             jz  .Write2
  783.             and bl, ATA_ST_ERR+ATA_ST_DF
  784.             cmp bl, 0
  785.             jz  .ChkTimOutW
  786.             xor eax, eax
  787.             mov al, ATA_ERR
  788.             jmp .Back
  789. .ChkTimOutW cmp DWORD [pit_ticks], 2000 ; 2sec timeout
  790.             jna .PollWr
  791.             xor eax, eax
  792.             mov al, ATA_TIMEOUT
  793.             jmp .Back
  794.             ; sect_count times
  795.             ; Write SectSize/2 words to PORT_DATA
  796. .Write2     mov eax, DWORD [ata_iden_logsectsize]
  797.             shr eax, 1                  ; to get word instead of byte (divide by 2)
  798.             mul ebx
  799.             mov ecx, eax                ; EDX not important
  800.             push esi
  801.             mov esi, DWORD [ata_mem_addr]
  802.             mov dx, [ata_port_base]
  803.             add dx, ATA_PORT_DATA       ; Don't use rep outsw, because it's too fast!
  804. .NextR      outsw
  805.             nop                         ; delay
  806.             nop
  807.             nop
  808.             nop
  809.             loop .NextR
  810.             pop esi
  811.             ; flush (0xE7) after each write (maybe in the loop after every cycle!?)
  812.             mov al, ATA_CMD_FLUSH_CACHE_EXT
  813.             mov dx, [ata_port_base]
  814.             add dx, ATA_PORT_COMMAND
  815.             out dx, al
  816.             xor eax, eax
  817.             mov al, ATA_OK
  818. .Back       ret
  819.  
  820.  
  821.  
  822.  
  823. %endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement