I've tried wading through the SATA and AHCI specs but it's like swimming in molasses. There is probably a simple command to send that flushes the data but I haven't been able to find it. I'm really hoping someone can point me in the right direction.
Code: Select all
; RAX = LBA sector, BX = Sector count, RDX = Buffer to write sectors
sata_write:
mov rcx, rbx
shl rcx, 9 ; Multiply by 512 to get expected number of bytes
call sata_tables_setup
mov [CMD_TAB.CMD_FIS.command_byte], ATA_CMD_WRITE_DMA_EXT
call send_SATA_command
xor rax, rax ; I added this section but still no joy :(
xor rbx, rbx
xor rcx, rcx
call sata_tables_setup
mov [CMD_TAB.CMD_FIS.command_byte], ATA_CMD_CACHE_FLUSH_EXT
call send_SATA_command
ret
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Set common table values ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; IN: RAX = LBA sector, BX = Sector count, ECX = number of bytes to transfer, RDX = Buffer to write data
sata_tables_setup:
push rax
push rcx
CLEAR_BLOCK CMD_LST, CMD_LST.size shr 3
CLEAR_BLOCK CMD_TAB, CMD_TAB.size shr 3
CLEAR_BLOCK RX_FIS, RX_FIS.size shr 3
pop rcx
pop rax
mov [CMD_LST.command_information], 0x0005 ; set up the command list
mov [CMD_LST.prdt_length], 1
mov [CMD_LST.command_table], CMD_TAB
mov [CMD_TAB.CMD_FIS.fis_type], FIS_TYPE_REG_H2D ; now set up the command FIS
mov [CMD_TAB.CMD_FIS.command], 0x80 ; we're sending a command (set .c bit 7)
mov qword[CMD_TAB.CMD_FIS.lba0], rax ; setup lba fields, 1st sector is 1
shl dword[CMD_TAB.CMD_FIS.device], 8
mov [CMD_TAB.CMD_FIS.device], 1 shl 6 ; LBA MODE!
test rcx, rcx
jz @f
mov [CMD_TAB.CMD_FIS.count], bx ; 1 to 65535 sectors
mov eax, ecx
sub eax, 1 ; bit 0 must be 1. actual bytes = byte_count + 1
mov [CMD_TAB.PRDT.memory], rdx ; now set up the PRDT
mov [CMD_TAB.PRDT.byte_count], eax ; bytes to transfer
@@: ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Ready, set and send, error if failure ;;;;;;;;;;;;;;;;;;;;;;;;;;
; IN : ECX = expected number of bytes to transfer
; OUT: RDI,*
send_SATA_command:
push rdi
mov rdi, [DRIVE_TABLE]
.wait_for_not_bsy:
pause
test dword[ABAR_PORTS_rdi.TASK_FILE], 0x80 ; first ensure the device is not busy
jnz .wait_for_not_bsy
and [ABAR_PORTS_rdi.COMMAND], 0xFFFFFFFE
mov [ABAR_PORTS_rdi.COMMAND_ISSUE], 0
.wait_for_idle:
pause
test [ABAR_PORTS_rdi.COMMAND], 1 ; first ensure the device is not busy
jnz .wait_for_idle
cmp [ABAR_PORTS_rdi.COMMAND_ISSUE], 0
jnz .wait_for_idle
mov [ABAR_PORTS_rdi.COMMAND_LIST], CMD_LST ; send CMD_LST to the device
btc [ABAR_PORTS_rdi.COMMAND], 4 ; FRE
mov [ABAR_PORTS_rdi.FIS], RX_FIS ; send the RX_FIS to the device
bts [ABAR_PORTS_rdi.COMMAND], 4 ; FRE
bts [ABAR_PORTS_rdi.COMMAND], 0 ; ST
mov [ABAR_PORTS_rdi.COMMAND_ISSUE], 1
@@:
pause
test [ABAR_PORTS_rdi.COMMAND_ISSUE], 1
jnz @b
test [ABAR_PORTS_rdi.TASK_FILE], 0x80
jnz @b
test dword[ABAR_PORTS_rdi.IRQ_STATUS], 0x40000000 ; task file error
jnz .error
test [ABAR_PORTS_rdi.TASK_FILE], 0x01 ; error
jnz .error
test [ABAR_PORTS_rdi.TASK_FILE], 0x20 ; drive fault
jnz .error
;and [ABAR_PORTS_rdi.COMMAND], 0xFFFFFFEE
btc [ABAR_PORTS_rdi.COMMAND], 0 ; ST
btc [ABAR_PORTS_rdi.COMMAND], 4 ; FRE
cmp [CMD_LST.prdt_successful_count], ecx ; ensure the controller transferred the correct # of bytes
jne .error
pop rdi
ret
.error:
print_ch ' '
mov rsi, .sata_error
call os_print_string
hlt
ret
.sata_error db "SATA ERROR!", 0