mirror of
https://github.com/danbulant/Cosmos
synced 2026-06-11 18:51:41 +00:00
[AHCI] First working AHCI Controller
This commit is contained in:
parent
d4b4bd4d28
commit
96a35b2b6a
1 changed files with 99 additions and 70 deletions
|
|
@ -10,10 +10,10 @@ using Cosmos.Core.Memory.Old;
|
|||
|
||||
namespace Cosmos.HAL.BlockDevice
|
||||
{
|
||||
public class AHCI
|
||||
public class AHCI : Drivers.PCIDriver
|
||||
{
|
||||
internal static Debugger mAHCIDebugger = new Debugger("HAL", "AHCI");
|
||||
internal static PCIDevice xDevice = HAL.PCI.GetDevice(0x01, 0x06);
|
||||
internal static PCIDevice xDevice = HAL.PCI.GetDevice(0x001, 0x0006);
|
||||
|
||||
private static List<StoragePort> mPorts = new List<StoragePort>();
|
||||
private static GenericRegisters mGeneric;
|
||||
|
|
@ -55,16 +55,16 @@ namespace Cosmos.HAL.BlockDevice
|
|||
|
||||
internal static void InitDriver()
|
||||
{
|
||||
if (xDevice != null)
|
||||
{
|
||||
AHCI Driver = new AHCI(xDevice);
|
||||
}
|
||||
|
||||
if (xDevice == null) return;
|
||||
AHCI Driver = new AHCI(xDevice);
|
||||
}
|
||||
|
||||
internal PCIDevice GetDevice() => xDevice;
|
||||
internal override PCIDevice GetDevice() => xDevice;
|
||||
|
||||
public AHCI(PCIDevice aAHCIDevice)
|
||||
{
|
||||
mAHCIDebugger.Send("Something wrong!");
|
||||
aAHCIDevice.EnableBusMaster(true);
|
||||
aAHCIDevice.EnableMemory(true);
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ namespace Cosmos.HAL.BlockDevice
|
|||
{
|
||||
if(xPort.mPortType == PortType.SATA)
|
||||
{
|
||||
mAHCIDebugger.Send($"{xPort.mPortName} Port [0:{xPort.mPortNumber}]");
|
||||
mAHCIDebugger.Send($"{xPort.mPortName} Port 0:{xPort.mPortNumber}");
|
||||
var xMBRData = new byte[512];
|
||||
xPort.ReadBlock(0UL, 1U, xMBRData);
|
||||
var xMBR = new MBR(xMBRData);
|
||||
|
|
@ -88,6 +88,7 @@ namespace Cosmos.HAL.BlockDevice
|
|||
if (xMBR.EBRLocation != 0)
|
||||
{
|
||||
// EBR Detected!
|
||||
mAHCIDebugger.Send("EBR Detected within MBR code");
|
||||
var xEBRData = new byte[512];
|
||||
xPort.ReadBlock(xMBR.EBRLocation, 1U, xEBRData);
|
||||
var xEBR = new EBR(xEBRData);
|
||||
|
|
@ -99,7 +100,7 @@ namespace Cosmos.HAL.BlockDevice
|
|||
}
|
||||
}
|
||||
|
||||
mAHCIDebugger.Send($"Number of MBR partitions in port [0:{xPort.mPortNumber}]: ");
|
||||
mAHCIDebugger.Send($"Number of MBR partitions found on port 0:{xPort.mPortNumber} ");
|
||||
mAHCIDebugger.SendNumber(xMBR.Partitions.Count);
|
||||
for (int i = 0; i < xMBR.Partitions.Count; i++)
|
||||
{
|
||||
|
|
@ -119,16 +120,50 @@ namespace Cosmos.HAL.BlockDevice
|
|||
else if (xPort.mPortType == PortType.SATAPI)
|
||||
{
|
||||
mAHCIDebugger.Send($"{xPort.mPortName} Port 0:{xPort.mPortNumber}");
|
||||
// TODO: Implement ISO-9660 or UDF and Fix SATAPI
|
||||
|
||||
// Just to test Read Sector!
|
||||
|
||||
//byte[] xMBRData = new byte[512];
|
||||
//xPort.ReadBlock(0UL, 1U, xMBRData);
|
||||
//MBR xMBR = new MBR(xMBRData);
|
||||
|
||||
//mAHCIDebugger.Send($"Number of corrupted MBR partitions found on port 0:{xPort.mPortNumber} ");
|
||||
//mAHCIDebugger.SendNumber(xMBR.Partitions.Count);
|
||||
//for (int i = 0; i < xMBR.Partitions.Count; i++)
|
||||
//{
|
||||
// var xPart = xMBR.Partitions[i];
|
||||
// if (xPart == null)
|
||||
// {
|
||||
// Console.WriteLine("Null partition found at idx: " + i);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var xPartDevice = new Partition(xPort, xPart.StartSector, xPart.SectorCount);
|
||||
// BlockDevice.Devices.Add(xPartDevice);
|
||||
// Console.WriteLine("Found corrupted partition at idx: " + i);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Wait(int microsecondsTimeout)
|
||||
public static void HBAReset()
|
||||
{
|
||||
mGeneric.GlobalHostControl = 1;
|
||||
uint HR = 0;
|
||||
do
|
||||
{
|
||||
Wait(1);
|
||||
HR = mGeneric.GlobalHostControl & 1;
|
||||
} while (HR != 0);
|
||||
}
|
||||
|
||||
public static void Wait(int microsecondsTimeout)
|
||||
{
|
||||
byte xVoid;
|
||||
for (int i = 0; i < microsecondsTimeout; i++)
|
||||
{
|
||||
// Random IOPort
|
||||
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
|
||||
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
|
||||
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
|
||||
|
|
@ -144,26 +179,26 @@ namespace Cosmos.HAL.BlockDevice
|
|||
|
||||
private void GetCapabilities()
|
||||
{
|
||||
NumOfPorts = mGeneric.Capabilities & 0x1F;
|
||||
SupportsExternalSATA = (mGeneric.Capabilities >> 5 & 1) == 1;
|
||||
EnclosureManagementSupported = (mGeneric.Capabilities >> 6 & 1) == 1;
|
||||
CommandCompletionCoalsecingSupported = (mGeneric.Capabilities >> 7 & 1) == 1;
|
||||
NumOfCommandSlots = mGeneric.Capabilities >> 8 & 0x1F;
|
||||
PartialStateCapable = (mGeneric.Capabilities >> 13 & 1) == 1;
|
||||
SlumberStateCapable = (mGeneric.Capabilities >> 14 & 1) == 1;
|
||||
PIOMultipleDRQBlock = (mGeneric.Capabilities >> 15 & 1) == 1;
|
||||
FISBasedSwitchingSupported = (mGeneric.Capabilities >> 16 & 1) == 1;
|
||||
SupportsPortMutliplier = (mGeneric.Capabilities >> 17 & 1) == 1;
|
||||
SupportsAHCIModeOnly = (mGeneric.Capabilities >> 18 & 1) == 1;
|
||||
InterfaceSpeedSupport = mGeneric.Capabilities >> 20 & 0x0F;
|
||||
SupportsCommandListOverride = (mGeneric.Capabilities >> 24 & 1) == 1;
|
||||
SupportsActivityLED = (mGeneric.Capabilities >> 25 & 1) == 1;
|
||||
NumOfPorts = mGeneric.Capabilities & 0x1F;
|
||||
SupportsExternalSATA = (mGeneric.Capabilities >> 5 & 1) == 1;
|
||||
EnclosureManagementSupported = (mGeneric.Capabilities >> 6 & 1) == 1;
|
||||
CommandCompletionCoalsecingSupported = (mGeneric.Capabilities >> 7 & 1) == 1;
|
||||
NumOfCommandSlots = mGeneric.Capabilities >> 8 & 0x1F;
|
||||
PartialStateCapable = (mGeneric.Capabilities >> 13 & 1) == 1;
|
||||
SlumberStateCapable = (mGeneric.Capabilities >> 14 & 1) == 1;
|
||||
PIOMultipleDRQBlock = (mGeneric.Capabilities >> 15 & 1) == 1;
|
||||
FISBasedSwitchingSupported = (mGeneric.Capabilities >> 16 & 1) == 1;
|
||||
SupportsPortMutliplier = (mGeneric.Capabilities >> 17 & 1) == 1;
|
||||
SupportsAHCIModeOnly = (mGeneric.Capabilities >> 18 & 1) == 1;
|
||||
InterfaceSpeedSupport = mGeneric.Capabilities >> 20 & 0x0F;
|
||||
SupportsCommandListOverride = (mGeneric.Capabilities >> 24 & 1) == 1;
|
||||
SupportsActivityLED = (mGeneric.Capabilities >> 25 & 1) == 1;
|
||||
SupportsAggressiveLinkPowerManagement = (mGeneric.Capabilities >> 26 & 1) == 1;
|
||||
SupportsStaggeredSpinup = (mGeneric.Capabilities >> 27 & 1) == 1;
|
||||
SupportsMechanicalPresenceSwitch = (mGeneric.Capabilities >> 28 & 1) == 1;
|
||||
SupportsSNotificationRegister = (mGeneric.Capabilities >> 29 & 1) == 1;
|
||||
SupportsNativeCommandQueuing = (mGeneric.Capabilities >> 30 & 1) == 1;
|
||||
Supports64bitAddressing = (mGeneric.Capabilities >> 31 & 1) == 1;
|
||||
SupportsStaggeredSpinup = (mGeneric.Capabilities >> 27 & 1) == 1;
|
||||
SupportsMechanicalPresenceSwitch = (mGeneric.Capabilities >> 28 & 1) == 1;
|
||||
SupportsSNotificationRegister = (mGeneric.Capabilities >> 29 & 1) == 1;
|
||||
SupportsNativeCommandQueuing = (mGeneric.Capabilities >> 30 & 1) == 1;
|
||||
Supports64bitAddressing = (mGeneric.Capabilities >> 31 & 1) == 1;
|
||||
}
|
||||
|
||||
private void GetPorts()
|
||||
|
|
@ -171,45 +206,40 @@ namespace Cosmos.HAL.BlockDevice
|
|||
// Search for disks
|
||||
var xImplementedPort = mGeneric.ImplementedPorts;
|
||||
var xPort = 0;
|
||||
while (xPort < NumOfPorts)
|
||||
for(; xPort < 32; xPort++)
|
||||
{
|
||||
if ((xImplementedPort & 1) != 0)
|
||||
{
|
||||
PortRegisters xPortReg = new PortRegisters((uint)mABAR + 0x100 + (uint)(0x80 * xPort), (uint)xPort);
|
||||
PortRegisters xPortReg = new PortRegisters((uint)mABAR + 0x100, (uint)xPort);
|
||||
PortType PortType = CheckPortType(xPortReg);
|
||||
xPortReg.mPortType = PortType;
|
||||
var xPortString = "0:" + ((xPort.ToString().Length <= 1) ? xPort.ToString().PadLeft(1, '0') : xPort.ToString());
|
||||
if (PortType == PortType.SATA) // If Port Type was SATA.
|
||||
if (PortType == PortType.SATA) // If Port type was SATA.
|
||||
{
|
||||
Console.WriteLine("Initializing Port " + xPortString + " with type SATA");
|
||||
UInt16[] xSectorData = new UInt16[256];
|
||||
mAHCIDebugger.Send("Initializing Port " + xPortString + " with type SATA");
|
||||
PortRebase(xPortReg, (uint)xPort);
|
||||
SATA xSATAPort = new SATA(xPortReg);
|
||||
var xSATAPort = new SATA(xPortReg);
|
||||
mPorts.Add(xSATAPort);
|
||||
}
|
||||
else if (PortType == PortType.SATAPI) // If Port Type was SATAPI.
|
||||
else if (PortType == PortType.SATAPI) // If Port type was SATAPI.
|
||||
{
|
||||
mAHCIDebugger.Send("SATAPI");
|
||||
Console.WriteLine("Initializing Port " + xPortString + " with type Serial ATAPI");
|
||||
mAHCIDebugger.Send("Initializing Port " + xPortString + " with type Serial ATAPI");
|
||||
//PortRebase(xPortReg, (uint)xPort);
|
||||
//SATAPI xSATAPIPort = new SATAPI(xPortReg);
|
||||
//var xSATAPIPort = new SATAPI(xPortReg);
|
||||
//mPorts.Add(xSATAPIPort);
|
||||
}
|
||||
else if (PortType == PortType.SEMB) // If Port Type was SEMB.
|
||||
else if (PortType == PortType.SEMB) // If Port type was SEMB.
|
||||
{
|
||||
Console.WriteLine("SEMB Drive at port " + xPortString + " found, which is not supported yet!");
|
||||
mAHCIDebugger.Send("SEMB Drive at port " + xPortString + " found, which is not supported yet!");
|
||||
}
|
||||
else if (PortType == PortType.PM) // If Port Type was Port Mulitplier.
|
||||
else if (PortType == PortType.PM) // If Port type was Port Mulitplier.
|
||||
{
|
||||
Console.WriteLine("Port Multiplier Drive at port " + xPortString + " found, which is not supported yet!");
|
||||
mAHCIDebugger.Send("Port Multiplier Drive at port " + xPortString + " found, which is not supported yet!");
|
||||
}
|
||||
else if (PortType == PortType.Nothing)
|
||||
mAHCIDebugger.Send("No drive found at port: " + xPortString);
|
||||
else
|
||||
else if (PortType != PortType.Nothing)
|
||||
mAHCIDebugger.Send("Unknown drive found with signature: 0x" + xPortReg.SIG);// If Implemented Port value was not zero and non of the above.
|
||||
}
|
||||
xImplementedPort >>= 1;
|
||||
xPort++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -219,10 +249,8 @@ namespace Cosmos.HAL.BlockDevice
|
|||
var xSPD = (CurrentInterfaceSpeedStatus)((aPort.SSTS >> 4) & 0x0F);
|
||||
var xDET = (DeviceDetectionStatus)(aPort.SSTS & 0x0F);
|
||||
var xSignature = aPort.SIG;
|
||||
//var LBALow = (byte)(Port.SIG >> 08);
|
||||
//var LBAMedium = (byte)(Port.SIG >> 16);
|
||||
//var LBAHigh = (byte)(Port.SIG >> 24);
|
||||
|
||||
// Check if not reading wrong data!
|
||||
if (xIPM != InterfacePowerManagementStatus.Active)
|
||||
return PortType.Nothing;
|
||||
if (xDET != DeviceDetectionStatus.DeviceDetectedWithPhy)
|
||||
|
|
@ -241,49 +269,47 @@ namespace Cosmos.HAL.BlockDevice
|
|||
private void PortRebase(PortRegisters aPort, uint aPortNumber)
|
||||
{
|
||||
mAHCIDebugger.Send("Stop");
|
||||
if (!StopCMD(aPort)) aPort.SCTL = 1;
|
||||
if (!StopCMD(aPort)) SATA.PortReset(aPort);
|
||||
|
||||
ulong mCLBAddress = Heap.MemAlloc(1024);
|
||||
aPort.CLB = (uint)mCLBAddress & 0xFFFFFFFF;
|
||||
|
||||
var mFBAddress = Heap.MemAlloc(256);
|
||||
aPort.FB = (uint)mFBAddress & 0xFFFFFFFF;
|
||||
aPort.CLB = (uint)Base.AHCI + (0x400 * aPortNumber);
|
||||
aPort.FB = (uint)Base.AHCI + 0x8000 + (0x100 * aPortNumber);
|
||||
|
||||
aPort.SERR = 1;
|
||||
aPort.IS = 0;
|
||||
aPort.IE = 0;
|
||||
|
||||
|
||||
new MemoryBlock(aPort.CLB, 1024).Fill(0);
|
||||
new MemoryBlock(aPort.FB, 256).Fill(0);
|
||||
|
||||
GetCommandHeader(aPort); // Rebasing Command Header
|
||||
|
||||
StartCMD(aPort);
|
||||
GetCommandHeader(aPort); // Rebase Command header
|
||||
|
||||
if (!StartCMD(aPort)) SATA.PortReset(aPort);
|
||||
|
||||
aPort.IS = 0;
|
||||
aPort.IE = 0xFFFFFFFF;
|
||||
|
||||
mAHCIDebugger.Send("Finished!");
|
||||
}
|
||||
|
||||
private static HBACommandHeader[] GetCommandHeader(PortRegisters aPort)
|
||||
{
|
||||
var xCTBAAddress = Heap.MemAlloc(256);
|
||||
HBACommandHeader[] xCMDHeader = new HBACommandHeader[32];
|
||||
for (uint i = 0; i < xCMDHeader.Length; i++)
|
||||
{
|
||||
xCMDHeader[i] = new HBACommandHeader(aPort.CLB, i)
|
||||
{
|
||||
PRDTL = 8, // 8 prdt entries per command table
|
||||
// 256 bytes per command table, 64+16+48+16*8
|
||||
CTBA = xCTBAAddress + (256 * i),
|
||||
//TODO: Use the below register as the upper base address if HBA
|
||||
// supports S64A (64-bit Addressing)
|
||||
PRDTL = 8,
|
||||
|
||||
CTBA = (uint)(Base.AHCI + 0xA000) + (0x2000 * aPort.mPortNumber) + (0x100 * i),
|
||||
|
||||
CTBAU = 0
|
||||
};
|
||||
new MemoryBlock(xCMDHeader[i].CTBA, 256).Fill(0);
|
||||
new MemoryBlock(xCMDHeader[i].CTBA, 0x100).Fill(0);
|
||||
}
|
||||
return xCMDHeader;
|
||||
}
|
||||
|
||||
private void StartCMD(PortRegisters aPort)
|
||||
private bool StartCMD(PortRegisters aPort)
|
||||
{
|
||||
int xSpin;
|
||||
for (xSpin = 0; xSpin < 101; xSpin++)
|
||||
|
|
@ -291,12 +317,15 @@ namespace Cosmos.HAL.BlockDevice
|
|||
if ((aPort.CMD & (uint)CommandAndStatus.CMDListRunning) == 0) break;
|
||||
Wait(5000);
|
||||
}
|
||||
if (xSpin == 101) return;
|
||||
if (xSpin == 101) return false;
|
||||
|
||||
aPort.CMD |= (1 << 4);
|
||||
aPort.CMD |= (1 << 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Thanks to Microsoft for the detailed info about stopping command process!
|
||||
private bool StopCMD(PortRegisters aPort)
|
||||
{
|
||||
int xSpin;
|
||||
|
|
|
|||
Loading…
Reference in a new issue