Merge pull request #763 from KingLuigi4932/patch-6

[FirstWorking] Implementing AHCI Controller Driver
This commit is contained in:
fanoI 2018-01-06 20:16:50 +01:00 committed by GitHub
commit eafd38ecac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1951 additions and 119 deletions

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Cosmos.Core.MemoryGroup
{
public class AHCI
{
public MemoryBlock DataBlock;
public AHCI(uint aSectorSize)
{
DataBlock = new Core.MemoryBlock(0x0046C000, aSectorSize * 1024);
DataBlock.Fill(0);
}
}
}

View file

@ -0,0 +1,384 @@
using System;
using System.Collections.Generic;
using Cosmos.HAL;
using Cosmos.Debug.Kernel;
using Cosmos.HAL.BlockDevice;
using Cosmos.HAL.BlockDevice.Ports;
using Cosmos.HAL.BlockDevice.Registers;
using Cosmos.Core;
using Cosmos.Core.Memory.Old;
namespace Cosmos.HAL.BlockDevice
{
public class AHCI
{
internal static Debugger mAHCIDebugger = new Debugger("HAL", "AHCI");
internal static PCIDevice xDevice = HAL.PCI.GetDeviceClass(HAL.ClassID.MassStorageController,
HAL.SubclassID.SATAController,
HAL.ProgramIF.SATA_AHCI);
private static List<StoragePort> mPorts = new List<StoragePort>();
private static GenericRegisters mGeneric;
private static ulong mABAR;
// Capabilities
#region Capabilities
private static bool Supports64bitAddressing;
private static bool SupportsNativeCommandQueuing;
private static bool SupportsSNotificationRegister;
private static bool SupportsMechanicalPresenceSwitch;
private static bool SupportsStaggeredSpinup;
private static bool SupportsAggressiveLinkPowerManagement;
private static bool SupportsActivityLED;
private static bool SupportsCommandListOverride;
private static uint InterfaceSpeedSupport;
private static bool SupportsAHCIModeOnly;
private static bool SupportsPortMutliplier;
private static bool FISBasedSwitchingSupported;
private static bool PIOMultipleDRQBlock;
private static bool SlumberStateCapable;
private static bool PartialStateCapable;
private static uint NumOfCommandSlots;
private static bool CommandCompletionCoalsecingSupported;
private static bool EnclosureManagementSupported;
private static bool SupportsExternalSATA;
private static uint NumOfPorts;
#endregion
// Constants
public const ulong RegularSectorSize = 512UL;
// Informations
public string SerialNo;
public string Version
{
get => ((byte)mGeneric.AHCIVersion >> 24) + (byte)(mGeneric.AHCIVersion >> 16) + "." + (byte)(mGeneric.AHCIVersion >> 8) + ((byte)(mGeneric.AHCIVersion) > 0 ? "." + (byte)mGeneric.AHCIVersion : "");
}
internal static void InitDriver()
{
if (xDevice != null)
{
AHCI Driver = new AHCI(xDevice);
}
}
internal PCIDevice GetDevice() => xDevice;
public AHCI(PCIDevice aAHCIDevice)
{
aAHCIDevice.EnableBusMaster(true);
aAHCIDevice.EnableMemory(true);
mABAR = aAHCIDevice.BaseAddressBar[5].BaseAddress;
mGeneric = new GenericRegisters(aAHCIDevice.BaseAddressBar[5].BaseAddress);
mGeneric.GlobalHostControl |= (1U << 31); // Enable AHCI
GetCapabilities();
mPorts.Capacity = (int)NumOfPorts;
GetPorts();
foreach(StoragePort xPort in mPorts)
{
if(xPort.mPortType == PortType.SATA)
{
mAHCIDebugger.Send($"{xPort.mPortName} Port 0:{xPort.mPortNumber}");
var xMBRData = new byte[512];
xPort.ReadBlock(0UL, 1U, xMBRData);
var xMBR = new MBR(xMBRData);
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);
for (int i = 0; i < xEBR.Partitions.Count; i++)
{
//var xPart = xEBR.Partitions[i];
//var xPartDevice = new Partition(xSATA, xPart.StartSector, xPart.SectorCount);
//Devices.Add(xPartDevice);
}
}
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++)
{
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 partition at idx: " + i);
}
}
}
else if (xPort.mPortType == PortType.SATAPI)
{
mAHCIDebugger.Send($"{xPort.mPortName} Port 0:{xPort.mPortNumber}");
// 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);
// }
//}
}
}
}
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;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
xVoid = Core.Global.BaseIOGroups.TextScreen.Data1.Byte;
}
}
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;
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;
}
private void GetPorts()
{
// Search for disks
var xImplementedPort = mGeneric.ImplementedPorts;
var xPort = 0;
for(; xPort < 32; xPort++)
{
if ((xImplementedPort & 1) != 0)
{
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.
{
mAHCIDebugger.Send("Initializing Port " + xPortString + " with type SATA");
PortRebase(xPortReg, (uint)xPort);
var xSATAPort = new SATA(xPortReg);
mPorts.Add(xSATAPort);
}
else if (PortType == PortType.SATAPI) // If Port type was SATAPI.
{
mAHCIDebugger.Send("Initializing Port " + xPortString + " with type Serial ATAPI");
//PortRebase(xPortReg, (uint)xPort);
//var xSATAPIPort = new SATAPI(xPortReg);
//mPorts.Add(xSATAPIPort);
}
else if (PortType == PortType.SEMB) // If Port type was SEMB.
{
mAHCIDebugger.Send("SEMB Drive at port " + xPortString + " found, which is not supported yet!");
}
else if (PortType == PortType.PM) // If Port type was Port Mulitplier.
{
mAHCIDebugger.Send("Port Multiplier Drive at port " + xPortString + " found, which is not supported yet!");
}
else if (PortType != PortType.Nothing)
throw new Exception("SATA Error");
}
xImplementedPort >>= 1;
}
}
private PortType CheckPortType(PortRegisters aPort)
{
var xIPM = (InterfacePowerManagementStatus)((aPort.SSTS >> 8) & 0x0F);
var xSPD = (CurrentInterfaceSpeedStatus)((aPort.SSTS >> 4) & 0x0F);
var xDET = (DeviceDetectionStatus)(aPort.SSTS & 0x0F);
var xSignature = aPort.SIG;
// Check if the port is active!
if (xIPM != InterfacePowerManagementStatus.Active)
return PortType.Nothing;
if (xDET != DeviceDetectionStatus.DeviceDetectedWithPhy)
return PortType.Nothing;
xSignature >>= 16;
switch ((AHCISignature)xSignature)
{
case AHCISignature.SATA: return PortType.SATA;
case AHCISignature.SATAPI: return PortType.SATAPI;
case AHCISignature.SEMB: return PortType.SEMB;
case AHCISignature.PortMultiplier: return PortType.PM;
case AHCISignature.Nothing: return PortType.Nothing;
default: throw new Exception("SATA Error: Unknown drive found at port: " + aPort.mPortNumber);;
}
}
private void PortRebase(PortRegisters aPort, uint aPortNumber)
{
mAHCIDebugger.Send("Stop");
if (!StopCMD(aPort)) SATA.PortReset(aPort);
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); // Rebase Command header
if (!StartCMD(aPort)) SATA.PortReset(aPort);
aPort.IS = 0;
aPort.IE = 0xFFFFFFFF;
mAHCIDebugger.Send("Finished!");
}
private static HBACommandHeader[] GetCommandHeader(PortRegisters aPort)
{
HBACommandHeader[] xCMDHeader = new HBACommandHeader[32];
for (uint i = 0; i < xCMDHeader.Length; i++)
{
xCMDHeader[i] = new HBACommandHeader(aPort.CLB, i)
{
PRDTL = 8,
CTBA = (uint)(Base.AHCI + 0xA000) + (0x2000 * aPort.mPortNumber) + (0x100 * i),
CTBAU = 0
};
new MemoryBlock(xCMDHeader[i].CTBA, 0x100).Fill(0);
}
return xCMDHeader;
}
private bool StartCMD(PortRegisters aPort)
{
int xSpin;
for (xSpin = 0; xSpin < 101; xSpin++)
{
if ((aPort.CMD & (uint)CommandAndStatus.CMDListRunning) == 0) break;
Wait(5000);
}
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;
aPort.CMD &= ~(1U << 0); //Bit 0
for (xSpin = 0; xSpin < 101; xSpin++)
{
if ((aPort.CMD & (uint)CommandAndStatus.CMDListRunning) == 0) break;
Wait(5000);
}
if (xSpin == 101) return false;
for (xSpin = 0; xSpin < 101; xSpin++)
{
if ((aPort.CI == 0)) break;
Wait(50);
}
if (xSpin == 101) return false;
aPort.CMD &= ~(1U << 4); //Bit 4
if (SupportsCommandListOverride)
{
if ((aPort.TFD & (uint)ATADeviceStatus.Busy) != 0)
{
aPort.CMD |= (1U << 3);
}
}
for (xSpin = 0; xSpin < 101; xSpin++)
{
if ((aPort.CMD & (uint)CommandAndStatus.CMDListRunning) == 0 &&
(aPort.CMD & (uint)CommandAndStatus.FISRecieveRunning) == 0 &&
(aPort.CMD & (uint)CommandAndStatus.StartProccess) == 0 &&
(aPort.CMD & (uint)CommandAndStatus.FISRecieveEnable) == 0) break;
Wait(5000);
}
if (xSpin == 101)
{
if (SupportsCommandListOverride)
aPort.CMD |= (1U << 3);
else
aPort.CMD &= ~(1U << 3);
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,80 @@
using System;
using Cosmos.HAL.BlockDevice;
namespace Cosmos.HAL.BlockDevice
{
public class IDE
{
private static PCIDevice xDevice = HAL.PCI.GetDeviceClass(HAL.ClassID.MassStorageController,
HAL.SubclassID.IDEInterface);
internal static void InitDriver()
{
if (xDevice != null)
{
Console.WriteLine("ATA Primary Master");
Initialize(Ata.ControllerIdEnum.Primary, Ata.BusPositionEnum.Master);
//Console.WriteLine("ATA Primary Slave");
//Initialize(Ata.ControllerIdEnum.Primary, Ata.BusPositionEnum.Slave);
Console.WriteLine("ATA Secondary Master");
Initialize(Ata.ControllerIdEnum.Secondary, Ata.BusPositionEnum.Master);
//Console.WriteLine("ATA Secondary Slave");
//Initialize(Ata.ControllerIdEnum.Secondary, Ata.BusPositionEnum.Slave);
}
}
private static void Initialize(Ata.ControllerIdEnum aControllerID, Ata.BusPositionEnum aBusPosition)
{
var xIO = aControllerID == Ata.ControllerIdEnum.Primary ? Core.Global.BaseIOGroups.ATA1 : Core.Global.BaseIOGroups.ATA2;
var xATA = new AtaPio(xIO, aControllerID, aBusPosition);
if (xATA.DriveType == AtaPio.SpecLevel.Null)
return;
else if (xATA.DriveType == AtaPio.SpecLevel.ATA)
{
BlockDevice.Devices.Add(xATA);
Ata.AtaDebugger.Send("ATA device with speclevel ATA found.");
}
else if (xATA.DriveType == AtaPio.SpecLevel.ATAPI)
{
Ata.AtaDebugger.Send("ATA device with speclevel ATAPI found, which is not supported yet!");
return;
}
var xMbrData = new byte[512];
xATA.ReadBlock(0UL, 1U, xMbrData);
var xMBR = new MBR(xMbrData);
if (xMBR.EBRLocation != 0)
{
//EBR Detected
var xEbrData = new byte[512];
xATA.ReadBlock(xMBR.EBRLocation, 1U, xEbrData);
var xEBR = new EBR(xEbrData);
for (int i = 0; i < xEBR.Partitions.Count; i++)
{
//var xPart = xEBR.Partitions[i];
//var xPartDevice = new BlockDevice.Partition(xATA, xPart.StartSector, xPart.SectorCount);
//BlockDevice.BlockDevice.Devices.Add(xPartDevice);
}
}
// TODO Change this to foreach when foreach is supported
Ata.AtaDebugger.Send("Number of MBR partitions found:");
Ata.AtaDebugger.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(xATA, xPart.StartSector, xPart.SectorCount);
BlockDevice.Devices.Add(xPartDevice);
Console.WriteLine("Found partition at idx: " + i);
}
}
}
}
}

View file

@ -0,0 +1,368 @@
using System;
using System.Collections.Generic;
using Cosmos.Core;
using Cosmos.Core.Memory.Old;
using Cosmos.HAL.BlockDevice.Registers;
using Cosmos.Debug.Kernel;
namespace Cosmos.HAL.BlockDevice.Ports
{
public class SATA : StoragePort
{
internal static Debugger mSATADebugger = new Debugger("HAL", "SATA");
public override PortType mPortType => PortType.SATA;
public override string mPortName => "SATA";
public override uint mPortNumber => mPortReg.mPortNumber;
public PortRegisters mPortReg;
public Core.MemoryGroup.AHCI Mem;
// Constants
public const ulong RegularSectorSize = 512UL;
// Properties
private string mSerialNo;
private string mFirmwareRev;
private string mModelNo;
public string SerialNo { get => mSerialNo; }
public string FirmwareRev { get => mFirmwareRev; }
public string ModelNo { get => mModelNo; }
public SATA(PortRegisters aSATAPort)
{
// Check if it is really a SATA Port!
if (aSATAPort.mPortType != PortType.SATA || (aSATAPort.CMD & (1U << 24)) != 0)
{
throw new Exception($" 0:{aSATAPort.mPortNumber} is not a SATA port!\n");
}
Mem = new Core.MemoryGroup.AHCI((uint)RegularSectorSize);
mPortReg = aSATAPort;
// Setting Offset arg to Global offset
mBlockSize = RegularSectorSize;
// TODO: Use SendSATACommand(ATACommands.Identify) and copy the useful isIdentify if's from SendSATA28Command
// But make sure that isIdentify returns the exact value (true if the command is identify
// or false if not identify).
SendSATA28Command((ATACommands)0x00, 0, 0);
UInt16[] xBuffer = new UInt16[256];
Mem.DataBlock.Read16(xBuffer);
mSerialNo = GetString(xBuffer, 10, 20);
mFirmwareRev = GetString(xBuffer, 23, 8);
mModelNo = GetString(xBuffer, 27, 40);
mBlockCount = ((UInt32)xBuffer[61] << 16 | xBuffer[60]) - 1;
}
public void SendSATACommand(ATACommands aCommand)
{
mPortReg.IS = 0xFFFF;
int xSlot = FindCMDSlot();
if (xSlot == -1) return;
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
xCMDHeader.CFL = 5;
xCMDHeader.PRDTL = 1;
xCMDHeader.Write = 0;
xCMDHeader.CTBA = (uint)((uint)(Base.AHCI + 0xA000) + (0x2000 * mPortNumber) + (0x100 * xSlot));
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, xCMDHeader.PRDTL);
uint DataBaseAddress = Mem.DataBlock.Base;
xCMDTable.PRDTEntry[0].DBA = DataBaseAddress;
xCMDTable.PRDTEntry[0].DBC = 511;
xCMDTable.PRDTEntry[0].InterruptOnCompletion = 1;
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
{
FISType = (byte)FISType.FIS_Type_RegisterH2D,
IsCommand = 1,
Command = (byte)aCommand,
Device = 0
};
int xSpin = 0;
while (((mPortReg.TFD & 0x88) != 0) && xSpin < 1000000) xSpin++;
if (xSpin == 1000000)
{
mSATADebugger.Send($"Port {mPortNumber} timed out!");
return;
};
mPortReg.CI = 1U;
while (true)
{
if ((mPortReg.CI & (1 << xSlot)) == 0) break;
if ((mPortReg.IS & (1 << 30)) != 0)
{
throw new Exception("SATA Fatal error: Command aborted");
//mSATADebugger.Send("[Fatal]: Fatal error occurred while sending command!");
//PortReset(mPortReg);
return;
}
}
//Console.ForegroundColor = ConsoleColor.Green;
//Console.Write("[Success]: ");
//Console.Write("Command has been sent successfully!\n");
//Console.ResetColor();
return;
}
public void SendSATA28Command(ATACommands aCommand, uint aStart, uint aCount)
{
bool isIdentify = false;
if (aStart == 0 && aCount == 0) isIdentify = true;
mPortReg.IS = 0xFFFF;
int xSlot = FindCMDSlot();
if (xSlot == -1) return;
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
xCMDHeader.CFL = 5;
xCMDHeader.PRDTL = 1;
xCMDHeader.Write = 0;
xCMDHeader.CTBA = (uint)((uint)(Base.AHCI + 0xA000) + (0x2000 * mPortNumber) + (0x100 * xSlot));
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, xCMDHeader.PRDTL);
uint DataBaseAddress = Mem.DataBlock.Base;
// Last entry
if (isIdentify)
{
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBA = DataBaseAddress;
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBC = 511;
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].InterruptOnCompletion = 1;
}
else
{
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBA = DataBaseAddress;
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBC = aCount * 512 - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].InterruptOnCompletion = 1;
}
if (isIdentify)
{
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
{
FISType = (byte)FISType.FIS_Type_RegisterH2D,
IsCommand = 1,
Command = (byte)ATACommands.Identify,
Device = 0
};
}
else
{
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
{
FISType = (byte)FISType.FIS_Type_RegisterH2D,
IsCommand = 1,
Command = (byte)aCommand,
LBA0 = (byte)((aStart) & 0xFF),
LBA1 = (byte)((aStart >> 8) & 0xFF),
LBA2 = (byte)((aStart >> 16) & 0xFF),
Device = (byte)(0x40 | ((aStart >> 24) & 0x0F)),
CountL = (byte)(aCount & 0xFF)
};
}
int xSpin = 0;
while (((mPortReg.TFD & 0x88) != 0) && xSpin < 1000000) xSpin++;
if (xSpin == 1000000)
{
mSATADebugger.Send($"Port {mPortNumber} timed out!");
return;
};
mPortReg.CI = 1U;
while (true)
{
if ((mPortReg.CI & (1 << xSlot)) == 0) break;
if ((mPortReg.IS & (1 << 30)) != 0)
{
throw new Exception("SATA Fatal error: Command aborted");
//mSATADebugger.Send("[Fatal]: Fatal error occurred while sending command!");
//PortReset(mPortReg);
return;
}
}
//Console.ForegroundColor = ConsoleColor.Green;
//Console.Write("[Success]: ");
//Console.Write("Command has been sent successfully!\n");
//Console.ResetColor();
return;
}
public void SendSATA48Command(ATACommands aCommand, ulong aStart, uint aCount)
{
mPortReg.IS = 0xFFFF;
int xSlot = FindCMDSlot();
if (xSlot == -1) return;
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
xCMDHeader.CFL = 5;
xCMDHeader.PRDTL = 1;
xCMDHeader.Write = 0;
xCMDHeader.CTBA = (uint)((uint)(Base.AHCI + 0xA000) + (0x2000 * mPortNumber) + (0x100 * xSlot));
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, xCMDHeader.PRDTL);
uint DataBaseAddress = Mem.DataBlock.Base;
// Last entry
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBA = DataBaseAddress;
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBC = (aCount * 512) - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].InterruptOnCompletion = 1;
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
{
FISType = (byte)FISType.FIS_Type_RegisterH2D,
IsCommand = 1,
Command = (byte)aCommand,
LBA0 = (byte)((aStart >> 00) & 0xFF),
LBA1 = (byte)((aStart >> 08) & 0xFF),
LBA2 = (byte)((aStart >> 16) & 0xFF),
LBA3 = (byte)((aStart >> 24) & 0xFF),
LBA4 = (byte)((aStart >> 32) & 0xFF),
LBA5 = (byte)((aStart >> 40) & 0xFF),
Device = 1 << 6,
CountL = (byte)(aCount & 0xFF),
CountH = (byte)((aCount >> 8) & 0xFF)
};
int xSpin = 0;
while (((mPortReg.TFD & 0x88) != 0) && xSpin < 1000000) xSpin++;
if (xSpin == 1000000)
{
mSATADebugger.Send($"Port {mPortNumber} timed out!");
return;
};
mPortReg.CI = 1U;
while (true)
{
if ((mPortReg.CI & (1 << xSlot)) == 0) break;
if ((mPortReg.IS & (1 << 30)) != 0)
{
throw new Exception("SATA Fatal error: Command aborted");
//mSATADebugger.Send("[Fatal]: Fatal error occurred while sending command!");
//PortReset(mPortReg);
return;
}
}
//Console.ForegroundColor = ConsoleColor.Green;
//Console.Write("[Success]: ");
//Console.Write("Command has been sent successfully!\n");
//Console.ResetColor();
return;
}
public static void PortReset(PortRegisters aPort)
{
// TODO: Make a connection between AHCI Methods and SATA
// Semi-StopCMD()
aPort.CMD &= ~(1U << 0);
int i;
for(i = 0; i <= 50; i++)
{
if ((aPort.CMD & (1 << 0)) == 0) break;
AHCI.Wait(10000);
}
if (i == 101) AHCI.HBAReset();
aPort.SCTL = 1;
AHCI.Wait(1000);
aPort.SCTL &= ~(1U << 0);
while ((aPort.SSTS & 0x0F) != 3) ;
aPort.SERR = 1;
while ((aPort.SCTL & 0x0F) != 0) ;
}
private void HBAReset() => AHCI.HBAReset();
private int FindCMDSlot()
{
// If not set in SACT and CI, the slot is free
var xSlots = (mPortReg.SACT | mPortReg.CI);
for (int i = 0; i < 32; i++)
{
if ((xSlots & 1) == 0)
return i;
xSlots >>= 1;
}
//Console.ForegroundColor = ConsoleColor.Red;
//Console.Write("[Error]: ");
//Console.Write("Cannot find a free command slot!\n");
//Console.ResetColor();
return -1;
}
protected string GetString(UInt16[] aBuffer, int aIndexStart, int aStringLength)
{
// Would be nice to convert to byte[] and use
// new string(ASCIIEncoding.ASCII.GetChars(xBytes));
// But it requires some code Cosmos doesnt support yet
var xChars = new char[aStringLength];
for (int i = 0; i < aStringLength / 2; i++)
{
UInt16 xChar = aBuffer[aIndexStart + i];
xChars[i * 2] = (char)(xChar >> 8);
xChars[i * 2 + 1] = (char)xChar;
}
return new string(xChars);
}
// BlockDevice Methods
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
{
//CheckDataSize(aData, aBlockCount);
//CheckBlockNo(aBlockNo, aBlockCount);
SendSATA48Command(ATACommands.ReadDmaExt, (uint)aBlockNo, (uint)aBlockCount);
Mem.DataBlock.Read8(aData);
}
public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
{
Mem.DataBlock.Write8(aData);
SendSATA48Command(ATACommands.WriteDmaExt, (uint)(aBlockNo), (uint)aBlockCount);
SendSATACommand(ATACommands.CacheFlush);
}
}
}

View file

@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.Text;
using Cosmos.Core.Memory.Old;
using Cosmos.HAL.BlockDevice.Registers;
using Cosmos.Core;
using Cosmos.Debug.Kernel;
namespace Cosmos.HAL.BlockDevice.Ports
{
public class SATAPI : StoragePort
{
internal static Debugger mSATAPIDebugger = new Debugger("HAL", "SATAPI");
public PortRegisters mPortReg;
public override PortType mPortType => PortType.SATAPI;
public override string mPortName => "SATAPI";
public override uint mPortNumber => mPortReg.mPortNumber;
public SATAPI(PortRegisters aSATAPIPort)
{
// Check if it is really a SATAPI Port!
if (aSATAPIPort.mPortType != PortType.SATAPI || (aSATAPIPort.CMD & (1U << 24)) == 0)
{
throw new Exception($"SATAPI Error: 0:{mPortNumber} is not SATAPI port!");
}
mSATAPIDebugger.Send("SATAPI Constructor");
mPortReg = aSATAPIPort;
mBlockSize = 2048;
}
public void SendSATAPICommand(ATACommands aCommand, uint aStart, uint aCount)
{
mPortReg.IS = unchecked((uint)-1);
int xSlot = FindCMDSlot(mPortReg);
if (xSlot == -1) return;
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
xCMDHeader.CFL = 5;
xCMDHeader.ATAPI = 1;
xCMDHeader.PRDTL = (ushort)(((aCount - 1) >> 4) + 1);
xCMDHeader.Write = 0;
xCMDHeader.CTBA = Heap.MemAlloc(128 + ((uint)xCMDHeader.PRDTL) * 16);
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, xCMDHeader.PRDTL);
uint DataBaseAddress = 0x0046C000;
for (int i = 0; i < xCMDHeader.PRDTL - 1; i++)
{
xCMDTable.PRDTEntry[i].DBA = DataBaseAddress;
xCMDTable.PRDTEntry[i].DBC = 8 * 1024 - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
xCMDTable.PRDTEntry[i].InterruptOnCompletion = 1;
DataBaseAddress += 8 * 1024; // 4K words
aCount -= 16; // 16 sectors
}
// Last entry
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBA = DataBaseAddress;
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBC = aCount * 512 - 1; // 8K bytes (this value should always be set to 1 less than the actual value)
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].InterruptOnCompletion = 1;
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
{
FISType = (byte)FISType.FIS_Type_RegisterH2D,
IsCommand = 1,
Command = (byte)ATACommands.Packet,
Device = 1 << 4
};
byte[] xATAPICMD = new byte[12];
xATAPICMD[0] = (byte)aCommand;
xATAPICMD[2] = (byte)((aStart >> 0x18) & 0xFF);
xATAPICMD[3] = (byte)((aStart >> 0x10) & 0xFF);
xATAPICMD[4] = (byte)((aStart >> 0x08) & 0xFF);
xATAPICMD[5] = (byte)((aStart >> 0x00) & 0xFF);
xATAPICMD[9] = (byte)(aCount);
for (uint i = 0; i < xATAPICMD.Length; i++)
new Core.MemoryBlock(xCMDTable.ACMD, 12).Bytes[i] = xATAPICMD[i];
int xSpin = 0;
do xSpin++; while ((mPortReg.TFD & 0x88) != 0 && xSpin < 1000000);
if (xSpin == 1000000)
{
mSATAPIDebugger.Send($"Port {mPortNumber} timed out!");
return;
};
mPortReg.CI = 1U;
while(true)
{
if((mPortReg.CI & (1 << xSlot)) == 0) break;
if ((mPortReg.IS & (1 << 30)) != 0)
{
throw new Exception("SATA Fatal error: Command aborted");
//mSATADebugger.Send("[Fatal]: Fatal error occurred while sending command!");
//PortReset(mPortReg);
return;
}
}
//Console.ForegroundColor = ConsoleColor.Green;
//Console.Write("\n[Success]: ");
//Console.Write("Command has been sent successfully!");
//Console.ResetColor();
return;
}
public int FindCMDSlot(PortRegisters aPort)
{
// If not set in SACT and CI, the slot is free
var xSlots = (aPort.SACT | aPort.CI);
for (int i = 1; i < 32; i++)
{
if ((xSlots & 1) == 0)
return i;
xSlots >>= 1;
}
mSATAPIDebugger.Send("SATA Error: Cannot find a free command slot!");
return -1;
}
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
{
SendSATAPICommand(ATACommands.Read, (uint)aBlockNo, (uint)aBlockCount);
byte[] xByte = new byte[512];
new MemoryBlock(0x0046C000, 512).Read8(xByte);
for (int i = 0; i < 512; i++)
{
Console.Write(xByte[i]);
}
}
public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
{
// To be implemented!
}
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using Cosmos.HAL.BlockDevice.Registers;
namespace Cosmos.HAL.BlockDevice.Ports
{
public abstract class StoragePort : BlockDevice
{
public abstract PortType mPortType { get; }
public abstract string mPortName { get; }
public abstract uint mPortNumber { get; }
}
}

View file

@ -0,0 +1,793 @@
using System;
using System.Collections.Generic;
using System.Text;
using Cosmos.Core;
namespace Cosmos.HAL.BlockDevice.Registers
{
public enum Base : uint
{
AHCI = 0x00400000
}
// Registers
public class GenericRegisters
{
private MemoryBlock xBlock;
private uint xAddress;
public GenericRegisters(uint aAddress)
{
xAddress = aAddress;
xBlock = new MemoryBlock(aAddress, 0x100);
}
public uint Capabilities
{
get { return xBlock[0x00]; }
set { xBlock[0x00] = value; }
}
public uint GlobalHostControl
{
get { return xBlock[0x04]; }
set { xBlock[0x04] = value; }
}
public uint InterruptStatus
{
get { return xBlock[0x08]; }
set { xBlock[0x08] = value; }
}
public uint ImplementedPorts
{
get { return xBlock[0x0C]; }
set { xBlock[0x0C] = value; }
}
public uint AHCIVersion
{
get { return xBlock[0x10]; }
set { xBlock[0x10] = value; }
}
public uint CCC_Control
{
get { return xBlock[0x14]; }
set { xBlock[0x14] = value; }
}
public uint CCC_Ports
{
get { return xBlock[0x18]; }
set { xBlock[0x18] = value; }
}
public uint EM_Location
{
get { return xBlock[0x1C]; }
set { xBlock[0x1C] = value; }
}
public uint EM_Control
{
get { return xBlock[0x20]; }
set { xBlock[0x20] = value; }
}
public uint ExtendedCapabilities
{
get { return xBlock[0x24]; }
set { xBlock[0x24] = value; }
}
public uint BIOSHandOffStatus
{
get { return xBlock[0x28]; }
set { xBlock[0x28] = value; }
}
}
public class PortRegisters
{
private MemoryBlock xBlock;
private uint xAddress;
public uint mPortNumber;
public PortType mPortType = PortType.Nothing;
public bool Active;
public PortRegisters(uint aAddress, uint aPortNumber)
{
xAddress = aAddress;
mPortNumber = aPortNumber;
xBlock = new MemoryBlock(aAddress + (0x80 * mPortNumber), 0x80);
Active = false;
}
public uint CLB
{
get { return xBlock[0x00]; }
set { xBlock[0x00] = value; }
}
public uint CLBU
{
get { return xBlock[0x04]; }
set { xBlock[0x04] = value; }
}
public uint FB
{
get { return xBlock[0x08]; }
set { xBlock[0x08] = value; }
}
public uint FBU
{
get { return xBlock[0x0C]; }
set { xBlock[0x0C] = value; }
}
public uint IS
{
get { return xBlock[0x10]; }
set { xBlock[0x10] = value; }
}
public uint IE
{
get { return xBlock[0x14]; }
set { xBlock[0x14] = value; }
}
public uint CMD
{
get { return xBlock[0x18]; }
set { xBlock[0x18] = value; }
}
public uint Reserved
{
get { return xBlock[0x1C]; }
}
public uint TFD
{
get { return xBlock[0x20]; }
set { xBlock[0x20] = value; }
}
public uint SIG
{
get { return xBlock[0x24]; }
set { xBlock[0x24] = value; }
}
public uint SSTS
{
get { return xBlock[0x28]; }
set { xBlock[0x28] = value; }
}
public uint SCTL
{
get { return xBlock[0x2C]; }
set { xBlock[0x2C] = value; }
}
public uint SERR
{
get { return xBlock[0x30]; }
set { xBlock[0x30] = value; }
}
public uint SACT
{
get { return xBlock[0x34]; }
set { xBlock[0x34] = value; }
}
public uint CI
{
get { return xBlock[0x38]; }
set { xBlock[0x38] = value; }
}
public uint SNTF
{
get { return xBlock[0x3C]; }
set { xBlock[0x3C] = value; }
}
public uint FBS
{
get { return xBlock[0x40]; }
set { xBlock[0x40] = value; }
}
public uint DEVSLP
{
get { return xBlock[0x44]; }
set { xBlock[0x44] = value; }
}
}
// Command List
public class HBACommandHeader
{
private MemoryBlock xBlock;
private uint xAddress;//
private uint xSlot;
public HBACommandHeader(uint aAddress, uint aSlot)
{
xAddress = aAddress;
xSlot = aSlot;
xBlock = new MemoryBlock(aAddress + (32 * aSlot), 0x20);
xBlock.Fill(0);
}
public byte CFL
{
get { return (byte)(xBlock.Bytes[0x00] & 0x1F); }
set { xBlock.Bytes[0x00] = value; }
}
public byte ATAPI
{
get { return (byte)((xBlock.Bytes[0x00] >> 5) & 1); }
set { xBlock.Bytes[0x00] |= (byte)(value << 5); }
}
public byte Write
{
get { return (byte)((xBlock.Bytes[0x00] >> 6) & 1); }
set { xBlock.Bytes[0x00] |= (byte)(value << 6); }
}
public byte Prefetchable
{
get { return (byte)((xBlock.Bytes[0x00] >> 7) & 1); }
set { xBlock.Bytes[0x00] |= (byte)(value << 7); }
}
public byte Reset
{
get { return (byte)((xBlock.Bytes[0x01]) & 1); }
set { xBlock.Bytes[0x01] |= (byte)(value); }
}
public byte BIST
{
get { return (byte)((xBlock.Bytes[0x01] >> 1) & 1); }
set { xBlock.Bytes[0x01] |= (byte)(value << 1); }
}
public byte ClearBusy
{
get { return (byte)((xBlock.Bytes[0x01] >> 2) & 1); }
set { xBlock.Bytes[0x01] |= (byte)(value << 2); }
}
public byte Reserved
{
get { return (byte)((xBlock.Bytes[0x01] >> 3) & 1); }
}
public byte PMP
{
get { return (byte)((xBlock.Bytes[0x01] >> 4) & 0x0F); }
set { xBlock.Bytes[0x01] = (byte)(value << 4); }
}
public ushort PRDTL
{
get { return xBlock.Words[0x02]; }
set { xBlock.Words[0x02] = value; }
}
public uint PRDBC
{
get { return xBlock[0x04]; }
set { xBlock[0x04] = value; }
}
public uint CTBA
{
get { return xBlock[0x08]; }
set { xBlock[0x08] = value; }
}
public uint CTBAU
{
get { return xBlock[0x0C]; }
set { xBlock[0x0C] = value; }
}
public uint Reserved1
{
get { return xBlock[0x10]; }
}
public uint Reserved2
{
get { return xBlock[0x14]; }
}
public uint Reserved3
{
get { return xBlock[0x18]; }
}
public uint Reserved4
{
get { return xBlock[0x1C]; }
}
}
public class HBACommandTable
{
private MemoryBlock xBlock;
private uint xAddress;
public HBACommandTable(uint aAddress, uint aPRDTCount)
{
xAddress = aAddress;
xBlock = new MemoryBlock(aAddress, 0x80);
xBlock.Fill(0);
PRDTEntry = new HBAPRDTEntry[aPRDTCount];
for(uint i = 0; i < aPRDTCount; i++)
{
PRDTEntry[i] = new HBAPRDTEntry(aAddress + 0x80, i);
}
}
public uint CFIS
{
get { return xAddress; }
}
public uint ACMD
{
get { return xAddress + 0x40; }
}
public uint Reserved
{
get { return xBlock[0x50]; }
}
public HBAPRDTEntry[] PRDTEntry;
}
public class HBAPRDTEntry
{
private MemoryBlock xBlock;
private uint xAddress;
private uint xEntry;
public HBAPRDTEntry(uint aAddress, uint aEntry)
{
xAddress = aAddress;
xEntry = aEntry;
xBlock = new MemoryBlock(aAddress + (0x10 * xEntry), 0x10);
xBlock.Fill(0);
}
public uint DBA
{
get { return xBlock[0x00]; }
set { xBlock[0x00] = value; }
}
public uint DBAU
{
get { return xBlock[0x04]; }
set { xBlock[0x04] = value; }
}
public uint Reserved
{
get { return xBlock[0x08]; }
}
public uint DBC
{
get { return xBlock[0x0C] & 0x3FFFFF; }
set { xBlock[0x0C] = value; }
}
public uint Reserved1
{
get { return xBlock[0x0E] << 6; }
}
public byte InterruptOnCompletion
{
get { return (byte)(xBlock.Bytes[0x0F] >> 7); }
set { xBlock.Bytes[0x0F] = (byte)(value << 7); }
}
}
// FISes
public class FISRegisterH2D
{
private MemoryBlock xBlock;
private uint xAddress;
public FISRegisterH2D(uint aAddress)
{
xAddress = aAddress;
xBlock = new MemoryBlock(aAddress, 20);
xBlock.Fill(0);
}
public byte FISType
{
get { return (byte)(xBlock.Bytes[0x00]); }
set { xBlock.Bytes[0x00] = value; }
}
public byte IsCommand
{
get { return (byte)((xBlock.Bytes[0x01] >> 7)); }
set { xBlock.Bytes[0x01] = (byte)(value << 7); }
}
public byte Command
{
get { return xBlock.Bytes[0x02]; }
set { xBlock.Bytes[0x02] = value; }
}
public byte FeatureLow
{
get { return xBlock.Bytes[0x03]; }
set { xBlock.Bytes[0x03] = value; }
}
public byte LBA0
{
get { return xBlock.Bytes[0x04]; }
set { xBlock.Bytes[0x04] = value; }
}
public byte LBA1
{
get { return xBlock.Bytes[0x05]; }
set { xBlock.Bytes[0x05] = value; }
}
public byte LBA2
{
get { return xBlock.Bytes[0x06]; }
set { xBlock.Bytes[0x06] = value; }
}
public byte Device
{
get { return xBlock.Bytes[0x07]; }
set { xBlock.Bytes[0x07] = value; }
}
public byte LBA3
{
get { return xBlock.Bytes[0x08]; }
set { xBlock.Bytes[0x08] = value; }
}
public byte LBA4
{
get { return xBlock.Bytes[0x09]; }
set { xBlock.Bytes[0x09] = value; }
}
public byte LBA5
{
get { return xBlock.Bytes[0x0A]; }
set { xBlock.Bytes[0x0A] = value; }
}
public byte FeatureHigh
{
get { return xBlock.Bytes[0x0B]; }
set { xBlock.Bytes[0x0B] = value; }
}
public byte CountL
{
get { return xBlock.Bytes[0x0C]; }
set { xBlock.Bytes[0x0C] = value; }
}
public byte CountH
{
get { return xBlock.Bytes[0x0D]; }
set { xBlock.Bytes[0x0D] = value; }
}
public byte ICC
{
get { return xBlock.Bytes[0x0E]; }
set { xBlock.Bytes[0x0E] = value; }
}
public byte Control
{
get { return xBlock.Bytes[0x0F]; }
set { xBlock.Bytes[0x0F] = value; }
}
public byte Reserved1
{
get { return xBlock.Bytes[0x10]; }
}
public byte Reserved2
{
get { return xBlock.Bytes[0x11]; }
}
public byte Reserved3
{
get { return xBlock.Bytes[0x12]; }
}
public byte Reserved4
{
get { return xBlock.Bytes[0x13]; }
}
}
public class FISRegisterD2H
{
private MemoryBlock xBlock;
private uint xAddress;
public FISRegisterD2H(uint aAddress)
{
xAddress = aAddress;
xBlock = new MemoryBlock(aAddress, 20);
}
public FISType FISType
{
get { return (FISType)xBlock.Bytes[0x00]; }
set { xBlock.Bytes[0x00] = (byte)value; }
}
public byte PortMultiplier
{
get { return (byte)(xBlock.Bytes[0x00] << 8); }
set { xBlock.Bytes[0x00] = (byte)value; }
}
public byte Reserved
{
get { return (byte)(xBlock.Bytes[0x00] << 12); }
}
public byte InterruptBit
{
get { return (byte)(xBlock.Bytes[0x00] << 14); }
set { xBlock.Bytes[0x00] = (byte)(value << 14); }
}
public byte Reserved1
{
get { return (byte)(xBlock.Bytes[0x00] << 15); }
}
public byte Status
{
get { return (byte)(xBlock.Bytes[0x00] << 16); }
set { xBlock.Bytes[0x00] = (byte)(value << 16); }
}
public byte Error
{
get { return (byte)(xBlock.Bytes[0x00] << 24); }
set { xBlock.Bytes[0x00] = (byte)(value << 24); }
}
public byte LBA0
{
get { return xBlock.Bytes[0x04]; }
set { xBlock.Bytes[0x04] = value; }
}
public byte LBA1
{
get { return (byte)(xBlock.Bytes[0x04] << 8); }
set { xBlock.Bytes[0x04] = (byte)(value << 8); }
}
public byte LBA2
{
get { return (byte)(xBlock.Bytes[0x04] << 16); }
set { xBlock.Bytes[0x04] = (byte)(value << 16); }
}
public byte Device
{
get { return (byte)(xBlock.Bytes[0x04] << 24); }
set { xBlock.Bytes[0x04] = (byte)(value << 24); }
}
public byte LBA3
{
get { return xBlock.Bytes[0x08]; }
set { xBlock.Bytes[0x08] = value; }
}
public byte LBA4
{
get { return (byte)(xBlock.Bytes[0x08] << 8); }
set { xBlock.Bytes[0x08] = (byte)(value << 8); }
}
public byte LBA5
{
get { return (byte)(xBlock.Bytes[0x08] << 16); }
set { xBlock.Bytes[0x08] = (byte)(value << 16); }
}
public byte Reserved2
{
get { return (byte)(xBlock.Bytes[0x08] << 24); }
}
public byte CountL
{
get { return xBlock.Bytes[0x0C]; }
set { xBlock.Bytes[0x0C] = value; }
}
public byte CountH
{
get { return (byte)(xBlock.Bytes[0x0C] << 8); }
set { xBlock.Bytes[0x0C] = (byte)(value << 8); }
}
public byte Reserved3
{
get { return (byte)(xBlock.Bytes[0x0C] << 16); }
}
public byte Reserved4
{
get { return (byte)(xBlock.Bytes[0x0C] << 24); }
}
public byte Reserved5
{
get { return xBlock.Bytes[0x10]; }
}
public byte Reserved6
{
get { return xBlock.Bytes[0x11]; }
}
public byte Reserved7
{
get { return xBlock.Bytes[0x12]; }
}
public byte Reserved8
{
get { return xBlock.Bytes[0x13]; }
}
}
// Enums
public enum PortType
{
Nothing = 0x00,
SATA = 0x01,
SATAPI = 0x02,
SEMB = 0x03,
PM = 0x04
}
public enum FISType
{
FIS_Type_RegisterH2D = 0x27, // Register FIS: Host to Device
FIS_Type_RegisterD2H = 0x34, // Register FIS: Device to Host
FIS_Type_DMA_Activate = 0x39, // DMA Activate
FIS_Type_DMA_Setup = 0x41, // DMA Setup: Device to Host
FIS_Type_Data = 0x46, // Data FIS: Bidirectional
FIS_Type_BIST = 0x58, // BIST
FIS_Type_PIO_Setup = 0x5F, // PIO Setup: Device to Host
FIS_Type_DeviceBits = 0xA1 // Device bits
}
public enum FISSize : byte
{
//FISRegisterH2D = Marshal.SizeOf(FISRegisterH2D);
FISRegisterH2D = 40 / sizeof(uint)
}
public enum AHCISignature : uint // Drive Signature to identify what drive is plugged to Port X:X
{
SATA = 0x0000,
PortMultiplier = 0x9669,
SATAPI = 0xEB14,
SEMB = 0xC33C,
Nothing = 0xFFFF
}
public enum InterfacePowerManagementStatus : uint // SATA Status: Interface Power Management Status
{
NotPresent = 0x00,
Active = 0x01,
Partial = 0x02,
Slumber = 0x06,
DeviceSleep = 0x08
}
public enum CurrentInterfaceSpeedStatus : uint // SATA Status: Current Interface Speed
{
NotPresent = 0x00,
Gen1Rate = 0x01,
Gen2Rate = 0x02,
Gen3Rate = 0x03
}
public enum DeviceDetectionStatus : uint // SATA Status: Device Detection Status
{
NotDetected = 0x00,
DeviceDetectedNoPhy = 0x01,
DeviceDetectedWithPhy = 0x03,
PhyOffline = 0x04
}
public enum ATADeviceStatus : uint
{
Busy = 0x80,
DRQ = 0x08
}
public enum CommandAndStatus : uint
{
ICC_Reserved0 = 0x0000000F,
ICC_DevSleep = 0x00000008,
ICC_Slumber = 0x00000006,
ICC_Partial = 0x00000002,
ICC_Active = 0x00000001,
ICC_Idle = 0x00000000,
ASP = (01 << 27),
ALPE = (01 << 26),
EnableATAPILED = (01 << 25),
ATAPIDevice = (01 << 24),
APSTE = (01 << 23),
FISSwitchPort = (01 << 22),
ExternalSATAPort = (01 << 21),
ColdPresenceDetect = (01 << 20),
MPSP = (01 << 19),
HotPlugCapPort = (01 << 18),
PortMultAttach = (01 << 17),
ColdPresenceState = (01 << 16),
CMDListRunning = (01 << 15),
FISRecieveRunning = (01 << 14),
MPSS = (01 << 13),
CurrentCMDSlot = (01 << 12),
Reserved0 = (01 << 07),
FISRecieveEnable = (01 << 04),
CMDListOverride = (01 << 03),
PowerOnDevice = (01 << 02),
SpinUpDevice = (01 << 01),
StartProccess = (01 << 00),
Null = 0xFFFF
}
public enum InterruptStatus : int
{
ColdPortDetectStatus = (01 << 31),
TaskFileErrorStatus = (01 << 30),
HostBusFatalErrorStatus = (01 << 29),
HostBusDataErrorStatus = (01 << 28),
InterfaceFatalErrorStatus = (01 << 27),
InterfaceNFatalErrorStatus = (01 << 26),
OverflowStatus = (01 << 24),
IncorrectPMStatus = (01 << 23),
PhyRdyChangeStatus = (01 << 22),
DevMechanicalPresenceStatus = (01 << 07),
PortConnectChangeStatus = (01 << 06),
DescriptorProcessed = (01 << 05),
UnknownFISInterrupt = (01 << 04),
SetDeviceBitsInterrupt = (01 << 03),
DMASetupFISInterrupt = (01 << 02),
PIOSetupFISInterrupt = (01 << 01),
D2HRegFISInterrupt = (01 << 00),
Null = 0xFFFF
}
public enum InterruptEnable : uint
{
OverflowEnable = (01 << 24),
IncorrectPMEnable = (01 << 23),
PhyRdyChangeInterruptEnable = (01 << 22),
DevMechanicalPresenceEnable = (01 << 07),
PortChangeInterruptEnable = (01 << 06),
DescProcessedInterruptEnable = (01 << 05),
UnknownFISInterruptEnable = (01 << 04),
SetDeviceBitsInterruptEnable = (01 << 03),
DMASetupFISInterruptEnable = (01 << 02),
PIOSetupFISInterruptEnable = (01 << 01),
D2HRegFISInterruptEnable = (01 << 00),
Null = 0xFFFF
}
public enum ATACommands : byte
{
ReadDma = 0xC8,
ReadDmaExt = 0x25,
WriteDma = 0xCA,
WriteDmaExt = 0x35,
CacheFlush = 0xE7,
CacheFlushExt = 0xEA,
Packet = 0xA0,
IdentifyPacket = 0xA1,
IdentifyDMA = 0xEE,
Identify = 0xEC,
Read = 0xA8,
Eject = 0x1B
}
public enum Bases : uint
{
SATA = 0x00400000
}
}

View file

@ -145,7 +145,7 @@ namespace Cosmos.HAL.Drivers.PCI.Video
public VMWareSVGAII()
{
device = (HAL.PCI.GetDevice(0x15AD, 0x0405));
device = (HAL.PCI.GetDevice(HAL.VendorID.VMWare, HAL.DeviceID.SVGAIIAdapter));
device.EnableMemory(true);
uint basePort = device.BaseAddressBar[0].BaseAddress;
IndexPort = new IOPort((ushort)(basePort + (uint)IOPortOffset.Index));

View file

@ -1,128 +1,61 @@
using System;
using System;
using Cosmos.Core;
using Cosmos.Debug.Kernel;
using Cosmos.HAL.BlockDevice;
namespace Cosmos.HAL
{
public static class Global
{
public static readonly Debugger mDebugger = new Debugger("HAL", "Global");
//static public PIT PIT = new PIT();
// Must be static init, other static inits rely on it not being null
public static TextScreenBase TextScreen = new TextScreen();
public static PCI Pci;
static public void Init(TextScreenBase textScreen)
public static class Global
{
if (textScreen != null)
{
TextScreen = textScreen;
}
public static readonly Debugger mDebugger = new Debugger("HAL", "Global");
mDebugger.Send("Before Core.Global.Init");
Core.Global.Init();
//static public PIT PIT = new PIT();
// Must be static init, other static inits rely on it not being null
//TODO Redo this - Global init should be other.
// Move PCI detection to hardware? Or leave it in core? Is Core PC specific, or deeper?
// If we let hardware do it, we need to protect it from being used by System.
// Probably belongs in hardware, and core is more specific stuff like CPU, memory, etc.
//Core.PCI.OnPCIDeviceFound = PCIDeviceFound;
public static TextScreenBase TextScreen = new TextScreen();
public static PCI Pci;
//TODO: Since this is FCL, its "common". Otherwise it should be
// system level and not accessible from Core. Need to think about this
// for the future.
Console.WriteLine("Finding PCI Devices");
mDebugger.Send("PCI Devices");
PCI.Setup();
Console.WriteLine("Starting ACPI");
mDebugger.Send("ACPI Init");
ACPI.Start();
mDebugger.Send("Done initializing Cosmos.HAL.Global");
mDebugger.Send("ATA Primary Master");
InitAta(Ata.ControllerIdEnum.Primary, Ata.BusPositionEnum.Master);
//TODO Need to change code to detect if ATA controllers are present or not. How to do this? via PCI enum?
// They do show up in PCI space as well as the fixed space.
// Or is it always here, and was our compiler stack corruption issue?
mDebugger.Send("ATA Secondary Master");
InitAta(Ata.ControllerIdEnum.Secondary, Ata.BusPositionEnum.Master);
//InitAta(BlockDevice.Ata.ControllerIdEnum.Secondary, BlockDevice.Ata.BusPositionEnum.Slave);
}
public static void EnableInterrupts()
{
CPU.EnableInterrupts();
}
private static void InitAta(Ata.ControllerIdEnum aControllerID,
Ata.BusPositionEnum aBusPosition)
{
var xIO = aControllerID == Ata.ControllerIdEnum.Primary
? Core.Global.BaseIOGroups.ATA1
: Core.Global.BaseIOGroups.ATA2;
var xATA = new AtaPio(xIO, aControllerID, aBusPosition);
if (xATA.DriveType == AtaPio.SpecLevel.Null)
{
return;
}
if (xATA.DriveType == AtaPio.SpecLevel.ATA)
{
BlockDevice.BlockDevice.Devices.Add(xATA);
Ata.AtaDebugger.Send("ATA device with speclevel ATA found.");
}
else
{
//Ata.AtaDebugger.Send("ATA device with spec level " + (int)xATA.DriveType +
// " found, which is not supported!");
return;
}
var xMbrData = new byte[512];
xATA.ReadBlock(0UL, 1U, xMbrData);
var xMBR = new MBR(xMbrData);
if (xMBR.EBRLocation != 0)
{
//EBR Detected
var xEbrData = new byte[512];
xATA.ReadBlock(xMBR.EBRLocation, 1U, xEbrData);
var xEBR = new EBR(xEbrData);
for (int i = 0; i < xEBR.Partitions.Count; i++)
static public void Init(TextScreenBase textScreen)
{
//var xPart = xEBR.Partitions[i];
//var xPartDevice = new BlockDevice.Partition(xATA, xPart.StartSector, xPart.SectorCount);
//BlockDevice.BlockDevice.Devices.Add(xPartDevice);
}
}
if (textScreen != null)
{
TextScreen = textScreen;
}
mDebugger.Send("Before Core.Global.Init");
Core.Global.Init();
//TODO Redo this - Global init should be other.
// Move PCI detection to hardware? Or leave it in core? Is Core PC specific, or deeper?
// If we let hardware do it, we need to protect it from being used by System.
// Probably belongs in hardware, and core is more specific stuff like CPU, memory, etc.
//Core.PCI.OnPCIDeviceFound = PCIDeviceFound;
//TODO: Since this is FCL, its "common". Otherwise it should be
// system level and not accessible from Core. Need to think about this
// for the future.
Console.WriteLine("Finding PCI Devices");
mDebugger.Send("PCI Devices");
PCI.Setup();
Console.WriteLine("Starting ACPI");
mDebugger.Send("ACPI Init");
ACPI.Start();
IDE.InitDriver();
AHCI.InitDriver();
//EHCI.InitDriver();
mDebugger.Send("Done initializing Cosmos.HAL.Global");
// TODO Change this to foreach when foreach is supported
Ata.AtaDebugger.Send("Number of MBR partitions found:");
Ata.AtaDebugger.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
public static void EnableInterrupts()
{
var xPartDevice = new Partition(xATA, xPart.StartSector, xPart.SectorCount);
BlockDevice.BlockDevice.Devices.Add(xPartDevice);
Console.WriteLine("Found partition at idx" + i);
CPU.EnableInterrupts();
}
}
public static bool InterruptsEnabled => CPU.mInterruptsEnabled;
}
public static bool InterruptsEnabled => CPU.mInterruptsEnabled;
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -6,6 +6,70 @@ using Cosmos.Debug.Kernel;
namespace Cosmos.HAL
{
public enum ClassID
{
PCIDevice_2_0 = 0x00,
MassStorageController = 0x01,
NetworkController = 0x02,
DisplayController = 0x03,
MultimediaDevice = 0x04,
MemoryController = 0x05,
BridgeDevice = 0x06,
SimpleCommController = 0x07,
BaseSystemPreiph = 0x08,
InputDevice = 0x09,
DockingStations = 0x0A,
Proccesors = 0x0B,
SerialBusController = 0x0C,
WirelessController = 0x0D,
InteligentController = 0x0E,
SateliteCommController = 0x0F,
EncryptionController = 0x10,
SignalProcessingController = 0x11,
ProcessingAccelerators = 0x12,
NonEssentialInstsrumentation = 0x13,
Coprocessor = 0x40,
Unclassified = 0xFF
}
public enum SubclassID
{
// MassStorageController:
SCSIStorageController = 0x00,
IDEInterface = 0x01,
FloppyDiskController = 0x02,
IPIBusController = 0x03,
RAIDController = 0x04,
ATAController = 0x05,
SATAController = 0x06,
SASController = 0x07,
NVMController = 0x08,
UnknownMassStorage = 0x09,
}
public enum ProgramIF
{
// MassStorageController:
SATA_VendorSpecific = 0x00,
SATA_AHCI = 0x01,
SATA_SerialStorageBus = 0x02,
SAS_SerialStorageBus = 0x01,
NVM_NVMHCI = 0x01,
NVM_NVMExpress = 0x02
}
public enum VendorID
{
Intel = 0x8086,
AMD = 0x0438,
VMWare = 0x15AD
}
public enum DeviceID
{
SVGAIIAdapter = 0x0405
}
public class PCI
{
private static List<PCIDevice> Devices;
@ -61,12 +125,13 @@ namespace Cosmos.HAL
CheckBus(xPCIDevice.SecondaryBusNumber);
}
public static PCIDevice GetDevice(ushort VendorID, ushort DeviceID)
public static PCIDevice GetDevice(VendorID aVendorID, DeviceID aDeviceID)
{
for (int i = 0; i < Devices.Count; i++)
{
var xDevice = Devices[i];
if (xDevice.VendorID == VendorID && xDevice.DeviceID == DeviceID)
if ((VendorID)xDevice.VendorID == aVendorID &&
(DeviceID)xDevice.DeviceID == aDeviceID)
{
return Devices[i];
}
@ -74,12 +139,28 @@ namespace Cosmos.HAL
return null;
}
public static PCIDevice GetDeviceClass(ushort Class, ushort SubClass)
public static PCIDevice GetDeviceClass(ClassID Class, SubclassID SubClass)
{
for (int i = 0; i < Devices.Count; i++)
{
var xDevice = Devices[i];
if (xDevice.ClassCode == Class && xDevice.Subclass == SubClass)
if ((ClassID)xDevice.ClassCode == Class &&
(SubclassID)xDevice.Subclass == SubClass)
{
return Devices[i];
}
}
return null;
}
public static PCIDevice GetDeviceClass(ClassID aClass, SubclassID aSubClass, ProgramIF aProgIF)
{
for (int i = 0; i < Devices.Count; i++)
{
var xDevice = Devices[i];
if ((ClassID)xDevice.ClassCode == aClass &&
(SubclassID)xDevice.Subclass == aSubClass &&
(ProgramIF)xDevice.ProgIF == aProgIF)
{
return Devices[i];
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -198,6 +198,20 @@ namespace Cosmos.HAL
WriteRegister16(0x04, command);
}
public void EnableBusMaster(bool enable)
{
UInt16 command = ReadRegister16(0x04);
UInt16 flags = (1 << 2);
if (enable)
command |= flags;
else
command &= (ushort)~flags;
WriteRegister16(0x04, command);
}
public class DeviceClass
{
public static string GetString(PCIDevice device)
@ -345,4 +359,4 @@ namespace Cosmos.HAL
get { return isIO; }
}
}
}
}