mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-30 22:18:21 +00:00
Integrate uACPI & remove own ACPI parsing code
This commit adds uACPI as a submodule and removes all handwritten table parsing code as well as struct definitions, since they now work via uACPI. There's also now an ability to shut down by using the power button.
This commit is contained in:
@@ -1,86 +1,12 @@
|
||||
#include <arch/acpi.h>
|
||||
#include <limine.h>
|
||||
#include <logging.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/vmm.h>
|
||||
#include <kernel/pmm.h>
|
||||
#include <string.h>
|
||||
|
||||
static size_t headercount;
|
||||
static sdtheader_t **headers;
|
||||
#include <stdint.h>
|
||||
|
||||
static volatile struct limine_rsdp_request rsdpreq = {
|
||||
.id = LIMINE_RSDP_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
bool arch_acpi_checksumok(void *table) {
|
||||
sdtheader_t *header = table;
|
||||
uint8_t *ptr = table;
|
||||
uint8_t sum = 0;
|
||||
for (int i = 0; i < header->length; ++i)
|
||||
sum += *ptr++;
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
void *arch_acpi_findtable(char *sig, int n) {
|
||||
for (size_t i = 0; i < headercount; ++i) {
|
||||
if (headers[i] == NULL)
|
||||
continue;
|
||||
|
||||
if (strncmp(sig, headers[i]->sig, 4) == 0) {
|
||||
if (n-- == 0)
|
||||
return headers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *map_table(void *physical) {
|
||||
// TODO map according to header length entry
|
||||
uintmax_t pageoffset = (uintptr_t)physical % PAGE_SIZE;
|
||||
void *virt = vmm_map(NULL, PAGE_SIZE * 16, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_NOEXEC, physical);
|
||||
__assert(virt);
|
||||
return (void *)((uintptr_t)virt + pageoffset);
|
||||
}
|
||||
|
||||
void arch_acpi_init() {
|
||||
// FIXME search if no response
|
||||
__assert(rsdpreq.response);
|
||||
rsdp_t *rsdp = map_table(FROM_HHDM(rsdpreq.response->address));
|
||||
|
||||
if (rsdp->revision == 0) {
|
||||
printf("\e[93macpi: version 1.0 -- Using RSDT instead of XSDT.\e[0m\n");
|
||||
rsdt_t *rsdt = map_table((void *)(uint64_t)rsdp->rsdt);
|
||||
__assert(arch_acpi_checksumok(rsdt));
|
||||
|
||||
headercount = (rsdt->header.length - sizeof(sdtheader_t)) / sizeof(uint32_t);
|
||||
headers = alloc(sizeof(sdtheader_t *) * headercount);
|
||||
__assert(headers);
|
||||
|
||||
// TODO map according to the header length entry
|
||||
for (size_t i = 0; i < headercount; ++i) {
|
||||
// map it
|
||||
void *addr = map_table((void *)(uint64_t)rsdt->tables[i]);
|
||||
if (arch_acpi_checksumok(addr))
|
||||
headers[i] = addr;
|
||||
}
|
||||
} else {
|
||||
xsdt_t *xsdt = map_table((void *)rsdp->xsdt);
|
||||
__assert(arch_acpi_checksumok(xsdt));
|
||||
|
||||
headercount = (xsdt->header.length - sizeof(sdtheader_t)) / sizeof(uint64_t);
|
||||
headers = alloc(sizeof(sdtheader_t *) * headercount);
|
||||
__assert(headers);
|
||||
|
||||
for (size_t i = 0; i < headercount; ++i) {
|
||||
// map it
|
||||
void *addr = map_table((void *)xsdt->tables[i]);
|
||||
if (arch_acpi_checksumok(addr))
|
||||
headers[i] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
printf("ACPI: %lu tables found\n", headercount);
|
||||
uintptr_t arch_get_rsdp(void) {
|
||||
return (uintptr_t)FROM_HHDM(rsdpreq.response->address);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <arch/acpi.h>
|
||||
#include <logging.h>
|
||||
#include <kernel/vmm.h>
|
||||
#include <arch/mmu.h>
|
||||
@@ -9,6 +8,9 @@
|
||||
#include <kernel/timer.h>
|
||||
#include <kernel/timekeeper.h>
|
||||
|
||||
#include <uacpi/tables.h>
|
||||
#include <uacpi/acpi.h>
|
||||
|
||||
#define IOAPIC_REG_ID 0
|
||||
#define IOAPIC_REG_ENTRYCOUNT 1
|
||||
#define IOAPIC_REG_PRIORITY 2
|
||||
@@ -33,47 +35,6 @@
|
||||
#define LVT_DELIVERY_NMI (0b100 << 8)
|
||||
#define LVT_MASK (1 << 16)
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
} __attribute__((packed)) listheader_t;
|
||||
|
||||
typedef struct {
|
||||
listheader_t header;
|
||||
uint16_t reserved;
|
||||
uint64_t addr;
|
||||
} __attribute__((packed)) lapicoverride_t;
|
||||
|
||||
typedef struct {
|
||||
listheader_t header;
|
||||
uint8_t id;
|
||||
uint8_t reserved;
|
||||
uint32_t addr;
|
||||
uint32_t intbase;
|
||||
} __attribute__((packed)) ioentry_t;
|
||||
|
||||
typedef struct {
|
||||
listheader_t header;
|
||||
uint8_t acpiid;
|
||||
uint8_t lapicid;
|
||||
uint32_t flags;
|
||||
} __attribute__((packed)) lapicentry_t;
|
||||
|
||||
typedef struct {
|
||||
listheader_t header;
|
||||
uint8_t acpiid;
|
||||
uint16_t flags;
|
||||
uint8_t lint;
|
||||
} __attribute__((packed)) lapicnmientry_t;
|
||||
|
||||
typedef struct {
|
||||
listheader_t header;
|
||||
uint8_t bus;
|
||||
uint8_t irq;
|
||||
uint32_t gsi;
|
||||
uint16_t flags;
|
||||
} __attribute__((packed)) ioapicoverride_t;
|
||||
|
||||
typedef struct {
|
||||
void *addr;
|
||||
int base;
|
||||
@@ -82,9 +43,9 @@ typedef struct {
|
||||
|
||||
static ioapicdesc_t *ioapics;
|
||||
|
||||
static madt_t *madt;
|
||||
static listheader_t *liststart;
|
||||
static listheader_t *listend;
|
||||
static struct acpi_madt *madt;
|
||||
static struct acpi_entry_hdr *liststart;
|
||||
static struct acpi_entry_hdr *listend;
|
||||
static void *lapicaddr;
|
||||
|
||||
static size_t overridecount;
|
||||
@@ -100,13 +61,13 @@ static ioapicdesc_t *ioapicfromgsi(int gsi) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline listheader_t *getnext(listheader_t *header) {
|
||||
static inline struct acpi_entry_hdr *getnext(struct acpi_entry_hdr *header) {
|
||||
uintptr_t ptr = (uintptr_t)header;
|
||||
return (listheader_t *)(ptr + header->length);
|
||||
return (struct acpi_entry_hdr *)(ptr + header->length);
|
||||
}
|
||||
|
||||
static inline void *getentry(int type, int n) {
|
||||
listheader_t *entry = liststart;
|
||||
struct acpi_entry_hdr *entry = liststart;
|
||||
|
||||
while (entry < listend) {
|
||||
if (entry->type == type) {
|
||||
@@ -120,7 +81,7 @@ static inline void *getentry(int type, int n) {
|
||||
}
|
||||
|
||||
static int getcount(int type) {
|
||||
listheader_t *entry = liststart;
|
||||
struct acpi_entry_hdr *entry = liststart;
|
||||
int count = 0;
|
||||
|
||||
while (entry < listend) {
|
||||
@@ -171,8 +132,8 @@ void arch_ioapic_setirq(uint8_t irq, uint8_t vector, uint8_t proc, bool masked)
|
||||
uint8_t polarity = 1; // active high
|
||||
uint8_t trigger = 0; // edge triggered
|
||||
for (uintmax_t i = 0; i < overridecount; ++i) {
|
||||
ioapicoverride_t *override = getentry(ACPI_MADT_TYPE_OVERRIDE, i);
|
||||
if (override->irq != irq)
|
||||
struct acpi_madt_interrupt_source_override *override = getentry(ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE, i);
|
||||
if (override->source != irq)
|
||||
continue;
|
||||
|
||||
polarity = override->flags & 2 ? 1 : 0; // active low
|
||||
@@ -210,9 +171,9 @@ void arch_apic_initap() {
|
||||
// get the acpi id for the local nmi sources
|
||||
|
||||
for (size_t i = 0; i < lapiccount; ++i) {
|
||||
lapicentry_t *current = getentry(ACPI_MADT_TYPE_LAPIC, i);
|
||||
if (_cpu()->id == current->lapicid) {
|
||||
_cpu()->acpiid = current->acpiid;
|
||||
struct acpi_madt_lapic *current = getentry(ACPI_MADT_ENTRY_TYPE_LAPIC, i);
|
||||
if (_cpu()->id == current->id) {
|
||||
_cpu()->acpiid = current->uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -221,10 +182,10 @@ void arch_apic_initap() {
|
||||
|
||||
isr_t *nmiisr = interrupt_allocate(nmi, NULL, IPL_MAX); // MAX IPL because NMI
|
||||
__assert(nmiisr);
|
||||
|
||||
|
||||
for (size_t i = 0; i < lapicnmicount; ++i) {
|
||||
lapicnmientry_t* current = getentry(ACPI_MADT_TYPE_LANMI, i);
|
||||
if (current->acpiid == _cpu()->acpiid || current->acpiid == 0xff)
|
||||
struct acpi_madt_lapic_nmi* current = getentry(ACPI_MADT_ENTRY_TYPE_LAPIC_NMI, i);
|
||||
if (current->uid == _cpu()->acpiid || current->uid == 0xff)
|
||||
writelapic(APIC_LVT_LINT0 + 0x10 * current->lint, (nmiisr->id & 0xff) | LVT_DELIVERY_NMI | (current->flags << 12));
|
||||
}
|
||||
}
|
||||
@@ -288,22 +249,25 @@ void arch_apic_sendipi(uint8_t cpu, uint8_t vec, uint8_t dest, uint8_t mode, uin
|
||||
}
|
||||
|
||||
void arch_apic_init() {
|
||||
madt = arch_acpi_findtable("APIC", 0);
|
||||
__assert(madt);
|
||||
uacpi_table tbl;
|
||||
|
||||
liststart = (void *)((uintptr_t)madt + sizeof(madt_t));
|
||||
listend = (void *)((uintptr_t)madt + madt->header.length);
|
||||
uacpi_status ret = uacpi_table_find_by_signature("APIC", &tbl);
|
||||
__assert(ret == UACPI_STATUS_OK);
|
||||
|
||||
overridecount = getcount(ACPI_MADT_TYPE_OVERRIDE);
|
||||
iocount = getcount(ACPI_MADT_TYPE_IOAPIC);
|
||||
lapiccount = getcount(ACPI_MADT_TYPE_LAPIC);
|
||||
lapicnmicount = getcount(ACPI_MADT_TYPE_LANMI);
|
||||
madt = tbl.ptr;
|
||||
liststart = (void *)((uintptr_t)madt + sizeof(struct acpi_madt));
|
||||
listend = (void *)((uintptr_t)madt + madt->hdr.length);
|
||||
|
||||
overridecount = getcount(ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE);
|
||||
iocount = getcount(ACPI_MADT_ENTRY_TYPE_IOAPIC);
|
||||
lapiccount = getcount(ACPI_MADT_ENTRY_TYPE_LAPIC);
|
||||
lapicnmicount = getcount(ACPI_MADT_ENTRY_TYPE_LAPIC_NMI);
|
||||
|
||||
// map LAPIC to virtual memory
|
||||
|
||||
lapicoverride_t *lapic64 = getentry(ACPI_MADT_TYPE_64BITADDR, 0);
|
||||
struct acpi_madt_lapic_address_override *lapic64 = getentry(ACPI_MADT_ENTRY_TYPE_LAPIC_ADDRESS_OVERRIDE, 0);
|
||||
|
||||
void *paddr = lapic64 ? (void *)lapic64->addr : (void *)(uint64_t)madt->addr;
|
||||
void *paddr = lapic64 ? (void *)lapic64->address : (void *)(uint64_t)madt->local_interrupt_controller_address;
|
||||
|
||||
if (lapic64)
|
||||
printf("\e[94mUsing 64 bit override for the local APIC address\n\e[0m");
|
||||
@@ -317,17 +281,17 @@ void arch_apic_init() {
|
||||
__assert(ioapics);
|
||||
|
||||
for (int i = 0; i < iocount; ++i) {
|
||||
ioentry_t *entry = getentry(ACPI_MADT_TYPE_IOAPIC, i);
|
||||
struct acpi_madt_ioapic *entry = getentry(ACPI_MADT_ENTRY_TYPE_IOAPIC, i);
|
||||
|
||||
__assert((entry->addr % PAGE_SIZE) == 0);
|
||||
ioapics[i].addr = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)(uint64_t)entry->addr);
|
||||
__assert((entry->address % PAGE_SIZE) == 0);
|
||||
ioapics[i].addr = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)(uint64_t)entry->address);
|
||||
__assert(ioapics[i].addr);
|
||||
ioapics[i].base = entry->intbase;
|
||||
ioapics[i].base = entry->gsi_base;
|
||||
ioapics[i].top = ioapics[i].base + ((readioapic(ioapics[i].addr, IOAPIC_REG_ENTRYCOUNT) >> 16) & 0xff) + 1;
|
||||
printf("ioapic%lu: addr %p base %lu top %lu\n", i, entry->addr, entry->intbase, ioapics[i].top);
|
||||
printf("ioapic%lu: addr %p base %lu top %lu\n", i, entry->address, entry->gsi_base, ioapics[i].top);
|
||||
for (int j = ioapics[i].base; j < ioapics[i].top; ++j)
|
||||
writeiored(ioapics[i].addr, j - ioapics[i].base, 0xfe, 0, 0, 0, 0, 1, 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// FIXME limine does this already but just in case the PIC should be masked
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <kernel/vmm.h>
|
||||
#include <kernel/interrupt.h>
|
||||
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/tables.h>
|
||||
|
||||
#define HPET_REG_CAPS 0
|
||||
#define HPET_REG_CONFIG 2
|
||||
#define HPET_REG_INTSTATUS 4
|
||||
@@ -62,10 +65,6 @@ void arch_hpet_waitus(time_t us) {
|
||||
arch_hpet_waitticks(us * ticksperus);
|
||||
}
|
||||
|
||||
bool arch_hpet_exists() {
|
||||
return arch_acpi_findtable("HPET", 0) != NULL;
|
||||
}
|
||||
|
||||
static void counterirq(isr_t *isr, context_t *context) {
|
||||
write64(HPET_REG_CONFIG, 0);
|
||||
|
||||
@@ -75,26 +74,36 @@ static void counterirq(isr_t *isr, context_t *context) {
|
||||
write64(HPET_REG_CONFIG, 1 + ((type == TYPE_LEGACY) ? 2 : 0));
|
||||
}
|
||||
|
||||
bool arch_hpet_exists() {
|
||||
// This is assumed by arch_hpet_init below
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t arch_hpet_init() {
|
||||
__assert(arch_hpet_exists());
|
||||
hpet_t *table = arch_acpi_findtable("HPET", 0);
|
||||
printf("hpet%lu: %lu bits %lu comparators\n", table->hpetnum, 32 + table->countersize * 32, table->comparatorcount);
|
||||
__assert(table->addrid == 0);
|
||||
__assert((table->addr & PAGE_SIZE) == 0);
|
||||
hpet = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)table->addr);
|
||||
uacpi_table tbl;
|
||||
struct acpi_hpet *table;
|
||||
|
||||
__assert(uacpi_table_find_by_signature("HPET", &tbl) == UACPI_STATUS_OK);
|
||||
table = tbl.ptr;
|
||||
|
||||
printf("hpet%lu: %lu bits %lu comparators\n", table->number,
|
||||
(table->block_id & ACPI_HPET_COUNT_SIZE_CAP) ? 64 : 32,
|
||||
(table->block_id >> ACPI_HPET_NUMBER_OF_COMPARATORS_SHIFT) & ACPI_HPET_NUMBER_OF_COMPARATORS_MASK);
|
||||
__assert(table->address.address_space_id == ACPI_AS_ID_SYS_MEM);
|
||||
__assert((table->address.address & PAGE_SIZE) == 0);
|
||||
hpet = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)table->address.address);
|
||||
__assert(hpet);
|
||||
|
||||
uint64_t capabilities = read64(HPET_REG_CAPS);
|
||||
|
||||
ticksperus = 1000000000 / HPET_CAP_FSPERTICK(capabilities);
|
||||
printf("hpet%lu: %lu ticks per us (%lu fs per tick)\n", table->hpetnum, ticksperus, HPET_CAP_FSPERTICK(capabilities));
|
||||
printf("hpet%lu: %lu ticks per us (%lu fs per tick)\n", table->number, ticksperus, HPET_CAP_FSPERTICK(capabilities));
|
||||
__assert(ticksperus);
|
||||
|
||||
write64(HPET_REG_CONFIG, 0);
|
||||
write64(HPET_REG_COUNTER, 0);
|
||||
|
||||
if (table->countersize == 0) {
|
||||
if (!(table->block_id & ACPI_HPET_COUNT_SIZE_CAP)) {
|
||||
int selectedtimer = 2;
|
||||
uint64_t timerconfig = read64(HPET_TIMER_CONFIG(selectedtimer));
|
||||
// a 32 bit main counter will require more handling on our side.
|
||||
@@ -122,7 +131,7 @@ time_t arch_hpet_init() {
|
||||
|
||||
write64(HPET_TIMER_CONFIG(selectedtimer), timerconfig);
|
||||
write64(HPET_TIMER_COMPARATOR(selectedtimer), 0x80000000);
|
||||
printf("hpet%d: timer %d on isr %d using %s\n", table->hpetnum, selectedtimer, isr->id & 0xff, "legacy replacement");
|
||||
printf("hpet%d: timer %d on isr %d using %s\n", table->number, selectedtimer, isr->id & 0xff, "legacy replacement");
|
||||
} else {
|
||||
type = TYPE_64BIT;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/gdt.h>
|
||||
#include <arch/idt.h>
|
||||
#include <kernel/acpi.h>
|
||||
#include <kernel/term.h>
|
||||
#include <kernel/pmm.h>
|
||||
#include <arch/mmu.h>
|
||||
@@ -57,7 +58,7 @@ void kernel_entry() {
|
||||
vmm_init();
|
||||
alloc_init();
|
||||
cmdline_parse();
|
||||
arch_acpi_init();
|
||||
acpi_early_init();
|
||||
arch_apic_init();
|
||||
cpu_initstate();
|
||||
// XXX fall back to another clock source
|
||||
@@ -68,6 +69,8 @@ void kernel_entry() {
|
||||
arch_smp_wakeup();
|
||||
pci_init();
|
||||
|
||||
acpi_init();
|
||||
|
||||
vmmcache_init();
|
||||
|
||||
vfs_init();
|
||||
|
||||
Reference in New Issue
Block a user