BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / master / kernel / acpi / acpi.c

// Related

Nucleus

Barry System headers (remove libc dependency) 18495cf (3 years, 2 months ago)
/*
 * This file controls ACPI.  It finds the ACPI Root System Descriptor Table then
 * searches it for more tables, which can be initialised separately.
 */

#include <stdint.h>
#include <nucleus/kernel.h>
#include <nucleus/lib.h>
#include <nucleus/memory.h>
#include "acpi.h"

/* Root System Descriptor Pointer */
struct RSDPDesc {
	char signature[8];
	uint8_t checksum;
	char oem[6];
	uint8_t revision;
	uint32_t rsdt;
} __attribute__((packed));

void init_apic(struct SDTHeader *);
void init_fadt(struct SDTHeader *);
void init_dsdt(struct SDTHeader *);

/* Table handlers */
struct TableHandler {
	char *sig;
	void (*handler)(struct SDTHeader *);
} handlers[] = {
	{ "APIC", init_apic },
	{ "FACP", init_fadt },
	{ "DSDT", init_dsdt },
};

/* Match a signature to a handler */
void
init_table(struct SDTHeader *table)
{
	uint32_t i, check = 0;
	char *byte = (void *) table;

	set_page((uintptr_t) table, PAGE_ADDR((uintptr_t) table) |
	         PTE_PRESENT | PTE_WRITE);
	flush_tlb((uintptr_t) table);

	/* Checksum */
	for (i = 0; i < table->length; i++)
		check += byte[i];
	if (check % 0x100)
		return;

	/* Match handler */
	for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) {
		if (memcmp(table->signature, handlers[i].sig, 4))
			continue;
		handlers[i].handler(table);
	}
}

/* Initialise ACPI */
void
init_acpi(void *ebda)
{
	/* Search for Root System Descriptor Table */
	char *sig;
	for (sig = ebda; sig < (char *) 0x100000; sig++) {
		if (!memcmp(sig, "RSD PTR ", 8))
			break;
	}
	if (sig == (char *) 0x100000)
		return;

	/* RSDT checksum */
	uint32_t i, check = 0;
	for (i = 0; i < sizeof(struct RSDPDesc); i++)
		check += sig[i];
	if (check % 0x100)
		return;

	/* Iterate tables */
	uint32_t j;
	struct SDTHeader *rsdt = (void *) ((struct RSDPDesc *) sig)->rsdt;
	struct SDTHeader **table = (void *) (rsdt + 1);
	set_page((uintptr_t) rsdt, PAGE_ADDR((uintptr_t) rsdt) |
	         PTE_PRESENT | PTE_WRITE);
	flush_tlb((uintptr_t) rsdt);
	for (i = 0; i < (rsdt->length - sizeof(struct SDTHeader)) / 4; i++)
		init_table(table[i]);
}