Skip to content

Instantly share code, notes, and snippets.

@SplittyDev
Last active April 27, 2018 06:28
Show Gist options
  • Save SplittyDev/8225226 to your computer and use it in GitHub Desktop.
Save SplittyDev/8225226 to your computer and use it in GitHub Desktop.
The ACPI driver
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using IO = SplitsysOS_Source.Core.PortIO;
namespace SplitsysOS_Source.Drivers
{
public unsafe class ACPI : IDriver
{
public string Name
{
get { return "ACPI"; }
}
public string Description
{
get { return "Advanced Configuration and Power Interface Driver"; }
}
public string Author
{
get { return "Splitty"; }
}
public void Init ()
{
DriverPool.RegisteredDriver drv = DriverPool.Register (this);
drv.RegisterFunction ("Enable", this.Enable);
drv.RegisterFunction ("Disable", this.Disable);
DriverPool.Register (drv);
_Init ();
}
public void Load ()
{
Enable ();
Console.WriteLine ("ACPI Enabled");
}
public void Unload ()
{
Disable ();
Console.WriteLine ("ACPI Disabled");
}
internal int* SMI_CMD;
internal byte ACPI_ENABLE;
internal byte ACPI_DISABLE;
internal int* PM1a_CNT;
internal int* PM1b_CNT;
internal short SLP_TYPa;
internal short SLP_TYPb;
internal short SLP_EN;
internal short SCI_EN;
internal byte PM1_CNT_LEN;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct RSDPtr
{
internal fixed byte Signature[8];
internal byte CheckSum;
internal fixed byte OemID[6];
internal byte Revision;
internal int RsdtAddress;
}
[StructLayout (LayoutKind.Sequential, Pack = 1)]
internal struct FACP
{
internal fixed byte Signature[4];
internal int Length;
internal fixed byte unneded1[40 - 8];
internal int* DSDT;
internal fixed byte unneded2[48 - 44];
internal int* SMI_CMD;
internal byte ACPI_ENABLE;
internal byte ACPI_DISABLE;
internal fixed byte unneded3[64 - 54];
internal int* PM1a_CNT_BLK;
internal int* PM1b_CNT_BLK;
internal fixed byte unneded4[89 - 72];
internal byte PM1_CNT_LEN;
}
internal byte* Facp = null;
internal ushort smiIO;
internal ushort pm1aIO;
internal ushort pm1bIO;
internal bool _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;
if (ptr != null && acpiCheckHeader ((byte*)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 += (*((byte*)ptr + i));
addr = (i == 0) ? addr : addr << 8;
}
yeuse = (byte*)addr;
Facp = (byte*)yeuse;
if (Compare ("FACP", Facp) == 0)
{
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_", (byte*)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 = (ushort)SMI_CMD;
pm1aIO = (ushort)PM1a_CNT;
pm1bIO = (ushort)PM1b_CNT;
return true;
}
}
}
}
ptr += 4;
}
}
return false;
}
internal void Enable ()
{
if (IO.inw (pm1aIO) == 0)
{
if (SMI_CMD != null && ACPI_ENABLE != 0)
{
IO.outb (smiIO, ACPI_ENABLE);
int i;
for (i = 0; i < 300; i++)
{
if ((IO.inb (pm1aIO) & 1) == 1)
break;
}
if (PM1b_CNT != null)
for (; i < 300; i++)
{
if ((IO.inw (pm1bIO) & 1) == 1)
break;
}
//if (i < 300) return true;
//else return false;
}
//else return false;
}
//else return true;
}
internal void Disable () { IO.outb (smiIO, ACPI_DISABLE); }
/// <summary>
/// Shutdown the OS.
/// </summary>
public void Shutdown ()
{
System.Console.Clear ();
if (PM1a_CNT == null) Init ();
if ((int?)pm1aIO != null)
{
IO.outw (pm1aIO, (ushort)(SLP_TYPa | SLP_EN));
if (PM1b_CNT != null)
IO.outw (pm1bIO, (ushort)(SLP_TYPb | SLP_EN));
}
Console.Write ("It's now safe to turn off the computer.");
}
/// <summary>
/// Reboot the OS.
/// </summary>
public void Reboot ()
{
byte good = 0x02;
while ((good & 0x02) != 0)
good = IO.inb (0x64);
IO.outb (0x64, 0xFE);
// ToDo: Halt CPU
}
// ACPI Functions
internal int Compare (string c1, byte* c2)
{
for (int i = 0; i < c1.Length; i++)
{
if (c1[i] != (char)c2[i]) { return -1; }
}
return 0;
}
internal int acpiCheckHeader (byte* ptr, string sig)
{
return Compare (sig, ptr);
}
internal 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; }
}
internal 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;
}
internal 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;
}
internal 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;
}
internal bool Check_RSD (uint address)
{
byte sum = 0;
byte* check = (byte*)address;
for (int i = 0; i < 20; i++)
sum += *(check++);
return (sum == 0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment