mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 12:30:32 +00:00
Merge pull request #763 from KingLuigi4932/patch-6
[FirstWorking] Implementing AHCI Controller Driver
This commit is contained in:
commit
eafd38ecac
11 changed files with 1951 additions and 119 deletions
17
source/Cosmos.Core/MemoryGroup/AHCI.cs
Normal file
17
source/Cosmos.Core/MemoryGroup/AHCI.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
384
source/Cosmos.HAL2/BlockDevice/AHCI.cs
Normal file
384
source/Cosmos.HAL2/BlockDevice/AHCI.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
80
source/Cosmos.HAL2/BlockDevice/IDE.cs
Normal file
80
source/Cosmos.HAL2/BlockDevice/IDE.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
368
source/Cosmos.HAL2/BlockDevice/Ports/Sata.cs
Normal file
368
source/Cosmos.HAL2/BlockDevice/Ports/Sata.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
148
source/Cosmos.HAL2/BlockDevice/Ports/Satapi.cs
Normal file
148
source/Cosmos.HAL2/BlockDevice/Ports/Satapi.cs
Normal 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!
|
||||
}
|
||||
}
|
||||
}
|
||||
14
source/Cosmos.HAL2/BlockDevice/Ports/StoragePort.cs
Normal file
14
source/Cosmos.HAL2/BlockDevice/Ports/StoragePort.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
793
source/Cosmos.HAL2/BlockDevice/Registers/AHCIRegs.cs
Normal file
793
source/Cosmos.HAL2/BlockDevice/Registers/AHCIRegs.cs
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue