using Cosmos.Core; using Cosmos.Debug.Kernel; using System; using System.Runtime.InteropServices; namespace Cosmos.Core { /// /// 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 mDebugger = new Debugger("System", "Global"); /// /// RSD table struct. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] 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 /// /// IO port. /// private static IOPort smiIO, pm1aIO, pm1bIO; // ACPI variables /// /// SMI CMD. /// private static int* SMI_CMD; /// /// ACPI ENABLE. /// private static byte ACPI_ENABLE; /// /// ACPI DISABLE. /// private static byte ACPI_DISABLE; /// /// PM1a CNT /// private static int* PM1a_CNT; /// /// PM1b CNT /// private static int* PM1b_CNT; /// /// SLP TYPa /// private static short SLP_TYPa; /// /// SLP TYPb /// private static short SLP_TYPb; /// /// SLP EN. /// private static short SLP_EN; /// /// SCI EN. /// private static short SCI_EN; /// /// PM1 CNT LEN1 /// private static byte PM1_CNT_LEN; /// /// Check ACPI header. /// /// /// /// 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. /// /// String. /// Pointer to the head of the byte array. /// 0 - identical, -1 different. static int Compare(string c1, byte* c2) { for (int i = 0; i < c1.Length; i++) { if (c1[i] != c2[i]) { return -1; } } return 0; } /// /// Check RSD checksum. /// /// Address to check. /// True if RSDT table checksum is good. static bool Check_RSD(uint address) { byte sum = 0; byte* check = (byte*)address; for (int i = 0; i < 20; i++) sum += *(check++); return (sum == 0); } /// /// Start the ACPI. /// /// Initialize the ACPI. (default = true) /// Enable the ACPI. (default = true) public static void Start(bool initialize = true, bool enable = true) { if (initialize) Init(); if (enable) Enable(); } /// /// Shutdown the ACPI. /// /// Thrown on IO error. public static void Shutdown() { Console.Clear(); if (PM1a_CNT == null) Init(); pm1aIO.Word = (ushort)(SLP_TYPa | SLP_EN); if (PM1b_CNT != null) pm1bIO.Word = (ushort)(SLP_TYPb | SLP_EN); Global.CPU.Halt(); } /// /// Reboot ACPI. /// Not implemented. /// /// Thrown always. public static void Reboot() { throw new NotImplementedException("ACPI Reset not implemented yet."); //TODO } /// /// Initialize the ACPI. /// /// true on success, false on failure. private static bool Init() { byte* ptr = (byte*)RSDPAddress(); int addr = 0; for (int i = 19; i >= 16; i--) { addr += (*(ptr + i)); addr = (i == 16) ? addr : addr << 8; } ptr = (byte*)addr; ptr += 4; addr = 0; for (int i = 3; i >= 0; i--) { addr += (*(ptr + i)); addr = (i == 0) ? addr : addr << 8; } int length = addr; ptr -= 4; if (ptr != null && acpiCheckHeader(ptr, "RSDT") == 0) { addr = 0; int entrys = length; entrys = (entrys - 36) / 4; ptr += 36; byte* yeuse; while (0 < entrys--) { for (int i = 3; i >= 0; i--) { addr += (*(ptr + i)); addr = (i == 0) ? addr : addr << 8; } yeuse = (byte*)addr; Facp = yeuse; if (acpiCheckHeader((byte*)facpget(0), "DSDT") == 0) { byte* S5Addr = (byte*)facpget(0) + 36; int dsdtLength = *(facpget(0) + 1) - 36; while (0 < dsdtLength--) { if (Compare("_S5_", S5Addr) == 0) break; S5Addr++; } if (dsdtLength > 0) { 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; SCI_EN = 1; smiIO = new IOPort((ushort)SMI_CMD); pm1aIO = new IOPort((ushort)PM1a_CNT); pm1bIO = new IOPort((ushort)PM1b_CNT); return true; } } } ptr += 4; } } return false; } /// /// Enable ACPI. /// public static void Enable() { smiIO = new IOPort(ACPI_ENABLE); } /// /// Disable ACPI. /// public static void Disable() { smiIO = new IOPort(ACPI_DISABLE); } /// /// Get the RSDP address. /// /// uint value. private static unsafe uint RSDPAddress() { for (uint addr = 0xE0000; addr < 0x100000; addr += 4) if (Compare("RSD PTR ", (byte*)addr) == 0) if (Check_RSD(addr)) return addr; uint ebda_address = *((uint*)0x040E); ebda_address = (ebda_address * 0x10) & 0x000fffff; for (uint addr = ebda_address; addr < ebda_address + 1024; addr += 4) if (Compare("RSD PTR ", (byte*)addr) == 0) return addr; return 0; } /// /// Check RSDT table /// /// A pointer to the RSDT /// RSDT table address private static uint* acpiCheckRSDPtr(uint* ptr) { string sig = "RSD PTR "; RSDPtr* rsdp = (RSDPtr*)ptr; byte* bptr; byte check = 0; int i; if (Compare(sig, (byte*)rsdp) == 0) { bptr = (byte*)ptr; for (i = 0; i < 20; i++) { check += *bptr; bptr++; } if (check == 0) { Compare("RSDT", (byte*)rsdp->RsdtAddress); if (rsdp->RsdtAddress != 0) return (uint*)rsdp->RsdtAddress; } } 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; } } /// /// 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; } } } }