nixos-riscv/opensbi-test-plic.patch

187 lines
5.3 KiB
Diff
Raw Normal View History

2024-08-21 09:22:43 +02:00
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
2024-08-21 10:03:19 +02:00
index 0ae604a..3708c3a 100644
2024-08-21 09:22:43 +02:00
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -9,6 +9,9 @@
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
+#include <sbi/sbi_console.h>
+
+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;
}
2024-08-21 10:03:19 +02:00
@@ -47,8 +52,156 @@ void sbi_irqchip_exit(struct sbi_scratch *scratch)
2024-08-21 09:22:43 +02:00
{
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)
+
2024-08-21 09:44:53 +02:00
+static void dumpregs(void)
+{
+ char *prefix = "\t";
+ char *suffix = "\t";
+ sbi_printf("Registers:\n");
+ sbi_printf("%sMIE%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIE));
+ sbi_printf("%sMIP%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIP));
+ sbi_printf("%sMSTATUS%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MSTATUS));
+ sbi_printf("%sMIDELEG%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_MIDELEG));
+ sbi_printf("%sSIE%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_SIE));
+ sbi_printf("%sSIP%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_SIP));
+ sbi_printf("%sSSTATUS%s: 0x%" PRILX "\n",
+ prefix, suffix, csr_read(CSR_SSTATUS));
+}
+
2024-08-21 09:22:43 +02:00
+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)
+{
2024-08-21 09:44:53 +02:00
+ sbi_printf("Hello from supervisor\n");
+ sbi_printf("Waiting for interrupt...\n");
2024-08-21 09:31:09 +02:00
+ int i = 0;
+ char *s = "-\\|/";
2024-08-21 09:22:43 +02:00
+ while (1) {
2024-08-21 09:44:53 +02:00
+ for (volatile unsigned long j = 0; j < 100000; j++);
2024-08-21 09:31:09 +02:00
+ sbi_printf("\r%c", s[i++]);
+ if (i >= 4)
+ i = 0;
2024-08-21 09:22:43 +02:00
+ }
+ return 0;
+}
+
2024-08-21 10:03:19 +02:00
+static void supervisor_trap_entry(void)
+{
+ sbi_printf("\nSupervisor Trap Entry Reached!\n");
+}
2024-08-21 09:22:43 +02:00
+
+static void do_plic_test(void)
+{
+ 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");
+
+
+ /* 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
2024-08-21 10:03:19 +02:00
+ asm volatile("csrw stvec, %0" : : "r"(&supervisor_trap_entry));
2024-08-21 09:22:43 +02:00
+ sbi_printf("Enabled supervisor delegation:\n");
+
2024-08-21 09:44:53 +02:00
+ dumpregs();
2024-08-21 09:22:43 +02:00
+
+ /* 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");
+
2024-08-21 09:29:22 +02:00
+// /* Enable external timer interrupts */
+// csr_set(CSR_MIE, MIE_MEIE); /* Needed? */
+// csr_set(CSR_MSTATUS, MSTATUS_MIE); /* Needed? */
2024-08-21 09:22:43 +02:00
+
+ /* Enable timer interrupt */
+ *mtimecmp = *mtime + 10000;
+
+ sbi_printf("Timer alarm programmed\n");
+ sbi_printf("Switching to supervisor\n");
+
2024-08-21 09:44:53 +02:00
+ dumpregs();
+
2024-08-21 09:22:43 +02:00
+ // 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
+ }
+}
+
+