You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/10/03 15:26:18 UTC

[incubator-nuttx] branch master updated: arch: qemu-rv: Add M-timer handling for BUILD_KERNEL

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 2fa872e304 arch: qemu-rv: Add M-timer handling for BUILD_KERNEL
2fa872e304 is described below

commit 2fa872e304bf2360638ce46fbc7ec1534ead4ce4
Author: Masayuki Ishikawa <ma...@gmail.com>
AuthorDate: Mon Oct 3 12:15:01 2022 +0900

    arch: qemu-rv: Add M-timer handling for BUILD_KERNEL
    
    Summary:
    - In RISC-V, BUILD_KERNEL uses S-mode and to use M-mode timer
      we need to handle it by using OpenSBI or self-implementation.
    - This commit adds M-timer self-implementation for BUILD_KERNEL.
    
    Impact:
    - qemu-rv only
    
    Testing:
    - Tested with rv-virt:knsh64 on qemu-6.2
    
    Signed-off-by: Masayuki Ishikawa <Ma...@jp.sony.com>
---
 arch/risc-v/src/qemu-rv/Make.defs                  |   1 +
 .../{qemu_rv_timerisr.c => qemu_rv_exception_m.S}  |  90 +++++++++++------
 arch/risc-v/src/qemu-rv/qemu_rv_irq.c              |   8 ++
 arch/risc-v/src/qemu-rv/qemu_rv_start.c            |  75 ++++++++++----
 arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c         | 109 +++++++++++++++++++++
 5 files changed, 235 insertions(+), 48 deletions(-)

diff --git a/arch/risc-v/src/qemu-rv/Make.defs b/arch/risc-v/src/qemu-rv/Make.defs
index 3033111cc3..3c5982a8b0 100644
--- a/arch/risc-v/src/qemu-rv/Make.defs
+++ b/arch/risc-v/src/qemu-rv/Make.defs
@@ -30,6 +30,7 @@ CHIP_CSRCS += qemu_rv_timerisr.c qemu_rv_allocateheap.c
 
 ifeq ($(CONFIG_BUILD_KERNEL),y)
 CHIP_CSRCS += qemu_rv_mm_init.c
+CMN_ASRCS  += qemu_rv_exception_m.S
 endif
 
 ifeq ($(CONFIG_MM_PGALLOC),y)
diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c b/arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
similarity index 55%
copy from arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c
copy to arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
index fd594f4ca6..3d6a0fcc75 100644
--- a/arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c
+++ b/arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c
+ * arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,50 +24,82 @@
 
 #include <nuttx/config.h>
 
-#include <assert.h>
-#include <stdint.h>
-#include <time.h>
-#include <debug.h>
+#include <arch/arch.h>
+#include <arch/irq.h>
+#include <arch/mode.h>
 
-#include <nuttx/arch.h>
-#include <nuttx/clock.h>
-#include <nuttx/spinlock.h>
-#include <nuttx/timers/arch_alarm.h>
-#include <arch/board/board.h>
+#include <sys/types.h>
 
-#include "riscv_internal.h"
-#include "riscv_mtimer.h"
-#include "hardware/qemu_rv_memorymap.h"
-#include "hardware/qemu_rv_clint.h"
+#include "chip.h"
+
+#include "riscv_macros.S"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define MTIMER_FREQ 10000000
+/* Provide a default section for the exeception handler. */
+
+#ifndef EXCEPTION_SECTION
+#  define EXCEPTION_SECTION .text
+#endif
+
+/****************************************************************************
+ * Public Symbols
+ ****************************************************************************/
+
+.section .text
+.balign  8
+.global  __trap_vec_m
 
 /****************************************************************************
- * Public Functions
+ * Name: __trap_vec_m
+ *
+ * Description:
+ *   All M-mode exceptions and interrupts will be handled from here. If
+ *   kernel is in S-mode delegated exceptions and interrupts are handled.
+ *
  ****************************************************************************/
 
+__trap_vec_m:
+  j    exception_m
+
 /****************************************************************************
- * Name: up_timer_initialize
+ * Name: exception_m
  *
  * Description:
- *   This function is called during start-up to initialize
- *   the timer interrupt.
+ *   Handles interrupts for m-mode
  *
  ****************************************************************************/
 
-void up_timer_initialize(void)
-{
-#ifndef CONFIG_BUILD_KERNEL
-  struct oneshot_lowerhalf_s *lower = riscv_mtimer_initialize(
-    QEMU_RV_CLINT_MTIME, QEMU_RV_CLINT_MTIMECMP,
-    RISCV_IRQ_MTIMER, MTIMER_FREQ);
+.section EXCEPTION_SECTION
+.global exception_m
+.align  8
 
-  DEBUGASSERT(lower);
+exception_m:
 
-  up_alarm_set_lowerhalf(lower);
-#endif
-}
+  /* Swap mscratch with sp */
+  /* NOTE: mscratch has been set in up_mtimer_initialize() */
+
+  csrrw     sp, mscratch, sp
+
+  /* Save the context */
+
+  save_ctx  sp
+
+  /* Handle the mtimer interrupt */
+  /* NOTE: we assume exception/interrupt only happens for mtimer */
+
+  jal       ra, qemu_rv_mtimer_interrupt
+
+  /* Restore the context */
+
+  load_ctx  sp
+
+  /* Swap mscratch with sp */
+
+  csrrw     sp, mscratch, sp
+
+  /* Return from exception */
+
+  mret
diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_irq.c b/arch/risc-v/src/qemu-rv/qemu_rv_irq.c
index 424ec2fef3..6cdffcbb2c 100644
--- a/arch/risc-v/src/qemu-rv/qemu_rv_irq.c
+++ b/arch/risc-v/src/qemu-rv/qemu_rv_irq.c
@@ -163,6 +163,14 @@ void up_enable_irq(int irq)
 
       SET_CSR(CSR_IE, IE_TIE);
     }
+#ifdef CONFIG_BUILD_KERNEL
+  else if (irq == RISCV_IRQ_MTIMER)
+    {
+      /* Read m/sstatus & set timer interrupt enable in m/sie */
+
+      SET_CSR(mie, MIE_MTIE);
+    }
+#endif
   else if (irq > RISCV_IRQ_EXT)
     {
       extirq = irq - RISCV_IRQ_EXT;
diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_start.c b/arch/risc-v/src/qemu-rv/qemu_rv_start.c
index d9aacda827..f88ed108fa 100644
--- a/arch/risc-v/src/qemu-rv/qemu_rv_start.c
+++ b/arch/risc-v/src/qemu-rv/qemu_rv_start.c
@@ -49,6 +49,34 @@
 #  error "Target requires kernel in S-mode, enable CONFIG_ARCH_USE_S_MODE"
 #endif
 
+/****************************************************************************
+ * Extern Function Declarations
+ ****************************************************************************/
+
+#ifdef CONFIG_BUILD_KERNEL
+extern void __trap_vec(void);
+extern void __trap_vec_m(void);
+extern void up_mtimer_initialize(void);
+#endif
+
+/****************************************************************************
+ * Name: qemu_rv_clear_bss
+ ****************************************************************************/
+
+void qemu_rv_clear_bss(void)
+{
+  uint32_t *dest;
+
+  /* Clear .bss.  We'll do this inline (vs. calling memset) just to be
+   * certain that there are no issues with the state of global variables.
+   */
+
+  for (dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; )
+    {
+      *dest++ = 0;
+    }
+}
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -69,8 +97,6 @@ uintptr_t g_idle_topstack = QEMU_RV_IDLESTACK_TOP;
 
 void qemu_rv_start(int mhartid)
 {
-  uint32_t *dest;
-
   /* Configure FPU */
 
   riscv_fpuconfig();
@@ -80,14 +106,9 @@ void qemu_rv_start(int mhartid)
       goto cpux;
     }
 
-  /* Clear .bss.  We'll do this inline (vs. calling memset) just to be
-   * certain that there are no issues with the state of global variables.
-   */
-
-  for (dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; )
-    {
-      *dest++ = 0;
-    }
+#ifndef CONFIG_BUILD_KERNEL
+  qemu_rv_clear_bss();
+#endif
 
   showprogress('A');
 
@@ -99,12 +120,6 @@ void qemu_rv_start(int mhartid)
 
   /* Do board initialization */
 
-#ifdef CONFIG_ARCH_USE_S_MODE
-  /* Initialize the per CPU areas */
-
-  riscv_percpu_add_hart(mhartid);
-#endif
-
   showprogress('C');
 
 #ifdef CONFIG_BUILD_KERNEL
@@ -116,6 +131,7 @@ void qemu_rv_start(int mhartid)
   nx_start();
 
 cpux:
+
 #ifdef CONFIG_SMP
   riscv_cpu_boot(mhartid);
 #endif
@@ -126,9 +142,16 @@ cpux:
     }
 }
 
-#ifdef CONFIG_ARCH_USE_S_MODE
+#ifdef CONFIG_BUILD_KERNEL
+
 void qemu_rv_start_s(int mhartid)
 {
+  qemu_rv_clear_bss();
+
+  /* Initialize the per CPU areas */
+
+  riscv_percpu_add_hart(mhartid);
+
   /* Disable MMU and enable PMP */
 
   WRITE_CSR(satp, 0x0);
@@ -151,13 +174,27 @@ void qemu_rv_start_s(int mhartid)
 
   /* Set the trap vector for S-mode */
 
-  extern void __trap_vec(void);
   WRITE_CSR(stvec, (uintptr_t)__trap_vec);
 
+  /* Set the trap vector for M-mode */
+
+  WRITE_CSR(mtvec, (uintptr_t)__trap_vec_m);
+
+  /* Initialize mtimer before entering to S-mode */
+
+  up_mtimer_initialize();
+
   /* Set mepc to the entry */
 
   WRITE_CSR(mepc, (uintptr_t)qemu_rv_start);
-  asm volatile("mret");
+
+  /* Set a0 to mhartid explicitly and enter to S-mode */
+
+  asm volatile (
+      "mv a0, %0 \n"
+      "mret \n"
+      :: "r" (mhartid)
+  );
 }
 #endif
 
diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c b/arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c
index fd594f4ca6..2e8e0a6f61 100644
--- a/arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c
+++ b/arch/risc-v/src/qemu-rv/qemu_rv_timerisr.c
@@ -37,6 +37,7 @@
 
 #include "riscv_internal.h"
 #include "riscv_mtimer.h"
+#include "riscv_percpu.h"
 #include "hardware/qemu_rv_memorymap.h"
 #include "hardware/qemu_rv_clint.h"
 
@@ -45,6 +46,55 @@
  ****************************************************************************/
 
 #define MTIMER_FREQ 10000000
+#define TICK_COUNT (10000000 / TICK_PER_SEC)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_BUILD_KERNEL
+
+/****************************************************************************
+ * Name: qemu_rv_ssoft_interrupt
+ *
+ * Description:
+ *   This function is S-mode software interrupt handler to proceed
+ *   the OS timer
+ *
+ ****************************************************************************/
+
+static int qemu_rv_ssoft_interrupt(int irq, void *context, void *arg)
+{
+  /* Cleaer Supervisor Software Interrupt */
+
+  CLEAR_CSR(sip, SIP_SSIP);
+
+  /* Proceed the OS timer */
+
+  nxsched_process_timer();
+  return 0;
+}
+
+/****************************************************************************
+ * Name: qemu_rv_reload_mtimecmp
+ *
+ * Description:
+ *   This function is called during start-up to initialize mtimecmp
+ *   for CONFIG_BUILD_KERNEL=y
+ *
+ ****************************************************************************/
+
+static void qemu_rv_reload_mtimecmp(void)
+{
+  uint64_t current;
+  uint64_t next;
+
+  current = READ_CSR(time);
+  next = current + TICK_COUNT;
+  putreg64(next, QEMU_RV_CLINT_MTIMECMP);
+}
+
+#endif /* CONFIG_BUILD_KERNEL */
 
 /****************************************************************************
  * Public Functions
@@ -69,5 +119,64 @@ void up_timer_initialize(void)
   DEBUGASSERT(lower);
 
   up_alarm_set_lowerhalf(lower);
+#else
+  /* NOTE: This function is called in S-mode */
+
+  irq_attach(RISCV_IRQ_SSOFT, qemu_rv_ssoft_interrupt, NULL);
+  up_enable_irq(RISCV_IRQ_SSOFT);
 #endif
 }
+
+#ifdef CONFIG_BUILD_KERNEL
+
+/****************************************************************************
+ * Name: up_mtimer_initialize
+ *
+ * Description:
+ *   This function is called during start-up to initialize the M-mode timer
+ *
+ ****************************************************************************/
+
+void up_mtimer_initialize(void)
+{
+  uintptr_t irqstacktop = riscv_percpu_get_irqstack();
+
+  /* Set the irq stack base to mscratch */
+
+  WRITE_CSR(mscratch,
+            irqstacktop - STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK));
+
+  /* NOTE: we do not attach a handler for mtimer,
+   * because it is handled in the exception_m directly
+   */
+
+  up_enable_irq(RISCV_IRQ_MTIMER);
+  qemu_rv_reload_mtimecmp();
+}
+
+/****************************************************************************
+ * Name: qemu_rv_mtimer_interrupt
+ *
+ * Description:
+ *   In RISC-V with S-mode, M-mode timer must be handled in M-mode
+ *   This function is called from exception_m in M-mode directly
+ *
+ ****************************************************************************/
+
+void qemu_rv_mtimer_interrupt(void)
+{
+  uint64_t current;
+  uint64_t next;
+
+  /* Update mtimercmp */
+
+  current = getreg64(QEMU_RV_CLINT_MTIMECMP);
+  next = current + TICK_COUNT;
+  putreg64(next, QEMU_RV_CLINT_MTIMECMP);
+
+  /* Post Supervisor Software Interrupt */
+
+  SET_CSR(sip, SIP_SSIP);
+}
+
+#endif /* CONFIG_BUILD_KERNEL */