From 866912eb5f7906da2545f27f7bbef01a7d61c87f Mon Sep 17 00:00:00 2001 From: Peter Mikkelsen Date: Thu, 31 Jul 2025 22:35:04 +0200 Subject: Oops, commit missing files from last commit --- src/acpi.c | 89 ++++++++++++++++++++++++++++++++++++++++++ src/apic.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/keyboard.c | 25 ++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 src/acpi.c create mode 100644 src/apic.c create mode 100644 src/keyboard.c (limited to 'src') 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; +} diff --git a/src/apic.c b/src/apic.c new file mode 100644 index 0000000..26adfae --- /dev/null +++ b/src/apic.c @@ -0,0 +1,121 @@ +#include "aplos.h" + +enum { + APIC_BASE = 0x1B, + + SPURIOUS_INTERRUPT_VECTOR = 0xF0, + END_OF_INTERRUPT = 0xB0 +}; + +static volatile uint32_t *apic_base; +static volatile uint8_t *ioapic_reg; +static volatile uint32_t *ioapic_data; +static uint8_t ioapic_max_entries; + +static uint32_t read_apic_reg(uint64_t); +static void write_apic_reg(uint64_t, uint32_t); +static uint32_t read_ioapic_reg(uint8_t); +static void write_ioapic_reg(uint8_t, uint32_t); + +void +setup_apic(struct ioapic_info *ioapic) +{ + uint64_t v = get_msr(APIC_BASE); + uint64_t addr = v & 0x0000000FFFFFF000; + + apic_base = (uint32_t *)map_page(addr, 1, false); + write_apic_reg(SPURIOUS_INTERRUPT_VECTOR, read_apic_reg(SPURIOUS_INTERRUPT_VECTOR) | 0x1FF); + + uint8_t *ioapic_base = (uint8_t*)map_page(ioapic->base, 1, false); + ioapic_reg = ioapic_base; + ioapic_data = (uint32_t*)(ioapic_base+16); + + ioapic_max_entries = (read_ioapic_reg(1) >> 16)&0xFF; +} + +void +apic_end_of_interrupt(void) +{ + write_apic_reg(END_OF_INTERRUPT, 0); +} + +struct ioapic_redirection +read_redirection(uint8_t n) +{ + assert(n <= ioapic_max_entries); + struct ioapic_redirection r; + + uint32_t low = read_ioapic_reg(0x10+2*n); + uint32_t high = read_ioapic_reg(0x11+2*n); + + r.vector = low & 0xFF; + r.delivery_mode = (low >> 8) & 0x7; + r.destination_mode = (low >> 11) & 0x1; + r.delivery_status = (low >> 12) & 0x1; + r.pin_polarity = (low >> 13) & 0x1; + r.remote_irr = (low >> 14) & 0x1; + r.trigger_mode = (low >> 15) & 0x1; + r.mask = (low >> 16) & 0x1; + r.reserved = (low >> 17) & 0xFF; + r.reserved |= high & 0xFFFFFF; + if(r.destination_mode) + r.destination = (high >> 24) & 0xF; + else + r.destination = (high >> 24) & 0xFF; + return r; +} + +void +write_redirection(uint8_t n, struct ioapic_redirection r) +{ + uint32_t high, low; + high = low = 0; + assert(n <= ioapic_max_entries); + assert(r.vector >= 0x10 && r.vector <= 0xFE); + + low |= r.vector & 0xFF; + low |= (r.delivery_mode & 0x7) << 8; + low |= (r.destination_mode & 0x1) << 11; + low |= (r.delivery_status & 0x1) << 12; + low |= (r.pin_polarity & 0x1) << 13; + low |= (r.remote_irr & 0x1) << 14; + low |= (r.trigger_mode & 0x1) << 15; + low |= (r.mask & 0x1) << 16; + low |= (r.reserved & 0xF) << 17; + high |= (r.reserved & 0xFFFFFF00) >> 8; + if(r.destination_mode) + high |= (r.destination & 0xF) << 24; + else + high |= (r.destination & 0xFF) << 24; + + write_ioapic_reg(0x10+2*n, low); + write_ioapic_reg(0x11+2*n, high); +} + +static uint32_t +read_apic_reg(uint64_t r) +{ + r /= 4; + return apic_base[r]; +} + +static void +write_apic_reg(uint64_t r, uint32_t v) +{ + r /= 4; + apic_base[r] = v; +} + +static uint32_t +read_ioapic_reg(uint8_t r) +{ + *ioapic_reg = r; + return *ioapic_data; +} + +static void +write_ioapic_reg(uint8_t r, uint32_t v) +{ + *ioapic_reg = r; + *ioapic_data = v; +} diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..4c9803c --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,25 @@ +#include "aplos.h" + +void +setup_keyboard(void) +{ + uint8_t n = 1; /* TODO: it isn't always at 1, the ACPI tables should tell us if not */ + + struct ioapic_redirection r = read_redirection(n); + + r.vector = 32; + r.delivery_mode = 0; + r.destination_mode = 0; + r.mask = 0; + r.destination = boot_apic_id(); + + write_redirection(n, r); +} + +bool +keyboard_interrupt_handler(uint32_t) +{ + uint8_t scancode = in_uint8(0x60); + print(u8"KBD INTR: %x8\n", scancode); + return true; +} -- cgit v1.2.3