mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 05:52:11 +00:00
842 lines
32 KiB
C#
842 lines
32 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Cosmos.Core;
|
|
using Cosmos.Core.Memory.Old;
|
|
using Cosmos.Debug.Kernel;
|
|
using Cosmos.HAL.Drivers.PCI.Controllers;
|
|
|
|
namespace Cosmos.HAL.BlockDevice
|
|
{
|
|
#region Registers
|
|
|
|
//TODO: Must be struct
|
|
public class GenericRegisters
|
|
{
|
|
public uint CAP;
|
|
public uint GHC;
|
|
public uint IS;
|
|
public uint PI;
|
|
public uint VS;
|
|
public uint CCC_CTL;
|
|
public uint CCC_PORTS;
|
|
public uint EM_LOC;
|
|
public uint EM_CTL;
|
|
public uint CAP2;
|
|
public uint BOHC;
|
|
public byte[] Reserved0;
|
|
public byte[] VendorSpecific;
|
|
public PortRegisters[] Ports;
|
|
}
|
|
|
|
public class PortRegisters
|
|
{
|
|
public uint CLB;
|
|
public uint CLBU;
|
|
public uint FB;
|
|
public uint FBU;
|
|
public uint IS;
|
|
public uint IE;
|
|
public uint CMD;
|
|
public uint Reserved0;
|
|
public uint TFD;
|
|
public uint SIG;
|
|
public uint SSTS;
|
|
public uint SCTL;
|
|
public uint SERR;
|
|
public uint SACT;
|
|
public uint CI;
|
|
public uint SNTF;
|
|
public uint FBS;
|
|
public uint[] Reserved1;
|
|
public uint[] VendorSpecific;
|
|
}
|
|
|
|
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 class HBACommandHeader
|
|
{
|
|
// DWord 0
|
|
public byte CFL; // 5 bits
|
|
public byte ATAPI; // 1 bit
|
|
public byte Write; // 1 = H2D | 0 = D2H // 1bit
|
|
public byte Prefetchable; // 1 bit
|
|
|
|
public byte Reset; // 1 bit
|
|
public byte BIST; // 1 bit
|
|
public byte ClearBusy; // 1 bit
|
|
public byte Reserved0; // 1 bit
|
|
public byte PMP; // 4 bits
|
|
|
|
public ushort PRDTL; // Physical region descriptor table length in entries
|
|
|
|
// DWord 1
|
|
public uint PRDBC; // Physical region descriptor byte count transferred
|
|
|
|
public uint CTBA; // Command table descriptor base address
|
|
public uint CTBAU; // Command table descriptor base address upper 32 bits (4 bytes)
|
|
|
|
// Reserved1; // [4]
|
|
}
|
|
|
|
public class HBACommandTable
|
|
{
|
|
// 0x00
|
|
public byte CFIS; // [64] // = 64
|
|
|
|
// 0x40
|
|
public byte ACMD; // [16] // = 16 + 64 = 80
|
|
|
|
// 0x50
|
|
public byte Reserved; // [48] // = 48 + 80 = 128
|
|
|
|
public HBAPRDTEntry[] PRDTEntry; // [1] // = 44 + 128 = 172
|
|
}
|
|
public class HBAPRDTEntry
|
|
{
|
|
public uint DBA; // Data base address
|
|
public uint DBAU; // Data base address upper 32 bits
|
|
public uint Reserved0;
|
|
|
|
public uint DBC; // Byte count, 4M max // 22 bits (2.75 Bytes)
|
|
public uint Reserved1; // Reserved // 9 bits
|
|
public int InterruptOnCompletion; // Interrupt on completion // 1 bit
|
|
}
|
|
|
|
public enum PortType
|
|
{
|
|
Nothing = 0x00,
|
|
SATA = 0x01,
|
|
SATAPI = 0x02,
|
|
SEMB = 0x03,
|
|
PM = 0x04
|
|
}
|
|
|
|
public class FISRegisterH2D
|
|
{
|
|
public byte FISType;
|
|
|
|
//public byte Options;
|
|
// Reserved
|
|
public byte IsCommand;
|
|
public byte Command;
|
|
public byte FeatureL;
|
|
|
|
public byte LBA0;
|
|
public byte LBA1;
|
|
public byte LBA2;
|
|
public byte Device;
|
|
|
|
public byte LBA3;
|
|
public byte LBA4;
|
|
public byte LBA5;
|
|
public byte FeatureH;
|
|
|
|
public byte CountL;
|
|
public byte CountH;
|
|
public byte ICC;
|
|
public byte Control;
|
|
|
|
public byte Res2;
|
|
|
|
public static explicit operator byte(FISRegisterH2D v)
|
|
{
|
|
byte xValue = sizeof(byte) * 16;
|
|
return xValue;
|
|
}
|
|
}
|
|
|
|
public class FISRegisterD2H
|
|
{
|
|
public byte FISType;
|
|
|
|
//public byte Options;
|
|
// Reserved
|
|
//public byte InterruptBit;
|
|
// Rseerved
|
|
public byte Status;
|
|
public byte Error;
|
|
|
|
public byte LBA0;
|
|
public byte LBA1;
|
|
public byte LBA2;
|
|
public byte Device;
|
|
|
|
public byte LBA3;
|
|
public byte LBA4;
|
|
public byte LBA5;
|
|
// Reserved
|
|
|
|
public byte CountL;
|
|
public byte CountH;
|
|
public byte ICC;
|
|
public ushort Res2;
|
|
// Reserved
|
|
public uint Res3;
|
|
// Reserved
|
|
|
|
public static explicit operator byte(FISRegisterD2H v)
|
|
{
|
|
byte xValue = sizeof(byte) * 15;
|
|
return xValue;
|
|
}
|
|
}
|
|
|
|
public class FISData
|
|
{
|
|
public byte FISType;
|
|
|
|
public byte Payload;
|
|
}
|
|
#endregion
|
|
|
|
#region Enums
|
|
public enum DriveSignature : uint // Drive Signature to identify what drive is plugged to Port X:X
|
|
{
|
|
SATADrive = 0x00000101,
|
|
PMDrive = 0x96690101,
|
|
SATAPIDrive = 0xEB140101,
|
|
SEMBDrive = 0xC33C0101,
|
|
NullDrive = 0xFFFFFFFF
|
|
}
|
|
|
|
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 SATACommands : uint
|
|
{
|
|
ReadPio = AtaPio.Cmd.ReadPio,
|
|
ReadPioExt = AtaPio.Cmd.ReadPioExt,
|
|
ReadDma = AtaPio.Cmd.ReadDma,
|
|
ReadDmaExt = AtaPio.Cmd.ReadDmaExt,
|
|
WritePio = AtaPio.Cmd.WritePio,
|
|
WritePioExt = AtaPio.Cmd.WritePioExt,
|
|
WriteDma = AtaPio.Cmd.WriteDma,
|
|
WriteDmaExt = AtaPio.Cmd.WriteDmaExt,
|
|
CacheFlush = AtaPio.Cmd.CacheFlush,
|
|
CacheFlushExt = AtaPio.Cmd.CacheFlushExt,
|
|
Packet = AtaPio.Cmd.Packet,
|
|
IdentifyPacket = AtaPio.Cmd.IdentifyPacket,
|
|
Identify = AtaPio.Cmd.Identify,
|
|
Read = AtaPio.Cmd.Read,
|
|
Eject = AtaPio.Cmd.Eject
|
|
}
|
|
|
|
public enum Bases : uint { SATA = 0x00400000 }
|
|
#endregion
|
|
|
|
public class SATA : BlockDevice
|
|
{
|
|
private static uint mPortLocation;
|
|
private static uint[] mPorts = new uint[32];
|
|
|
|
private static uint mABAR;
|
|
private static MemoryBlock mSATAMemory;
|
|
internal static Debugger mSATADebugger = new Debugger("HAL", "SATA");
|
|
|
|
public static GenericRegisters mGeneric;
|
|
|
|
public List<int> SATAPorts = new List<int>(32);
|
|
|
|
public static InterfacePowerManagementStatus mIPM;
|
|
public static DeviceDetectionStatus mDET;
|
|
private int xPort;
|
|
private bool is64DMA;
|
|
|
|
#region Registers
|
|
internal class Registers
|
|
{
|
|
public static PortRegisters PortRegisters(int aPortNumber)
|
|
{
|
|
mPortLocation = 0x100 + (0x80 * (uint)aPortNumber);
|
|
PortRegisters xPortReg = new PortRegisters();
|
|
xPortReg.CLB = mSATAMemory[mPortLocation + 0x00];
|
|
xPortReg.CLBU = mSATAMemory[mPortLocation + 0x04];
|
|
xPortReg.FB = mSATAMemory[mPortLocation + 0x08];
|
|
xPortReg.FBU = mSATAMemory[mPortLocation + 0x0C];
|
|
xPortReg.IS = mSATAMemory[mPortLocation + 0x10];
|
|
xPortReg.IE = mSATAMemory[mPortLocation + 0x14];
|
|
xPortReg.CMD = mSATAMemory[mPortLocation + 0x18];
|
|
xPortReg.Reserved0 = mSATAMemory[mPortLocation + 0x1C];
|
|
xPortReg.TFD = mSATAMemory[mPortLocation + 0x20];
|
|
xPortReg.SIG = mSATAMemory[mPortLocation + 0x24];
|
|
xPortReg.SSTS = mSATAMemory[mPortLocation + 0x28];
|
|
xPortReg.SCTL = mSATAMemory[mPortLocation + 0x2C];
|
|
xPortReg.SERR = mSATAMemory[mPortLocation + 0x30];
|
|
xPortReg.SACT = mSATAMemory[mPortLocation + 0x34];
|
|
xPortReg.CI = mSATAMemory[mPortLocation + 0x38];
|
|
xPortReg.SNTF = mSATAMemory[mPortLocation + 0x3C];
|
|
xPortReg.FBS = mSATAMemory[mPortLocation + 0x40];
|
|
xPortReg.Reserved1 = GetValueArray(0x44, 11);
|
|
xPortReg.VendorSpecific = GetValueArray(0x70, 4);
|
|
mIPM = (InterfacePowerManagementStatus)((byte)((xPortReg.SSTS >> 8) & 0x0F));
|
|
mDET = (DeviceDetectionStatus)((byte)(xPortReg.SSTS & 0x0F));
|
|
return xPortReg;
|
|
}
|
|
public static PortRegisters PortRegisters(int[] aPortsArray)
|
|
{
|
|
foreach (int xPortNumber in aPortsArray)
|
|
{
|
|
mPortLocation = 0x100 + (0x80 * (uint)xPortNumber);
|
|
PortRegisters xPortReg = new PortRegisters();
|
|
xPortReg.CLB = mSATAMemory[mPortLocation + 0x00];
|
|
xPortReg.CLBU = mSATAMemory[mPortLocation + 0x04];
|
|
xPortReg.FB = mSATAMemory[mPortLocation + 0x08];
|
|
xPortReg.FBU = mSATAMemory[mPortLocation + 0x0C];
|
|
xPortReg.IS = mSATAMemory[mPortLocation + 0x10];
|
|
xPortReg.IE = mSATAMemory[mPortLocation + 0x14];
|
|
xPortReg.CMD = mSATAMemory[mPortLocation + 0x18];
|
|
xPortReg.Reserved0 = mSATAMemory[mPortLocation + 0x1C];
|
|
xPortReg.TFD = mSATAMemory[mPortLocation + 0x20];
|
|
xPortReg.SIG = mSATAMemory[mPortLocation + 0x24];
|
|
xPortReg.SSTS = mSATAMemory[mPortLocation + 0x28];
|
|
xPortReg.SCTL = mSATAMemory[mPortLocation + 0x2C];
|
|
xPortReg.SERR = mSATAMemory[mPortLocation + 0x30];
|
|
xPortReg.SACT = mSATAMemory[mPortLocation + 0x34];
|
|
xPortReg.CI = mSATAMemory[mPortLocation + 0x38];
|
|
xPortReg.SNTF = mSATAMemory[mPortLocation + 0x3C];
|
|
xPortReg.FBS = mSATAMemory[mPortLocation + 0x40];
|
|
xPortReg.Reserved1 = GetValueArray(0x44, 11);
|
|
xPortReg.VendorSpecific = GetValueArray(0x70, 4);
|
|
return xPortReg;
|
|
}
|
|
PortRegisters mNullPort = new PortRegisters();
|
|
return mNullPort;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Note: This method only work when SATA is initialized!
|
|
/// </summary>
|
|
public static int GetPortNumber()
|
|
{
|
|
foreach (int mPort in mPorts)
|
|
{
|
|
if (mPort == 1)
|
|
{
|
|
return mPort; // Return mPort SATA Type
|
|
}
|
|
else
|
|
{
|
|
// If mPort's value is not 1 then it is a CD/DVD Drive Port, Port Multiplier, SEMB Port or Nothing in the Port
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
public static uint[] GetValueArray(uint aStartAddress, int aAmount)
|
|
{
|
|
uint[] FinishedArray = new uint[aAmount];
|
|
|
|
int i = 0;
|
|
for (uint ui = aStartAddress; ui < aAmount; ui += 0x04)
|
|
{
|
|
while (i < aAmount)
|
|
{
|
|
FinishedArray[i] = mSATAMemory[ui];
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
return FinishedArray;
|
|
}
|
|
public static byte[] GetByteValueArray(uint aStartAddress, int aAmount)
|
|
{
|
|
byte[] FinishedArray = new byte[aAmount];
|
|
|
|
for (uint ui = aStartAddress; ui < aAmount; ui += 0x04)
|
|
{
|
|
for (int i = 0; i < aAmount; i++)
|
|
{
|
|
FinishedArray[i] = mSATAMemory.Bytes[ui];
|
|
}
|
|
}
|
|
return FinishedArray;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
public SATA(uint ABAROffset)
|
|
{
|
|
// Setting Offset arg to Global offset
|
|
mABAR = ABAROffset;
|
|
mSATAMemory = new MemoryBlock(mABAR, 0x10FF);
|
|
|
|
mGeneric = new GenericRegisters
|
|
{
|
|
CAP = mSATAMemory[0x00],
|
|
GHC = mSATAMemory[0x04],
|
|
IS = mSATAMemory[0x08],
|
|
PI = mSATAMemory[0x0C],
|
|
VS = mSATAMemory[0x10],
|
|
CCC_CTL = mSATAMemory[0x14],
|
|
CCC_PORTS = mSATAMemory[0x18],
|
|
EM_LOC = mSATAMemory[0x1C],
|
|
EM_CTL = mSATAMemory[0x20],
|
|
CAP2 = mSATAMemory[0x24],
|
|
BOHC = mSATAMemory[0x28],
|
|
//Reserved0 = Registers.GetByteValueArray(0x2C, 29),
|
|
//VendorSpecific = Registers.GetByteValueArray(0xA0, 20),
|
|
Ports = new PortRegisters[32]
|
|
};
|
|
while (((mSATAMemory[0x04] >> 31) & 1) == 0) ;
|
|
mBlockSize = 512;
|
|
mBlockCount = 256;
|
|
Console.WriteLine("-- 00 --");
|
|
SearchForDisks(mGeneric);
|
|
}
|
|
|
|
|
|
|
|
private void SearchForDisks(GenericRegisters aGeneric)
|
|
{
|
|
// Search for disks
|
|
var xImplementedPort = aGeneric.PI;
|
|
var xPort = 0;
|
|
var xPortType = 0U;
|
|
while(xPort < 32)
|
|
{
|
|
if ((xImplementedPort & 1) != 0)
|
|
{
|
|
PortType PortType = CheckPortType(Registers.PortRegisters(xPort));
|
|
var xPortString = "0:" + xPort;
|
|
if (PortType == PortType.SATA) // If Port Type was SATA.
|
|
{
|
|
Console.WriteLine("SATA drive at port " + xPortString + " found");
|
|
Console.WriteLine("SATA Drive at port " + xPortString);
|
|
PortRebase(Registers.PortRegisters(xPort), xPort);
|
|
ushort ReadedBits = new ushort();
|
|
SATAPorts.Add(xPort);
|
|
mSATADebugger.Send("Readen bits: " + ReadedBits);
|
|
xPortType = 0x01;
|
|
}
|
|
else if (PortType == PortType.SATAPI) // If Port Type was SATAPI.
|
|
{
|
|
Console.WriteLine("SATAPI drive at port " + xPortString + " found, which is not supported yet!");
|
|
Console.WriteLine("CD/DVD Drive at port " + xPortString + " found, which is not supported yet!");
|
|
xPortType = 0x02;
|
|
}
|
|
else if (PortType == PortType.SEMB) // If Port Type was SEMB.
|
|
{
|
|
//Console.WriteLine("SEMB drive at port " + xPortString + " found, which is not supported yet!");
|
|
Console.WriteLine("SEMB Drive at port " + xPortString + " found, which is not supported yet!");
|
|
xPortType = 0x03;
|
|
}
|
|
else if (PortType == PortType.PM) // If Port Type was Port Mulitplier.
|
|
{
|
|
//Console.WriteLine("Port Multiplier drive at port " + xPortString + " found, which is not supported yet!");
|
|
Console.WriteLine("Port Multiplier Drive at port " + xPortString + " found, which is not supported yet!");
|
|
xPortType = 0x04;
|
|
}
|
|
//else if (PortType == PortType.Nothing) // If Nothing in this Port.
|
|
//else // If Implemented Port value was not zero and non of the above.
|
|
}
|
|
mPorts[xPort] = xPortType;
|
|
xImplementedPort >>= 1;
|
|
xPort++;
|
|
}
|
|
}
|
|
|
|
private PortType CheckPortType(PortRegisters Port)
|
|
{
|
|
DriveSignature xSignature = (DriveSignature)Port.SIG;
|
|
uint xSATAStatus = Port.SSTS;
|
|
|
|
if (mIPM != InterfacePowerManagementStatus.Active)
|
|
return PortType.Nothing;
|
|
if (mDET != DeviceDetectionStatus.DeviceDetectedWithPhy)
|
|
return PortType.Nothing;
|
|
|
|
switch (xSignature)
|
|
{
|
|
case DriveSignature.SATAPIDrive:
|
|
return PortType.SATAPI;
|
|
case DriveSignature.SEMBDrive:
|
|
return PortType.SEMB;
|
|
case DriveSignature.PMDrive:
|
|
return PortType.PM;
|
|
case DriveSignature.NullDrive:
|
|
return PortType.Nothing;
|
|
default:
|
|
return PortType.SATA;
|
|
}
|
|
}
|
|
|
|
public void PortRebase(PortRegisters aPort, int aPortNumber)
|
|
{
|
|
StopCMD(aPort);
|
|
|
|
var CLBAddress = Heap.MemAlloc(1024);
|
|
var FBAddress = Heap.MemAlloc(256);
|
|
Console.WriteLine(CLBAddress.ToString());
|
|
mSATAMemory[mPortLocation] = CLBAddress;
|
|
new MemoryBlock(mSATAMemory[mPortLocation], 1024).Fill(0);
|
|
//if(is64DMA)
|
|
//{
|
|
// mSATAMemory[mPortLocation + 0x04] |= CLBUAddress;
|
|
// new MemoryBlock(mSATAMemory[mPortLocation + 0x04], 1024).Fill(0);
|
|
//}
|
|
|
|
mSATAMemory[mPortLocation + 0x08] = FBAddress;
|
|
new MemoryBlock(mSATAMemory[mPortLocation + 0x08], 256).Fill(0);
|
|
//if (is64DMA)
|
|
//{
|
|
// mSATAMemory[mPortLocation + 0x0C] |= FBUAddress;
|
|
// new MemoryBlock(mSATAMemory[mPortLocation + 0x0C], 256).Fill(0);
|
|
//}
|
|
|
|
GetCommandHeader(aPort, aPortNumber); // Rebasing Command Header
|
|
|
|
StartCMD(aPort);
|
|
}
|
|
|
|
public static HBACommandHeader[] GetCommandHeader(PortRegisters aPort, int aPortNumber)
|
|
{
|
|
HBACommandHeader[] xCMDHeader = new HBACommandHeader[32];
|
|
for (int i = 0; i < xCMDHeader.Length; i++)
|
|
{
|
|
xCMDHeader[i] = new HBACommandHeader();
|
|
xCMDHeader[i].PRDTL = 8; // 8 prdt entries per command table
|
|
// 256 bytes per command table, 64+16+48+16*8
|
|
xCMDHeader[i].CTBA = Heap.MemAlloc(256);
|
|
xCMDHeader[i].CTBAU = 0;
|
|
new MemoryBlock(xCMDHeader[i].CTBA, 256).Fill(0);
|
|
var xCMDHeaderMem = new MemoryBlock(mSATAMemory[mPortLocation + 0x00], 1024);
|
|
xCMDHeaderMem[0x02] = xCMDHeader[i].PRDTL;
|
|
xCMDHeaderMem[0x08] = xCMDHeader[i].CTBA << 7;
|
|
xCMDHeaderMem[0x0C] = xCMDHeader[i].CTBAU;
|
|
}
|
|
return xCMDHeader;
|
|
}
|
|
|
|
public void StartCMD(PortRegisters aPort)
|
|
{
|
|
while ((mSATAMemory[mPortLocation + 0x18] & (uint)CommandAndStatus.CMDListRunning) != 0)
|
|
{
|
|
//Console.WriteLine("Command list is already running");
|
|
continue;
|
|
}
|
|
Console.WriteLine("Starting Process");
|
|
mSATAMemory[mPortLocation + 0x18] |= (uint)CommandAndStatus.FISRecieveEnable;
|
|
mSATAMemory[mPortLocation + 0x18] |= (uint)CommandAndStatus.StartProccess;
|
|
}
|
|
|
|
public void StopCMD(PortRegisters aPort)
|
|
{
|
|
Console.WriteLine("Stopping Process");
|
|
mSATAMemory[mPortLocation + 0x18] &= ~(uint)CommandAndStatus.FISRecieveEnable;
|
|
mSATAMemory[mPortLocation + 0x18] &= ~(uint)CommandAndStatus.StartProccess;
|
|
|
|
while ((mSATAMemory[mPortLocation + 0x18] & (uint)(CommandAndStatus.FISRecieveRunning | CommandAndStatus.CMDListRunning)) != 0) ;
|
|
}
|
|
|
|
private bool InternalTransfer(PortRegisters aPort, uint aStartLow, uint aStartHigh, uint aCount, ushort aBuffer, bool aWrite = false)
|
|
{
|
|
//mSATAMemory[mPortLocation + 0x10] = unchecked((uint)-1);
|
|
new MemoryBlock(mSATAMemory.Base + mPortLocation + 0x10, sizeof(uint)).Fill(0);
|
|
int xSpin = 0; // Spin lock Timeout Counter
|
|
int xSlot = FindCMDSlot(aPort);
|
|
Console.WriteLine("My Slot: " + xSlot);
|
|
if (xSlot == -1)
|
|
return false;
|
|
|
|
HBACommandHeader xCMDHeader = GetCommandHeader(aPort, Registers.GetPortNumber())[xSlot];
|
|
//mSATAMemory[mPortLocation + 0x00] += (uint)xSlot;
|
|
xCMDHeader.CFL = (byte)(17 / sizeof(uint));
|
|
xCMDHeader.Write = (aWrite ? (byte)1 : (byte)0);
|
|
xCMDHeader.PRDTL = (ushort)(((aCount - 1) >> 4) + 1);
|
|
var xCMDHeaderMem = new MemoryBlock(mSATAMemory[mPortLocation + 0x00], 1024);
|
|
xCMDHeaderMem[0x00] = (uint)xCMDHeader.PRDTL << 16;
|
|
xCMDHeaderMem[0x00] = (uint)xCMDHeader.Write << 6;
|
|
xCMDHeaderMem[0x00] = (uint)xCMDHeader.CFL << 0;
|
|
|
|
Console.WriteLine(xCMDHeaderMem[0x00].ToString());
|
|
Console.WriteLine(xCMDHeaderMem.Base.ToString());
|
|
Console.WriteLine(xCMDHeader.CTBA.ToString());
|
|
|
|
Console.WriteLine("Before Command Table Initialization");
|
|
HBACommandTable xCMDTable = new HBACommandTable(); // xCMDHeader.CTBA
|
|
var xCMDTableMem = new MemoryBlock(xCMDHeader.CTBA, 256);
|
|
xCMDTableMem.Fill(0, (((158 / 8) + (xCMDHeader.PRDTL - 1U)) * 24), 0);
|
|
xCMDTable.PRDTEntry = new HBAPRDTEntry[1];
|
|
xCMDTable.PRDTEntry[0] = new HBAPRDTEntry();
|
|
Console.WriteLine("After Command Table Initialization");
|
|
|
|
Console.WriteLine("Before MemAlloc");
|
|
var xDataBA = Heap.MemAlloc(sizeof(ushort));
|
|
Console.WriteLine(xDataBA);
|
|
var xDataMem = new MemoryBlock(xDataBA, sizeof(ushort));
|
|
xDataMem[0x00] = aBuffer;
|
|
Console.WriteLine(xDataMem[0x00]);
|
|
Console.WriteLine("After MemAlloc");
|
|
uint i = 1;
|
|
while (i - 1 < xCMDHeader.PRDTL - 1)
|
|
{
|
|
|
|
Console.WriteLine("On Loop Command Table Initialization");
|
|
xCMDTable.PRDTEntry[i - 1].DBA = (uint)(xDataBA);
|
|
xCMDTable.PRDTEntry[i - 1].DBC = 8 * 1024 - 1;
|
|
xCMDTable.PRDTEntry[i - 1].InterruptOnCompletion = 1;
|
|
xCMDTableMem[(0x80 * i) + 0x00] = xCMDTable.PRDTEntry[i - 1].DBA << 1;
|
|
xCMDTableMem[(0x80 * i) + 0x0C] = xCMDTable.PRDTEntry[i - 1].DBC;
|
|
xCMDTableMem[(0x80 * i) + 0x0C] = (uint)xCMDTable.PRDTEntry[i - 1].InterruptOnCompletion << 31;
|
|
aBuffer += 4 * 1024;
|
|
aCount -= 16;
|
|
i++;
|
|
}
|
|
Console.WriteLine("Last Command Table Initialization");
|
|
|
|
// Last entry
|
|
xCMDTable.PRDTEntry[i - 1].DBA = xDataBA;
|
|
xCMDTable.PRDTEntry[i - 1].DBC = (aCount << 9) - 1;
|
|
xCMDTable.PRDTEntry[i - 1].InterruptOnCompletion = 1;
|
|
xCMDTableMem[(0x80 * i) + 0x00] = xCMDTable.PRDTEntry[i - 1].DBA << 1;
|
|
xCMDTableMem[(0x80 * i) + 0x0C] = xCMDTable.PRDTEntry[i - 1].DBC;
|
|
xCMDTableMem[(0x80 * i) + 0x0C] = (uint)xCMDTable.PRDTEntry[i - 1].InterruptOnCompletion << 31;
|
|
|
|
Console.WriteLine("Setup Command FIS");
|
|
// Setup the command
|
|
uint xCMDFISAddress = Heap.MemAlloc(0x10);
|
|
|
|
xCMDTableMem[0x00] = (uint)xCMDFISAddress;
|
|
FISRegisterH2D xCMDFIS = new FISRegisterH2D();
|
|
xCMDFIS.FISType = (byte)FISType.FIS_Type_RegisterH2D;
|
|
xCMDFIS.IsCommand = 1;
|
|
xCMDFIS.Command = (aWrite ? (byte)SATACommands.WriteDmaExt : (byte)SATACommands.ReadDmaExt);
|
|
|
|
xCMDFIS.LBA0 = (byte)aStartLow;
|
|
xCMDFIS.LBA1 = (byte)(aStartLow >> 8);
|
|
xCMDFIS.LBA2 = (byte)(aStartLow >> 16);
|
|
xCMDFIS.Device = 1 << 6; // LBA Mode
|
|
|
|
xCMDFIS.LBA3 = 0x00;
|
|
xCMDFIS.LBA4 = 0x00;
|
|
xCMDFIS.LBA5 = 0x00;
|
|
|
|
xCMDFIS.CountL = (byte)(aCount & 0xFF);
|
|
xCMDFIS.CountH = (byte)((aCount >> 8) & 0xFF);
|
|
var xCMDFISMem = new MemoryBlock((uint)xCMDTableMem[0x00], 0x10);
|
|
Console.WriteLine("Setting values to memory offset: " + xCMDTableMem[0x00]);
|
|
|
|
// DWord 0
|
|
xCMDFISMem[0x00] = (byte)(xCMDFIS.FISType); // FIS Type
|
|
xCMDFISMem[0x00] = (byte)(xCMDFIS.IsCommand >> 15); // IsCommand(or)Control
|
|
xCMDFISMem[0x00] = (byte)(xCMDFIS.Command >> 16); // Command register
|
|
|
|
// DWord 1
|
|
xCMDFISMem[0x04] = (byte)(xCMDFIS.LBA0); // LBA Low register
|
|
xCMDFISMem[0x04] = (byte)(xCMDFIS.LBA1 >> 8); // LBA Mid register
|
|
xCMDFISMem[0x04] = (byte)(xCMDFIS.LBA2 >> 16); // LBA Hgh register
|
|
xCMDFISMem[0x04] = (byte)(xCMDFIS.Device >> 24); // Device register
|
|
|
|
// DWord 2
|
|
xCMDFISMem[0x08] = (byte)(xCMDFIS.LBA3); // LBA register
|
|
xCMDFISMem[0x08] = (byte)(xCMDFIS.LBA4 >> 8); // LBA register
|
|
xCMDFISMem[0x08] = (byte)(xCMDFIS.LBA5 >> 16); // LBA register
|
|
|
|
// DWord 3
|
|
xCMDFISMem[0x0C] = (byte)(xCMDFIS.CountL); // Count Low register
|
|
xCMDFISMem[0x0C] = (byte)(xCMDFIS.CountH); // Count Hgh register
|
|
|
|
Console.WriteLine(Cosmos.Common.Extensions.ToHexString.ToHex(new MemoryBlock(xCMDFISAddress, 0x10)[0x00]));
|
|
|
|
Console.WriteLine("Spinning on xSpin");
|
|
do
|
|
{
|
|
xSpin++;
|
|
Console.WriteLine(xSpin);
|
|
} while (((mSATAMemory[mPortLocation + 0x20] & (uint)(ATADeviceStatus.Busy | ATADeviceStatus.DRQ)) > 0 && xSpin < 1000000));
|
|
|
|
if (xSpin == 1000000)
|
|
{
|
|
Console.WriteLine("Port timed out");
|
|
return false;
|
|
}
|
|
|
|
mSATAMemory[mPortLocation + 0x38] = (uint)(1 << xSlot); // Issue with Command
|
|
|
|
// Wait for Completion
|
|
do
|
|
{
|
|
// If error occured
|
|
if (((mSATAMemory[mPortLocation + 0x10] >> 30) & 1) != 0)
|
|
{
|
|
Console.WriteLine("Write or Read Disk Error!");
|
|
return false;
|
|
}
|
|
} while (((mSATAMemory[mPortLocation + 0x38] >> xSlot) & 1) != 0);
|
|
|
|
// Fill in the data
|
|
if (!aWrite)
|
|
{
|
|
aBuffer = xDataMem.Words[0x00];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool Read(PortRegisters aPort, uint aStartLow, uint aStartHigh, uint aCount, ushort aBuffer)
|
|
=> InternalTransfer(aPort, aStartLow, aStartHigh, aCount, aBuffer, false);
|
|
|
|
public bool Write(PortRegisters aPort, uint aStartLow, uint aStartHigh, uint aCount, ushort aBuffer)
|
|
=> InternalTransfer(aPort, aStartLow, aStartHigh, aCount, aBuffer, true);
|
|
|
|
public int FindCMDSlot(PortRegisters aPort)
|
|
{
|
|
// If not set in SACT and CI, the slot is free
|
|
var xSlots = (mSATAMemory[mPortLocation + 0x34] | mSATAMemory[mPortLocation + 0x38]);
|
|
//for(int i = 0; i < aPort.VendorSpecific.Length; i++)
|
|
////mSATADebugger.SendInternalNumber(aPort.VendorSpecific[i]);
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
if ((xSlots & 1) == 0)
|
|
{
|
|
return i;
|
|
}
|
|
xSlots >>= 1;
|
|
}
|
|
//Console.WriteLine("Cannot find free Command list Entry");
|
|
return -1;
|
|
}
|
|
|
|
public SATA(int xPort)
|
|
{
|
|
}
|
|
|
|
public override void ReadBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
|
|
{
|
|
CheckDataSize(aData, aBlockCount);
|
|
if(SATAPorts.Count > 0)
|
|
{
|
|
var xPort = Registers.PortRegisters(SATAPorts[0]);
|
|
for(int i = 0; i < aData.Length; i += 2)
|
|
{
|
|
ushort xData = (ushort)((aData[i + 1] << 8) | aData[i]);
|
|
Read(xPort, (uint)aBlockNo, 0, (uint)aBlockCount, xData);
|
|
for (int ui = 0; ui < 200; ui++) ;
|
|
aData[i+0] = (byte)(xData);
|
|
aData[i+1] = (byte)(xData >> 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteBlock(ulong aBlockNo, ulong aBlockCount, byte[] aData)
|
|
{
|
|
CheckDataSize(aData, aBlockCount);
|
|
var xPort = Registers.PortRegisters(SATAPorts[0]);
|
|
for (int i = 0; i < aData.Length; i += 2)
|
|
{
|
|
ushort xData = (ushort)((aData[i + 1] << 8) | aData[i]);
|
|
Write(xPort, (uint)aBlockNo, 0, (uint)aBlockCount, xData);
|
|
for (int ui = 0; ui < 200; ui++) ;
|
|
}
|
|
// Might not work for some reasons :|
|
|
}
|
|
}
|
|
}
|