diff --git a/arch/risc-v/src/qemu-rv/Make.defs b/arch/risc-v/src/qemu-rv/Make.defs index 3033111cc38..3c5982a8b0a 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_exception_m.S b/arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S new file mode 100644 index 00000000000..3d6a0fcc75a --- /dev/null +++ b/arch/risc-v/src/qemu-rv/qemu_rv_exception_m.S @@ -0,0 +1,105 @@ +/**************************************************************************** + * 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 + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "chip.h" + +#include "riscv_macros.S" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* 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 + +/**************************************************************************** + * 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: exception_m + * + * Description: + * Handles interrupts for m-mode + * + ****************************************************************************/ + +.section EXCEPTION_SECTION +.global exception_m +.align 8 + +exception_m: + + /* 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 424ec2fef3c..6cdffcbb2c2 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 d9aacda8274..f88ed108fac 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 fd594f4ca6c..2e8e0a6f616 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 */