mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-31 13:21:05 +00:00
363 lines
No EOL
12 KiB
C#
363 lines
No EOL
12 KiB
C#
using Cosmos.Core.Common;
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Cosmos.HAL
|
|
{
|
|
public unsafe class ACPI
|
|
{
|
|
private static int* SMI_CMD;
|
|
private static byte ACPI_ENABLE;
|
|
private static byte ACPI_DISABLE;
|
|
private static int* PM1a_CNT;
|
|
private static int* PM1b_CNT;
|
|
private static short SLP_TYPa;
|
|
private static short SLP_TYPb;
|
|
private static short SLP_EN;
|
|
private static short SCI_EN;
|
|
private static byte PM1_CNT_LEN;
|
|
|
|
|
|
static int Compare(string c1, byte* c2)
|
|
{
|
|
|
|
for (int i = 0; i < c1.Length; i++)
|
|
{
|
|
if (c1[i] != (char)c2[i]) { return -1; }
|
|
}
|
|
return 0;
|
|
}
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
struct RSDPtr
|
|
{
|
|
public fixed byte Signature[8];
|
|
public byte CheckSum;
|
|
public fixed byte OemID[6];
|
|
public byte Revision;
|
|
public int RsdtAddress;
|
|
};
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
struct FACP
|
|
{
|
|
public fixed byte Signature[4];
|
|
public int Length;
|
|
|
|
public fixed byte unneded1[40 - 8];
|
|
public int* DSDT;
|
|
public fixed byte unneded2[48 - 44];
|
|
public int* SMI_CMD;
|
|
public byte ACPI_ENABLE;
|
|
public byte ACPI_DISABLE;
|
|
public fixed byte unneded3[64 - 54];
|
|
public int* PM1a_CNT_BLK;
|
|
public int* PM1b_CNT_BLK;
|
|
public fixed byte unneded4[89 - 72];
|
|
public byte PM1_CNT_LEN;
|
|
};
|
|
static byte* Facp = null;
|
|
static int* facpget(int number)
|
|
{
|
|
|
|
if (number == 0) { return (int*)*((int*)(Facp + 40)); }
|
|
else if (number == 1) { return (int*)*((int*)(Facp + 48)); }
|
|
else if (number == 2) { return (int*)*((int*)(Facp + 64)); }
|
|
else if (number == 3) { return (int*)*((int*)(Facp + 68)); }
|
|
else { return null; }
|
|
|
|
}
|
|
static byte facpbget(int number)
|
|
{
|
|
if (number == 0) { return *(Facp + 52); }
|
|
else if (number == 1) { return *(Facp + 53); }
|
|
else if (number == 2) { return *(Facp + 89); }
|
|
else return 0;
|
|
}
|
|
// check if the given address has a valid header
|
|
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)
|
|
{
|
|
// check checksum rsdpd
|
|
bptr = (byte*)ptr;
|
|
for (i = 0; i < 20; i++)
|
|
{
|
|
check += *bptr;
|
|
bptr++;
|
|
}
|
|
//Console.WriteLine("0x" + check.ToHex());
|
|
// found valid rsdpd
|
|
if (check == 0)
|
|
{
|
|
//string str = rsdp->RsdtAddress.ToHex();
|
|
//Console.WriteLine("seen"); Console.WriteLine(str);
|
|
Compare("RSDT", (byte*)rsdp->RsdtAddress);
|
|
if (rsdp->RsdtAddress != 0)
|
|
return (uint*)rsdp->RsdtAddress;
|
|
}
|
|
}
|
|
Console.WriteLine("Unable to find RSDT. ACPI not available");
|
|
return null;
|
|
}
|
|
|
|
static uint RSDPAddress()
|
|
{
|
|
|
|
// check bios
|
|
for (uint addr = 0xE0000; addr < 0x100000; addr += 4)
|
|
if (Compare("RSD PTR ", (byte*)addr) == 0)
|
|
if (Check_RSD(addr))
|
|
return addr;
|
|
// check extended bios
|
|
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;
|
|
|
|
// not found
|
|
return 0;
|
|
}
|
|
// checks for a given header and validates checksum
|
|
static int acpiCheckHeader(byte* ptr, string sig)
|
|
{
|
|
return Compare(sig, ptr);
|
|
}
|
|
|
|
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);
|
|
}
|
|
private static Core.Common.IOPort smiIO, pm1aIO, pm1bIO;
|
|
public static int Enable()
|
|
{
|
|
// check if acpi is enabled
|
|
|
|
if (pm1aIO.Word == 0)
|
|
{
|
|
// check if acpi can be enabled
|
|
if (SMI_CMD != null && ACPI_ENABLE != 0)
|
|
{
|
|
smiIO.Byte = ACPI_ENABLE;
|
|
//CPUBus.Write8((byte)SMI_CMD, ACPI_ENABLE); // send acpi enable command
|
|
// give 3 seconds time to enable acpi
|
|
int i;
|
|
for (i = 0; i < 300; i++)
|
|
{
|
|
if ((pm1aIO.Word & 1) == 1)
|
|
//if ((CPUBus.Read16((ushort)PM1a_CNT) & SCI_EN) == 1)
|
|
break;
|
|
|
|
}
|
|
if (PM1b_CNT != null)
|
|
for (; i < 300; i++)
|
|
{
|
|
//if ((CPUBus.Read16((ushort)PM1b_CNT) & SCI_EN) == 1)
|
|
if ((pm1bIO.Word & 1) == 1)
|
|
break;
|
|
}
|
|
if (i < 300)
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Couldn't enable ACPI.");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("No known way to enable ACPI.");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
public static void Disable()
|
|
{
|
|
smiIO.Byte = ACPI_DISABLE;
|
|
}
|
|
public static int Init()
|
|
{
|
|
byte* ptr = (byte*)RSDPAddress(); int addr = 0;
|
|
|
|
for (int i = 19; i >= 16; i--)
|
|
{
|
|
addr += (*((byte*)ptr + i));
|
|
addr = (i == 16) ? addr : addr << 8;
|
|
}
|
|
|
|
ptr = (byte*)addr;
|
|
ptr += 4; addr = 0;
|
|
for (int i = 3; i >= 0; i--)
|
|
{
|
|
addr += (*((byte*)ptr + i));
|
|
addr = (i == 0) ? addr : addr << 8;
|
|
}
|
|
int length = addr;
|
|
|
|
ptr -= 4;
|
|
// check if address is correct ( if acpi is available on this pc )
|
|
if (ptr != null && acpiCheckHeader((byte*)ptr, "RSDT") == 0)
|
|
{
|
|
addr = 0;
|
|
// the RSDT contains an unknown number of pointers to acpi tables
|
|
|
|
int entrys = length;
|
|
entrys = (entrys - 36) / 4;
|
|
ptr += 36; // skip header information
|
|
byte* yeuse;
|
|
|
|
while (0 < entrys--)
|
|
{
|
|
for (int i = 3; i >= 0; i--)
|
|
{
|
|
addr += (*((byte*)ptr + i));
|
|
addr = (i == 0) ? addr : addr << 8;
|
|
}
|
|
yeuse = (byte*)addr;
|
|
// check if the desired table is reached
|
|
Facp = (byte*)yeuse;
|
|
if (Compare("FACP", Facp) == 0)
|
|
{
|
|
if (acpiCheckHeader((byte*)facpget(0), "DSDT") == 0)
|
|
{
|
|
// search the \_S5 package in the DSDT
|
|
byte* S5Addr = (byte*)facpget(0) + 36; // skip header
|
|
int dsdtLength = *(facpget(0) + 1) - 36;
|
|
while (0 < dsdtLength--)
|
|
{
|
|
if (Compare("_S5_", (byte*)S5Addr) == 0)
|
|
break;
|
|
S5Addr++;
|
|
}
|
|
// check if \_S5 was found
|
|
if (dsdtLength > 0)
|
|
{
|
|
// check for valid AML structure
|
|
if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12)
|
|
{
|
|
S5Addr += 5;
|
|
S5Addr += ((*S5Addr & 0xC0) >> 6) + 2; // calculate PkgLength size
|
|
|
|
if (*S5Addr == 0x0A)
|
|
S5Addr++; // skip byteprefix
|
|
SLP_TYPa = (short)(*(S5Addr) << 10);
|
|
S5Addr++;
|
|
|
|
if (*S5Addr == 0x0A)
|
|
S5Addr++; // skip byteprefix
|
|
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 0;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("\\_S5 parse error.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("\\_S5 not present.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("DSDT invalid.\n");
|
|
}
|
|
}
|
|
ptr += 4;
|
|
}
|
|
Console.WriteLine("No valid FACP present.\n");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("No ACPI.\n");
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
public static void Reboot()
|
|
{
|
|
Core.Common.CPU.DisableInterrupts();
|
|
byte good = 0x02;
|
|
while ((good & 0x02) != 0)
|
|
good = Inb(0x64);
|
|
Outb(0x64, 0xFE);
|
|
|
|
Cosmos.Core.Global.CPU.Halt();
|
|
}
|
|
|
|
static Core.Common.IOPort io = new Core.Common.IOPort(0);
|
|
static int PP = 0, D = 0;
|
|
public static void Outb(ushort port, byte data)
|
|
{
|
|
if (io.Port != port)
|
|
io = new Core.Common.IOPort(port);
|
|
io.Byte = data;
|
|
PP = port;
|
|
D = data;
|
|
|
|
}
|
|
public static byte Inb(ushort port)
|
|
{
|
|
if (io.Port != port)
|
|
io = new Core.Common.IOPort(port);
|
|
return io.Byte;
|
|
|
|
}
|
|
|
|
public static void Shutdown()
|
|
{
|
|
// send the shutdown command
|
|
Console.Clear();
|
|
if (PM1a_CNT == null) Init();
|
|
if (pm1aIO != null)
|
|
{
|
|
pm1aIO.Word = (ushort)(SLP_TYPa | SLP_EN);
|
|
if (PM1b_CNT != null)
|
|
pm1bIO.Word = (ushort)(SLP_TYPb | SLP_EN);
|
|
|
|
}
|
|
// Console.WriteLine("It is now safe to turn off your computer");
|
|
}
|
|
}
|
|
} |