ahci sata writes only flush to disk when virtualbox shutdown
Posted: Wed Sep 28, 2016 2:23 am
I have written an ahci sata driver that seems to work ok. I can read and write to any sector on the disk. No problem. Except that is, the writes only hit the disk when I "shutdown the machine" in virtualbox. If I write a sector to disk, and then read back the same sector, the data isn't there. Only after I restart does it appear.
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.
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