I'm working on an AHCI driver for some firmware I've been writing the past few weeks. I read the OSDev wiki page for AHCI and implemented an identification procedure. However, I'm running into a problem where the HBA port 0's signature is 0xFFFFFFFF. I realized that the offset of the signature is past how much I can map (by 0x400).
Essentially, I map BAR5 to 0xFA000000 (to 0xFA000FFF). I realized that port 0's signature is at 0xFA001400, which is past how much I map. How am I supposed to map more space, i.e. 8kb? Shouldn't the BAR size be 0x2000? (or something else bigger than 0x1000?)
Debug logs:
Code: Select all
ahci: pci address is 8000fa00 (bus 0 dev 31 fn 0)
pci: BAR size is 00001000
ahci: mapped BAR5 to fa000000
ahci: port 00000000 is good
ahci: port signature is ffffffff
PCI mapping:
Code: Select all
// Function is called like this in my AHCI init code:
// pci_map_bar(addr, PCI_BAR5, AHCI_BASE_MEM, (1<<2) | (1<<1), PCIBARTYPE_MEMSPACE);
// which translates to
// pci_map_bar(0x8000fa00, 36, 0xfa000000, (1<<2) | (1<<1), 1); (i think, i may have done the conversion of PCI_BAR5 wrong)
void pci_map_bar(uint32_t pci_addr, uint8_t bar, uint32_t val, uint32_t flags, uint8_t type){
// Get size of the bar
uint32_t og_bar = pci_read_dword(pci_addr+bar);
pci_write_dword(pci_addr+bar, 0xffffffff); // Write all 1s
uint32_t size = (~(pci_read_dword(pci_addr+bar)))+1;
dprintf(DEBUG_VERBOSE, "pci: BAR size is %x\n", size);
// Restore the original bar.
pci_write_dword(pci_addr+bar, og_bar);
if(type == PCIBARTYPE_IO){
pci_write_dword(pci_addr + bar, val | (1<<0)); // Bit 0 always set.
goto flush;
}
pci_write_dword(pci_addr + bar, val); // Tell the PCI config space we want
// to set the BAR to this.
flush:
// Tell the PCI bus this is correct!
uint16_t command = pci_read_word(pci_addr + PCI_COMMAND) | flags;
pci_write_word(pci_addr + PCI_COMMAND, command);
}
Code: Select all
uint32_t ahci__init(){
uint32_t addr = pci_does_device_exist(0x01, 0x06); // TODO: some may show themselves as subclass=0x01. Unimplemented.
dprintf(DEBUG_INFO, "ahci: pci address is %x\n", addr);
// Map BAR5 to 0xfa000000. This is the start of the host bus adapter memory space.
pci_map_bar(addr, PCI_BAR5, AHCI_BASE_MEM, (1<<2) | (1<<1), PCIBARTYPE_MEMSPACE);
dprintf(DEBUG_VERBOSE, "ahci: mapped BAR5 to %x\n", AHCI_BASE_MEM);
HBA_MEM* mem = (HBA_MEM*)AHCI_BASE_MEM;
uint32_t pi = mem->pi;
for(int i = 0; i < 32; i++){
if(pi & 1){
uint32_t v = ahci__checktype(&mem->ports[i]); // Get signature of
// the disk on this port.
if(v == 0) goto cont; // Not a device, skip!
dprintf(DEBUG_VERBOSE, "ahci: port %x is good\n", i);
dprintf(DEBUG_VERBOSE, "ahci: port signature is %x\n", v);
if(v != IDENT_SATAPI && v != IDENT_SEMB && v != IDENT_PM) return IDENT_SATA;
}
cont:
pi >>= 1;
}
}
uint32_t ahci__checktype(HBA_PORT* port){
uint32_t ssts = port->ssts;
uint8_t ipm = (ssts >> 8) & 0x0F;
uint8_t det = ssts & 0x0F;
if(ipm != 1 && det != 3) return 0; // No device!
return port->sig;
}
