103 lines
2.0 KiB
C
103 lines
2.0 KiB
C
#include <arch/acpi.h>
|
|
#include <socks/vm.h>
|
|
#include <socks/printk.h>
|
|
#include <stddef.h>
|
|
|
|
static struct acpi_rsdp rsdp;
|
|
|
|
static struct acpi_rsdp_10 *search_for_rsdp(void)
|
|
{
|
|
uint64_t *start = vm_phys_to_virt(0x80000);
|
|
uint64_t *end = vm_phys_to_virt(0xFFFFF);
|
|
|
|
for (uint64_t *i = start; i < end; i++) {
|
|
if (*i == ACPI_SIG_RSDP) {
|
|
return (struct acpi_rsdp_10 *)i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int init_rsdt(void)
|
|
{
|
|
struct acpi_rsdp_10 *x = search_for_rsdp();
|
|
|
|
if (!x) {
|
|
printk("acpi: not available");
|
|
return -1;
|
|
}
|
|
|
|
uint8_t *b = (uint8_t *)x;
|
|
size_t chksum = 0;
|
|
for (unsigned int i = 0; i < sizeof *x; i++) {
|
|
chksum += b[i];
|
|
}
|
|
|
|
if (chksum & 0xFF) {
|
|
printk("acpi: not available");
|
|
return -1;
|
|
}
|
|
|
|
if (x->r_revision == 2) {
|
|
chksum = 0;
|
|
|
|
for (unsigned int i = sizeof *x; i < sizeof(struct acpi_rsdp_20); i++) {
|
|
chksum += b[i];
|
|
}
|
|
|
|
if (chksum & 0xFF) {
|
|
printk("acpi: not available");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
memcpy(&rsdp.rsdp_20, x, sizeof rsdp.rsdp_20);
|
|
return 0;
|
|
}
|
|
|
|
static struct acpi_sdt *find_via_rsdt(uint32_t sig)
|
|
{
|
|
struct acpi_rsdt *rsdt = vm_phys_to_virt(rsdp.rsdp_10.r_rsdt_ptr);
|
|
unsigned long nr_tables = (rsdt->r_header.s_length - sizeof(struct acpi_sdt)) / sizeof(uint32_t);
|
|
|
|
for (unsigned long i = 0; i < nr_tables; i++) {
|
|
struct acpi_sdt *table = vm_phys_to_virt(rsdt->r_tables[i]);
|
|
if (*(uint32_t *)table == sig) {
|
|
return table;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct acpi_sdt *find_via_xsdt(uint32_t sig)
|
|
{
|
|
struct acpi_xsdt *xsdt = vm_phys_to_virt(rsdp.rsdp_20.r_xsdt_ptr);
|
|
unsigned long nr_tables = (xsdt->x_header.s_length - sizeof(struct acpi_sdt)) / sizeof(uint64_t);
|
|
|
|
for (unsigned long i = 0; i < nr_tables; i++) {
|
|
struct acpi_sdt *table = vm_phys_to_virt(xsdt->x_tables[i]);
|
|
if (*(uint32_t *)table == sig) {
|
|
return table;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct acpi_sdt *acpi_find_sdt(uint32_t sig)
|
|
{
|
|
if (!rsdp.rsdp_10.r_sig[0]) {
|
|
if (init_rsdt() != 0) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (rsdp.rsdp_10.r_revision == 0) {
|
|
return find_via_rsdt(sig);
|
|
} else {
|
|
return find_via_xsdt(sig);
|
|
}
|
|
}
|