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 --- build.bat | 1 + dts.txt | 71 ++++++++++++++++++++++------------ kernel/aplic.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/aplic.h | 1 + kernel/start.c | 41 +++++++++++++++++++- kernel/vm.c | 6 ++- run.bat | 2 +- 7 files changed, 213 insertions(+), 28 deletions(-) diff --git a/build.bat b/build.bat index 2631aad..98e0cf3 100644 --- a/build.bat +++ b/build.bat @@ -19,3 +19,4 @@ ld.lld -T kernel\linker.lds -o build\kernel.elf ^ build\lib.o ^ build\vm.o ^ build\spinlock.o ^ + build\aplic.o ^ diff --git a/dts.txt b/dts.txt index 76baf0f..27fab1f 100644 --- a/dts.txt +++ b/dts.txt @@ -9,19 +9,19 @@ poweroff { value = <0x5555>; offset = <0x00>; - regmap = <0x05>; + regmap = <0x07>; compatible = "syscon-poweroff"; }; reboot { value = <0x7777>; offset = <0x00>; - regmap = <0x05>; + regmap = <0x07>; compatible = "syscon-reboot"; }; platform-bus@4000000 { - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; ranges = <0x00 0x00 0x4000000 0x2000000>; #address-cells = <0x01>; #size-cells = <0x01>; @@ -47,9 +47,9 @@ riscv,cbop-block-size = <0x40>; riscv,cboz-block-size = <0x40>; riscv,cbom-block-size = <0x40>; - riscv,isa-extensions = "i\0m\0a\0f\0d\0c\0h\0zic64b\0zicbom\0zicbop\0zicboz\0ziccamoa\0ziccif\0zicclsm\0ziccrse\0zicntr\0zicsr\0zifencei\0zihintntl\0zihintpause\0zihpm\0za64rs\0zawrs\0zfa\0zca\0zcf\0zcd\0zba\0zbb\0zbc\0zbs\0ssccptr\0sscounterenw\0sstc\0sstvala\0sstvecd\0svadu"; + riscv,isa-extensions = "i\0m\0a\0f\0d\0c\0h\0zic64b\0zicbom\0zicbop\0zicboz\0ziccamoa\0ziccif\0zicclsm\0ziccrse\0zicntr\0zicsr\0zifencei\0zihintntl\0zihintpause\0zihpm\0za64rs\0zawrs\0zfa\0zca\0zcf\0zcd\0zba\0zbb\0zbc\0zbs\0smaia\0ssaia\0ssccptr\0sscounterenw\0sstc\0sstvala\0sstvecd\0svadu"; riscv,isa-base = "rv32i"; - riscv,isa = "rv32imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_za64rs_zawrs_zfa_zca_zcf_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu"; + riscv,isa = "rv32imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_za64rs_zawrs_zfa_zca_zcf_zcd_zba_zbb_zbc_zbs_smaia_ssaia_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu"; mmu-type = "riscv,sv32"; interrupt-controller { @@ -90,7 +90,7 @@ chosen { stdout-path = "/soc/serial@10000000"; - rng-seed = <0x5f758113 0x4bedcbae 0x8493ad0a 0xe997c57f 0xc946bc79 0x8236414e 0x1e1f433a 0x1282b065>; + rng-seed = <0x72c53a52 0xfcf8fc4c 0xee0c1f91 0xcefabeac 0xba9af070 0xb02709fc 0x9ddabb5d 0xc421731b>; }; soc { @@ -101,103 +101,125 @@ rtc@101000 { interrupts = <0x0b 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x101000 0x00 0x1000>; compatible = "google,goldfish-rtc"; }; serial@10000000 { interrupts = <0x0a 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; clock-frequency = "\08@"; reg = <0x00 0x10000000 0x00 0x100>; compatible = "ns16550a"; }; test@100000 { - phandle = <0x05>; + phandle = <0x07>; reg = <0x00 0x100000 0x00 0x1000>; compatible = "sifive,test1\0sifive,test0\0syscon"; }; virtio_mmio@10008000 { interrupts = <0x08 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10008000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10007000 { interrupts = <0x07 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10007000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10006000 { interrupts = <0x06 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10006000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10005000 { interrupts = <0x05 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10005000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10004000 { interrupts = <0x04 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10004000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10003000 { interrupts = <0x03 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10003000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10002000 { interrupts = <0x02 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10002000 0x00 0x1000>; compatible = "virtio,mmio"; }; virtio_mmio@10001000 { interrupts = <0x01 0x04>; - interrupt-parent = <0x04>; + interrupt-parent = <0x06>; reg = <0x00 0x10001000 0x00 0x1000>; compatible = "virtio,mmio"; }; aplic@d000000 { - phandle = <0x04>; + phandle = <0x06>; riscv,num-sources = <0x60>; reg = <0x00 0xd000000 0x00 0x8000>; - interrupts-extended = <0x02 0x09>; + msi-parent = <0x04>; interrupt-controller; #interrupt-cells = <0x02>; compatible = "riscv,aplic"; }; aplic@c000000 { - phandle = <0x03>; - riscv,delegate = <0x04 0x01 0x60>; - riscv,children = <0x04>; + phandle = <0x05>; + riscv,delegate = <0x06 0x01 0x60>; + riscv,children = <0x06>; riscv,num-sources = <0x60>; reg = <0x00 0xc000000 0x00 0x8000>; - interrupts-extended = <0x02 0x0b>; + msi-parent = <0x03>; interrupt-controller; #interrupt-cells = <0x02>; compatible = "riscv,aplic"; }; + imsics@28000000 { + phandle = <0x04>; + riscv,num-ids = <0xff>; + reg = <0x00 0x28000000 0x00 0x1000>; + interrupts-extended = <0x02 0x09>; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + + imsics@24000000 { + phandle = <0x03>; + riscv,num-ids = <0xff>; + reg = <0x00 0x24000000 0x00 0x1000>; + interrupts-extended = <0x02 0x0b>; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + clint@2000000 { interrupts-extended = <0x02 0x03 0x02 0x07>; reg = <0x00 0x2000000 0x00 0x10000>; @@ -206,9 +228,10 @@ pci@30000000 { interrupt-map-mask = <0x1800 0x00 0x00 0x07>; - interrupt-map = <0x00 0x00 0x00 0x01 0x04 0x20 0x04 0x00 0x00 0x00 0x02 0x04 0x21 0x04 0x00 0x00 0x00 0x03 0x04 0x22 0x04 0x00 0x00 0x00 0x04 0x04 0x23 0x04 0x800 0x00 0x00 0x01 0x04 0x21 0x04 0x800 0x00 0x00 0x02 0x04 0x22 0x04 0x800 0x00 0x00 0x03 0x04 0x23 0x04 0x800 0x00 0x00 0x04 0x04 0x20 0x04 0x1000 0x00 0x00 0x01 0x04 0x22 0x04 0x1000 0x00 0x00 0x02 0x04 0x23 0x04 0x1000 0x00 0x00 0x03 0x04 0x20 0x04 0x1000 0x00 0x00 0x04 0x04 0x21 0x04 0x1800 0x00 0x00 0x01 0x04 0x23 0x04 0x1800 0x00 0x00 0x02 0x04 0x20 0x04 0x1800 0x00 0x00 0x03 0x04 0x21 0x04 0x1800 0x00 0x00 0x04 0x04 0x22 0x04>; + interrupt-map = <0x00 0x00 0x00 0x01 0x06 0x20 0x04 0x00 0x00 0x00 0x02 0x06 0x21 0x04 0x00 0x00 0x00 0x03 0x06 0x22 0x04 0x00 0x00 0x00 0x04 0x06 0x23 0x04 0x800 0x00 0x00 0x01 0x06 0x21 0x04 0x800 0x00 0x00 0x02 0x06 0x22 0x04 0x800 0x00 0x00 0x03 0x06 0x23 0x04 0x800 0x00 0x00 0x04 0x06 0x20 0x04 0x1000 0x00 0x00 0x01 0x06 0x22 0x04 0x1000 0x00 0x00 0x02 0x06 0x23 0x04 0x1000 0x00 0x00 0x03 0x06 0x20 0x04 0x1000 0x00 0x00 0x04 0x06 0x21 0x04 0x1800 0x00 0x00 0x01 0x06 0x23 0x04 0x1800 0x00 0x00 0x02 0x06 0x20 0x04 0x1800 0x00 0x00 0x03 0x06 0x21 0x04 0x1800 0x00 0x00 0x04 0x06 0x22 0x04>; ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x03 0x00 0x03 0x00 0x01 0x00>; reg = <0x00 0x30000000 0x00 0x10000000>; + msi-parent = <0x04>; dma-coherent; bus-range = <0x00 0xff>; linux,pci-domain = <0x00>; 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(); diff --git a/run.bat b/run.bat index 7b16197..967b919 100644 --- a/run.bat +++ b/run.bat @@ -1,5 +1,5 @@ @echo off -qemu-system-riscv32 -M virt,aia=aplic -cpu rv32 -smp 1 -m 128M -nographic -serial mon:stdio -bios none -kernel build\kernel.elf +qemu-system-riscv32 -M virt,aia=aplic-imsic -cpu rv32 -smp 1 -m 128M -nographic -serial mon:stdio -bios none -kernel build\kernel.elf cmd /c exit -- cgit