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:
8infy
2024-09-01 19:51:39 +03:00
parent 476d4bad74
commit db55f99e23
14 changed files with 758 additions and 266 deletions
+3 -77
View File
@@ -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);
}
+37 -73
View File
@@ -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
+22 -13
View File
@@ -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;
}
+4 -1
View File
@@ -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();