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 <masayuki.ishik...@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 <masayuki.ishik...@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 */