summaryrefslogtreecommitdiff
path: root/src/kernel/madt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/madt.c')
-rw-r--r--src/kernel/madt.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/kernel/madt.c b/src/kernel/madt.c
new file mode 100644
index 0000000..62e0535
--- /dev/null
+++ b/src/kernel/madt.c
@@ -0,0 +1,179 @@
+#include <stdint.h>
+#include <libc.h>
+#include <acpi.h>
+#include <int.h>
+#include <kernel.h>
+#include <stddef.h>
+#include <heap.h>
+#include <printf.h>
+#include <smp.h>
+#include <madt.h>
+#include <cpuid.h>
+
+//madt entry types. there's more, we don't need em yet
+#define LOCAL_APIC 0
+#define IO_APIC 1
+#define IO_INT_OVERRIDE 2
+#define IO_APIC_NMI_SOURCE 3
+#define IO_APIC_NMI 4
+#define MADT_LOCAL_APIC_ADDR_OVERRIDE 5
+
+struct madt_sdt {
+ sdt_head header;
+ uint32_t apic_base;
+ uint32_t flags;
+} __attribute__((packed));
+
+struct madt_entry {
+ uint8_t type;
+ uint8_t length;
+} __attribute__((packed));
+
+struct madt_local_apic {
+ uint8_t processor_id;
+ uint8_t apic_id;
+ uint32_t flags;
+} __attribute__((packed));
+
+struct madt_local_apic_override {
+ uint16_t reserved;
+ void *apic_base;
+} __attribute__((packed));
+
+struct madt_ioapic {
+ uint8_t apic_id;
+ uint8_t reserved;
+ uint32_t addr;
+ uint32_t gsi_base;
+} __attribute__((packed));
+
+struct madt_io_int_override {
+ uint8_t bus_src; //not sure what this is used for.
+ uint8_t irq;
+ uint32_t global_vector;
+ uint16_t flags;
+} __attribute__((packed));
+
+static struct madt_sdt *madt;
+
+
+void init_madt() {
+ madt = find_sdt(SDT_MADT);
+}
+
+void debug_madt() {
+ struct madt_entry *entry;
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+ printf("MADT debug: ");
+ switch(entry->type) {
+ case LOCAL_APIC:
+ printf("local APIC\n");
+ break;
+ case IO_APIC:
+ printf("IOAPIC\n");
+ break;
+ case IO_INT_OVERRIDE:
+ printf("IOAPIC interupt override\n");
+ break;
+ case IO_APIC_NMI_SOURCE:
+ printf("IOAPIC NMI\n");
+ break;
+ case IO_APIC_NMI:
+ printf("Local APIC NMI\n");
+ break;
+ case MADT_LOCAL_APIC_ADDR_OVERRIDE:
+ printf("APIC addr override\n");
+ break;
+ default:
+ printf("other\n");
+ break;
+ }
+ }
+}
+
+unsigned int irq_to_gsi(unsigned int irq) {
+ struct madt_io_int_override *irq_override;
+ struct madt_entry *entry;
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+
+ if(entry->type == IO_INT_OVERRIDE) {
+ irq_override = (void *)entry + 2;
+ if(irq_override->irq == irq) return irq_override->global_vector;
+ }
+ }
+ return (uint32_t)irq; //no entry found
+}
+
+void get_ioapic(struct ioapic_fixedlen *ret) {
+ struct madt_entry *entry;
+ struct madt_ioapic *mpio_entry;
+
+ ret->count = 0;
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+ if(entry->type == IO_APIC) {
+ mpio_entry = (void *)entry + 2;
+ if(ret->count) {
+ ret->ioapic = realloc(ret->ioapic, ++ret->count * sizeof(struct ioapic_t));
+ }
+ else {
+ ret->ioapic = malloc(++ret->count * sizeof(struct ioapic_t));
+ }
+ ret->ioapic[ret->count - 1].address = PHYS_TO_VIRT((uintptr_t)mpio_entry->addr);
+ ret->ioapic[ret->count - 1].gsi_base = mpio_entry->gsi_base;
+ }
+ }
+}
+
+lapic_t get_lapic() {
+ struct madt_local_apic_override *ap_override;
+ struct madt_entry *entry;
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+
+ if(entry->type == MADT_LOCAL_APIC_ADDR_OVERRIDE) {
+ ap_override = (void *)entry + 2;
+
+ return (lapic_t)PHYS_TO_VIRT(ap_override->apic_base);
+ }
+ }
+ return (lapic_t)PHYS_TO_VIRT((uint64_t)madt->apic_base);
+}
+
+void get_coreinfo(struct cores_info *cores) {
+ struct madt_local_apic *ap_info;
+ struct madt_entry *entry;
+ uint32_t unused_cpuid, ebx;
+
+ __get_cpuid(1, &unused_cpuid, &ebx, &unused_cpuid, &unused_cpuid);
+ cores->bsp = ebx << 24;
+
+ bzero(cores, sizeof(*cores));
+
+ for(
+ entry = (void *)madt + sizeof(*madt);
+ (void *)entry < (void *)madt + madt->header.length;
+ entry = (void *)entry + entry->length) {
+
+ if(entry->type == LOCAL_APIC) {
+ ap_info = (void *)entry + 2;
+ if(ap_info->flags & 1) {
+ cores->apic_id[cores->corecount] = ap_info->processor_id;
+ cores->corecount++;
+ }
+ }
+ }
+}