2021-08-24 14:09:29 -05:00

180 lines
4.3 KiB
C

#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++;
}
}
}
}