[Solved] AHCI SATA read freezes on VirtualBox
Posted: Wed Jan 18, 2017 10:13 am
The title says it all. I can detect SATA disks, and the kernel log output is sensible:
But when I read from SATA (using the exact same technique I do to identify), it freezes and the bit I set in the command issue register never clears.
Here's the relevant code:
It works on QEMU, though. Is there something obvious I'm missing because I've been awake for a long time?
Code: Select all
[00000039] ahci: detecting AHCI controller...
[0000003E] ahci: found AHCI controller on PCI slot 00:0D:00
[0000003E] PCI device 00:0D:00 MMIO at 0xF0806000, mapped at 0xE0013000 -> 0xE0014FFF
[0000003F] ahci: found SATA device 'VBOX HARDDISK' on AHCI port 10
[00000045] Registered AHCI device, device number 0
Here's the relevant code:
Code: Select all
; clear all nescessary structures
mov edi, ahci_command_list
mov ecx, end_ahci_command_list - ahci_command_list
xor al, al
rep stosb
mov edi, ahci_command_table
mov ecx, end_ahci_command_table - ahci_command_table
xor al, al
rep stosb
; make the command list
mov [ahci_command_list.cfis_length], (end_ahci_command_fis-ahci_command_fis+3) / 4
mov [ahci_command_list.prdt_length], 1
mov dword[ahci_command_list.command_table], ahci_command_table
; the command FIS
mov [ahci_command_fis.fis_type], AHCI_FIS_H2D
mov [ahci_command_fis.flags], 0x80
mov [ahci_command_fis.command], SATA_READ_LBA28
mov [ahci_command_fis.device], 0xE0
mov eax, [.count]
mov [ahci_command_fis.count], ax
; LBA...
mov eax, dword[.lba]
mov [ahci_command_fis.lba0], al
shr eax, 8
mov [ahci_command_fis.lba1], al
shr eax, 8
mov [ahci_command_fis.lba2], al
shr eax, 8
mov [ahci_command_fis.lba3], al
; the PRDT
mov eax, [.buffer_phys]
mov dword[ahci_prdt.base], eax
mov eax, [.count]
shl eax, 9 ; mul 512
mov [ahci_prdt.count], eax
; send the command to the device
movzx edi, [.port]
shl edi, 7
add edi, AHCI_ABAR_PORT_CONTROL
add edi, [ahci_abar]
mov eax, [edi+AHCI_PORT_IRQ_STATUS]
mov [edi+AHCI_PORT_IRQ_STATUS], eax
and dword[edi+AHCI_PORT_COMMAND], not 1
and dword[edi+AHCI_PORT_COMMAND_ISSUE], not 1
mov dword[edi+AHCI_PORT_COMMAND_LIST], ahci_command_list
mov dword[edi+AHCI_PORT_COMMAND_LIST+4], 0
or dword[edi+AHCI_PORT_COMMAND], 1
or dword[edi+AHCI_PORT_COMMAND_ISSUE], 1
.loop:
test dword[edi+AHCI_PORT_COMMAND_ISSUE], 1 ; never leaves this loop!!
jnz .loop
.after_loop:
; turn off the command execution
and dword[edi+AHCI_PORT_COMMAND], not 1
and dword[edi+AHCI_PORT_COMMAND_ISSUE], not 1