summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/acpi.c89
-rw-r--r--src/apic.c121
-rw-r--r--src/keyboard.c25
3 files changed, 235 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;
+}
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;
+}