Documentation

This commit is contained in:
Thomas Lovén 2022-01-17 14:38:40 +01:00
parent 0b4a9fdb1e
commit 5f8ed13a95
4 changed files with 103 additions and 83 deletions

27
documentation/5 - acpi.md Normal file
View File

@ -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`

View File

@ -1,5 +1,5 @@
#include <cpu.h> #include <cpu.h>
#include <multiboot.h>
#include <memory.h> #include <memory.h>
#include <string.h> #include <string.h>
#include <debug.h> #include <debug.h>
@ -12,108 +12,100 @@ struct rsdp { // 5.2.5.3
char OEMID[6]; char OEMID[6];
uint8_t revision; uint8_t revision;
uint32_t rsdt_p; uint32_t rsdt_p;
uint32_t length; // only if revision >= 2 uint8_t _[14]; // Fields for 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
}__attribute__((packed)); }__attribute__((packed));
struct sdt_header { // 5.2.6 struct sdt {
char signature[4]; char signature[4];
uint32_t length; uint32_t length;
uint8_t revision; uint8_t _[28];
uint8_t checksum; uint32_t data[];
char OEMID[6];
char OEMtable[8];
uint32_t OEMrevision;
uint32_t creatorID;
uint32_t creatorRevision;
uint8_t data[];
}__attribute__((packed)); }__attribute__((packed));
struct madt_header { // 5.2.12
uint32_t controllerAddress; // MADT (5.2.12)
uint32_t flags; #define MADT_TYPE_LAPIC 0
uint8_t fields[]; #define MADT_TYPE_IOAPIC 1
}__attribute__((packed)); #define MADT_TYPE_ISO 2
struct madt_field { struct madt_field {
uint8_t type; uint8_t type;
uint8_t length; uint8_t length;
uint8_t data[]; union {
}__attribute__((packed)); // Processor Local APIC (5.2.12.2)
struct {
// MADT field type: 0
#define MADT_TYPE_LAPIC 0
struct madt_data_lapic { // 5.2.12.2
uint8_t id; uint8_t id;
uint8_t apic; uint8_t apic;
uint32_t flags; uint32_t flags;
}__attribute__((packed)); }__attribute__((packed)) lapic;
// I/O APIC (5.2.12.3)
// MADT field type: 1 struct {
#define MADT_TYPE_IOAPIC 1
struct madt_data_ioapic { // 5.2.12.3
uint8_t id; uint8_t id;
uint8_t reserved; uint8_t reserved;
uint32_t address; uint32_t address;
uint32_t base; uint32_t base;
}__attribute__((packed)); }__attribute__((packed)) ioapic;
// Interrupt source override (5.2.12.5)
// MADT field type: 2 struct {
#define MADT_TYPE_ISO 2
struct madt_data_iso { // 5.2.12.5
uint8_t bus; uint8_t bus;
uint8_t source; uint8_t source;
uint32_t interrupt; uint32_t interrupt;
uint16_t flags; uint16_t flags;
}__attribute__((packed)) iso;
};
}__attribute__((packed));
struct madt_header {
uint32_t controllerAddress;
uint32_t flags;
struct madt_field fields[];
}__attribute__((packed)); }__attribute__((packed));
void acpi_parse() { static void madt_parse(struct madt_header *madt, size_t length)
{
int cpu_i=0; int cpu_i=0;
struct rsdp *rsdp = kernel_boot_data.rsdp;
struct sdt_header *rsdt = P2V(rsdp->rsdt_p);
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]);
if(h->length == 0) continue;
if(!strncmp(h->signature, "APIC", 4)) { // 5.2.12
struct madt_header *madt = P2V(h->data);
for( for(
struct madt_field *f = (void *)madt->fields; struct madt_field *f = madt->fields;
(size_t)f <= (size_t)h + h->length; (size_t)f <= (size_t)madt + length;
f = incptr(f, f->length) f = incptr(f, f->length)
) { ) {
switch(f->type) { switch(f->type) {
case MADT_TYPE_LAPIC: { case MADT_TYPE_LAPIC: {
struct madt_data_lapic *lapic = (void *)f->data;
struct cpu *cpu = P2V(pmm_alloc()); struct cpu *cpu = P2V(pmm_alloc());
cpus[cpu_i++] = cpu; cpus[cpu_i++] = cpu;
cpu->id = lapic->id; cpu->id = f->lapic.id;
cpu->apic_id = lapic->apic; cpu->apic_id = f->lapic.apic;
cpu->flags = lapic->flags; cpu->flags = f->lapic.flags;
break; break;
} }
case MADT_TYPE_IOAPIC: { case MADT_TYPE_IOAPIC: {
struct madt_data_ioapic *_ioapic = (void *)f->data; ioapic.id = f->ioapic.id;
ioapic.id = _ioapic->id; ioapic.addr = f->ioapic.address;
ioapic.addr = _ioapic->address; ioapic.base = f->ioapic.base;
ioapic.base = _ioapic->base;
break; break;
} }
case MADT_TYPE_ISO: { case MADT_TYPE_ISO: {
struct madt_data_iso *iso = (void *)f->data; irq_redirects[f->iso.source] = f->iso.interrupt;
irq_redirects[iso->source] = iso->interrupt;
break; break;
} }
default: 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));
}
} }
} }

View File

@ -1,6 +1,7 @@
#include <cpu.h> #include <cpu.h>
#include <cpu/interrupts.h> #include <cpu/interrupts.h>
#include <ports.h> #include <ports.h>
#include <multiboot.h>
struct cpu *cpus[16]; struct cpu *cpus[16];
struct ioapic ioapic = {0,0,0}; struct ioapic ioapic = {0,0,0};
@ -31,7 +32,7 @@ void early_cpu_init() {
} }
void cpu_init() { void cpu_init() {
acpi_parse(); acpi_parse(kernel_boot_data.rsdp);
pic_disable(); pic_disable();
apic_init(); apic_init();
ioapic_init(); ioapic_init();

View File

@ -33,7 +33,7 @@ uint64_t read_msr(uint32_t);
uint64_t write_msr(uint32_t msr, uint64_t value); uint64_t write_msr(uint32_t msr, uint64_t value);
// cpu/acpi.c // cpu/acpi.c
void acpi_parse(); void acpi_parse(void *_rsdp);
// cpu/apic.c // cpu/apic.c
void apic_init(); void apic_init();