diff --git a/documentation/5 - acpi.md b/documentation/5 - acpi.md new file mode 100644 index 0000000..3d9d073 --- /dev/null +++ b/documentation/5 - acpi.md @@ -0,0 +1,27 @@ +# Parsing ACPI information + +> - [ACPI Specification](https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf) + +ACPI is a standard for controlling things like power and temperatures in computers. It's also useful for getting some information about the machine, such as number of processors - which is what Mittos will be using it for (at least at first). + +The bootloader will find the Root System Descriptor Pointer and provide it in a boot tag. Then the data just needs to be parsed. + +The RSDP contains a pointer to the Root System Descriptor Table which contains pointers to more System Descriptor Tables. + +The important fields for parsing a System Descript Tables are as follows: +```c +struct sdt { + char signature[4]; + uint32_t length; + uint8_t _[28]; + uint32_t data[]; +}__attribute__((packed)); +``` + +So I step through the pointers in the RSDT data field until I find an SDT with signature "APIC". That should contain the Multiple APIC Description Table. + +The MADT in turn contains a number of fields with information - among other things - about Processor Local APICs, I/O Apics and IRQ redirections. +Those are things I may be interested in, and therefore store in some global data structures. + +## Relevant files +- `src/kernel/cpu/acpi.c` \ No newline at end of file diff --git a/src/kernel/cpu/acpi.c b/src/kernel/cpu/acpi.c index 79f7998..46389a7 100644 --- a/src/kernel/cpu/acpi.c +++ b/src/kernel/cpu/acpi.c @@ -1,5 +1,5 @@ #include -#include + #include #include #include @@ -12,108 +12,100 @@ struct rsdp { // 5.2.5.3 char OEMID[6]; uint8_t revision; uint32_t rsdt_p; - uint32_t length; // only if revision >= 2 - uint64_t xsdt_p; // only if revision >= 2 - uint8_t checksum2; // only if revision >= 2 - uint8_t reserved[3]; // only if revision >= 2 + uint8_t _[14]; // Fields for revision >= 2 }__attribute__((packed)); -struct sdt_header { // 5.2.6 +struct sdt { char signature[4]; uint32_t length; - uint8_t revision; - uint8_t checksum; - char OEMID[6]; - char OEMtable[8]; - uint32_t OEMrevision; - uint32_t creatorID; - uint32_t creatorRevision; - uint8_t data[]; + uint8_t _[28]; + uint32_t data[]; }__attribute__((packed)); -struct madt_header { // 5.2.12 - uint32_t controllerAddress; - uint32_t flags; - uint8_t fields[]; -}__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; - uint8_t data[]; + union { + // Processor Local APIC (5.2.12.2) + struct { + uint8_t id; + uint8_t apic; + uint32_t flags; + }__attribute__((packed)) lapic; + // I/O APIC (5.2.12.3) + struct { + uint8_t id; + uint8_t reserved; + uint32_t address; + uint32_t base; + }__attribute__((packed)) ioapic; + // Interrupt source override (5.2.12.5) + struct { + uint8_t bus; + uint8_t source; + uint32_t interrupt; + uint16_t flags; + }__attribute__((packed)) iso; + }; }__attribute__((packed)); -// MADT field type: 0 -#define MADT_TYPE_LAPIC 0 -struct madt_data_lapic { // 5.2.12.2 - uint8_t id; - uint8_t apic; +struct madt_header { + uint32_t controllerAddress; uint32_t flags; -}__attribute__((packed)); - -// MADT field type: 1 -#define MADT_TYPE_IOAPIC 1 -struct madt_data_ioapic { // 5.2.12.3 - uint8_t id; - uint8_t reserved; - uint32_t address; - uint32_t base; -}__attribute__((packed)); - -// MADT field type: 2 -#define MADT_TYPE_ISO 2 -struct madt_data_iso { // 5.2.12.5 - uint8_t bus; - uint8_t source; - uint32_t interrupt; - uint16_t flags; + struct madt_field fields[]; }__attribute__((packed)); -void acpi_parse() { +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: + } + } +} - struct rsdp *rsdp = kernel_boot_data.rsdp; - struct sdt_header *rsdt = P2V(rsdp->rsdt_p); +void acpi_parse(void *_rsdp) { + struct rsdp *rsdp = _rsdp; - uint32_t *table = (void *)rsdt->data; - int entries = (rsdt->length - sizeof(struct sdt_header))/sizeof(uint32_t); - for(int i = 0; i < entries; i++) { - struct sdt_header *h = P2V(table[i]); + 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 - struct madt_header *madt = P2V(h->data); - for( - struct madt_field *f = (void *)madt->fields; - (size_t)f <= (size_t)h + h->length; - f = incptr(f, f->length) - ) { - switch(f->type) { - case MADT_TYPE_LAPIC: { - struct madt_data_lapic *lapic = (void *)f->data; - struct cpu *cpu = P2V(pmm_alloc()); - cpus[cpu_i++] = cpu; - cpu->id = lapic->id; - cpu->apic_id = lapic->apic; - cpu->flags = lapic->flags; - break; - } - case MADT_TYPE_IOAPIC: { - struct madt_data_ioapic *_ioapic = (void *)f->data; - ioapic.id = _ioapic->id; - ioapic.addr = _ioapic->address; - ioapic.base = _ioapic->base; - break; - } - case MADT_TYPE_ISO: { - struct madt_data_iso *iso = (void *)f->data; - irq_redirects[iso->source] = iso->interrupt; - break; - } - default: - } - } + madt_parse(P2V(h->data), h->length - sizeof(struct sdt)); } } } \ No newline at end of file diff --git a/src/kernel/cpu/cpu.c b/src/kernel/cpu/cpu.c index d370888..e634adf 100644 --- a/src/kernel/cpu/cpu.c +++ b/src/kernel/cpu/cpu.c @@ -1,6 +1,7 @@ #include #include #include +#include struct cpu *cpus[16]; struct ioapic ioapic = {0,0,0}; @@ -31,7 +32,7 @@ void early_cpu_init() { } void cpu_init() { - acpi_parse(); + acpi_parse(kernel_boot_data.rsdp); pic_disable(); apic_init(); ioapic_init(); diff --git a/src/kernel/include/cpu.h b/src/kernel/include/cpu.h index 5d4c96c..d056fcd 100644 --- a/src/kernel/include/cpu.h +++ b/src/kernel/include/cpu.h @@ -33,7 +33,7 @@ uint64_t read_msr(uint32_t); uint64_t write_msr(uint32_t msr, uint64_t value); // cpu/acpi.c -void acpi_parse(); +void acpi_parse(void *_rsdp); // cpu/apic.c void apic_init();