202 lines
5.6 KiB
C
202 lines
5.6 KiB
C
#include "arch/amd64/hw/acpi.h"
|
|
#include "arch/amd64/hw/apic.h"
|
|
#include "arch/amd64/hw/rtc.h"
|
|
#include "sys/char/ring.h"
|
|
#include "sys/char/line.h"
|
|
#include "sys/char/chr.h"
|
|
#include "sys/string.h"
|
|
#include "sys/debug.h"
|
|
#include "sys/panic.h"
|
|
#include "user/acpi.h"
|
|
#include "sys/dev.h"
|
|
#include "acpi.h"
|
|
|
|
static uintptr_t early_rsdp, early_rsdp_v2;
|
|
|
|
struct acpi_rsdp_ext *acpi_rsdp = NULL;
|
|
struct acpi_madt *acpi_madt = NULL;
|
|
struct acpi_fadt *acpi_fadt = NULL;
|
|
struct acpi_mcfg *acpi_mcfg = NULL;
|
|
|
|
static struct chrdev _acpi_event_dev = {
|
|
.dev_data = NULL,
|
|
.write = NULL,
|
|
.read = simple_line_read,
|
|
.ioctl = NULL
|
|
};
|
|
|
|
static uint8_t checksum(const void *ptr, size_t size) {
|
|
uint8_t v = 0;
|
|
for (size_t i = 0; i < size; ++i) {
|
|
v += ((const uint8_t *) ptr)[i];
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static uint32_t acpi_power_button_handler(void *ctx) {
|
|
ring_putc(NULL, &_acpi_event_dev.buffer, ACEV_POWER_BUTTON, 0);
|
|
return 0;
|
|
}
|
|
|
|
static ACPI_STATUS acpica_init(void) {
|
|
ACPI_STATUS ret;
|
|
ACPI_OBJECT arg1;
|
|
ACPI_OBJECT_LIST args;
|
|
|
|
/*
|
|
* 0 = PIC
|
|
* 1 = APIC
|
|
* 2 = SAPIC ?
|
|
*/
|
|
arg1.Type = ACPI_TYPE_INTEGER;
|
|
arg1.Integer.Value = 1;
|
|
args.Count = 1;
|
|
args.Pointer = &arg1;
|
|
|
|
if (ACPI_FAILURE(ret = AcpiInitializeSubsystem())) {
|
|
kerror("AcpiInitializeSubsystem: %s\n", AcpiFormatException(ret));
|
|
return ret;
|
|
}
|
|
|
|
if (ACPI_FAILURE(ret = AcpiInitializeTables(NULL, 0, FALSE))) {
|
|
kerror("AcpiInitializeTables: %s\n", AcpiFormatException(ret));
|
|
return ret;
|
|
}
|
|
|
|
if (ACPI_FAILURE(ret = AcpiLoadTables())) {
|
|
kerror("ACPI INIT failure %s\n", AcpiFormatException(ret));
|
|
return ret;
|
|
}
|
|
|
|
if (ACPI_FAILURE(ret = AcpiEvaluateObject(NULL, "\\_PIC", &args, NULL))) {
|
|
if (ret != AE_NOT_FOUND) {
|
|
kerror("ACPI INIT failure %s\n", AcpiFormatException(ret));
|
|
return ret;
|
|
}
|
|
kwarn("\\_PIC = AE_NOT_FOUND\n");
|
|
// Guess that's ok?
|
|
}
|
|
|
|
if (ACPI_FAILURE(ret = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION))) {
|
|
kerror("ACPI INIT failure %s\n", AcpiFormatException(ret));
|
|
return ret;
|
|
}
|
|
|
|
if (ACPI_FAILURE(ret = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION))) {
|
|
kerror("ACPI INIT failure %s\n", AcpiFormatException(ret));
|
|
return ret;
|
|
}
|
|
|
|
if (ACPI_FAILURE(ret = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
|
|
acpi_power_button_handler,
|
|
NULL))) {
|
|
kwarn("Failed to install ACPI power button handler: %s\n", AcpiFormatException(ret));
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
void amd64_acpi_set_rsdp(uintptr_t addr) {
|
|
early_rsdp = addr;
|
|
}
|
|
|
|
void amd64_acpi_set_rsdp2(uintptr_t addr) {
|
|
early_rsdp_v2 = addr;
|
|
}
|
|
|
|
static uintptr_t locate_rsdp(void) {
|
|
// TODO: support rsdpv2
|
|
if (early_rsdp) {
|
|
if (checksum((void *) early_rsdp, sizeof(struct acpi_rsdp)) != 0) {
|
|
kwarn("Provided RSDP has invalid checksum, falling back to scan method\n");
|
|
} else {
|
|
return early_rsdp;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0xFFFFFF0000000000 + 0x000E0000; i < 0xFFFFFF0000000000 + 0x000FFFFF - 8; ++i) {
|
|
if (!strncmp((const char *) i, "RSD PTR ", 8)) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void amd64_acpi_init(void) {
|
|
struct acpi_rsdt *rsdt;
|
|
acpi_madt = NULL;
|
|
|
|
acpi_rsdp = (struct acpi_rsdp_ext *) locate_rsdp();
|
|
|
|
if (!acpi_rsdp) {
|
|
panic("Failed to find RSDP\n");
|
|
}
|
|
|
|
kdebug("Found RSDP: %p\n", acpi_rsdp);
|
|
if (checksum(acpi_rsdp, sizeof(struct acpi_rsdp)) != 0) {
|
|
kdebug("RSDP is invalid\n");
|
|
while (1);
|
|
}
|
|
|
|
kdebug("RSDP revision %d\n", acpi_rsdp->rsdp.rev);
|
|
rsdt = (struct acpi_rsdt *) (0xFFFFFF0000000000 + acpi_rsdp->rsdp.rsdt_address);
|
|
kdebug("RSDT: %p\n", rsdt);
|
|
|
|
if (checksum(rsdt, rsdt->hdr.length) != 0) {
|
|
kdebug("RSDT is invalid\n");
|
|
while (1);
|
|
}
|
|
|
|
for (size_t i = 0; i < (rsdt->hdr.length - sizeof(struct acpi_header)) / sizeof(uint32_t); ++i) {
|
|
uintptr_t entry_addr = 0xFFFFFF0000000000 + rsdt->entry[i];
|
|
struct acpi_header *hdr = (struct acpi_header *) entry_addr;
|
|
|
|
if (!strncmp((const char *) hdr, "APIC", 4)) {
|
|
kdebug("Found MADT = %p\n", entry_addr);
|
|
if (checksum(hdr, hdr->length) != 0) {
|
|
kdebug("Entry is invalid\n");
|
|
while (1);
|
|
}
|
|
|
|
acpi_madt = (struct acpi_madt *) hdr;
|
|
} else if (!strncmp((const char *) hdr, "FACP", 4)) {
|
|
kdebug("Found FADT = %p\n", entry_addr);
|
|
if (checksum(hdr, hdr->length) != 0) {
|
|
kdebug("Entry is invalid\n");
|
|
while (1);
|
|
}
|
|
|
|
acpi_fadt = (struct acpi_fadt *) hdr;
|
|
} else if (!strncmp((const char *) hdr, "HPET", 4)) {
|
|
kdebug("Found HPET = %p\n", entry_addr);
|
|
if (checksum(hdr, hdr->length) != 0) {
|
|
kdebug("Entry is invalid\n");
|
|
while (1);
|
|
}
|
|
} else if (!strncmp((const char *) hdr, "MCFG", 4)) {
|
|
kdebug("Found MCFG = %p\n", entry_addr);
|
|
if (checksum(hdr, hdr->length) != 0) {
|
|
panic("Entry is invalid\n");
|
|
}
|
|
|
|
acpi_mcfg = (struct acpi_mcfg *) hdr;
|
|
}
|
|
}
|
|
|
|
if (acpi_fadt) {
|
|
rtc_set_century(acpi_fadt->century);
|
|
}
|
|
|
|
if (!acpi_madt) {
|
|
panic("ACPI: No MADT present\n");
|
|
}
|
|
|
|
if (ACPI_FAILURE(acpica_init())) {
|
|
panic("Failed to initialize ACPICA\n");
|
|
}
|
|
|
|
ring_init(&_acpi_event_dev.buffer, 16);
|
|
dev_add(DEV_CLASS_CHAR, 0, &_acpi_event_dev, "acpi");
|
|
}
|