From b7287bd4df14d07480414df479a27ec944e654ce Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Mallo Date: Wed, 21 Aug 2024 09:22:43 +0200 Subject: [PATCH] Port supervisor PLIC test to OpenSBI --- lagarto-ox.nix | 3 +- opensbi-test-plic.patch | 182 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 opensbi-test-plic.patch diff --git a/lagarto-ox.nix b/lagarto-ox.nix index dd8ee93..d55b1f6 100644 --- a/lagarto-ox.nix +++ b/lagarto-ox.nix @@ -333,7 +333,8 @@ patches = [ ./opensbi-timer-debug.patch #./opensbi-enable-meip.patch - ./opensbi-enable-seip.patch + #./opensbi-enable-seip.patch + ./opensbi-test-plic.patch ./opensbi-dump-mregs.patch #./opensbi-dont-delegate.patch #./ox-alveo-platform-plic.patch diff --git a/opensbi-test-plic.patch b/opensbi-test-plic.patch new file mode 100644 index 0000000..49c2950 --- /dev/null +++ b/opensbi-test-plic.patch @@ -0,0 +1,182 @@ +diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c +index 0ae604a..fc0c286 100644 +--- a/lib/sbi/sbi_irqchip.c ++++ b/lib/sbi/sbi_irqchip.c +@@ -9,6 +9,9 @@ + + #include + #include ++#include ++ ++static void do_plic_test(void); + + static int default_irqfn(void) + { +@@ -37,8 +40,10 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot) + if (rc) + return rc; + +- if (ext_irqfn != default_irqfn) +- csr_set(CSR_MIE, MIP_MEIP); ++ //csr_set(CSR_MIE, MIP_SEIP); ++ //csr_set(CSR_MSTATUS, MSTATUS_SIE); ++ ++ do_plic_test(); + + return 0; + } +@@ -47,8 +52,152 @@ void sbi_irqchip_exit(struct sbi_scratch *scratch) + { + const struct sbi_platform *plat = sbi_platform_ptr(scratch); + +- if (ext_irqfn != default_irqfn) +- csr_clear(CSR_MIE, MIP_MEIP); ++ //csr_clear(CSR_MIE, MIP_SEIP); ++ //csr_clear(CSR_MSTATUS, MSTATUS_SIE); + + sbi_platform_irqchip_exit(plat); + } ++ ++ ++/* ----------------- PLIC tests ---------------- */ ++ ++ ++#define MIE_MEIE (1UL << 11) // Machine External Interrupt Enable ++#define SIE_SEIE (1UL << 9) ++#define MIDELEG_SEIE (1UL << 9) // Delegate Machine External Interrupt to Supervisor ++#define PLIC_TIMER_PORT 4 ++// Base address of PLIC ++#define PLIC_BASE 0x0000000040800000UL ++#define PLIC_PRIORITY_OFFSET 0x0UL ++#define PLIC_PENDING_OFFSET 0x1000UL ++#define PLIC_ENABLE_OFFSET 0x2000UL ++#define PLIC_THRESHOLD_OFFSET 0x200000UL ++#define PLIC_CLAIM_OFFSET 0x200004UL ++ ++// Aux timer ++#define AUX_TIMER_BASE 0x40010000UL ++#define MTIMECMP_OFFSET 0x4000UL ++#define MTIME_OFFSET 0xBFF8UL ++ ++#define MSTATUS_MPP_MASK (3 << 11) ++#define MSTATUS_MPP_SUPERVISOR (1 << 11) ++ ++static void __attribute__((optimize("O0"))) switch_to_supervisor_mode(int (*target_address)(void)) ++{ ++ unsigned long mstatus; ++ ++ // Read the current mstatus ++ asm volatile("csrr %0, mstatus" : "=r"(mstatus)); ++ ++ // Set the MPP field to supervisor mode ++ mstatus = (mstatus & ~MSTATUS_MPP_MASK) | MSTATUS_MPP_SUPERVISOR; ++ ++ // Write back the modified mstatus ++ asm volatile("csrw mstatus, %0" : : "r"(mstatus)); ++ ++ // Set the mepc to the target address ++ asm volatile("csrw mepc, %0" : : "r"(target_address)); ++ ++ // Use mret to return to the specified address in supervisor mode ++ asm volatile("mret"); ++} ++ ++static int supervisor_mode_code(void) ++{ ++ sbi_printf("Hello from supervisor, waiting for interrupt\n"); ++ int count = 0; ++ while (1) { ++ if (count == 10000) { ++ sbi_printf("."); ++ count = 0; ++ } ++ count++; ++ } ++ return 0; ++} ++ ++ ++static void do_plic_test(void) ++{ ++ char *prefix = "\t"; ++ char *suffix = "\t"; ++ sbi_printf("--- TESTING PLIC ---\n"); ++ ++ volatile unsigned long *mtime = (unsigned long *)(AUX_TIMER_BASE + MTIME_OFFSET); ++ volatile unsigned long *mtimecmp = (unsigned long *)(AUX_TIMER_BASE + MTIMECMP_OFFSET); ++ ++ /* Disable auxiliar timer interrupt */ ++ *mtimecmp = 0xffffffffUL; ++ sbi_printf("Timer interrupt disabled\n"); ++ ++ sbi_printf("%sSIE%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_SIE)); ++ sbi_printf("%sSSTATUS%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_SSTATUS)); ++ sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_MIDELEG)); ++ ++ /* Enable supervisor interrupt delegation */ ++ csr_set(CSR_SIE, SIE_SEIE); // Enable supervisor external interrupts ++ csr_set(CSR_SSTATUS, SSTATUS_SIE); // Enable global interrupts in supervisor mode ++ csr_set(CSR_MIDELEG, MIDELEG_SEIE); // Delegate machine interrupts to supervisor mode ++ sbi_printf("Enabled supervisor delegation:\n"); ++ ++ sbi_printf("%sSIE%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_SIE)); ++ sbi_printf("%sSSTATUS%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_SSTATUS)); ++ sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_MIDELEG)); ++ ++ /* Configure PLIC aux timer input */ ++ volatile unsigned *plic_priority = (unsigned *)(PLIC_BASE + PLIC_PRIORITY_OFFSET + PLIC_TIMER_PORT * 4); ++ volatile unsigned *plic_enable = (unsigned *)(PLIC_BASE + PLIC_ENABLE_OFFSET); ++ volatile unsigned *plic_threshold = (unsigned *)(PLIC_BASE + PLIC_THRESHOLD_OFFSET); ++ ++ *plic_priority = PLIC_TIMER_PORT; ++ *plic_threshold = PLIC_TIMER_PORT - 1; ++ *plic_enable |= (1 << PLIC_TIMER_PORT); ++ ++ sbi_printf("Timer enabled in PLIC\n"); ++ ++ sbi_printf("%sMIE%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_MIE)); ++ sbi_printf("%sMSTATUS%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_MSTATUS)); ++ ++ /* Enable external timer interrupts */ ++ csr_set(CSR_MIE, MIE_MEIE); /* Needed? */ ++ csr_set(CSR_MSTATUS, MSTATUS_MIE); /* Needed? */ ++ ++ sbi_printf("External timer interrupts enabled in machine mode\n"); ++ ++ sbi_printf("%sMIE%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_MIE)); ++ sbi_printf("%sMSTATUS%s: 0x%" PRILX "\n", ++ prefix, suffix, csr_read(CSR_MSTATUS)); ++ ++ /* Enable timer interrupt */ ++ *mtimecmp = *mtime + 10000; ++ ++ sbi_printf("Timer alarm programmed\n"); ++ sbi_printf("Switching to supervisor\n"); ++ ++ // Switch to supervisor mode and execute supervisor_mode_code ++ switch_to_supervisor_mode(&supervisor_mode_code); ++ ++ /* Never reached */ ++ ++ int count = 0; ++ // Main loop ++ while (1) { ++ if (count == 10000) { ++ sbi_printf("Still in machine mode\n"); ++ count = 0; ++ } ++ count++; ++ // Main application code ++ } ++} ++ ++