Documentation
This commit is contained in:
parent
0b4a9fdb1e
commit
5f8ed13a95
27
documentation/5 - acpi.md
Normal file
27
documentation/5 - acpi.md
Normal 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`
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user