108 lines
2.4 KiB
C
108 lines
2.4 KiB
C
#include <cpu.h>
|
|
|
|
#include <memory.h>
|
|
#include <string.h>
|
|
#include <debug.h>
|
|
|
|
// ACPI Specification:
|
|
// https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
|
|
|
|
struct rsdp { // 5.2.5.3
|
|
char signature[8];
|
|
uint8_t checksum;
|
|
char OEMID[6];
|
|
uint8_t revision;
|
|
uint32_t rsdt_p;
|
|
uint8_t _[14]; // Fields for revision >= 2
|
|
}__attribute__((packed));
|
|
|
|
struct sdt {
|
|
char signature[4];
|
|
uint32_t length;
|
|
uint8_t _[28];
|
|
uint32_t data[];
|
|
}__attribute__((packed));
|
|
|
|
|
|
// MADT (5.2.12)
|
|
#define MADT_TYPE_LAPIC 0
|
|
#define MADT_TYPE_IOAPIC 1
|
|
#define MADT_TYPE_ISO 2
|
|
|
|
struct madt_field {
|
|
uint8_t type;
|
|
uint8_t length;
|
|
union {
|
|
struct { // Processor Local APIC (5.2.12.2)
|
|
uint8_t id;
|
|
uint8_t apic;
|
|
uint32_t flags;
|
|
}__attribute__((packed)) lapic;
|
|
struct { // I/O APIC (5.2.12.3)
|
|
uint8_t id;
|
|
uint8_t reserved;
|
|
uint32_t address;
|
|
uint32_t base;
|
|
}__attribute__((packed)) ioapic;
|
|
struct { // Interrupt source override (5.2.12.5)
|
|
uint8_t bus;
|
|
uint8_t source;
|
|
uint32_t interrupt;
|
|
uint16_t flags;
|
|
}__attribute__((packed)) iso;
|
|
};
|
|
}__attribute__((packed));
|
|
|
|
struct madt_header {
|
|
uint32_t controllerAddress;
|
|
uint32_t flags;
|
|
struct madt_field fields[];
|
|
}__attribute__((packed));
|
|
|
|
|
|
static void madt_parse(struct madt_header *madt, size_t length)
|
|
{
|
|
int cpu_i=0;
|
|
for(struct madt_field *f = madt->fields;
|
|
(size_t)f <= (size_t)madt + length;
|
|
f = incptr(f, f->length)
|
|
) {
|
|
switch(f->type) {
|
|
case MADT_TYPE_LAPIC: {
|
|
struct cpu *cpu = P2V(pmm_alloc());
|
|
cpus[cpu_i++] = cpu;
|
|
cpu->id = f->lapic.id;
|
|
cpu->apic_id = f->lapic.apic;
|
|
cpu->flags = f->lapic.flags;
|
|
break;
|
|
}
|
|
case MADT_TYPE_IOAPIC: {
|
|
ioapic.id = f->ioapic.id;
|
|
ioapic.addr = f->ioapic.address;
|
|
ioapic.base = f->ioapic.base;
|
|
break;
|
|
}
|
|
case MADT_TYPE_ISO: {
|
|
irq_redirects[f->iso.source] = f->iso.interrupt;
|
|
break;
|
|
}
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
void acpi_parse(void *_rsdp) {
|
|
struct rsdp *rsdp = _rsdp;
|
|
|
|
struct sdt *rsdt = P2V(rsdp->rsdt_p);
|
|
int rsdt_entries = (rsdt->length - sizeof(struct sdt))/sizeof(uint32_t);
|
|
|
|
for(int i = 0; i < rsdt_entries; i++) {
|
|
struct sdt *h = P2V(rsdt->data[i]);
|
|
if(h->length == 0) continue;
|
|
|
|
if(!strncmp(h->signature, "APIC", 4)) { // 5.2.12
|
|
madt_parse(P2V(h->data), h->length - sizeof(struct sdt));
|
|
}
|
|
}
|
|
} |