/// <summary> /// Initalize ports /// </summary> private void initPorts() { PortInfo = new AHCIPortInfo[mSupportedPorts]; for (int i = 0; i < mSupportedPorts; i++) { PortInfo[i] = new AHCIPortInfo(); PortInfo[i].PortNumber = i; initPort(PortInfo[i]); } }
/// <summary> /// Find free command header on port /// </summary> /// <param name="port">Port info</param> /// <returns>Command header number</returns> private int findFreeCommandHeader(AHCIPortInfo port) { AHCI_Port_registers *portReg = port.PortRegisters; uint slotValues = (portReg->CI | portReg->SACT); // Find free slot. for (int i = 0; i < NUM_CMD_HEADERS; i++) { if ((slotValues & (1 << i)) == 0) { return(i); } } // No free slot found. return(-1); }
/// <summary> /// ATA transfer /// </summary> /// <param name="info">AHCI port info</param> /// <param name="offset">LBA</param> /// <param name="count">Num of sectors</param> /// <param name="buffer">Buffer ptr</param> /// <param name="write">Write action?</param> /// <returns></returns> public int AtaTransfer(AHCIPortInfo info, int offset, int count, byte *buffer, bool write) { AHCI_Port_registers *portReg = info.PortRegisters; portReg->IS = 0; int fullCount = count * 512; int headerNumber = findFreeCommandHeader(info); if (headerNumber == -1) { return(0); } AHCI_Command_header *header = info.CommandHeader + headerNumber; header->Options = (ushort)((sizeof(AHCI_REG_H2D) / 4) | ((write? CMD_HEAD_WRITE: CMD_HEAD_READ))); int prdtl = (fullCount / 2024) + 1; header->Prdtl = (ushort)prdtl; byte *curBuf = buffer; int curOffset = 0; AHCI_Command_table_entry *cmdTable = (AHCI_Command_table_entry *)Heap.AlignedAlloc(128, sizeof(AHCI_Command_table_entry) + (sizeof(AHCI_PRDT_Entry) * prdtl)); Memory.Memclear(cmdTable, sizeof(AHCI_Command_table_entry) + (sizeof(AHCI_PRDT_Entry) * prdtl)); header->CTBA = (uint)Paging.GetPhysicalFromVirtual(cmdTable); for (int i = 0; i < header->Prdtl - 1; i++) { AHCI_PRDT_Entry *entry = (AHCI_PRDT_Entry *)((int)cmdTable + sizeof(AHCI_Command_table_entry) + (sizeof(AHCI_PRDT_Entry) * i)); entry->DBA = (uint)Paging.GetPhysicalFromVirtual(curBuf); entry->DBAU = 0x00; entry->Misc = 2023; curBuf += 2024; curOffset += 2024; } AHCI_PRDT_Entry *lastEntry = (AHCI_PRDT_Entry *)((int)cmdTable + sizeof(AHCI_Command_table_entry) + (sizeof(AHCI_PRDT_Entry) * (prdtl - 1))); lastEntry->DBA = (uint)Paging.GetPhysicalFromVirtual(curBuf); lastEntry->DBAU = 0x00; lastEntry->Misc = (fullCount - curOffset) - 1; AHCI_REG_H2D *fis = (AHCI_REG_H2D *)cmdTable->CFIS; fis->FisType = (int)AHCI_FIS.REG_H2D; fis->Command = ATA_CMD_READ_DMA_EX; fis->Options = (1 << 7); fis->LBA0 = (byte)(offset & 0xFF); fis->LBA1 = (byte)((offset >> 8) & 0xFF); fis->LBA2 = (byte)((offset >> 16) & 0xFF); fis->Device = (1 << 6); fis->LBA3 = 0x00; fis->LBA4 = 0x00; fis->LBA5 = 0x00; fis->CountLo = (byte)(count & 0xFF); fis->CountHi = (byte)((count >> 8) & 0xFF); // Wait until port ready while ((info.PortRegisters->TFD & (ATA_DEV_BUSY | ATA_DEV_DRQ)) > 0) { Tasking.Yield(); } info.PortRegisters->CI = (uint)(1 << headerNumber); while (true) { if ((info.PortRegisters->CI & (1 << headerNumber)) == 0) { break; } Tasking.Yield(); } if ((info.PortRegisters->IS & PxIS_TFES) > 0) { return(0); } return(0); }
/// <summary> /// Initalize port /// </summary> /// <param name="portInfo">Port info</param> private void initPort(AHCIPortInfo portInfo) { AHCI_Port_registers *portReg = mPorts + portInfo.PortNumber; portInfo.CommandHeader = (AHCI_Command_header *)Heap.AlignedAlloc(4048, sizeof(AHCI_Command_header) * NUM_CMD_HEADERS); Memory.Memset(portInfo.CommandHeader, 0xFF, sizeof(AHCI_Command_header) * NUM_CMD_HEADERS); portInfo.Type = GetPortType(portReg); // Port found? if (portInfo.Type == AHCI_PORT_TYPE.NO) { return; } // NOTE: We support only SATA for now.. if (portInfo.Type != AHCI_PORT_TYPE.SATA) { switch (portInfo.Type) { case AHCI_PORT_TYPE.PM: Console.Write("[AHCI] Unsupported type PM found on port "); Console.WriteNum(portInfo.PortNumber); Console.WriteLine(""); break; case AHCI_PORT_TYPE.SATAPI: Console.Write("[AHCI] Unsupported type SATAPI found on port "); Console.WriteNum(portInfo.PortNumber); Console.WriteLine(""); break; case AHCI_PORT_TYPE.SEMB: Console.Write("[AHCI] Unsupported type SEMB found on port "); Console.WriteNum(portInfo.PortNumber); Console.WriteLine(""); break; } return; } stopPort(portReg); AHCI_Received_FIS *Fises = (AHCI_Received_FIS *)Heap.AlignedAlloc(256, sizeof(AHCI_Received_FIS)); Memory.Memclear(Fises, sizeof(AHCI_Received_FIS)); portReg->CLB = (uint)Paging.GetPhysicalFromVirtual(portInfo.CommandHeader); portReg->CLBU = 0x00; portReg->FB = (uint)Paging.GetPhysicalFromVirtual(Fises); portReg->FBU = 0x00; AHCI_Command_table_entry *cmdTable = (AHCI_Command_table_entry *)Heap.AlignedAlloc(128, sizeof(AHCI_Command_table_entry)); Memory.Memclear(cmdTable, sizeof(AHCI_Command_table_entry)); for (int i = 0; i < NUM_CMD_HEADERS; i++) { portInfo.CommandHeader[i].Prdtl = 0; portInfo.CommandHeader[i].CTBA = (uint)cmdTable; portInfo.CommandHeader[i].CTBAU = 0x00; } startPort(portReg); portInfo.PortRegisters = portReg; char *name = (char *)Heap.Alloc(5); name[0] = 'H'; name[1] = 'D'; name[2] = 'A'; name[3] = (char)('0' + portInfo.PortNumber); name[4] = '\0'; string nameStr = Util.CharPtrToString(name); Node node = new Node(); node.Read = readImpl; //node.Write = writeImpl; AHCICookie cookie = new AHCICookie(); cookie.AHCI = this; cookie.PortInfo = portInfo; node.Cookie = cookie; Disk.InitalizeNode(node, nameStr); RootPoint dev = new RootPoint(nameStr, node); VFS.MountPointDevFS.AddEntry(dev); }