mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-28 13:18:22 +00:00
Merge pull request #8 from d-tatianin/uacpi-integration
uACPI integration
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
|
||||
@@ -66,6 +67,9 @@ void kernel_entry() {
|
||||
arch_apic_timerinit();
|
||||
sched_init();
|
||||
arch_smp_wakeup();
|
||||
pci_init();
|
||||
|
||||
acpi_init();
|
||||
|
||||
vmmcache_init();
|
||||
|
||||
@@ -89,7 +93,6 @@ void kernel_entry() {
|
||||
block_init();
|
||||
pseudodevices_init();
|
||||
arch_e9_initdev();
|
||||
pci_init();
|
||||
keyboard_init();
|
||||
mouse_init();
|
||||
arch_ps2_init();
|
||||
@@ -124,3 +127,7 @@ void kernel_entry() {
|
||||
sched_runinit();
|
||||
sched_threadexit();
|
||||
}
|
||||
|
||||
cpu_t *_bsp(void) {
|
||||
return &bsp_cpu;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -28,6 +29,7 @@ typedef struct _isr_t {
|
||||
struct _isr_t *prev;
|
||||
void (*func)(struct _isr_t *self, context_t *ctx);
|
||||
void (*eoi)(struct _isr_t *self);
|
||||
void *priv;
|
||||
long id;
|
||||
long priority;
|
||||
bool pending;
|
||||
|
||||
@@ -11,6 +11,9 @@ typedef semaphore_t mutex_t;
|
||||
#define MUTEX_ACQUIRE(m, i) \
|
||||
semaphore_wait(m, i)
|
||||
|
||||
#define MUTEX_ACQUIRE_TIMED(m, t, i) \
|
||||
semaphore_timedwait(m, t, i)
|
||||
|
||||
#define MUTEX_RELEASE(m) \
|
||||
semaphore_signal(m)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <spinlock.h>
|
||||
#include <time.h>
|
||||
|
||||
#define SEM_TAIL 0
|
||||
#define SEM_HEAD 1
|
||||
@@ -24,7 +25,9 @@ typedef struct semaphore_t{
|
||||
|
||||
|
||||
int semaphore_wait(semaphore_t *sem, bool interruptible);
|
||||
int semaphore_timedwait(semaphore_t *sem, time_t timeoutusec, bool interruptible);
|
||||
void semaphore_signal(semaphore_t *sem);
|
||||
void semaphore_reset(semaphore_t *sem);
|
||||
bool semaphore_test(semaphore_t *sem);
|
||||
bool semaphore_haswaiters(semaphore_t *sem);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _SPINLOCK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <kernel/interrupt.h>
|
||||
|
||||
typedef int spinlock_t;
|
||||
|
||||
@@ -11,6 +12,12 @@ static inline void spinlock_acquire(spinlock_t *lock){
|
||||
while(!__sync_bool_compare_and_swap(lock, 0, 1)) asm("pause");
|
||||
}
|
||||
|
||||
static inline bool spinlock_acquireirqclear(spinlock_t *lock){
|
||||
bool ret = interrupt_set(false);
|
||||
spinlock_acquire(lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool spinlock_try(spinlock_t *lock){
|
||||
return __sync_bool_compare_and_swap(lock, 0, 1);
|
||||
}
|
||||
@@ -19,4 +26,9 @@ static inline void spinlock_release(spinlock_t *lock){
|
||||
*lock = 0;
|
||||
}
|
||||
|
||||
static inline void spinlock_releaseirqrestore(spinlock_t *lock, bool irqstate){
|
||||
spinlock_release(lock);
|
||||
interrupt_set(irqstate);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,4 +35,8 @@ static inline time_t timespec_diffus(timespec_t a, timespec_t b) {
|
||||
return nsecdiff / 1000 + secdiff * 1000000;
|
||||
}
|
||||
|
||||
static inline time_t timespec_ns(timespec_t a) {
|
||||
return a.ns + a.s * 1000000000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,6 +54,8 @@ static inline uint16_t be_to_cpu_w(uint16_t w) {
|
||||
return __builtin_bswap16(w);
|
||||
}
|
||||
|
||||
cpu_t *_bsp(void);
|
||||
|
||||
static inline cpu_t *_cpu() {
|
||||
cpu_t *cpu;
|
||||
asm volatile ("mov %%gs:0, %%rax" : "=a"(cpu) : : "memory");
|
||||
|
||||
@@ -14,6 +14,16 @@ static inline uint32_t ind(uint16_t port) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void outw(uint16_t port, uint16_t data) {
|
||||
asm volatile("out %%ax, %%dx" : : "a"(data), "d"(port));
|
||||
}
|
||||
|
||||
static inline uint16_t inw(uint16_t port) {
|
||||
uint16_t ret;
|
||||
asm volatile("in %%dx, %%ax" : "=a"(ret) : "d"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t data) {
|
||||
asm volatile("out %%al, %%dx" : : "a"(data), "d"(port));
|
||||
}
|
||||
|
||||
@@ -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
@@ -88,6 +88,23 @@ int semaphore_wait(semaphore_t *sem, bool interruptible) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int semaphore_timedwait(semaphore_t *sem, time_t timeoutusec, bool interruptible) {
|
||||
time_t sleepus;
|
||||
|
||||
do {
|
||||
if (semaphore_test(sem))
|
||||
return true;
|
||||
|
||||
sleepus = min(timeoutusec, 10);
|
||||
timeoutusec -= sleepus;
|
||||
|
||||
if (sleepus)
|
||||
sched_sleepus(sleepus);
|
||||
} while (timeoutusec);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void semaphore_signal(semaphore_t *sem) {
|
||||
bool intstate = interrupt_set(false);
|
||||
spinlock_acquire(&sem->lock);
|
||||
@@ -108,6 +125,13 @@ void semaphore_signal(semaphore_t *sem) {
|
||||
interrupt_set(intstate);
|
||||
}
|
||||
|
||||
void semaphore_reset(semaphore_t *sem) {
|
||||
bool intstate = spinlock_acquireirqclear(&sem->lock);
|
||||
__assert(sem->head == NULL);
|
||||
sem->i = 0;
|
||||
spinlock_releaseirqrestore(&sem->lock, intstate);
|
||||
}
|
||||
|
||||
bool semaphore_haswaiters(semaphore_t *sem) {
|
||||
bool intstate = interrupt_set(false);
|
||||
spinlock_acquire(&sem->lock);
|
||||
|
||||
Reference in New Issue
Block a user