From 0a6815b7143a8ffd0e09777b5fbd12098d8884c2 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Wed, 31 Dec 2025 19:00:20 +0800 Subject: dev: PILC implementation --- build/kernel.elf | Bin 154536 -> 156920 bytes build/src/drivers/plic.o | Bin 0 -> 13800 bytes build/src/kernel/trap/handler.o | Bin 65848 -> 66984 bytes include/drivers/plic.h | 17 ++++++++++++ src/drivers/plic.cc | 60 ++++++++++++++++++++++++++++++++++++++++ src/kernel/trap/handler.cc | 17 ++++++++++++ 6 files changed, 94 insertions(+) create mode 100644 build/src/drivers/plic.o create mode 100644 include/drivers/plic.h create mode 100644 src/drivers/plic.cc diff --git a/build/kernel.elf b/build/kernel.elf index 679a7bb..db7f94d 100755 Binary files a/build/kernel.elf and b/build/kernel.elf differ diff --git a/build/src/drivers/plic.o b/build/src/drivers/plic.o new file mode 100644 index 0000000..846035b Binary files /dev/null and b/build/src/drivers/plic.o differ diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o index 570f268..43346a1 100644 Binary files a/build/src/kernel/trap/handler.o and b/build/src/kernel/trap/handler.o differ diff --git a/include/drivers/plic.h b/include/drivers/plic.h new file mode 100644 index 0000000..8e8d986 --- /dev/null +++ b/include/drivers/plic.h @@ -0,0 +1,17 @@ +#pragma once +#include "common/types.h" + +namespace PILC +{ + // Global initialization (executed only once by hart 0) + void init(); + + // Per-core initialization (executed when each CPU starts) + void inithart(); + + // Claim interrupt: Get the currently occurring interrupt number (IRQ) + int claim(); + + // End of interrupt: notify the PLIC that this IRQ has been handled + void complete(int irq); +} // namespace PILC diff --git a/src/drivers/plic.cc b/src/drivers/plic.cc new file mode 100644 index 0000000..a13537c --- /dev/null +++ b/src/drivers/plic.cc @@ -0,0 +1,60 @@ +#include "common/types.h" +#include "kernel/riscv.h" +#include "drivers/plic.h" + +// QEMU Virt PLIC address constants +constexpr uint64 PLIC_BASE = 0x0c000000L; +constexpr uint64 PLIC_PRIORITY = PLIC_BASE + 0x0; +constexpr uint64 PLIC_PENDING = PLIC_BASE + 0x1000; + +// S-Mode interrupt enable register: each Hart occupies 0x100 bytes +// Context 1 is Hart 0 S-Mode, Context 3 is Hart 1 S-Mode... +inline uint64 PLIC_SENABLE(int hart) +{ + return PLIC_BASE + 0x2080 + static_cast(hart) * 0x100; +} + +// S-Mode priority threshold and claim register: 0x2000 bytes per Hart +inline uint64 PLIC_STHRESHOLD(int hart) +{ + return PLIC_BASE + 0x201000 + static_cast(hart) * 0x2000; +} + +inline uint64 PLIC_SCLAIM(int hart) +{ + return PLIC_BASE + 0x201004 + static_cast(hart) * 0x2000; +} + +namespace PILC +{ + void init() + { + *reinterpret_cast(PLIC_PRIORITY + 10 * 4) = 1; // UART + *reinterpret_cast(PLIC_PRIORITY + 1 * 4) = 1; // VirtIO 0 + } + + void inithart() + { + int hart = static_cast(r_tp()); // 获取当前 hartid + + // Enable UART and VirtIO interrupts for the current Hart's S-Mode + // Set bit 10 and bit 1 in the register bitmap + *reinterpret_cast(PLIC_SENABLE(hart)) = (1 << 10) | (1 << 1); + + // Set the current Hart's S-Mode priority threshold to 0 + // Only interrupts with a priority higher than this threshold will be delivered + *reinterpret_cast(PLIC_STHRESHOLD(hart)) = 0; + } + + int claim() + { + int hart = static_cast(r_tp()); + return *reinterpret_cast(PLIC_SCLAIM(hart)); + } + + void complete(int irq) + { + int hart = static_cast(r_tp()); + *reinterpret_cast(PLIC_SCLAIM(hart)) = static_cast(irq); + } +} // namespace PILC diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc index f7f8725..d7f78de 100644 --- a/src/kernel/trap/handler.cc +++ b/src/kernel/trap/handler.cc @@ -5,6 +5,7 @@ #include "kernel/syscall.h" #include "kernel/mm.h" #include "kernel/timer.h" +#include "drivers/plic.h" #include "lib/string.h" @@ -58,6 +59,22 @@ namespace Trap if (is_interrupt && code == 9) { // Supervisor External Interrupt (IRQ 9) + int irq = PILC::claim(); + + if (irq == 10) + { + // uart_intr(); + } + else if (irq >= 1 && irq <= 8) + { + // virtio_disk_intr(); + } + + if (irq > 0) + { + PILC::complete(irq); + } + return 1; } else if (is_interrupt && code == 5) -- cgit v1.2.3