diff --git a/source/Cosmos.Core/ACPI.cs b/source/Cosmos.Core/ACPI.cs
index 20e4ef9fd8..169e04d4e0 100644
--- a/source/Cosmos.Core/ACPI.cs
+++ b/source/Cosmos.Core/ACPI.cs
@@ -1,13 +1,49 @@
-using System;
+using Cosmos.Debug.Kernel;
+using System;
+using System.Collections.Generic;
+using System.IO;
using System.Runtime.InteropServices;
+using System.Text;
namespace Cosmos.Core
{
+ ///
+ /// PCI IRQ Routing information.
+ ///
+ public class IrqRouting
+ {
+ ///
+ /// The address of the PCI device.
+ ///
+ public uint Address;
+
+ ///
+ /// The PCI pin number of the device.
+ ///
+ public byte Pin;
+
+ ///
+ /// Source.
+ ///
+ public byte Source;
+
+ ///
+ /// Source Index.
+ ///
+ public byte SourceIndex;
+ }
+
///
/// ACPI (Advanced Configuration and Power Interface) class.
///
public unsafe class ACPI
{
+
+ ///
+ /// Debugger instance at the System ring, of the Global section.
+ ///
+ public static readonly Debugger debugger = new Debugger("Core");
+
///
/// RSD table struct.
///
@@ -18,29 +54,317 @@ public unsafe struct RSDPtr
/// Signature.
///
public fixed byte Signature[8];
+
///
/// CheckSum
///
public byte CheckSum;
+
///
/// OemID
///
public fixed byte OemID[6];
+
///
/// Revision
///
public byte Revision;
+
///
/// RSDT Address
///
public int RsdtAddress;
};
- // New Port I/O
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct AcpiHeader
+ {
+ ///
+ /// Signature.
+ ///
+ public fixed byte Signature[4];
+
+ ///
+ /// Length.
+ ///
+ public uint Length;
+
+ ///
+ /// Revision.
+ ///
+ public byte Revision;
+
+ ///
+ /// Checksum.
+ ///
+ public byte Checksum;
+
+ ///
+ /// OEM ID.
+ ///
+ public fixed byte OEMID[6];
+
+ ///
+ /// OEM Table ID.
+ ///
+ public fixed byte OEMTableID[8];
+
+ ///
+ /// OEM Revision.
+ ///
+ public uint OEMRevision;
+
+ ///
+ /// CreatorID.
+ ///
+ public uint CreatorID;
+
+ ///
+ /// Creator Revision.
+ ///
+ public uint CreatorRevision;
+ };
+
+ ///
+ /// FADT struct.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct FADTPtr
+ {
+ ///
+ /// ACPI Header.
+ ///
+ public AcpiHeader Header;
+
+ ///
+ /// Firmware Control.
+ ///
+ public uint FirmwareCtrl;
+
+ ///
+ /// DSDT Signature.
+ ///
+ public uint Dsdt;
+
+ public byte Reserved;
+ public byte PreferredPowerManagementProfile;
+ public ushort SCI_Interrupt;
+ public uint SMI_CommandPort;
+
+ ///
+ /// ACPI Enable.
+ ///
+ public byte AcpiEnable;
+
+ ///
+ /// ACPI Disable.
+ ///
+ public byte AcpiDisable;
+
+ public byte S4BIOS_REQ;
+ public byte PSTATE_Control;
+ public uint PM1aEventBlock;
+ public uint PM1bEventBlock;
+ public uint PM1aControlBlock;
+ public uint PM1bControlBlock;
+ public uint PM2ControlBlock;
+ public uint PMTimerBlock;
+ public uint GPE0Block;
+ public uint GPE1Block;
+ public byte PM1EventLength;
+ public byte PM1ControlLength;
+ public byte PM2ControlLength;
+ public byte PMTimerLength;
+ public byte GPE0Length;
+ public byte GPE1Length;
+ public byte GPE1Base;
+ public byte CStateControl;
+ public ushort WorstC2Latency;
+ public ushort WorstC3Latency;
+ public ushort FlushSize;
+ public ushort FlushStride;
+ public byte DutyOffset;
+ public byte DutyWidth;
+ public byte DayAlarm;
+ public byte MonthAlarm;
+ public byte Century;
+
+ public ushort BootArchitectureFlags;
+
+ public byte Reserved2;
+ public uint Flags;
+
+ // 12 public byte structure; see below for details
+ public GenericAddressStructure ResetReg;
+
+ public byte ResetValue;
+ public byte Reserved3;
+ public byte Reserved34;
+ public byte Reserved35;
+
+ // 64bit pointers - Available on ACPI 2.0+
+ public ulong X_FirmwareControl;
+ public ulong X_Dsdt;
+
+ public GenericAddressStructure X_PM1aEventBlock;
+ public GenericAddressStructure X_PM1bEventBlock;
+ public GenericAddressStructure X_PM1aControlBlock;
+ public GenericAddressStructure X_PM1bControlBlock;
+ public GenericAddressStructure X_PM2ControlBlock;
+ public GenericAddressStructure X_PMTimerBlock;
+ public GenericAddressStructure X_GPE0Block;
+ public GenericAddressStructure X_GPE1Block;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct GenericAddressStructure
+ {
+ public byte AddressSpace;
+ public byte BitWidth;
+ public byte BitOffset;
+ public byte AccessSize;
+ public ulong Address;
+ };
+
///
- /// IO port.
+ /// MADT struct.
///
- private static ushort smiIO, pm1aIO, pm1bIO;
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct MADTPtr
+ {
+ ///
+ /// ACPI Header.
+ ///
+ public AcpiHeader Header;
+
+ ///
+ /// Local APIC Address.
+ ///
+ public uint LocalAPICAddress;
+
+ ///
+ /// Flags.
+ ///
+ public uint Flags;
+ }
+
+ ///
+ /// APIC Header struct.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ApicHeader
+ {
+ ///
+ /// APIC Type.
+ ///
+ public ApicType Type;
+
+ ///
+ /// Length.
+ ///
+ public byte Length;
+ }
+
+ ///
+ /// APIC Type enum.
+ ///
+ public enum ApicType : byte
+ {
+ LocalAPIC,
+ IOAPIC,
+ InterruptOverride
+ }
+
+ ///
+ /// ApicLocalApic struct.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct ApicLocalApic
+ {
+ ///
+ /// APIC Header.
+ ///
+ public ApicHeader Header;
+
+ ///
+ /// ACPI Processor ID.
+ ///
+ public byte AcpiProcessorId;
+
+ ///
+ /// APIC ID.
+ ///
+ public byte ApicId;
+
+ ///
+ /// APIC Flags.
+ ///
+ public uint Flags;
+ }
+
+ ///
+ /// ApicIOApic struct.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ApicIOApic
+ {
+ ///
+ /// APIC Header.
+ ///
+ public ApicHeader Header;
+
+ ///
+ /// APIC ID.
+ ///
+ public byte IOApicId;
+
+ ///
+ /// Reserved.
+ ///
+ public byte Reserved;
+
+ ///
+ /// IO APIC Base Address.
+ ///
+ public uint IOApicAddress;
+
+ ///
+ /// Global System Interrupt Base Address.
+ ///
+ public uint GlobalSystemInterruptBase;
+ }
+
+ ///
+ /// ApicInterruptOverride struct.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct ApicInterruptOverride
+ {
+ ///
+ /// APIC Header.
+ ///
+ public ApicHeader Header;
+
+ ///
+ /// Bus.
+ ///
+ public byte Bus;
+
+ ///
+ /// Source.
+ ///
+ public byte Source;
+
+ ///
+ /// Interrupt.
+ ///
+ public uint Interrupt;
+
+ ///
+ /// Floags.
+ ///
+ public ushort Flags;
+ }
// ACPI variables
///
@@ -56,6 +380,10 @@ public unsafe struct RSDPtr
///
private static byte ACPI_DISABLE;
///
+ /// Reset value to write into reset register when you need to reboot
+ ///
+ private static byte ResetValue;
+ ///
/// PM1a CNT
///
private static int* PM1a_CNT;
@@ -79,6 +407,30 @@ public unsafe struct RSDPtr
/// PM1 CNT LEN1
///
private static byte PM1_CNT_LEN;
+ ///
+ /// Global MADT.
+ ///
+ public static MADTPtr* MADT;
+ ///
+ /// Global IO APIC.
+ ///
+ public static ApicIOApic* IOAPIC;
+ ///
+ /// FADT table
+ ///
+ public static FADTPtr* FADT;
+
+ public static uint DSDTLenght = 0;
+
+ ///
+ /// PCI IRQ Routing Table.
+ ///
+ public static List IrqRoutingTable;
+
+ ///
+ /// PCI IRQ Routing Table.
+ ///
+ public static List LocalApicCpus;
///
/// Check ACPI header.
@@ -91,71 +443,6 @@ static int acpiCheckHeader(byte* ptr, string sig)
return Compare(sig, ptr);
}
- ///
- /// FACP.
- ///
- private static byte* Facp = null;
- ///
- /// FACP struct.
- ///
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- struct FACP
- {
- ///
- /// Signature.
- ///
- public fixed byte Signature[4];
- ///
- /// Length.
- ///
- public int Length;
-
- ///
- /// Unused.
- ///
- public fixed byte unneded1[40 - 8];
- ///
- /// DSDT.
- ///
- public int* DSDT;
- ///
- /// Unused.
- ///
- public fixed byte unneded2[48 - 44];
- ///
- /// SMI CMD.
- ///
- public int* SMI_CMD;
- ///
- /// ACPI ENABLE.
- ///
- public byte ACPI_ENABLE;
- ///
- /// ACPI DISABLE.
- ///
- public byte ACPI_DISABLE;
- ///
- /// Unused.
- ///
- public fixed byte unneded3[64 - 54];
- ///
- /// PM1a CNT BLK.
- ///
- public int* PM1a_CNT_BLK;
- ///
- /// PM1b CNT BLK.
- ///
- public int* PM1b_CNT_BLK;
- ///
- /// Unused.
- ///
- public fixed byte unneded4[89 - 72];
- ///
- /// PM1 CNT LEN.
- ///
- public byte PM1_CNT_LEN;
- };
-
///
/// Compare string to byte array.
///
@@ -164,7 +451,7 @@ struct FACP
/// 0 - identical, -1 different.
static int Compare(string c1, byte* c2)
{
- for (int i = 0; i < c1.Length; i++)
+ for (var i = 0; i < c1.Length; i++)
{
if (c1[i] != c2[i]) { return -1; }
}
@@ -179,9 +466,9 @@ static int Compare(string c1, byte* c2)
static bool Check_RSD(uint address)
{
byte sum = 0;
- byte* check = (byte*)address;
+ var check = (byte*)address;
- for (int i = 0; i < 20; i++)
+ for (var i = 0; i < 20; i++)
{
sum += *check++;
}
@@ -213,17 +500,16 @@ public static void Start(bool initialize = true, bool enable = true)
/// Thrown on IO error.
public static void Shutdown()
{
- Console.Clear();
if (PM1a_CNT == null)
{
Init();
}
- IOPort.Write16(pm1aIO, (ushort)(SLP_TYPa | SLP_EN));
+ IOPort.Write16((ushort)PM1a_CNT, (ushort)(SLP_TYPa | SLP_EN));
if (PM1b_CNT != null)
{
- IOPort.Write16(pm1bIO, (ushort)(SLP_TYPb | SLP_EN));
+ IOPort.Write16((ushort)PM1b_CNT, (ushort)(SLP_TYPb | SLP_EN));
}
CPU.Halt();
@@ -236,7 +522,22 @@ public static void Shutdown()
/// Thrown always.
public static void Reboot()
{
- throw new NotImplementedException("ACPI Reset not implemented yet."); //TODO
+ if (PM1a_CNT == null)
+ {
+ Init();
+ }
+
+ var header = FADT->Header;
+ if (header.Revision >= 2 && (FADT->Flags & (1 << 10)) != 0)
+ {
+ IOPort.Write16((ushort)FADT->ResetReg.Address, ResetValue);
+ }
+ else
+ {
+ throw new Exception("Hardware does not support ACPI reboot.");
+ }
+
+ throw new Exception("ACPI reboot failed.");
}
///
@@ -245,106 +546,283 @@ public static void Reboot()
/// true on success, false on failure.
private static bool Init()
{
- byte* ptr = (byte*)RSDPAddress();
- int addr = 0;
+ IOAPIC = null;
+ IrqRoutingTable = new List();
+ LocalApicCpus = new List();
+
+ var rsdp = RSDPAddress();
+ var ptr = (byte*)rsdp;
+
+ Global.debugger.Send("ACPI v" + rsdp->Revision);
- for (int i = 19; i >= 16; i--)
+ var rsdt = (AcpiHeader*)rsdp->RsdtAddress;
+ ptr = (byte*)rsdt;
+
+ var p = (uint*)(rsdt + 1);
+ var end = (uint*)((byte*)rsdt + rsdt->Length);
+
+ while (p < end)
{
- addr += *(ptr + i);
- addr = i == 16 ? addr : addr << 8;
- }
+ var address = *p++;
- ptr = (byte*)addr;
- ptr += 4; addr = 0;
+ ParseDT((AcpiHeader*)address);
+ }
- for (int i = 3; i >= 0; i--)
+ if (LocalApicCpus.Count > 0)
{
- addr += *(ptr + i);
- addr = i == 0 ? addr : addr << 8;
+ Global.debugger.Send("Found " + LocalApicCpus.Count + " CPUs via MADT.");
}
- int length = addr;
- ptr -= 4;
+ return true;
+ }
+
+ private static uint SdtLength = 0;
+
+ private static void ReadHeader(BinaryReader _reader)
+ {
+ Global.debugger.Send("SDT header:");
+
+ //Signature
+ Global.debugger.Send("\tSignature: " + Encoding.ASCII.GetString(_reader.ReadBytes(4)));
+
+ //Length
+ SdtLength = _reader.ReadUInt32();
+ Global.debugger.Send("\tLendth: " + SdtLength.ToString());
+
+ //Revision
+ Global.debugger.Send("\tRevision: " + _reader.ReadByte().ToString());
- if (ptr != null && acpiCheckHeader(ptr, "RSDT") == 0)
+ //Checksum
+ Global.debugger.Send("\tChecksum: " + _reader.ReadByte().ToString());
+
+ //OEM ID
+ Global.debugger.Send("\tOEM ID: " + Encoding.ASCII.GetString(_reader.ReadBytes(6)));
+
+ //OEMTableID
+ Global.debugger.Send("\tOEMTableID: " + Encoding.ASCII.GetString(_reader.ReadBytes(8)));
+
+ //OEMRevision
+ Global.debugger.Send("\tOEMRevision: " + _reader.ReadUInt32().ToString());
+
+ //OEMRevision
+ Global.debugger.Send("\tCreatorID: " + _reader.ReadUInt32().ToString());
+
+ //OEMRevision
+ Global.debugger.Send("\tCreatorRevision: " + _reader.ReadUInt32().ToString());
+ }
+
+ private static void ParseS5()
+ {
+ byte* S5Addr = (byte*)FADT->Dsdt;
+
+ while (0 < DSDTLenght--)
{
- addr = 0;
- int entrys = length;
- entrys = (entrys - 36) / 4;
- ptr += 36;
- byte* yeuse;
+ if (Compare("_S5_", S5Addr) == 0)
+ {
+ break;
+ }
+ S5Addr++;
+ }
- while (0 < entrys--)
+ if (DSDTLenght > 0)
+ {
+ if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12)
{
- for (int i = 3; i >= 0; i--)
+ S5Addr += 5;
+ S5Addr += ((*S5Addr & 0xC0) >> 6) + 2;
+ if (*S5Addr == 0x0A)
+ {
+ S5Addr++;
+ }
+ SLP_TYPa = (short)(*(S5Addr) << 10);
+ S5Addr++;
+ if (*S5Addr == 0x0A)
{
- addr += *(ptr + i);
- addr = i == 0 ? addr : addr << 8;
+ S5Addr++;
}
+ SLP_TYPb = (short)(*(S5Addr) << 10);
+
+ Global.debugger.Send("SLP_TYPa=" + SLP_TYPa);
+ Global.debugger.Send("SLP_TYPb=" + SLP_TYPb);
+ }
+ }
+ }
+
+ private static void ParsePRT()
+ {
+ /*
+ if (DSDTLenght > 0)
+ {
+ var dsdtBlock = new MemoryBlock08(FADT->Dsdt + (uint)sizeof(AcpiHeader), SdtLength - (uint)sizeof(AcpiHeader));
- yeuse = (byte*)addr;
- Facp = yeuse;
+ Stream stream = new MemoryStream(dsdtBlock.ToArray());
- if (acpiCheckHeader((byte*)facpget(0), "DSDT") == 0)
+ Global.debugger.Send("Create parser...");
+
+ var root = new Parser(stream);
+
+ Global.debugger.Send("Parse first node...");
+
+ var node = root.Parse();
+ foreach (var item in node.Nodes)
+ {
+ Global.debugger.Send("Node: " + item.Name);
+ }
+ }*/
+ }
+
+ private static void ParseDT(AcpiHeader* hdr)
+ {
+ var signature = Encoding.ASCII.GetString(hdr->Signature, 4);
+
+ Global.debugger.Send(signature + " detected");
+
+ if (signature == "FACP")
+ {
+ Global.debugger.Send("Parse FACP");
+
+ FADT = (FADTPtr*)hdr;
+
+ SMI_CMD = (int*)FADT->SMI_CommandPort;
+ ACPI_ENABLE = FADT->AcpiEnable;
+ ACPI_DISABLE = FADT->AcpiDisable;
+ PM1a_CNT = (int*)FADT->PM1aControlBlock;
+ PM1b_CNT = (int*)FADT->PM1bControlBlock;
+ PM1_CNT_LEN = FADT->PM1ControlLength;
+ SLP_EN = 1 << 13;
+
+
+ if (acpiCheckHeader((byte*)FADT->Dsdt, "DSDT") == 0)
+ {
+ uint dsdtAddress = FADT->Dsdt;
+ uint dsdtLength = (uint)(*((int*)FADT->Dsdt + 1) - sizeof(AcpiHeader));
+
+ var dsdtHeader = new MemoryBlock08(dsdtAddress, 36);
+ var _reader = new BinaryReader(new MemoryStream(dsdtHeader.ToArray()));
+
+ ReadHeader(_reader);
+
+ Global.debugger.Send("Parsing _S5...");
+
+ ParseS5();
+
+ Global.debugger.Send("Parsing _PRT...");
+
+ ParsePRT();
+ }
+ }
+ else if (signature == "APIC")
+ {
+ Global.debugger.Send("Parse APIC");
+
+ MADT = (MADTPtr*)hdr;
+
+ var p = (byte*)(MADT + 1);
+ var end = (byte*)MADT + MADT->Header.Length;
+ while (p < end)
+ {
+ var header = (ApicHeader*)p;
+ var type = header->Type;
+ var length = header->Length;
+
+ if (type == ApicType.LocalAPIC)
{
- byte* S5Addr = (byte*)facpget(0) + 36;
- int dsdtLength = *(facpget(0) + 1) - 36;
+ var pic = (ApicLocalApic*)p;
- while (0 < dsdtLength--)
+ if (((pic->Flags & 1) ^ ((pic->Flags >> 1) & 1)) != 0)
{
- if (Compare("_S5_", S5Addr) == 0)
- {
- break;
- }
- S5Addr++;
- }
+ LocalApicCpus.Add(pic->ApicId);
- if (dsdtLength > 0)
+ Global.debugger.Send("Found APIC " + (ulong)pic->ApicId + " (Processor ID:" + pic->AcpiProcessorId + ")");
+ }
+ }
+ else if (type == ApicType.IOAPIC)
+ {
+ var ioapic = (ApicIOApic*)p;
+ if (IOAPIC == null)
{
- if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12)
- {
- S5Addr += 5;
- S5Addr += ((*S5Addr & 0xC0) >> 6) + 2;
- if (*S5Addr == 0x0A)
- {
- S5Addr++;
- }
- SLP_TYPa = (short)(*S5Addr << 10);
- S5Addr++;
- if (*S5Addr == 0x0A)
- {
- S5Addr++;
- }
- SLP_TYPb = (short)(*S5Addr << 10);
- SMI_CMD = facpget(1);
- ACPI_ENABLE = facpbget(0);
- ACPI_DISABLE = facpbget(1);
- PM1a_CNT = facpget(2);
- PM1b_CNT = facpget(3);
- PM1_CNT_LEN = facpbget(3);
- SLP_EN = 1 << 13;
-
- smiIO = (ushort)SMI_CMD;
- pm1aIO = (ushort)PM1a_CNT;
- pm1bIO = (ushort)PM1b_CNT;
-
- return true;
- }
+ IOAPIC = ioapic;
}
+ Global.debugger.Send("Found IO APIC " + (ulong)ioapic->IOApicId + " (Address:0x" + ((ulong)ioapic->IOApicAddress).ToString("X") + ", GSIB:" + (ulong)ioapic->GlobalSystemInterruptBase + ")");
}
- ptr += 4;
+ else if (type == ApicType.InterruptOverride)
+ {
+ var ovr = (ApicInterruptOverride*)p;
+
+ Global.debugger.Send("Found APIC Interrupt Override (Bus: " + ((ulong)ovr->Bus).ToString() + ", Source:" + ((ulong)ovr->Source).ToString() + ", Interrupt:0x" + ((ulong)ovr->Interrupt).ToString("X") + ", Flags:" + ((ulong)ovr->Flags).ToString() + ")");
+ }
+
+ p += length;
}
}
+ }
+
+ /*
+ private static void PopulateNode(ParseNode op)
+ {
+ //Recursive function does a null reference exception trick the matrice with a Stack and iterative function
+ var sthack = new Stack();
+
+ sthack.Push(op);
+
+ while (sthack.Count != 0)
+ {
+ ParseNode current = sthack.Pop();
+
+ if (current.Arguments.Count > 0)
+ {
+ SearchPackage(current);
+ }
- return false;
+ if (current != null)
+ {
+ for (int i = current.Nodes.Count - 1; i >= 0; i--)
+ {
+ sthack.Push(current.Nodes[i]);
+ }
+ }
+ }
}
+
+ private static void SearchPackage(ParseNode op)
+ {
+ for (int x = 0; x < op.Op.ParseArgs.Length; x++)
+ {
+ if (op.Op.ParseArgs[x] == ParseArgFlags.DataObjectList || op.Op.ParseArgs[x] == ParseArgFlags.TermList || op.Op.ParseArgs[x] == ParseArgFlags.ObjectList)
+ continue;
+
+ if (op.Arguments[x].ToString() == "Package")
+ {
+ Global.debugger.Send("Package found!");
+
+ //var arg = (ParseNode)op.Arguments[x];
+
+ /*
+ for (int y = 0; y < arg.Nodes.Count; y++)
+ {
+ List package = arg.Nodes[y].Nodes;
+
+ var irqRouting = new IrqRouting()
+ {
+ Address = (uint)package[0].ConstantValue,
+ Pin = (byte)package[1].ConstantValue,
+ Source = (byte)package[2].ConstantValue,
+ SourceIndex = (byte)package[3].ConstantValue
+ };
+
+ IrqRoutingTable.Add(irqRouting);
+ }
+
+ }
+ }
+ }*/
+
///
/// Enable ACPI.
///
public static void Enable()
{
- smiIO = ACPI_ENABLE;
}
///
@@ -352,14 +830,13 @@ public static void Enable()
///
public static void Disable()
{
- smiIO = ACPI_DISABLE;
}
///
/// Get the RSDP address.
///
/// uint value.
- private static unsafe uint RSDPAddress()
+ private static unsafe RSDPtr* RSDPAddress()
{
for (uint addr = 0xE0000; addr < 0x100000; addr += 4)
{
@@ -367,118 +844,52 @@ private static unsafe uint RSDPAddress()
{
if (Check_RSD(addr))
{
- return addr;
+ return (RSDPtr*)addr;
}
}
}
- uint ebda_address = *(uint*)0x040E;
- ebda_address = (ebda_address * 0x10) & 0x000fffff;
+ var ebda_address = *(uint*)0x040E;
+ ebda_address = ebda_address * 0x10 & 0x000fffff;
- for (uint addr = ebda_address; addr < ebda_address + 1024; addr += 4)
+ for (var addr = ebda_address; addr < ebda_address + 1024; addr += 4)
{
if (Compare("RSD PTR ", (byte*)addr) == 0)
{
- return addr;
+ return (RSDPtr*)addr;
}
}
- return 0;
+ return null;
}
- ///
- /// Check RSDT table
- ///
- /// A pointer to the RSDT
- /// RSDT table address
- private static uint* acpiCheckRSDPtr(uint* ptr)
+ public static uint RemapIRQ(uint irq)
{
- string sig = "RSD PTR ";
- var rsdp = (RSDPtr*)ptr;
+ var p = (byte*)(MADT + 1);
+ var end = (byte*)MADT + MADT->Header.Length;
- byte* bptr;
- byte check = 0;
- int i;
-
- if (Compare(sig, (byte*)rsdp) == 0)
+ while (p < end)
{
- bptr = (byte*)ptr;
+ var header = (ApicHeader*)p;
+ var type = header->Type;
+ var length = header->Length;
- for (i = 0; i < 20; i++)
+ if (type == ApicType.InterruptOverride)
{
- check += *bptr;
- bptr++;
- }
+ var ovr = (ApicInterruptOverride*)p;
- if (check == 0)
- {
- Compare("RSDT", (byte*)rsdp->RsdtAddress);
-
- if (rsdp->RsdtAddress != 0)
+ if (ovr->Source == irq)
{
- return (uint*)rsdp->RsdtAddress;
+ Global.debugger.Send("IRQ" + irq + " remapped to IRQ" + ovr->Interrupt);
+
+ return ovr->Interrupt;
}
}
- }
-
- return null;
- }
- ///
- /// Get data from the FACP table.
- ///
- /// Index number of the data to get.
- ///
- /// - 0 - ACPI ENABLE
- /// - 1 - ACPI DISABLE
- /// - 2 - PM1 CNT LEN
- /// - other - 0
- ///
- ///
- /// byte value.
- private static byte facpbget(int number)
- {
- switch (number)
- {
- case 0:
- return *(Facp + 52);
- case 1:
- return *(Facp + 53);
- case 2:
- return *(Facp + 89);
- default:
- return 0;
+ p += length;
}
- }
- ///
- /// Get pointer to the data on the FACP.
- ///
- /// Index number of the data to get.
- ///
- /// - 0 - DSDT
- /// - 1 - SMI CMD
- /// - 2 - PM1a
- /// - 3 - PM1b
- /// - other - null
- ///
- ///
- /// int pointer.
- private static int* facpget(int number)
- {
- switch (number)
- {
- case 0:
- return (int*)*(int*)(Facp + 40);
- case 1:
- return (int*)*(int*)(Facp + 48);
- case 2:
- return (int*)*(int*)(Facp + 64);
- case 3:
- return (int*)*(int*)(Facp + 68);
- default:
- return null;
- }
+ return irq;
}
}
}
\ No newline at end of file
diff --git a/source/Cosmos.Core/INTs.cs b/source/Cosmos.Core/INTs.cs
index 662e970ff3..c07ad280da 100644
--- a/source/Cosmos.Core/INTs.cs
+++ b/source/Cosmos.Core/INTs.cs
@@ -283,6 +283,7 @@ public static void SetIntHandler(byte aIntNo, IRQDelegate aHandler) {
/// IRQ index.
/// IRQ handler.
public static void SetIrqHandler(byte aIrqNo, IRQDelegate aHandler) {
+ IOAPIC.SetEntry((uint)aIrqNo + 0x20);
SetIntHandler((byte)(0x20 + aIrqNo), aHandler);
}
@@ -303,13 +304,7 @@ private static void IRQ(uint irq, ref IRQContext aContext) {
///
/// A IEQ context.
public static void HandleInterrupt_Default(ref IRQContext aContext) {
- if (aContext.Interrupt >= 0x20 && aContext.Interrupt <= 0x2F) {
- if (aContext.Interrupt >= 0x28) {
- Global.PIC.EoiSlave();
- } else {
- Global.PIC.EoiMaster();
- }
- }
+ LocalAPIC.EndOfInterrupt();
}
///
@@ -327,12 +322,12 @@ public static void HandleInterrupt_Default(ref IRQContext aContext) {
#region Default Interrupt Handlers
///
- /// IRQ 0 - System timer. Reserved for the system. Cannot be changed by a user.
+ /// IRQ 0 - System (APIC) timer. Reserved for the system. Cannot be changed by a user.
///
/// IRQ context.
public static void HandleInterrupt_20(ref IRQContext aContext) {
IRQ(0x20, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
//public static IRQDelegate IRQ01;
@@ -343,43 +338,43 @@ public static void HandleInterrupt_20(ref IRQContext aContext) {
public static void HandleInterrupt_21(ref IRQContext aContext) {
IRQ(0x21, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_22(ref IRQContext aContext) {
IRQ(0x22, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_23(ref IRQContext aContext) {
IRQ(0x23, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_24(ref IRQContext aContext) {
IRQ(0x24, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_25(ref IRQContext aContext) {
IRQ(0x25, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_26(ref IRQContext aContext) {
IRQ(0x26, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_27(ref IRQContext aContext) {
IRQ(0x27, ref aContext);
- Global.PIC.EoiMaster();
+ LocalAPIC.EndOfInterrupt();
}
public static void HandleInterrupt_28(ref IRQContext aContext) {
IRQ(0x28, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
///
@@ -388,7 +383,7 @@ public static void HandleInterrupt_28(ref IRQContext aContext) {
/// IRQ context.
public static void HandleInterrupt_29(ref IRQContext aContext) {
IRQ(0x29, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
///
@@ -397,7 +392,7 @@ public static void HandleInterrupt_29(ref IRQContext aContext) {
/// IRQ context.
public static void HandleInterrupt_2A(ref IRQContext aContext) {
IRQ(0x2A, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
///
@@ -406,19 +401,26 @@ public static void HandleInterrupt_2A(ref IRQContext aContext) {
/// IRQ context.
public static void HandleInterrupt_2B(ref IRQContext aContext) {
IRQ(0x2B, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
+ ///
+ /// IRQ 12 - PS/2 Mouse. Reserved for the system.
+ ///
+ /// IRQ context.
public static void HandleInterrupt_2C(ref IRQContext aContext) {
IRQ(0x2C, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
-
+ ///
+ /// IRQ 13 - (Added for PIT Timer).
+ ///
+ /// IRQ context.
public static void HandleInterrupt_2D(ref IRQContext aContext) {
IRQ(0x2D, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
///
@@ -427,7 +429,7 @@ public static void HandleInterrupt_2D(ref IRQContext aContext) {
/// IRQ context.
public static void HandleInterrupt_2E(ref IRQContext aContext) {
IRQ(0x2E, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
///
@@ -436,7 +438,7 @@ public static void HandleInterrupt_2E(ref IRQContext aContext) {
/// IRQ context.
public static void HandleInterrupt_2F(ref IRQContext aContext) {
IRQ(0x2F, ref aContext);
- Global.PIC.EoiSlave();
+ LocalAPIC.EndOfInterrupt();
}
public static event IRQDelegate Interrupt30;
diff --git a/source/Cosmos.Core/IOAPIC.cs b/source/Cosmos.Core/IOAPIC.cs
new file mode 100644
index 0000000000..54eeddcd8d
--- /dev/null
+++ b/source/Cosmos.Core/IOAPIC.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Cosmos.Core.MemoryGroup;
+
+namespace Cosmos.Core
+{
+ ///
+ /// Local APIC class.
+ ///
+ public unsafe partial class IOAPIC
+ {
+ public const byte IOREGSEL = 0x00;
+ public const byte IOWIN = 0x10;
+
+ //IO APIC Registers
+ public const byte IOAPICID = 0x00;
+ public const byte IOAPICVER = 0x01;
+ public const byte IOAPICARB = 0x02;
+ public const byte IOREDTBL = 0x10;
+
+ ///
+ /// IO APIC Base Address.
+ ///
+ private static uint Address = 0;
+
+ ///
+ /// Initialize local APIC.
+ ///
+ public static void Initialize()
+ {
+ if (ACPI.IOAPIC == null)
+ {
+ //TODO: Fix ACPI tables on Bochs
+ //No APIC detected, hardcode APIC address
+ Address = 0xFEC00000;
+ }
+ else
+ {
+ Address = ACPI.IOAPIC->IOApicAddress;
+ }
+
+ Global.debugger.Send("IO APIC address:0x" + Address.ToString("X"));
+
+ uint x = In(IOAPICVER);
+ uint count = ((x >> 16) & 0xFF) + 1;
+
+ Global.debugger.Send("IO APIC pins:" + count);
+
+ //Disable All Entries, Make all interrupts edge triggered and not routed to any CPUs
+ for (uint i = 0; i < count; ++i)
+ {
+ SetEntry((byte)i, (1 << 16) | 0x20 + i);
+ }
+
+ Global.debugger.Send("IO APIC " + GetId() + " Initialized");
+ }
+
+ ///
+ /// IO APIC MMIO Out.
+ ///
+ /// IO APIC Register.
+ /// Data.
+ public static void Out(byte reg, uint val)
+ {
+ MMIOBase.Write32(Address + IOREGSEL, reg);
+ MMIOBase.Write32(Address + IOWIN, val);
+ }
+
+ ///
+ /// IO APIC MMIO In.
+ ///
+ /// IO APIC Register.
+ public static uint In(byte reg)
+ {
+ MMIOBase.Write32(Address + IOREGSEL, reg);
+ return MMIOBase.Read32(Address + IOWIN);
+ }
+
+ ///
+ /// Set IO APIC Entry.
+ ///
+ /// Irq ID.
+ public static void SetEntry(uint irq)
+ {
+ SetEntry((byte)ACPI.RemapIRQ(irq - 0x20), irq);
+ }
+
+ ///
+ /// Set IO APIC Entry.
+ ///
+ /// Irq ID.
+ public static void SetEntry(byte index, ulong data)
+ {
+ Out((byte)(IOREDTBL + index * 2), (uint)data);
+ Out((byte)(IOREDTBL + index * 2 + 1), (uint)(data >> 32));
+ }
+
+ ///
+ /// Get IO APIC ID.
+ ///
+ /// byte value.
+ public static byte GetId()
+ {
+ return (byte)((In(IOAPICID) >> 24) & 0xF0);
+ }
+ }
+}
diff --git a/source/Cosmos.Core/LocalAPIC.cs b/source/Cosmos.Core/LocalAPIC.cs
new file mode 100644
index 0000000000..25b1a3cbef
--- /dev/null
+++ b/source/Cosmos.Core/LocalAPIC.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Cosmos.Core.MemoryGroup;
+
+namespace Cosmos.Core
+{
+ ///
+ /// Local APIC class.
+ ///
+ public static unsafe class LocalAPIC
+ {
+ public const ushort LAPIC_ID = 0x0020;
+ public const ushort LAPIC_VER = 0x0030;
+ public const ushort LAPIC_TPR = 0x0080;
+ public const ushort LAPIC_APR = 0x0090;
+ public const ushort LAPIC_PPR = 0x00a0;
+ public const ushort LAPIC_EOI = 0x00b0;
+ public const ushort LAPIC_RRD = 0x00c0;
+ public const ushort LAPIC_LDR = 0x00d0;
+ public const ushort LAPIC_DFR = 0x00e0;
+ public const ushort LAPIC_SVR = 0x00f0;
+ public const ushort LAPIC_ISR = 0x0100;
+ public const ushort LAPIC_TMR = 0x0180;
+ public const ushort LAPIC_IRR = 0x0200;
+ public const ushort LAPIC_ESR = 0x0280;
+ public const ushort LAPIC_ICRLO = 0x0300;
+ public const ushort LAPIC_ICRHI = 0x0310;
+ public const ushort LAPIC_TIMER = 0x0320;
+ public const ushort LAPIC_THERMAL = 0x0330;
+ public const ushort LAPIC_PERF = 0x0340;
+ public const ushort LAPIC_LINT0 = 0x0350;
+ public const ushort LAPIC_LINT1 = 0x0360;
+ public const ushort LAPIC_ERROR = 0x0370;
+ public const ushort LAPIC_TICR = 0x0380;
+ public const ushort LAPIC_TCCR = 0x0390;
+ public const ushort LAPIC_TDCR = 0x03e0;
+
+ public const ushort ICR_FIXED = 0x00000000;
+ public const ushort ICR_LOWEST = 0x00000100;
+ public const ushort ICR_SMI = 0x00000200;
+ public const ushort ICR_NMI = 0x00000400;
+ public const ushort ICR_INIT = 0x00000500;
+ public const ushort ICR_STARTUP = 0x00000600;
+
+ public const ushort ICR_PHYSICAL = 0x00000000;
+ public const ushort ICR_LOGICAL = 0x00000800;
+
+ public const ushort ICR_IDLE = 0x00000000;
+ public const ushort ICR_SEND_PENDING = 0x00001000;
+
+ public const ushort ICR_DEASSERT = 0x00000000;
+ public const ushort ICR_ASSERT = 0x00004000;
+
+ public const ushort ICR_EDGE = 0x00000000;
+ public const ushort ICR_LEVEL = 0x00008000;
+
+ public const int ICR_NO_SHORTHAND = 0x00000000;
+ public const int ICR_SELF = 0x00040000;
+ public const int ICR_ALL_INCLUDING_SELF = 0x00080000;
+ public const int ICR_ALL_EXCLUDING_SELF = 0x000c0000;
+
+ public const int ICR_DESTINATION_SHIFT = 24;
+
+ ///
+ /// Local APIC Base Address.
+ ///
+ private static uint Address = 0;
+
+ ///
+ /// Initialize local APIC.
+ ///
+ public static void Initialize()
+ {
+ //Global.PIC.Disable();
+
+ //TODO: Fix ACPI tables on Bochs
+ if (ACPI.LocalApicCpus.Count == 0)
+ {
+ //No APIC detected, hardcode APIC address
+ Address = 0xFEE00000;
+ }
+ else
+ {
+ Address = ACPI.MADT->LocalAPICAddress;
+ }
+
+ Global.debugger.Send("Local APIC address:0x" + Address.ToString("X"));
+
+ //Enable All Interrupts
+ Out(LAPIC_TPR, 0);
+
+ // Logical Destination Mode
+ Out(LAPIC_DFR, 0xffffffff); // Flat mode
+ Out(LAPIC_LDR, 0x01000000); // All cpus use logical id 1
+
+ // Configure Spurious Interrupt Vector Register
+ Out(LAPIC_SVR, 0x100 | 0xFF);
+
+ // clear error status
+ Out(LAPIC_ESR, 0);
+ // clear unfinished interrupt
+ Out(LAPIC_EOI, 0);
+ // accept all level of interrupts
+ Out(LAPIC_TPR, 0);
+
+ Global.debugger.Send("Local APIC " + GetId() + " initialized");
+ }
+
+ ///
+ /// IO APIC MMIO Out.
+ ///
+ /// IO APIC Register.
+ /// Data.
+ public static void Out(uint reg, uint val)
+ {
+ MMIOBase.Write32(Address + reg, val);
+ }
+
+ ///
+ /// IO APIC MMIO In.
+ ///
+ /// IO APIC Register.
+ public static uint In(uint reg)
+ {
+ return MMIOBase.Read32(Address + reg);
+ }
+
+ ///
+ /// End of Interrupt.
+ ///
+ public static void EndOfInterrupt()
+ {
+ Out(LAPIC_EOI, 0);
+ }
+
+ ///
+ /// Get Local APIC ID.
+ ///
+ /// integer value.
+ public static uint GetId()
+ {
+ return In(LAPIC_ID) >> 24;
+ }
+ }
+}
diff --git a/source/Cosmos.Core/MMIO.cs b/source/Cosmos.Core/MMIO.cs
new file mode 100644
index 0000000000..ab6504a9ce
--- /dev/null
+++ b/source/Cosmos.Core/MMIO.cs
@@ -0,0 +1,149 @@
+using IL2CPU.API.Attribs;
+
+namespace Cosmos.Core
+{
+ ///
+ /// MMIOBase abstract class.
+ ///
+ public unsafe abstract class MMIOBase
+ {
+ ///
+ /// Address.
+ ///
+ protected readonly uint Address;
+
+ // all ctors are internal - Only Core ring can create it.. but hardware ring can use it.
+ ///
+ /// Create new instance of the class.
+ ///
+ /// An address.
+ protected MMIOBase(uint address)
+ {
+ Address = address;
+ }
+
+ ///
+ /// Create new instance of the class.
+ ///
+ /// A base address.
+ /// An offset from the base address.
+ protected MMIOBase(uint address, uint aOffset)
+ {
+ // C# math promotes things to integers, so we have this constructor
+ // to relieve the use from having to do so many casts
+ Address = address + aOffset;
+ }
+
+ ///
+ /// Write byte to adress.
+ ///
+ /// An address to write to.
+ /// A data.
+ public static void Write8(uint address, byte aData)
+ {
+ *(uint*)address = aData;
+ }
+
+ ///
+ /// Write Word to address.
+ ///
+ /// A address to write to.
+ /// A data.
+ public static void Write16(uint address, ushort aData)
+ {
+ *(uint*)address = aData;
+ }
+
+ ///
+ /// Write DWord to address.
+ ///
+ /// An address to write to.
+ /// A data.
+ public static void Write32(uint address, uint aData)
+ {
+ *(uint*)address = aData;
+ }
+
+ ///
+ /// Read byte from address.
+ ///
+ /// An address to read from.
+ /// byte value.
+ public static byte Read8(uint address)
+ {
+ return (byte)*(uint*)address;
+ }
+
+ ///
+ /// Read Word from address.
+ ///
+ /// An address to read from.
+ /// ushort value.
+ public static ushort Read16(uint address)
+ {
+ return (ushort)*(uint*)address;
+ }
+
+ ///
+ /// Read DWord from address.
+ ///
+ /// An address to read from.
+ /// uint value.
+ public static uint Read32(uint address)
+ {
+ return *(uint*)address;
+ }
+ }
+
+ ///
+ /// MMIO class. Used to read and write to address.
+ ///
+ public class MMIO : MMIOBase
+ {
+ ///
+ /// Create new instance of the class.
+ ///
+ /// An address.
+ public MMIO(uint address)
+ : base(address)
+ {
+ }
+
+ ///
+ /// Create new instance of the class.
+ ///
+ /// A base address.
+ /// Offset from the base address.
+ public MMIO(uint address, uint aOffset)
+ : base(address, aOffset)
+ {
+ }
+
+ ///
+ /// Get and set Byte value in address.
+ ///
+ public byte Byte
+ {
+ get => Read8(Address);
+ set => Write8(Address, value);
+ }
+
+ ///
+ /// Get and set Word value in address.
+ ///
+ public ushort Word
+ {
+ get => Read16(Address);
+ set => Write16(Address, value);
+ }
+
+ ///
+ /// Get and set DWord value in address.
+ ///
+ public uint DWord
+ {
+ get => Read32(Address);
+ set => Write32(Address, value);
+ }
+ }
+}
diff --git a/source/Cosmos.Core/MemoryBlock.cs b/source/Cosmos.Core/MemoryBlock.cs
index 2838bd404f..4a730caf6f 100644
--- a/source/Cosmos.Core/MemoryBlock.cs
+++ b/source/Cosmos.Core/MemoryBlock.cs
@@ -518,6 +518,33 @@ public unsafe byte this[uint aByteOffset]
(*(byte*)(Base + aByteOffset)) = value;
}
}
+
+ ///
+ /// Convert part for the memory block to array.
+ ///
+ /// A starting position of the data at the source memory block.
+ /// A index to be the staring index at the destination array.
+ /// Number of bytes to get.
+ /// uint array.
+ public unsafe byte[] ToArray(int aStart, int aIndex, int aCount)
+ {
+ byte* xDest = (byte*)(Base + aStart);
+ byte[] array = new byte[aCount];
+ fixed (byte* aArrayPtr = array)
+ {
+ MemoryOperations.Copy(aArrayPtr + aIndex, xDest, aCount);
+ }
+ return array;
+ }
+
+ ///
+ /// Convert the memory block to array.
+ ///
+ /// uint array.
+ public byte[] ToArray()
+ {
+ return ToArray(0, 0, (int)Size);
+ }
}
///
diff --git a/source/Cosmos.Core/PIC.cs b/source/Cosmos.Core/PIC.cs
index 41821e94c7..3a6d03f022 100644
--- a/source/Cosmos.Core/PIC.cs
+++ b/source/Cosmos.Core/PIC.cs
@@ -178,4 +178,4 @@ protected void Init(IOGroup.PIC aPIC, byte aBase, byte aIDunno, byte aMask)
IOPort.Wait();
}
}
-}
+}
\ No newline at end of file
diff --git a/source/Cosmos.HAL2/APICTimer.cs b/source/Cosmos.HAL2/APICTimer.cs
new file mode 100644
index 0000000000..2945d5a57b
--- /dev/null
+++ b/source/Cosmos.HAL2/APICTimer.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Cosmos.Core;
+using Cosmos.Core.MemoryGroup;
+
+namespace Cosmos.HAL
+{
+ ///
+ /// Local APIC Timer class.
+ ///
+ public static class APICTimer
+ {
+ ///
+ /// Tick Counter.
+ ///
+ public static uint Tick = 0;
+
+ ///
+ /// Tick Frequency.
+ ///
+ public static uint TickFrequency = 0;
+
+ ///
+ /// Initialize local APIC timer.
+ ///
+ public static void Initialize()
+ {
+ INTs.SetIntHandler(0x21, HandleApicTimer);
+
+ // setup timer, Intel IA manual 10-16 Vol. 3A
+ LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0xB); // divide timer counts by 1
+
+ Calibrate();
+
+ if (TickFrequency == 0)
+ {
+ throw new Exception("APIC timer is not calibrated");
+ }
+
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x20000 | 0x21); // periodic, bind to corresponding IRQ
+ LocalAPIC.Out(LocalAPIC.LAPIC_TDCR, 0xB);
+
+ Global.debugger.Send("Local APIC Timer Initialized");
+ }
+
+ public static void HandleApicTimer(ref INTs.IRQContext aContext)
+ {
+ Global.debugger.Send("APIC Timer IRQ");
+ //Tick++;
+ }
+
+ public static void Start()
+ {
+ SetTimerCount(TickFrequency / 100);
+ }
+
+ ///
+ /// Stop local APIC timer.
+ ///
+ public static void Stop()
+ {
+ LocalAPIC.Out(LocalAPIC.LAPIC_TIMER, 0x10000);
+ }
+
+ public static void SetTimerCount(uint count)
+ {
+ LocalAPIC.Out(LocalAPIC.LAPIC_TICR, count);
+ }
+
+ public static void Calibrate()
+ {
+ Global.debugger.Send("Calibrating APIC timer...");
+
+ SetTimerCount(0xFFFFFFFF); // Set APIC init counter to -1
+
+ Global.PIT.Wait(1000); // PIT sleep for 1000ms (10000µs)
+
+ Stop();
+
+ ulong ticks = 0xFFFFFFFF - LocalAPIC.In(LocalAPIC.LAPIC_TCCR); // Now we know how often the APIC timer has ticked in 10ms
+
+ Global.debugger.Send("APIC timer ticks per 10ms: " + ticks);
+
+ TickFrequency = (uint)(ticks * 1000 / 1000);
+
+ Global.debugger.Send("APIC timer tick frequency: " + TickFrequency);
+ }
+ }
+}
diff --git a/source/Cosmos.HAL2/Drivers/Network/AMDPCNetII.cs b/source/Cosmos.HAL2/Drivers/Network/AMDPCNetII.cs
index caaf1c4b6a..0102068b78 100644
--- a/source/Cosmos.HAL2/Drivers/Network/AMDPCNetII.cs
+++ b/source/Cosmos.HAL2/Drivers/Network/AMDPCNetII.cs
@@ -149,7 +149,6 @@ protected void HandleNetworkInterrupt(ref INTs.IRQContext aContext)
}
StatusRegister = cur_status;
- Core.Global.PIC.EoiSlave();
}
///
diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs
index c088298b5b..098b55b960 100644
--- a/source/Cosmos.HAL2/Global.cs
+++ b/source/Cosmos.HAL2/Global.cs
@@ -12,13 +12,13 @@ public static class Global
{
public static readonly Debugger debugger = new("Global");
- public static PIT PIT = new();
+ public static PIT PIT;
// Must be static init, other static inits rely on it not being null
public static TextScreenBase TextScreen = new TextScreen();
public static PCI Pci;
- public static readonly PS2Controller PS2Controller = new();
+ public static PS2Controller PS2Controller;
// TODO: continue adding exceptions to the list, as HAL and Core would be documented.
///
@@ -33,9 +33,27 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In
TextScreen = textScreen;
}
+ Console.Clear();
+
debugger.Send("Before Core.Global.Init");
Core.Global.Init();
+ Console.WriteLine("Starting ACPI");
+ debugger.Send("ACPI Init");
+ ACPI.Start();
+
+ Console.WriteLine("Starting APIC");
+ debugger.Send("Local APIC Init");
+ LocalAPIC.Initialize();
+ debugger.Send("IO APIC Init");
+ IOAPIC.Initialize();
+
+ Console.WriteLine("Starting PIT");
+ PIT = new PIT();
+
+ debugger.Send("Local APIC Timer Init");
+ APICTimer.Initialize();
+
//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.
@@ -50,16 +68,13 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In
debugger.Send("PCI Devices");
PCI.Setup();
- Console.WriteLine("Starting ACPI");
- debugger.Send("ACPI Init");
- ACPI.Start();
-
// http://wiki.osdev.org/%228042%22_PS/2_Controller#Initialising_the_PS.2F2_Controller
// TODO: USB should be initialized before the PS/2 controller
// TODO: ACPI should be used to check if a PS/2 controller exists
debugger.Send("PS/2 Controller Init");
if (InitPS2)
{
+ PS2Controller = new PS2Controller();
PS2Controller.Initialize(InitScrollWheel);
}
else
diff --git a/source/Cosmos.HAL2/PCIDevice.cs b/source/Cosmos.HAL2/PCIDevice.cs
index c02cabf3eb..2f0e56a4cd 100644
--- a/source/Cosmos.HAL2/PCIDevice.cs
+++ b/source/Cosmos.HAL2/PCIDevice.cs
@@ -107,6 +107,10 @@ public enum Config : byte
///
public bool Claimed { get; set; }
+ public bool SupportMsi = false;
+
+ public byte MsiOffset = 0;
+
public PCIDevice(uint bus, uint slot, uint function)
{
this.bus = bus;
@@ -132,6 +136,8 @@ public PCIDevice(uint bus, uint slot, uint function)
InterruptPIN = (PCIInterruptPIN)ReadRegister8((byte)Config.InterruptPIN);
InterruptLine = ReadRegister8((byte)Config.InterruptLine);
+ CheckMSI();
+
if ((uint)VendorID == 0xFF && (uint)DeviceID == 0xFFFF)
{
DeviceExists = false;
@@ -149,7 +155,7 @@ public PCIDevice(uint bus, uint slot, uint function)
BaseAddressBar[3] = new PCIBaseAddressBar(ReadRegister32(0x1C));
BaseAddressBar[4] = new PCIBaseAddressBar(ReadRegister32(0x20));
BaseAddressBar[5] = new PCIBaseAddressBar(ReadRegister32(0x24));
- }
+ }
}
public void EnableDevice()
@@ -185,6 +191,49 @@ public static ushort GetVendorID(ushort Bus, ushort Slot, ushort Function)
return (ushort)(IOPort.Read32(ConfigDataPort) >> (0x0 % 4 * 8) & 0xFFFF);
}
+ ///
+ /// Check if PCI Device supports MSI
+ ///
+ /// Boolean value.
+ private bool CheckMSI()
+ {
+ byte offset = ReadRegister8((byte)Config.CapabilityPointer);
+
+ while (offset > 0)
+ {
+ byte id = ReadRegister8(offset);
+
+ switch (id)
+ {
+ case 0x05:
+ SupportMsi = true;
+ MsiOffset = offset;
+ return true;
+ }
+ offset = ReadRegister8((byte)(offset + 1));
+ }
+
+ return false;
+ }
+
+ ///
+ /// Configure PCI Device to use MSI for interrupts.
+ ///
+ public void SetMSI(byte vector)
+ {
+ if (!SupportMsi)
+ {
+ return;
+ }
+
+ /*
+ ushort msgControl = ReadRegister16((byte)(MsiOffset + 2));
+ WriteRegister32((byte)(MsiOffset + 0x04), (uint)((0x0FEE << 20) | (0 << 12))); //use only APIC 0 since we don't support multiprocessing yet!
+ WriteRegister32((byte)(MsiOffset + (((msgControl << 7) & 1) == 1 ? 0x0C : 0x08)), vector);
+ WriteRegister16((byte)(MsiOffset + 2), (ushort)((msgControl | 1) & ~(0b111 << 4)));
+ */
+ }
+
#region IOReadWrite
///
/// Read register - 8-bit.
@@ -251,7 +300,7 @@ public void WriteRegister32(byte aRegister, uint value)
/// A slot.
/// A function.
/// UInt32 value.
- protected static uint GetAddressBase(uint aBus, uint aSlot, uint aFunction)
+ public static uint GetAddressBase(uint aBus, uint aSlot, uint aFunction)
{
return 0x80000000 | (aBus << 16) | ((aSlot & 0x1F) << 11) | ((aFunction & 0x07) << 8);
}