#include "aplos.h" enum { SDT_HEADER_SIZE = 36, SDT_LENGTH_OFFSET = 4, RSDT_VERSION_OFFSET = 15, RSDT_VENDOR_OFFSET = 9, RSDT_VENDOR_SIZE = 6, RSDT_RSDP_OFFSET = 16 }; static uint8_t *rsdp; static uint8_t *rsdt; static uint8_t *madt; static void parse_rsdt(uint64_t); static void parse_madt(struct ioapic_info *); static uint8_t *map_sdt(uint64_t); void setup_acpi(uint64_t rsdp_physical, struct ioapic_info *ioapic) { rsdp = (uint8_t *)map_page(rsdp_physical, 1, true); uint8_t version = rsdp[RSDT_VERSION_OFFSET]; char8_t vendor[RSDT_VENDOR_SIZE+1]; memcpy(vendor, rsdp+RSDT_VENDOR_OFFSET, RSDT_VENDOR_SIZE); vendor[RSDT_VENDOR_SIZE] = 0; switch(version){ case 0: parse_rsdt(read_uint32_le(rsdp+RSDT_RSDP_OFFSET)); break; default: print(u8"Unknown RSDP version :(\n"); panic(); } parse_madt(ioapic); } void parse_rsdt(uint64_t rsdt_physical) { rsdt = map_sdt(rsdt_physical); uint32_t length = read_uint32_le(rsdt+SDT_LENGTH_OFFSET); uint32_t entries = (length - SDT_HEADER_SIZE) / 4; uint32_t *ptrs = (uint32_t *)(((uint64_t)rsdt)+SDT_HEADER_SIZE); for(uint32_t i = 0; i < entries; i++){ uint8_t *ptr = map_sdt(ptrs[i]); if(utf8_cmp_n(ptr, u8"APIC", 4) == 0) madt = ptr; } } void parse_madt(struct ioapic_info *ioapic) { assert(madt != NULL); uint32_t length = read_uint32_le(madt+SDT_LENGTH_OFFSET); uint32_t offset = SDT_HEADER_SIZE + 8; while(offset < length){ uint8_t type = madt[offset]; uint8_t record_length = madt[offset+1]; switch(type){ case 1: /* I/O APIC */ ioapic->base = read_uint32_le(madt+offset+4); ioapic->interrupt_base = read_uint32_le(madt+offset+8); break; } offset += record_length; } } static uint8_t * map_sdt(uint64_t sdt_physical) { uint8_t *p = (uint8_t *)map_page(sdt_physical, 1, true); uint32_t length = read_uint32_le(p+4); uint32_t pages = (length + PAGE_SIZE - 1) / PAGE_SIZE; if(pages > 1){ /* Remap the thing */ p = (uint8_t *)map_page(sdt_physical, pages, true); } return p; }