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); }