From f95c522b0ae30dd3c4d9c4449de98d3b5c6e9a65 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Tue, 4 Jun 2024 18:56:27 +0200 Subject: Enable and configure APLIC & IMSIC --- kernel/aplic.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/aplic.h | 1 + kernel/start.c | 41 +++++++++++++++++++- kernel/vm.c | 6 ++- 4 files changed, 164 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/aplic.c b/kernel/aplic.c index 3b0a2f5..61a42c3 100644 --- a/kernel/aplic.c +++ b/kernel/aplic.c @@ -1,2 +1,121 @@ #include "kernel/aplic.h" #include "kernel/spinlock.h" + +static volatile char* APLIC_M = (volatile char*)0x0c00'0000; +static volatile char* APLIC_S = (volatile char*)0x0d00'0000; + +static volatile char* IMSIC_M = (volatile char*)0x2400'0000; +static volatile char* IMSIC_S = (volatile char*)0x2800'0000; + + +static inline uint32_t read(volatile char* base, uint32_t offset) +{ + return *(volatile uint32_t*)(base + offset); +} + +static inline void write(volatile char* base, uint32_t offset, uint32_t v) +{ + *(volatile uint32_t*)(base + offset) = v; +} + +enum +{ + DOMAINCFG_BASE = 0x8000'0000, + DOMAINCFG_DM = 0x0000'0004, + DOMAINCFG_DM_MSI = 0x0000'0004, + DOMAINCFG_IE = 0x0000'0100, +}; + +bool aplic_w_domaincfg(volatile char* base, uint32_t value) +{ + write(base, 0, value); + return (read(base, 0) & DOMAINCFG_DM) == (value & DOMAINCFG_DM); +} + +void aplic_w_sourcecfg(volatile char* base, uint32_t source, uint32_t v) +{ + write(base, 4 + 4 * (source - 1), v); +} + +void aplic_w_sourcecfg_delegate(volatile char* base, uint32_t source, uint32_t child) +{ + aplic_w_sourcecfg(base, source, (1U << 10) | (child & 0x3ff)); +} + +void aplic_w_sourcecfg_active_high(volatile char* base, uint32_t source) +{ + aplic_w_sourcecfg(base, source, 6); +} + +void aplic_w_smsiaddr(volatile char* base, void* addr) +{ + write(base, 0x1BC8, (uint32_t)addr >> 12); + write(base, 0x1BCC, 0); +} + +void aplic_enable_intr(volatile char* base, uint32_t source) +{ + write(base, 0x1EDC, source); +} + +void aplic_w_target_msi(volatile char* base, uint32_t source, uint32_t hart_index, uint32_t guest_index, uint32_t eiid) +{ + uint32_t v = ((hart_index & 0x3fff) << 18) | ((guest_index & 0x3f) << 12) | (eiid & 0x3ff); + write(base, 0x3000 + 4 * source, v); +} + +enum +{ + EIDELIVERY = 0x70, + EITHRESHOLD = 0x72, + EIE0 = 0xC0, +}; + +enum +{ + EIDELIVERY_DISABLED = 0, + EIDELIVERY_ENABLED = 1, +}; + +void imsic_w_seidelivery(uint32_t v) +{ + __asm__ volatile( + "csrw siselect, %0;" + "csrw sireg, %1;" + :: "r"(EIDELIVERY), "r"(v)); +} + +void imsic_w_seithreshold(uint32_t v) +{ + __asm__ volatile( + "csrw siselect, %0;" + "csrw sireg, %1;" + :: "r"(EITHRESHOLD), "r"(v)); +} + +void imsic_s_seie(uint32_t id) +{ + __asm__ volatile( + "csrw siselect, %0;" + "csrs sireg, %1;" + :: "r"(EIE0 + id / 32), "r"(1U << (id % 32))); +} + +void aplic_init() +{ + uint32_t domaincfg = DOMAINCFG_BASE | DOMAINCFG_DM_MSI | DOMAINCFG_IE; + if (!aplic_w_domaincfg(APLIC_M, domaincfg)) panic("aplic_init: enable APLIC M"); + if (!aplic_w_domaincfg(APLIC_S, domaincfg)) panic("aplic_init: enable APLIC S"); + + aplic_w_smsiaddr(APLIC_M, (void*)IMSIC_S); + + uint32_t uart_source = 10; + aplic_w_sourcecfg_delegate(APLIC_M, uart_source, 0); + aplic_w_sourcecfg_active_high(APLIC_S, uart_source); + aplic_w_target_msi(APLIC_S, uart_source, 0, 0, uart_source); + aplic_enable_intr(APLIC_S, uart_source); + + imsic_w_seithreshold(0); + imsic_w_seidelivery(EIDELIVERY_ENABLED); + imsic_s_seie(uart_source); +} diff --git a/kernel/aplic.h b/kernel/aplic.h index a3b5ccb..b96363d 100644 --- a/kernel/aplic.h +++ b/kernel/aplic.h @@ -2,4 +2,5 @@ #include "kernel/lib.h" +void aplic_init(); diff --git a/kernel/start.c b/kernel/start.c index b7170ae..859ae5d 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -3,6 +3,7 @@ #include "kernel/kalloc.h" #include "kernel/vm.h" #include "kernel/cpu.h" +#include "kernel/aplic.h" Cpu cpus[MAX_CPU]; @@ -12,13 +13,51 @@ extern uint32_t _ram_end; void kstrap() { - panic("kstrap"); + uint32_t scause; + __asm__ volatile("csrr %0, scause" : "=r"(scause)); + switch (scause) + { + case 0: panic("kstrap: Instruction address misaligned"); + case 1: panic("kstrap: Instruction access fault"); + case 2: panic("kstrap: Illegal instruction"); + case 3: panic("kstrap: Breakpoint"); + case 4: panic("kstrap: Load address misaligned"); + case 5: panic("kstrap: Load access fault"); + case 6: panic("kstrap: Store/AMO address misaligned"); + case 7: panic("kstrap: Store/AMO access fault"); + case 8: panic("kstrap: Environment call from U-mode"); + case 9: panic("kstrap: Environment call from S-mode"); + case 12: panic("kstrap: Instruction page fault"); + case 13: panic("kstrap: Load page fault"); + case 14: panic("kstrap: Reserved"); + case 15: panic("kstrap: Store/AMO page fault"); + case 18: panic("kstrap: Software check"); + case 19: panic("kstrap: Hardware error"); + default: panic("kstrap: Unknown"); + } +} + +void uart_init() +{ + volatile char* UART_BASE = (volatile char*)0x1000'0000; + + // Set LCR[1:0] to 0b11 for 8-bit words + *(UART_BASE + 3) = 0b0000'0011; + + // Set FCR[0] to 1 to enable FIFO + *(UART_BASE + 2) = 0b0000'0001; + + // Set IER[0] to 1 to enable interrupts on receive + *(UART_BASE + 1) = 0b0000'0001; } void kstart() { + uart_init(); + kalloc_init(); kvm_init(); + aplic_init(); panic("kstart: end"); } diff --git a/kernel/vm.c b/kernel/vm.c index c1adbe7..8ca6666 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -100,8 +100,10 @@ void kvm_init() kvm_map(&_stack_start, &_stack_start, &_stack_end - &_stack_start, VM_RW); kvm_map((void*)0x1000'0000, (void*)0x1000'0000, PAGE_SIZE, VM_RW); // UART - kvm_map((void*)0x0c00'0000, (void*)0x0c00'0000, 0x8000, VM_RW); // APLIC-M - kvm_map((void*)0x0d00'0000, (void*)0x0d00'0000, 0x8000, VM_RW); // APLIC-S + kvm_map((void*)0x0c00'0000, (void*)0x0c00'0000, 0x8000, VM_RW); // APLIC M + kvm_map((void*)0x0d00'0000, (void*)0x0d00'0000, 0x8000, VM_RW); // APLIC S + kvm_map((void*)0x2400'0000, (void*)0x2400'0000, 0x1000, VM_RW); // IMSIC M + kvm_map((void*)0x2800'0000, (void*)0x2800'0000, 0x1000, VM_RW); // IMSIC S w_satp(SATP_MODE_SV32 | ((uint32_t)kroot >> 12)); sfence_vma(); -- cgit