mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 22:12:25 +00:00
It is better to not to put 1500 lines in class were most of the lines are bunch of duplicated lines
354 lines
12 KiB
C#
354 lines
12 KiB
C#
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.SATA Mem;
|
|
|
|
// Constants
|
|
public const ulong RegularSectorSize = 512UL;
|
|
|
|
public SATA(PortRegisters aSATAPort)
|
|
{
|
|
// Check if it is really a SATA Port!
|
|
if(aSATAPort.mPortType != PortType.SATA || (aSATAPort.CMD & (1U << 24)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Error]");
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Console.WriteLine($" 0:{aSATAPort.mPortNumber} is not a SATA port!\n");
|
|
return;
|
|
}
|
|
|
|
Mem = new Core.MemoryGroup.SATA();
|
|
|
|
mPortReg = aSATAPort;
|
|
|
|
// Setting Offset arg to Global offset
|
|
mBlockSize = RegularSectorSize;
|
|
mBlockCount = 256;
|
|
|
|
SendSATACommand(ATACommands.Identify);
|
|
UInt16[] xBuffer = new UInt16[256];
|
|
System.Threading.Thread.Sleep(1000);
|
|
Mem.DataBlock.Read16(xBuffer);
|
|
|
|
var xBlockCount48 = (xBuffer[102] << 32 | (xBuffer[101] << 16 | xBuffer[100])) - 1;
|
|
mBlockCount = (ulong)xBlockCount48;
|
|
|
|
}
|
|
|
|
public void SendSATACommand(ATACommands aCommand)
|
|
{
|
|
bool isIdentify = (aCommand == ATACommands.Identify);
|
|
|
|
mPortReg.IS = unchecked((uint)-1);
|
|
|
|
int xSlot = FindCMDSlot();
|
|
if (xSlot == -1) return;
|
|
|
|
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
|
|
xCMDHeader.CFL = 5;
|
|
xCMDHeader.PRDTL = (ushort)((isIdentify) ? 1 : 0);
|
|
xCMDHeader.Write = 0;
|
|
|
|
xCMDHeader.CTBA = Heap.MemAlloc(256);
|
|
|
|
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, (uint)xSlot);
|
|
|
|
if (isIdentify)
|
|
{
|
|
Console.WriteLine("Identify");
|
|
xCMDTable.PRDTEntry = new HBAPRDTEntry[xCMDHeader.PRDTL];
|
|
for (uint i = 0; i < xCMDTable.PRDTEntry.Length; i++)
|
|
{
|
|
xCMDTable.PRDTEntry[i] = new HBAPRDTEntry(xCMDHeader.CTBA + 0x80, i);
|
|
}
|
|
|
|
var BaseAddress = Mem.DataBlock.Base;
|
|
xCMDTable.PRDTEntry[xCMDTable.PRDTEntry.Length - 1].DBA = BaseAddress - 2;
|
|
xCMDTable.PRDTEntry[xCMDTable.PRDTEntry.Length - 1].DBC = 511;
|
|
xCMDTable.PRDTEntry[xCMDTable.PRDTEntry.Length - 1].InterruptOnCompletion = 0;
|
|
}
|
|
|
|
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
|
|
{
|
|
FISType = (byte)FISType.FIS_Type_RegisterH2D,
|
|
IsCommand = 1,
|
|
Command = (byte)aCommand,
|
|
Device = 0,
|
|
};
|
|
|
|
int xSpin = 0;
|
|
do xSpin++; while ((mPortReg.TFD & 0x88) != 0 && xSlot < 1000000);
|
|
|
|
mPortReg.CI = 1U << xSlot;
|
|
|
|
while (true)
|
|
{
|
|
if ((mPortReg.CI & (1 << xSlot)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
if ((mPortReg.IS & (1 << 30)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Fatal]: ");
|
|
Console.Write("Fatal error occurred while sending command!\n");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((mPortReg.IS & (1 << 30)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Fatal]: ");
|
|
Console.Write("Fatal error occurred while sending command!\n");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
Console.Write("\n[Success]: ");
|
|
Console.Write("Command has been sent successfully!\n");
|
|
Console.ResetColor();
|
|
|
|
while (mPortReg.CI != 0) ;
|
|
|
|
return;
|
|
}
|
|
|
|
public void SendSATA24Command(ATACommands aCommand, uint aStart, uint aCount)
|
|
{
|
|
mPortReg.IS = unchecked((uint)-1);
|
|
|
|
int xSlot = FindCMDSlot();
|
|
if (xSlot == -1) return;
|
|
|
|
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
|
|
xCMDHeader.CFL = 5;
|
|
xCMDHeader.PRDTL = (ushort)(((aCount - 1) >> 4) + 1);
|
|
xCMDHeader.Write = 0;
|
|
|
|
xCMDHeader.CTBA = Heap.MemAlloc(256);
|
|
|
|
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, (uint)xSlot);
|
|
|
|
xCMDTable.PRDTEntry = new HBAPRDTEntry[xCMDHeader.PRDTL];
|
|
for (uint i = 0; i < xCMDTable.PRDTEntry.Length; i++)
|
|
{
|
|
xCMDTable.PRDTEntry[i] = new HBAPRDTEntry(xCMDHeader.CTBA + 0x80, i);
|
|
}
|
|
|
|
uint BaseAddress = Mem.DataBlock.Base;
|
|
for (uint i = 0; i < xCMDHeader.PRDTL - 1; i++)
|
|
{
|
|
xCMDTable.PRDTEntry[i].DBA = BaseAddress;
|
|
xCMDTable.PRDTEntry[i].DBC = 8191;
|
|
xCMDTable.PRDTEntry[i].InterruptOnCompletion = 0;
|
|
BaseAddress += 8192;
|
|
aCount -= 16;
|
|
}
|
|
|
|
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBA = BaseAddress - 2;
|
|
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBC = 512 * aCount - 1;
|
|
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].InterruptOnCompletion = 0;
|
|
|
|
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
|
|
{
|
|
FISType = (byte)FISType.FIS_Type_RegisterH2D,
|
|
IsCommand = 1,
|
|
Command = (byte)aCommand,
|
|
|
|
LBA0 = (byte)(aStart),
|
|
LBA1 = (byte)(aStart >> 8),
|
|
LBA2 = (byte)(aStart >> 16),
|
|
Device = (byte)(0x40 | ((aStart >> 24) & 0x0F)),
|
|
|
|
CountL = (byte)(aCount & 0xFF)
|
|
};
|
|
|
|
int xSpin = 0;
|
|
do xSpin++; while ((mPortReg.TFD & 0x88) != 0 && xSlot < 1000000);
|
|
|
|
mPortReg.CI = 1U << xSlot;
|
|
|
|
while (true)
|
|
{
|
|
if ((mPortReg.CI & (1 << xSlot)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
if ((mPortReg.IS & (1 << 30)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Fatal]: ");
|
|
Console.Write("Fatal error occurred while sending command!\n");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((mPortReg.IS & (1 << 30)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Fatal]: ");
|
|
Console.Write("Fatal error occurred while sending command!\n");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
Console.Write("\n[Success]: ");
|
|
Console.Write("Command has been sent successfully!\n");
|
|
Console.ResetColor();
|
|
|
|
while (mPortReg.CI != 0) ;
|
|
|
|
return;
|
|
}
|
|
|
|
public void SendSATA48Command(ATACommands aCommand, ulong aStart, uint aCount)
|
|
{
|
|
mPortReg.IS = unchecked((uint)-1);
|
|
|
|
int xSlot = FindCMDSlot();
|
|
if (xSlot == -1) return;
|
|
|
|
HBACommandHeader xCMDHeader = new HBACommandHeader(mPortReg.CLB, (uint)xSlot);
|
|
xCMDHeader.CFL = 5;
|
|
xCMDHeader.PRDTL = (ushort)(((aCount - 1) >> 4) + 1);
|
|
xCMDHeader.Write = 0;
|
|
|
|
xCMDHeader.CTBA = Heap.MemAlloc(256);
|
|
|
|
HBACommandTable xCMDTable = new HBACommandTable(xCMDHeader.CTBA, (uint)xSlot);
|
|
|
|
xCMDTable.PRDTEntry = new HBAPRDTEntry[xCMDHeader.PRDTL];
|
|
for (uint i = 0; i < xCMDTable.PRDTEntry.Length; i++)
|
|
{
|
|
xCMDTable.PRDTEntry[i] = new HBAPRDTEntry(xCMDHeader.CTBA + 0x80, i);
|
|
}
|
|
|
|
uint BaseAddress = Mem.DataBlock.Base;
|
|
for (uint i = 0; i < xCMDHeader.PRDTL - 1; i++)
|
|
{
|
|
xCMDTable.PRDTEntry[i].DBA = BaseAddress;
|
|
xCMDTable.PRDTEntry[i].DBC = 8191;
|
|
xCMDTable.PRDTEntry[i].InterruptOnCompletion = 0;
|
|
BaseAddress += 8192;
|
|
aCount -= 16;
|
|
}
|
|
|
|
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBA = BaseAddress - 2;
|
|
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].DBC = 512 * aCount - 1;
|
|
xCMDTable.PRDTEntry[xCMDHeader.PRDTL - 1].InterruptOnCompletion = 0;
|
|
|
|
FISRegisterH2D xCMDFIS = new FISRegisterH2D(xCMDTable.CFIS)
|
|
{
|
|
FISType = (byte)FISType.FIS_Type_RegisterH2D,
|
|
IsCommand = 1,
|
|
Command = (byte)aCommand,
|
|
|
|
LBA0 = (byte)(aStart),
|
|
LBA1 = (byte)(aStart >> 8),
|
|
LBA2 = (byte)(aStart >> 16),
|
|
LBA3 = (byte)(aStart >> 24),
|
|
LBA4 = (byte)(aStart >> 32),
|
|
LBA5 = (byte)(aStart >> 40),
|
|
Device = 0x40,
|
|
|
|
CountL = (byte)(aCount & 0xFF),
|
|
CountH = (byte)((aCount >> 8))
|
|
};
|
|
|
|
int xSpin = 0;
|
|
do xSpin++; while ((mPortReg.TFD & 0x88) != 0 && xSlot < 1000000);
|
|
|
|
mPortReg.CI = 1U << xSlot;
|
|
|
|
while (true)
|
|
{
|
|
if ((mPortReg.CI & (1 << xSlot)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
if ((mPortReg.IS & (1 << 30)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Fatal]: ");
|
|
Console.Write("Fatal error occurred while sending command!\n");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((mPortReg.IS & (1 << 30)) != 0)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.Write("\n[Fatal]: ");
|
|
Console.Write("Fatal error occurred while sending command!\n");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
Console.Write("\n[Success]: ");
|
|
Console.Write("Command has been sent successfully!\n");
|
|
Console.ResetColor();
|
|
|
|
while (mPortReg.CI != 0) ;
|
|
|
|
return;
|
|
}
|
|
|
|
public int FindCMDSlot()
|
|
{
|
|
// If not set in SACT and CI, the slot is free
|
|
var xSlots = (mPortReg.SACT | mPortReg.CI);
|
|
|
|
for (int i = 1; i < 32; i++)
|
|
{
|
|
if ((xSlots & 1) == 0)
|
|
return i;
|
|
xSlots >>= 1;
|
|
}
|
|
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Console.Write("\n[Error]: ");
|
|
Console.Write("Cannot find a free command slot!\n");
|
|
Console.ResetColor();
|
|
return -1;
|
|
}
|
|
|
|
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
|
|
{
|
|
SendSATA48Command(ATACommands.ReadDmaExt, (uint)aBlockNo, (uint)aBlockCount);
|
|
System.Threading.Thread.Sleep(500);
|
|
Mem.DataBlock.Read8(aData);
|
|
foreach (byte xData in aData)
|
|
mSATADebugger.SendNumber(xData);
|
|
}
|
|
|
|
public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
|
|
{
|
|
Mem.DataBlock.Write8(aData);
|
|
SendSATA48Command(ATACommands.WriteDmaExt, (uint)(aBlockNo), (uint)aBlockCount);
|
|
SendSATACommand(ATACommands.CacheFlush);
|
|
}
|
|
}
|
|
}
|