diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:35:04 +0200 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:35:04 +0200 |
commit | 866912eb5f7906da2545f27f7bbef01a7d61c87f (patch) | |
tree | 2472110bcf868837d84893bc257edcbafefe5a59 /src/acpi.c | |
parent | 5e12467c860372dfa10323365fb0df9db79c8f9b (diff) |
Diffstat (limited to 'src/acpi.c')
-rw-r--r-- | src/acpi.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/acpi.c b/src/acpi.c new file mode 100644 index 0000000..5cee000 --- /dev/null +++ b/src/acpi.c @@ -0,0 +1,89 @@ +#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; +} |