First, let me say how happy I am that this website exists. I've poured over a good deal of helpful information here in the past several months, and am truly grateful for all the assistance it has provided.
Unfortunantely I have been hitting a snag that I cannot seem to get past. When attempting to implement AHCI I am getting hung up with one problem or another. In it's current state my AHCI driver hangs when attempting to stop an AHCI port. This code is mostly straight from the wiki:
Code: Select all
uint16 ahci_stop_port(HBA_PORT *port) {
// Clear ST (bit0)
port->cmd &= ~HBA_PxCMD_ST;
// Clear FRE (bit4)
port->cmd &= ~HBA_PxCMD_FRE;
// Wait until FR (bit14), CR (bit15) are cleared
while(1)
{
if (port->cmd & HBA_PxCMD_FR)
continue;
if (port->cmd & HBA_PxCMD_CR)
continue;
break;
}
// Clear FRE (bit4)
return 1;
}
I am running this in QEMU, with:
Code: Select all
qemu-system-x86_64 -device ahci,id=ahci -smp 3 -m 512 -net none -hda ./bin/boot.vdi -drive id=disk,file=./bin/fs.vdi,if=none -device ide-drive,drive=disk,bus=ahci.0
And I have (I believe correctly) tested device type status:probing PCI...
PCI: 0:0.0: 8086 class: 6.0 (Bridge device) irq: 0
PCI: 0:1.0: 8086:7000: class: 6.1 (Bridge device) irq: 0
PCI: 0:1.1: 8086:7010: class: 1.1 (Storage controller) irq: 0
PCI: 0:1.3: 8086:7113: class: 6.80 (Bridge device) irq: 9
PCI: 0:2.0: 1234 class: 3.0 (Display controller) irq: 0
PCI: 0:3.0: 8086 class: 1.6 (Storage controller) irq: 11 bar5: febf1000
Intel ICH9 controller found (bus=0, slot=3, func=0, abar=0xfebf1000)
HBA in legacy mode
SATA device detected:
port[19].sig = c990ffff
ipm=5, spd=c, det=3
rebasing port[19]...
Code: Select all
void ahci_try_setup_known_device(char *dev_name, uint64 ahci_base_mem, uint16 bus, uint16 slot, uint16 func) {
cprintf("%s controller found (bus=%d, slot=%d, func=%d, abar=0x%x)\n", dev_name, bus, slot, func, ahci_base_mem);
HBA_MEM *ptr = (HBA_MEM *)&ahci_base_mem;
cprintf(" HBA in ");
if(ptr->ghc == 0x0){
cprintf("legacy mode\n");
}else{
cprintf("AHCI-only mode\n");
}
uint64 pi = ptr->pi;
for(int i = 0; (i != 32); i++){
uint64 port_mask = 1 << i;
if((pi & port_mask) == 0x0){
continue;
}
HBA_PORT *hba_port = (HBA_PORT *) &ptr->ports[i];
if(hba_port->sig != SATA_SIG_ATAPI && hba_port->sig != SATA_SIG_SEMB && hba_port->sig != SATA_SIG_PM){
//we may have found a SATA device, but what is the status of this device?
uint32 ssts = hba_port->ssts;
uint8 ipm = (ssts >> 8) & 0x0F;
uint8 spd = (ssts >> 4) & 0x0F;
uint8 det = ssts & 0x7; //the Device Detection (DET) flags are the bottom 3 bits
if (det != HBA_PORT_DET_PRESENT && ipm != HBA_PORT_IPM_ACTIVE){
//nope
}else if(hba_port->sig==SATA_SIG_ATAPI){
//ATAPI device
}else if(hba_port->sig==SATA_SIG_SEMB){
}else if(hba_port->sig==SATA_SIG_PM){
//port multiplier detected
}else{
cprintf("SATA device detected:\n");
cprintf(" port[%d].sig = %x\n", i, hba_port->sig);
cprintf(" ipm=%x, spd=%x, det=%x\n", ipm, spd, det);
ahci_sata_init(hba_port, i);
}
}
}
}