mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +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:
@@ -0,0 +1,3 @@
|
||||
[submodule "kernel-src/io/acpi/uacpi"]
|
||||
path = kernel-src/io/acpi/uacpi
|
||||
url = https://github.com/UltraOS/uACPI
|
||||
+3
-1
@@ -10,8 +10,10 @@ LDFLAGS=-ffreestanding -nostdlib -lgcc -Wl,-T,"$(ARCHDIR)/kernel.ld" -g
|
||||
PRINTFOPTS=-DPRINTF_DISABLE_SUPPORT_FLOAT
|
||||
# flanterm includes break if the headers are moved into the include dir in the tree
|
||||
FLANTERMINCDIR=$(shell pwd)/flanterm
|
||||
UACPIINCDIR=$(shell pwd)/io/acpi/uacpi/include
|
||||
UACPIOPTS=-DUACPI_OVERRIDE_LIBC -DUACPI_KERNEL_INITIALIZATION
|
||||
KERNELCONFIG=#-DX86_64_ENABLE_E9 -DSYSCALL_LOGGING
|
||||
CFLAGS=-g -ffreestanding -mcmodel=kernel -O2 -mno-red-zone -mgeneral-regs-only -mno-mmx -mno-sse -mno-sse2 -nostdlib -Wall -I "${INCDIR}" -I "$(ARCHINCDIR)" -I "$(FLANTERMINCDIR)" $(PRINTFOPTS) $(KERNELCONFIG)
|
||||
CFLAGS=-g -ffreestanding -mcmodel=kernel -O2 -mno-red-zone -mgeneral-regs-only -mno-mmx -mno-sse -mno-sse2 -nostdlib -Wall -I "${INCDIR}" -I "$(ARCHINCDIR)" -I "$(FLANTERMINCDIR)" -I "$(UACPIINCDIR)" $(UACPIOPTS) $(PRINTFOPTS) $(KERNELCONFIG)
|
||||
ASFLAGS=-felf64
|
||||
|
||||
.PHONY: all
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef _ACPI_H
|
||||
#define _ACPI_H
|
||||
|
||||
// Doesn't depend on PCI, only makes table search available
|
||||
void acpi_early_init(void);
|
||||
|
||||
// Loads the actual ACPI namespace, hooks up the power button
|
||||
void acpi_init(void);
|
||||
|
||||
int acpi_poweroff(void);
|
||||
int acpi_reboot(void);
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@
|
||||
#define IPL_DISK 500
|
||||
#define IPL_KEYBOARD 600
|
||||
#define IPL_MOUSE 650
|
||||
#define IPL_ACPI 700
|
||||
#define IPL_DPC 900
|
||||
#define IPL_NORMAL 1000
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <string.h>
|
||||
#include <printf.h>
|
||||
|
||||
#define uacpi_memcpy memcpy
|
||||
#define uacpi_memset memset
|
||||
#define uacpi_memcmp memcmp
|
||||
#define uacpi_strcmp strcmp
|
||||
#define uacpi_strlen strlen
|
||||
|
||||
#define uacpi_snprintf snprintf
|
||||
#define uacpi_vsnprintf vsnprintf
|
||||
@@ -1,92 +1,8 @@
|
||||
#ifndef _ACPI_H
|
||||
#define _ACPI_H
|
||||
#ifndef _ARCH_ACPI_H
|
||||
#define _ARCH_ACPI_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
char sig[8];
|
||||
uint8_t checksum;
|
||||
char oem[6];
|
||||
uint8_t revision;
|
||||
uint32_t rsdt;
|
||||
uint32_t length;
|
||||
uint64_t xsdt;
|
||||
uint8_t xchecksum;
|
||||
uint8_t reserved[3];
|
||||
} __attribute__((packed)) rsdp_t;
|
||||
|
||||
typedef struct {
|
||||
char sig[4];
|
||||
uint32_t length;
|
||||
uint8_t revision;
|
||||
uint8_t cechksum;
|
||||
char oemid[6];
|
||||
char oemtableid[8];
|
||||
uint32_t oemrevision;
|
||||
uint32_t creatorid;
|
||||
uint32_t creatorrevision;
|
||||
} __attribute__((packed)) sdtheader_t;
|
||||
|
||||
typedef struct {
|
||||
sdtheader_t header;
|
||||
uint64_t tables[];
|
||||
} __attribute__((packed)) xsdt_t;
|
||||
|
||||
typedef struct {
|
||||
sdtheader_t header;
|
||||
uint32_t tables[];
|
||||
} __attribute__((packed)) rsdt_t;
|
||||
|
||||
typedef struct {
|
||||
sdtheader_t header;
|
||||
uint32_t addr;
|
||||
uint32_t flags;
|
||||
} __attribute__((packed)) madt_t;
|
||||
|
||||
typedef struct {
|
||||
sdtheader_t header;
|
||||
uint8_t hwrev;
|
||||
uint8_t comparatorcount:5;
|
||||
uint8_t countersize:1;
|
||||
uint8_t reserved:1;
|
||||
uint8_t legacy_replacement:1;
|
||||
uint16_t pcivendor;
|
||||
uint8_t addrid;
|
||||
uint8_t bitwidth;
|
||||
uint8_t bitoffset;
|
||||
uint8_t reserved2;
|
||||
uint64_t addr;
|
||||
uint8_t hpetnum;
|
||||
uint16_t mintick;
|
||||
uint8_t pageprot;
|
||||
} __attribute__((packed)) hpet_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t address;
|
||||
uint16_t sgn;
|
||||
uint8_t startbus;
|
||||
uint8_t endbus;
|
||||
uint32_t reserved;
|
||||
} __attribute__((packed)) mcfgentry_t;
|
||||
|
||||
typedef struct {
|
||||
sdtheader_t header;
|
||||
uint64_t reserved;
|
||||
mcfgentry_t entries[];
|
||||
} __attribute__((packed)) mcfg_t;
|
||||
|
||||
#define ACPI_MADT_TYPE_LAPIC 0
|
||||
#define ACPI_MADT_TYPE_IOAPIC 1
|
||||
#define ACPI_MADT_TYPE_OVERRIDE 2
|
||||
#define ACPI_MADT_TYPE_IONMI 3
|
||||
#define ACPI_MADT_TYPE_LANMI 4
|
||||
#define ACPI_MADT_TYPE_64BITADDR 5
|
||||
#define ACPI_MADT_TYPE_X2APIC 9
|
||||
|
||||
bool arch_acpi_checksumok(void *table);
|
||||
void *arch_acpi_findtable(char *sig, int n);
|
||||
void arch_acpi_init();
|
||||
uintptr_t arch_get_rsdp(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,8 +11,11 @@
|
||||
#include <kernel/alloc.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/tables.h>
|
||||
|
||||
static size_t mcfgentrycount;
|
||||
static mcfgentry_t *mcfgentries;
|
||||
static struct acpi_mcfg_allocation *mcfgentries;
|
||||
static uint32_t (*pci_archread32)(int bus, int device, int function, uint32_t offset);
|
||||
static void (*pci_archwrite32)(int bus, int device, int function, uint32_t offset, uint32_t value);
|
||||
|
||||
@@ -31,13 +34,13 @@ static void legacy_write32(int bus, int device, int function, uint32_t offset, u
|
||||
outd(CONFDATA, value);
|
||||
}
|
||||
|
||||
static inline mcfgentry_t *getmcfgentry(int bus) {
|
||||
mcfgentry_t *entry;
|
||||
static inline struct acpi_mcfg_allocation *getmcfgentry(int bus) {
|
||||
struct acpi_mcfg_allocation *entry;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mcfgentrycount; ++i) {
|
||||
entry = &mcfgentries[i];
|
||||
if (bus >= entry->startbus && bus <= entry->endbus)
|
||||
if (bus >= entry->start_bus && bus <= entry->end_bus)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -48,21 +51,21 @@ static inline mcfgentry_t *getmcfgentry(int bus) {
|
||||
}
|
||||
|
||||
static uint32_t mcfg_read32(int bus, int device, int function, uint32_t offset) {
|
||||
mcfgentry_t *entry = getmcfgentry(bus);
|
||||
struct acpi_mcfg_allocation *entry = getmcfgentry(bus);
|
||||
if (entry == NULL)
|
||||
return 0xffffffff;
|
||||
|
||||
uint64_t base = (uint64_t)entry->address;
|
||||
volatile uint32_t *address = (uint32_t *)((uintptr_t)base + (((bus - entry->startbus) << 20) | (device << 15) | (function << 12) | (offset & ~0x3)));
|
||||
volatile uint32_t *address = (uint32_t *)((uintptr_t)base + (((bus - entry->start_bus) << 20) | (device << 15) | (function << 12) | (offset & ~0x3)));
|
||||
|
||||
return *address;
|
||||
}
|
||||
|
||||
static void mcfg_write32(int bus, int device, int function, uint32_t offset, uint32_t value) {
|
||||
mcfgentry_t *entry = getmcfgentry(bus);
|
||||
struct acpi_mcfg_allocation *entry = getmcfgentry(bus);
|
||||
|
||||
uint64_t base = (uint64_t)entry->address;
|
||||
volatile uint32_t *address = (uint32_t *)((uintptr_t)base + (((bus - entry->startbus) << 20) | (device << 15) | (function << 12) | (offset & ~0x3)));
|
||||
volatile uint32_t *address = (uint32_t *)((uintptr_t)base + (((bus - entry->start_bus) << 20) | (device << 15) | (function << 12) | (offset & ~0x3)));
|
||||
|
||||
*address = value;
|
||||
}
|
||||
@@ -77,20 +80,23 @@ static uint64_t msiformatmessage(uint32_t *data, int vector, int edgetrigger, in
|
||||
#define MCFG_MAPPING_SIZE(buscount) (4096l * 8l * 32l * (buscount))
|
||||
|
||||
static void pci_archinit() {
|
||||
mcfg_t *mcfg = arch_acpi_findtable("MCFG", 0);
|
||||
uacpi_table tbl;
|
||||
struct acpi_mcfg *mcfg;
|
||||
|
||||
if (mcfg) {
|
||||
uacpi_status ret = uacpi_table_find_by_signature("MCFG", &tbl);
|
||||
if (ret == UACPI_STATUS_OK) {
|
||||
printf("pci: MCFG table found. Using extended configuration space\n");
|
||||
mcfg = tbl.ptr;
|
||||
pci_archread32 = mcfg_read32;
|
||||
pci_archwrite32 = mcfg_write32;
|
||||
mcfgentrycount = (mcfg->header.length - sizeof(sdtheader_t)) / sizeof(mcfgentry_t);
|
||||
mcfgentries = alloc(sizeof(mcfgentry_t) * mcfgentrycount);
|
||||
mcfgentrycount = (mcfg->hdr.length - sizeof(struct acpi_sdt_hdr)) / sizeof(struct acpi_mcfg_allocation);
|
||||
mcfgentries = alloc(sizeof(struct acpi_mcfg_allocation) * mcfgentrycount);
|
||||
__assert(mcfgentries);
|
||||
memcpy(mcfgentries, mcfg->entries, sizeof(mcfgentry_t) * mcfgentrycount);
|
||||
memcpy(mcfgentries, mcfg->entries, sizeof(struct acpi_mcfg_allocation) * mcfgentrycount);
|
||||
for (int i = 0; i < mcfgentrycount; ++i) {
|
||||
void *phys = (void *)mcfgentries[i].address;
|
||||
uintmax_t pageoffset = (uintptr_t)phys % PAGE_SIZE;
|
||||
size_t mappingsize = pageoffset + MCFG_MAPPING_SIZE(mcfgentries[i].endbus - mcfgentries[i].startbus + 1);
|
||||
size_t mappingsize = pageoffset + MCFG_MAPPING_SIZE(mcfgentries[i].end_bus - mcfgentries[i].start_bus + 1);
|
||||
void *virt = vmm_map(NULL, mappingsize, VMM_FLAGS_PHYSICAL,
|
||||
ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC | ARCH_MMU_FLAGS_UC, phys);
|
||||
__assert(virt);
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
#include "uacpi/kernel_api.h"
|
||||
#include "uacpi/status.h"
|
||||
#include "uacpi/types.h"
|
||||
#include <kernel/acpi.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <arch/acpi.h>
|
||||
#include <logging.h>
|
||||
|
||||
#include <uacpi/uacpi.h>
|
||||
#include <uacpi/utilities.h>
|
||||
#include <uacpi/sleep.h>
|
||||
#include <uacpi/event.h>
|
||||
|
||||
|
||||
void acpi_early_init(void) {
|
||||
struct uacpi_init_params params = {
|
||||
.rsdp = arch_get_rsdp(),
|
||||
.log_level = UACPI_LOG_INFO,
|
||||
};
|
||||
|
||||
uacpi_status ret = uacpi_initialize(¶ms);
|
||||
__assert(ret == UACPI_STATUS_OK);
|
||||
}
|
||||
|
||||
void acpi_dopoweroff(uacpi_handle ctx) {
|
||||
(void)ctx;
|
||||
acpi_poweroff();
|
||||
}
|
||||
|
||||
static uacpi_interrupt_ret handle_pwrbtn(uacpi_handle ctx) {
|
||||
uacpi_kernel_schedule_work(UACPI_WORK_GPE_EXECUTION, acpi_dopoweroff, ctx);
|
||||
return UACPI_INTERRUPT_HANDLED;
|
||||
}
|
||||
|
||||
void acpi_init(void) {
|
||||
uacpi_status ret;
|
||||
|
||||
ret = uacpi_namespace_load();
|
||||
__assert(ret == UACPI_STATUS_OK);
|
||||
|
||||
uacpi_set_interrupt_model(UACPI_INTERRUPT_MODEL_IOAPIC);
|
||||
|
||||
ret = uacpi_namespace_initialize();
|
||||
__assert(ret == UACPI_STATUS_OK);
|
||||
|
||||
uacpi_install_fixed_event_handler(
|
||||
UACPI_FIXED_EVENT_POWER_BUTTON,
|
||||
handle_pwrbtn, UACPI_NULL
|
||||
);
|
||||
}
|
||||
|
||||
int acpi_poweroff(void) {
|
||||
uacpi_status ret = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5);
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
printf("acpi: unable to prepare for sleep: %s", uacpi_status_to_string(ret));
|
||||
return EIO;
|
||||
}
|
||||
|
||||
interrupt_set(false);
|
||||
|
||||
ret = uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5);
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
interrupt_set(true);
|
||||
printf("acpi: unable to enter S5: %s", uacpi_status_to_string(ret));
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_reboot(void) {
|
||||
/*
|
||||
* Windows does reboot via shutdown, so some hardware expects \_PTS(5)
|
||||
* to be called prior to rebooting, do that.
|
||||
*/
|
||||
uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5);
|
||||
|
||||
uacpi_status ret = uacpi_reboot();
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
printf("unable to perform system reset: %s\n", uacpi_status_to_string(ret));
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,551 @@
|
||||
#include "arch/context.h"
|
||||
#include "arch/cpu.h"
|
||||
#include "arch/mmu.h"
|
||||
#include "kernel/interrupt.h"
|
||||
#include "kernel/scheduler.h"
|
||||
#include "mutex.h"
|
||||
#include "semaphore.h"
|
||||
#include "spinlock.h"
|
||||
#include "uacpi/types.h"
|
||||
#include "util.h"
|
||||
#include <arch/io.h>
|
||||
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/pmm.h>
|
||||
#include <kernel/pci.h>
|
||||
#include <kernel/timekeeper.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <logging.h>
|
||||
|
||||
#include <uacpi/kernel_api.h>
|
||||
#include <uacpi/status.h>
|
||||
|
||||
|
||||
void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char *str) {
|
||||
const char *lvlstr;
|
||||
|
||||
switch (lvl) {
|
||||
case UACPI_LOG_DEBUG:
|
||||
lvlstr = "debug";
|
||||
break;
|
||||
case UACPI_LOG_TRACE:
|
||||
lvlstr = "trace";
|
||||
break;
|
||||
case UACPI_LOG_INFO:
|
||||
lvlstr = "info";
|
||||
break;
|
||||
case UACPI_LOG_WARN:
|
||||
lvlstr = "warn";
|
||||
break;
|
||||
case UACPI_LOG_ERROR:
|
||||
lvlstr = "error";
|
||||
break;
|
||||
default:
|
||||
lvlstr = "<invalid>";
|
||||
}
|
||||
|
||||
printf("acpi/%s %s", lvlstr, str)
|
||||
}
|
||||
|
||||
void *uacpi_kernel_alloc(uacpi_size size) {
|
||||
return alloc(size);
|
||||
}
|
||||
|
||||
void *uacpi_kernel_calloc(uacpi_size count, uacpi_size size) {
|
||||
return alloc(count * size);
|
||||
}
|
||||
|
||||
void uacpi_kernel_free(void *ptr) {
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
return free(ptr);
|
||||
}
|
||||
|
||||
void *uacpi_kernel_map(uacpi_phys_addr physical, uacpi_size length) {
|
||||
uintmax_t pageoffset = (uintptr_t)physical % PAGE_SIZE;
|
||||
void *virt = vmm_map(NULL, ROUND_UP(length, PAGE_SIZE), VMM_FLAGS_PHYSICAL,
|
||||
ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC,
|
||||
(void*)ROUND_DOWN(physical, PAGE_SIZE));
|
||||
__assert(virt);
|
||||
return (void *)((uintptr_t)virt + pageoffset);
|
||||
}
|
||||
|
||||
void uacpi_kernel_unmap(void *ptr, uacpi_size length) {
|
||||
uintptr_t addr = (uintptr_t)ptr;
|
||||
vmm_unmap((void*)ROUND_DOWN(addr, PAGE_SIZE), ROUND_UP(length, PAGE_SIZE), 0);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_raw_memory_read(
|
||||
uacpi_phys_addr address, uacpi_u8 width, uacpi_u64 *out
|
||||
) {
|
||||
void *ptr = uacpi_kernel_map(address, width);
|
||||
|
||||
switch (width) {
|
||||
case 1:
|
||||
*out = *(volatile uint8_t *)ptr;
|
||||
break;
|
||||
case 2:
|
||||
*out = *(volatile uint16_t *)ptr;
|
||||
break;
|
||||
case 4:
|
||||
*out = *(volatile uint32_t *)ptr;
|
||||
break;
|
||||
case 8:
|
||||
*out = *(volatile uint64_t *)ptr;
|
||||
break;
|
||||
default:
|
||||
uacpi_kernel_unmap(ptr, width);
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
uacpi_kernel_unmap(ptr, width);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_raw_memory_write(
|
||||
uacpi_phys_addr address, uacpi_u8 width, uacpi_u64 in
|
||||
) {
|
||||
void *ptr = uacpi_kernel_map(address, width);
|
||||
|
||||
switch (width) {
|
||||
case 1:
|
||||
*(volatile uint8_t *)ptr = in;
|
||||
break;
|
||||
case 2:
|
||||
*(volatile uint16_t *)ptr = in;
|
||||
break;
|
||||
case 4:
|
||||
*(volatile uint32_t *)ptr = in;
|
||||
break;
|
||||
case 8:
|
||||
*(volatile uint64_t *)ptr = in;
|
||||
break;
|
||||
default:
|
||||
uacpi_kernel_unmap(ptr, width);
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
uacpi_kernel_unmap(ptr, width);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
#ifdef __amd64__
|
||||
uacpi_status
|
||||
uacpi_kernel_raw_io_write(uacpi_io_addr addr, uacpi_u8 width,
|
||||
uacpi_u64 value) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
outb(addr, value);
|
||||
break;
|
||||
case 2:
|
||||
outw(addr, value);
|
||||
break;
|
||||
case 4:
|
||||
outd(addr, value);
|
||||
break;
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status
|
||||
uacpi_kernel_raw_io_read(uacpi_io_addr addr, uacpi_u8 width,
|
||||
uacpi_u64 *out) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
*out = inb(addr);
|
||||
break;
|
||||
case 2:
|
||||
*out = inw(addr);
|
||||
break;
|
||||
case 4:
|
||||
*out = ind(addr);
|
||||
break;
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
// Stolen from https://github.com/osdev0/cc-runtime/blob/dcdf5d82973e77edee597a047a3ef66300903de9/cc-runtime.c#L2229
|
||||
int __popcountdi2(int64_t a) {
|
||||
uint64_t x2 = (uint64_t)a;
|
||||
x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
|
||||
// Every 2 bits holds the sum of every pair of bits (32)
|
||||
x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
|
||||
// Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16)
|
||||
x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
|
||||
// Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8)
|
||||
uint32_t x = (uint32_t)(x2 + (x2 >> 32));
|
||||
// The lower 32 bits hold four 16 bit sums (5 significant bits).
|
||||
// Upper 32 bits are garbage
|
||||
x = x + (x >> 16);
|
||||
// The lower 16 bits hold two 32 bit sums (6 significant bits).
|
||||
// Upper 16 bits are garbage
|
||||
return (x + (x >> 8)) & 0x0000007F; // (7 significant bits)
|
||||
}
|
||||
#else
|
||||
uacpi_status uacpi_kernel_raw_io_read(uacpi_io_addr addr, uacpi_u8 width,
|
||||
uacpi_u64 *out) {
|
||||
return UACPI_STATUS_UNIMPLEMENTED;
|
||||
}
|
||||
uacpi_status uacpi_kernel_raw_io_write(uacpi_io_addr addr, uacpi_u8 width,
|
||||
uacpi_u64 value) {
|
||||
return UACPI_STATUS_UNIMPLEMENTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
uacpi_status uacpi_kernel_io_map(uacpi_io_addr base, uacpi_size size,
|
||||
uacpi_handle *outhandle) {
|
||||
*outhandle = (uacpi_handle)base;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
void uacpi_kernel_io_unmap(uacpi_handle handle) {
|
||||
(void)handle;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_io_read(uacpi_handle handle, uacpi_size offset,
|
||||
uacpi_u8 width, uacpi_u64 *out) {
|
||||
return uacpi_kernel_raw_io_read((uacpi_io_addr)handle + offset, width, out);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_io_write(uacpi_handle handle, uacpi_size offset,
|
||||
uacpi_u8 width, uacpi_u64 value) {
|
||||
return uacpi_kernel_raw_io_write((uacpi_io_addr)handle + offset, width, value);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_pci_read(
|
||||
uacpi_pci_address *address, uacpi_size offset,
|
||||
uacpi_u8 width, uacpi_u64 *out
|
||||
) {
|
||||
if (address->segment != 0) {
|
||||
printf("reading from PCI segment %u is not supported\n", address->segment);
|
||||
return UACPI_STATUS_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
switch (width) {
|
||||
case 1: {
|
||||
*out = pci_read8(address->bus, address->device, address->function, offset);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
*out = pci_read16(address->bus, address->device, address->function, offset);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
*out = pci_read32(address->bus, address->device, address->function, offset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_pci_write(
|
||||
uacpi_pci_address *address, uacpi_size offset,
|
||||
uacpi_u8 width, uacpi_u64 value
|
||||
) {
|
||||
if (address->segment != 0) {
|
||||
printf("writing to PCI segment %u is not supported\n", address->segment);
|
||||
return UACPI_STATUS_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
switch (width) {
|
||||
case 1: {
|
||||
pci_write8(address->bus, address->device, address->function, offset, value);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
pci_write16(address->bus, address->device, address->function, offset, value);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
pci_write32(address->bus, address->device, address->function, offset, value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_u64 uacpi_kernel_get_ticks(void) {
|
||||
// uACPI expects ticks in hundreds of nanoseconds
|
||||
return timespec_ns(timekeeper_timefromboot()) / 100;
|
||||
}
|
||||
|
||||
void uacpi_kernel_stall(uacpi_u8 usec) {
|
||||
timespec_t start = timekeeper_timefromboot();
|
||||
while (timespec_diffus(start, timekeeper_timefromboot()) < usec);
|
||||
}
|
||||
|
||||
void uacpi_kernel_sleep(uacpi_u64 msec) {
|
||||
sched_sleepus(msec * 1000);
|
||||
}
|
||||
|
||||
struct acpi_irqctx {
|
||||
uacpi_interrupt_handler handler;
|
||||
uacpi_handle ctx;
|
||||
};
|
||||
|
||||
static void acpi_irq(isr_t *isr, context_t *ctx) {
|
||||
struct acpi_irqctx *actx = isr->priv;
|
||||
actx->handler(actx->ctx);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_install_interrupt_handler(
|
||||
uacpi_u32 irq, uacpi_interrupt_handler handler, uacpi_handle ctx,
|
||||
uacpi_handle *outhandle
|
||||
) {
|
||||
struct acpi_irqctx *actx = alloc(sizeof(struct acpi_irqctx));
|
||||
__assert(actx);
|
||||
|
||||
isr_t *isr = interrupt_allocate(acpi_irq, arch_apic_eoi, IPL_ACPI);
|
||||
__assert(isr);
|
||||
|
||||
actx->handler = handler;
|
||||
actx->ctx = ctx;
|
||||
isr->priv = actx;
|
||||
|
||||
arch_ioapic_setirq(irq, isr->id & 0xff, _cpu()->id, false);
|
||||
|
||||
*outhandle = isr;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_uninstall_interrupt_handler(
|
||||
uacpi_interrupt_handler handler, uacpi_handle handle) {
|
||||
(void)handler; (void)handle;
|
||||
|
||||
// We currently don't have an API to unregister interrupts
|
||||
printf("acpi: interrupt handler uninstallation is a TODO\n");
|
||||
return UACPI_STATUS_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
struct acpi_work {
|
||||
uacpi_work_handler handler;
|
||||
uacpi_handle ctx;
|
||||
struct acpi_work *next;
|
||||
};
|
||||
|
||||
struct acpi_workctx {
|
||||
semaphore_t sem;
|
||||
spinlock_t queuelock;
|
||||
thread_t *thread;
|
||||
struct acpi_work *head;
|
||||
};
|
||||
|
||||
static struct acpi_workctx gpework;
|
||||
static struct acpi_workctx notifywork;
|
||||
|
||||
static void acpi_initwork(struct acpi_workctx *ctx, void (*proc)(void)) {
|
||||
SEMAPHORE_INIT(&ctx->sem, 0);
|
||||
SPINLOCK_INIT(ctx->queuelock);
|
||||
|
||||
ctx->thread = sched_newthread(proc, PAGE_SIZE * 4, 0, NULL, NULL);
|
||||
__assert(ctx->thread);
|
||||
sched_queue(ctx->thread);
|
||||
}
|
||||
|
||||
static void acpi_dowork(struct acpi_workctx *ctx) {
|
||||
for (;;) {
|
||||
semaphore_wait(&ctx->sem, true);
|
||||
|
||||
struct acpi_work *work = NULL;
|
||||
|
||||
bool irqstate = spinlock_acquireirqclear(&ctx->queuelock);
|
||||
if (ctx->head) {
|
||||
work = ctx->head;
|
||||
ctx->head = work->next;
|
||||
}
|
||||
spinlock_releaseirqrestore(&ctx->queuelock, irqstate);
|
||||
|
||||
if (work == NULL)
|
||||
continue;
|
||||
|
||||
work->handler(work->ctx);
|
||||
free(work);
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_dogpework() {
|
||||
sched_targetcpu(_bsp());
|
||||
sched_yield();
|
||||
|
||||
acpi_dowork(&gpework);
|
||||
}
|
||||
|
||||
static void acpi_donotifywork() {
|
||||
acpi_dowork(¬ifywork);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_initialize(uacpi_init_level lvl) {
|
||||
if (lvl != UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED)
|
||||
return UACPI_STATUS_OK;
|
||||
|
||||
acpi_initwork(&gpework, acpi_dogpework);
|
||||
acpi_initwork(¬ifywork, acpi_donotifywork);
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
void uacpi_kernel_deinitialize() { }
|
||||
|
||||
uacpi_status uacpi_kernel_schedule_work(
|
||||
uacpi_work_type type, uacpi_work_handler handler, uacpi_handle ctx) {
|
||||
struct acpi_work *work;
|
||||
struct acpi_workctx *workctx;
|
||||
|
||||
work = alloc(sizeof(*work));
|
||||
if (work == NULL)
|
||||
return UACPI_STATUS_OUT_OF_MEMORY;
|
||||
|
||||
work->ctx = ctx;
|
||||
work->handler = handler;
|
||||
|
||||
switch (type) {
|
||||
case UACPI_WORK_GPE_EXECUTION:
|
||||
workctx = &gpework;
|
||||
break;
|
||||
default:
|
||||
workctx = ¬ifywork;
|
||||
break;
|
||||
}
|
||||
|
||||
bool irqstate = spinlock_acquireirqclear(&workctx->queuelock);
|
||||
work->next = workctx->head;
|
||||
workctx->head = work;
|
||||
spinlock_releaseirqrestore(&workctx->queuelock, irqstate);
|
||||
|
||||
semaphore_signal(&workctx->sem);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static void work_await(struct acpi_workctx *ctx) {
|
||||
for (;;) {
|
||||
bool empty;
|
||||
|
||||
bool irqstate = spinlock_acquireirqclear(&ctx->queuelock);
|
||||
empty = ctx->head == NULL;
|
||||
spinlock_releaseirqrestore(&ctx->queuelock, irqstate);
|
||||
|
||||
if (empty)
|
||||
return;
|
||||
|
||||
sched_sleepus(100 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_wait_for_work_completion(void) {
|
||||
work_await(&gpework);
|
||||
work_await(¬ifywork);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_handle_firmware_request(
|
||||
uacpi_firmware_request *req) {
|
||||
switch(req->type) {
|
||||
case UACPI_FIRMWARE_REQUEST_TYPE_BREAKPOINT:
|
||||
break;
|
||||
case UACPI_FIRMWARE_REQUEST_TYPE_FATAL:
|
||||
printf("acpi: fatal firmware error: type=%d code=%d arg=%d\n",
|
||||
req->fatal.type, req->fatal.code, req->fatal.arg)
|
||||
break;
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_handle uacpi_kernel_create_mutex(void) {
|
||||
mutex_t *mut = alloc(sizeof(mutex_t));
|
||||
if (mut == NULL)
|
||||
return mut;
|
||||
|
||||
MUTEX_INIT(mut);
|
||||
return mut;
|
||||
}
|
||||
|
||||
void uacpi_kernel_free_mutex(uacpi_handle mut) {
|
||||
uacpi_kernel_free(mut);
|
||||
}
|
||||
|
||||
uacpi_bool uacpi_kernel_acquire_mutex(
|
||||
uacpi_handle mut, uacpi_u16 timeout) {
|
||||
if (timeout == 0xFFFF) {
|
||||
MUTEX_ACQUIRE(mut, true);
|
||||
return UACPI_TRUE;
|
||||
}
|
||||
|
||||
return MUTEX_ACQUIRE_TIMED(mut, timeout * 1000, true);
|
||||
}
|
||||
|
||||
void uacpi_kernel_release_mutex(uacpi_handle mut) {
|
||||
MUTEX_RELEASE(mut);
|
||||
}
|
||||
|
||||
uacpi_handle uacpi_kernel_create_event(void) {
|
||||
semaphore_t *sem = alloc(sizeof(semaphore_t));
|
||||
if (sem == NULL)
|
||||
return sem;
|
||||
|
||||
SEMAPHORE_INIT(sem, 1);
|
||||
return sem;
|
||||
}
|
||||
|
||||
void uacpi_kernel_free_event(uacpi_handle sem) {
|
||||
uacpi_kernel_free(sem);
|
||||
}
|
||||
|
||||
uacpi_bool uacpi_kernel_wait_for_event(
|
||||
uacpi_handle sem, uacpi_u16 timeout) {
|
||||
|
||||
if (timeout == 0xFFFF) {
|
||||
semaphore_wait(sem, true);
|
||||
return UACPI_TRUE;
|
||||
}
|
||||
|
||||
return semaphore_timedwait(sem, timeout * 1000, true);
|
||||
}
|
||||
|
||||
void uacpi_kernel_signal_event(uacpi_handle sem) {
|
||||
semaphore_signal(sem);
|
||||
}
|
||||
|
||||
void uacpi_kernel_reset_event(uacpi_handle sem) {
|
||||
semaphore_reset(sem);
|
||||
}
|
||||
|
||||
uacpi_thread_id uacpi_kernel_get_thread_id(void) {
|
||||
return _cpu()->thread;
|
||||
}
|
||||
|
||||
uacpi_handle uacpi_kernel_create_spinlock(void) {
|
||||
spinlock_t *lock = alloc(sizeof(spinlock_t));
|
||||
if (lock == NULL)
|
||||
return lock;
|
||||
|
||||
SPINLOCK_INIT(*lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
void uacpi_kernel_free_spinlock(uacpi_handle lock) {
|
||||
uacpi_kernel_free(lock);
|
||||
}
|
||||
|
||||
uacpi_cpu_flags uacpi_kernel_spinlock_lock(uacpi_handle lock) {
|
||||
return spinlock_acquireirqclear(lock);
|
||||
}
|
||||
|
||||
void uacpi_kernel_spinlock_unlock(uacpi_handle lock, uacpi_cpu_flags intstate) {
|
||||
spinlock_releaseirqrestore(lock, intstate);
|
||||
}
|
||||
Submodule
+1
Submodule kernel-src/io/acpi/uacpi added at c137b78de8
Reference in New Issue
Block a user