From 645147a79416eb9abc0dfd70b37659f925e62772 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 17 Mar 2022 11:20:42 +0200 Subject: [PATCH 1/2] RISC-V: Implement option to run NuttX in supervisor mode (S-mode) - Add config "ARCH_USE_S_MODE" which controls whether the kernel runs in M-mode or S-mode - Add more MSTATUS and most of the SSTATUS register definitions - Add more MIP flags for interrupt delegation - Add handling of interrupts from S-mode - Add handling of FPU from S-mode - Add new context handling functions that are not dependent on the trap handlers / ecall NOTE: S-mode requires a companion SW (SBI) which is not yet implemented, thus S-mode is not usable as is, yet. --- arch/risc-v/Kconfig | 22 ++ arch/risc-v/include/csr.h | 54 +++- arch/risc-v/include/irq.h | 23 +- arch/risc-v/include/mode.h | 93 +++++++ arch/risc-v/include/syscall.h | 103 ++++---- arch/risc-v/src/Makefile | 10 + .../{ => machine}/riscv_exception_common.S | 10 +- .../src/common/{ => machine}/riscv_vectors.S | 10 +- arch/risc-v/src/common/riscv_cpuindex.c | 9 + arch/risc-v/src/common/riscv_fpu.S | 3 +- arch/risc-v/src/common/riscv_getnewintctx.c | 13 +- arch/risc-v/src/common/riscv_internal.h | 56 +++++ .../src/common/riscv_schedulesigaction.c | 25 +- arch/risc-v/src/common/riscv_swint.c | 69 ++++-- .../src/common/supervisor/riscv_context.S | 234 ++++++++++++++++++ .../supervisor/riscv_exception_common.S | 137 ++++++++++ .../supervisor/riscv_exception_macros.S | 136 ++++++++++ .../supervisor/riscv_syscall_dispatch.S | 93 +++++++ .../src/common/supervisor/riscv_vectors.S | 52 ++++ arch/risc-v/src/mpfs/mpfs_irq_dispatch.c | 2 +- .../risc-v/bl602/bl602evb/src/bl602_ostest.c | 2 + .../risc-v/c906/smartl-c906/src/c906_ostest.c | 2 + boards/risc-v/mpfs/common/src/mpfs_ostest.c | 2 + .../qemu-rv/rv-virt/src/qemu_rv_ostest.c | 2 + 24 files changed, 1050 insertions(+), 112 deletions(-) create mode 100644 arch/risc-v/include/mode.h rename arch/risc-v/src/common/{ => machine}/riscv_exception_common.S (96%) rename arch/risc-v/src/common/{ => machine}/riscv_vectors.S (88%) create mode 100644 arch/risc-v/src/common/supervisor/riscv_context.S create mode 100644 arch/risc-v/src/common/supervisor/riscv_exception_common.S create mode 100644 arch/risc-v/src/common/supervisor/riscv_exception_macros.S create mode 100644 arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S create mode 100644 arch/risc-v/src/common/supervisor/riscv_vectors.S diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index b199d393e9691..e2fed3613311e 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -101,6 +101,7 @@ config ARCH_CHIP_MPFS select ARCH_HAVE_RESET select ARCH_HAVE_SPI_CS_CONTROL select ARCH_HAVE_PWM_MULTICHAN + select ARCH_HAVE_S_MODE select PMP_HAS_LIMITED_FEATURES ---help--- MicroChip Polarfire processor (RISC-V 64bit core with GCVX extensions). @@ -188,6 +189,27 @@ config ARCH_MMU_TYPE_SV39 bool default n +config ARCH_HAVE_S_MODE + bool + default n + +# Option to run NuttX in supervisor mode. This is obviously not usable in +# flat mode, is questionable in protected mode, but is mandatory in kernel +# mode. +# +# Kernel mode requires this as M-mode uses flat addressing and the kernel +# memory must be mapped in order to share memory between the kernel and +# different user tasks which reside in virtual memory. + +config ARCH_USE_S_MODE + bool "Run the NuttX kernel in S-mode" + default n + depends on ARCH_HAVE_S_MODE && BUILD_KERNEL && ARCH_USE_MMU + ---help--- + Most of the RISC-V implementations run in M-mode (flat addressing) + and/or U-mode (in case of separate kernel-/userspaces). This provides + an option to run the kernel in S-mode, if the target supports it. + # MPU has certain architecture dependent configurations, which are presented # here. Default is that the full RISC-V PMP specification is supported. diff --git a/arch/risc-v/include/csr.h b/arch/risc-v/include/csr.h index a5cb948b0c82b..3866f6637d217 100644 --- a/arch/risc-v/include/csr.h +++ b/arch/risc-v/include/csr.h @@ -299,13 +299,27 @@ /* In mstatus register */ +#define MSTATUS_UIE (0x1 << 0) /* User Interrupt Enable */ +#define MSTATUS_SIE (0x1 << 1) /* Supervisor Interrupt Enable */ #define MSTATUS_MIE (0x1 << 3) /* Machine Interrupt Enable */ +#define MSTATUS_SPIE (0x1 << 5) /* Supervisor Previous Interrupt Enable */ #define MSTATUS_MPIE (0x1 << 7) /* Machine Previous Interrupt Enable */ +#define MSTATUS_SPPU (0x0 << 8) /* Supervisor Previous Privilege (u-mode) */ +#define MSTATUS_SPPS (0x1 << 8) /* Supervisor Previous Privilege (s-mode) */ +#define MSTATUS_MPPU (0x0 << 11) /* Machine Previous Privilege (u-mode) */ +#define MSTATUS_MPPS (0x1 << 11) /* Machine Previous Privilege (s-mode) */ #define MSTATUS_MPPM (0x3 << 11) /* Machine Previous Privilege (m-mode) */ +#define MSTATUS_MPP_MASK (0x3 << 11) #define MSTATUS_FS (0x3 << 13) /* Machine Floating-point Status */ #define MSTATUS_FS_INIT (0x1 << 13) #define MSTATUS_FS_CLEAN (0x2 << 13) #define MSTATUS_FS_DIRTY (0x3 << 13) +#define MSTATUS_MPRV (0x1 << 17) /* Modify Privilege */ +#define MSTATUS_SUM (0x1 << 18) /* S mode access to U mode memory */ +#define MSTATUS_MXR (0x1 << 19) /* Make executable / readable */ +#define MSTATUS_TVM (0x1 << 20) /* Trap access to satp from S mode */ +#define MSTATUS_TW (0x1 << 21) /* Trap WFI instruction from S mode */ +#define MSTATUS_TSR (0x1 << 22) /* Trap supervisor return (sret) */ /* Mask of preserved bits for mstatus */ @@ -317,15 +331,47 @@ /* In mie (machine interrupt enable) register */ +#define MIE_SSIE (0x1 << 1) /* Supervisor Software Interrupt Enable */ #define MIE_MSIE (0x1 << 3) /* Machine Software Interrupt Enable */ +#define MIE_STIE (0x1 << 5) /* Supervisor Timer Interrupt Enable */ #define MIE_MTIE (0x1 << 7) /* Machine Timer Interrupt Enable */ +#define MIE_SEIE (0x1 << 9) /* Supervisor External Interrupt Enable */ #define MIE_MEIE (0x1 << 11) /* Machine External Interrupt Enable */ /* In mip (machine interrupt pending) register */ -#define MIP_MTIP (0x1 << 7) +#define MIP_SSIP (0x1 << 1) +#define MIP_STIP (0x1 << 5) +#define MIP_MTIP (0x1 << 7) +#define MIP_SEIP (0x1 << 9) -#define CSR_STR(csr) #csr +/* In sstatus register (which is a view of mstatus) */ + +#define SSTATUS_SIE MSTATUS_SIE +#define SSTATUS_SPIE MSTATUS_SPIE +#define SSTATUS_SPPU MSTATUS_SPPU +#define SSTATUS_SPPS MSTATUS_SPPS +#define SSTATUS_FS MSTATUS_FS +#define SSTATUS_FS_INIT MSTATUS_FS_INIT +#define SSTATUS_FS_CLEAN MSTATUS_FS_CLEAN +#define SSTATUS_FS_DIRTY MSTATUS_FS_DIRTY +#define SSTATUS_SUM MSTATUS_SUM +#define SSTATUS_MXR MSTATUS_MXR + +/* In sie register (which is a view of mie) */ + +#define SIE_SSIE MIE_SSIE +#define SIE_STIE MIE_STIE +#define SIE_SEIE MIE_SEIE + +/* In sip register (which is a view of mip) */ + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP +#define SIP_SEIP MIP_SEIP + +#define CSR_STR(csr) #csr +#define CSR_XSTR(str) CSR_STR(str) #define READ_CSR(reg) \ ({ \ @@ -359,8 +405,8 @@ /* In pmpcfg (PMP configuration) register */ #define PMPCFG_R (1 << 0) /* readable ? */ -#define PMPCFG_W (1 << 1) /* writeable ? */ -#define PMPCFG_X (1 << 2) /* excutable ? */ +#define PMPCFG_W (1 << 1) /* writable ? */ +#define PMPCFG_X (1 << 2) /* executable ? */ #define PMPCFG_RWX_MASK (7 << 0) /* access rights mask */ #define PMPCFG_A_OFF (0 << 3) /* null region (disabled) */ #define PMPCFG_A_TOR (1 << 3) /* top of range */ diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index 4ae804c5b9df6..38e8a942f8185 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -39,6 +39,7 @@ #include #include #include +#include #endif /**************************************************************************** @@ -50,7 +51,7 @@ /* IRQ 0-15 : (exception:interrupt=0) */ #define RISCV_IRQ_IAMISALIGNED (0) /* Instruction Address Misaligned */ -#define RISCV_IRQ_IAFAULT (1) /* Instruction Address Fault */ +#define RISCV_IRQ_IAFAULT (1) /* Instruction Access Fault */ #define RISCV_IRQ_IINSTRUCTION (2) /* Illegal Instruction */ #define RISCV_IRQ_BPOINT (3) /* Break Point */ #define RISCV_IRQ_LAMISALIGNED (4) /* Load Address Misaligned */ @@ -64,7 +65,7 @@ #define RISCV_IRQ_INSTRUCTIONPF (12) /* Instruction page fault */ #define RISCV_IRQ_LOADPF (13) /* Load page fault */ #define RISCV_IRQ_RESERVED (14) /* Reserved */ -#define RISCV_IRQ_SROREPF (15) /* Store/AMO page fault */ +#define RISCV_IRQ_STOREPF (15) /* Store/AMO page fault */ #define RISCV_MAX_EXCEPTION (15) @@ -99,6 +100,16 @@ # define CONFIG_SYS_NNEST 2 #endif +/* Amount of interrupt stacks (amount of harts) */ + +#ifdef CONFIG_IRQ_NSTACKS +# define IRQ_NSTACKS CONFIG_IRQ_NSTACKS +#elif defined CONFIG_SMP +# define IRQ_NSTACKS CONFIG_SMP_NCPUS +#else +# define IRQ_NSTACKS 1 +#endif + /* Processor PC */ #define REG_EPC_NDX 0 @@ -472,7 +483,7 @@ struct xcpt_syscall_s { uintptr_t sysreturn; /* The return PC */ #ifndef CONFIG_BUILD_FLAT - uintptr_t int_ctx; /* Interrupt context (i.e. mstatus) */ + uintptr_t int_ctx; /* Interrupt context (i.e. m-/sstatus) */ #endif }; #endif @@ -580,9 +591,9 @@ static inline irqstate_t up_irq_save(void) __asm__ __volatile__ ( - "csrrc %0, mstatus, %1\n" + "csrrc %0, " CSR_XSTR(CSR_STATUS) ", %1\n" : "=r" (flags) - : "r"(MSTATUS_MIE) + : "r"(STATUS_IE) : "memory" ); @@ -605,7 +616,7 @@ static inline void up_irq_restore(irqstate_t flags) { __asm__ __volatile__ ( - "csrw mstatus, %0\n" + "csrw " CSR_XSTR(CSR_STATUS) ", %0\n" : /* no output */ : "r" (flags) : "memory" diff --git a/arch/risc-v/include/mode.h b/arch/risc-v/include/mode.h new file mode 100644 index 0000000000000..1dc7eb4762639 --- /dev/null +++ b/arch/risc-v/include/mode.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * arch/risc-v/include/mode.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_INCLUDE_MODE_H +#define __ARCH_RISCV_INCLUDE_MODE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_ARCH_USE_S_MODE + +/* CSR definitions */ + +# define CSR_STATUS sstatus /* Global status register */ +# define CSR_EPC sepc /* Exception program counter */ +# define CSR_IE sie /* Interrupt enable register */ + +/* In status register */ + +# define STATUS_IE SSTATUS_SIE /* Global interrupt enable */ +# define STATUS_PIE SSTATUS_SPIE /* Previous interrupt enable */ +# define STATUS_PPP SSTATUS_SPPS /* Previous privilege */ +# define STATUS_SUM SSTATUS_SUM /* Access to user memory */ + +/* Interrupt bits */ + +# define IE_EIE SIE_SEIE /* External interrupt enable */ +# define IE_SIE SIE_SSIE /* Software interrupt enable */ +# define IE_TIE SIE_STIE /* Timer interrupt enable */ + +/* External, timer and software interrupt */ + +# define RISCV_IRQ_EXT RISCV_IRQ_SEXT /* PLIC IRQ */ +# define RISCV_IRQ_TIMER RISCV_IRQ_STIMER /* Timer IRQ */ +# define RISCV_IRQ_SOFT RISCV_IRQ_SSOFT /* SW IRQ */ + +#else + +/* CSR definitions */ + +# define CSR_STATUS mstatus /* Global status register */ +# define CSR_EPC mepc /* Exception program counter */ +# define CSR_IE mie /* Interrupt enable register */ + +/* In status register */ + +# define STATUS_IE MSTATUS_MIE /* Global interrupt enable */ +# define STATUS_PIE MSTATUS_MPIE /* Previous interrupt enable */ +# define STATUS_PPP MSTATUS_MPPM /* Previous privilege */ +# define STATUS_SUM 0 /* Not needed in M-mode */ + +/* Interrupt bits */ + +# define IE_EIE MIE_MEIE /* External interrupt enable */ +# define IE_SIE MIE_MSIE /* Software interrupt enable */ +# define IE_TIE MIE_MTIE /* Timer interrupt enable */ + +/* External, timer and software interrupt */ + +# define RISCV_IRQ_EXT RISCV_IRQ_MEXT /* PLIC IRQ */ +# define RISCV_IRQ_TIMER RISCV_IRQ_MTIMER /* Timer IRQ */ +# define RISCV_IRQ_SOFT RISCV_IRQ_MSOFT /* SW IRQ */ + +#endif + +#endif /* __ARCH_RISCV_INCLUDE_MODE_H */ diff --git a/arch/risc-v/include/syscall.h b/arch/risc-v/include/syscall.h index a357d1d84d169..27fdd83502299 100644 --- a/arch/risc-v/include/syscall.h +++ b/arch/risc-v/include/syscall.h @@ -57,6 +57,7 @@ /* RV64GC system calls ******************************************************/ +#ifndef CONFIG_ARCH_USE_S_MODE /* SYS call 1 and 2 are defined for internal use by the RISC-V port (see * arch/risc-v/include/syscall.h). In addition, SYS call 3 is the * return from a SYS call in kernel mode. The first four syscall values must, @@ -78,6 +79,7 @@ */ #define SYS_switch_context (2) +#endif /* CONFIG_ARCH_USE_S_MODE */ #ifdef CONFIG_LIB_SYSCALL /* SYS call 3: @@ -122,51 +124,6 @@ #define SYS_signal_handler_return (7) #endif /* !CONFIG_BUILD_FLAT */ -/* sys_call macros **********************************************************/ - -#ifndef __ASSEMBLY__ - -/* Context switching system calls *******************************************/ - -/* SYS call 0: - * - * int riscv_saveusercontext(uintptr_t *saveregs); - * - * Return: - * 0: Normal Return - * 1: Context Switch Return - */ - -#define riscv_saveusercontext(saveregs) \ - (int)sys_call1(SYS_save_context, (uintptr_t)(saveregs)) - -/* SYS call 1: - * - * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function; - */ - -#define riscv_fullcontextrestore(restoreregs) \ - sys_call1(SYS_restore_context, (uintptr_t)(restoreregs)) - -/* SYS call 2: - * - * void riscv_switchcontext(uintptr_t **saveregs, uintptr_t *restoreregs); - */ - -#define riscv_switchcontext(saveregs, restoreregs) \ - sys_call2(SYS_switch_context, (uintptr_t)(saveregs), (uintptr_t)(restoreregs)) - -#ifdef CONFIG_BUILD_KERNEL -/* SYS call 3: - * - * void riscv_syscall_return(void); - */ - -#define riscv_syscall_return() sys_call0(SYS_syscall_return) - -#endif -#endif /* __ASSEMBLY__ */ - /**************************************************************************** * Public Types ****************************************************************************/ @@ -207,7 +164,15 @@ static inline uintptr_t sys_call0(unsigned int nbr) asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0) : "memory" ); @@ -232,7 +197,15 @@ static inline uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1) asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0), "r"(r1) : "memory" ); @@ -259,7 +232,15 @@ static inline uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1, asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0), "r"(r1), "r"(r2) : "memory" ); @@ -287,7 +268,15 @@ static inline uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1, asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0), "r"(r1), "r"(r2), "r"(r3) : "memory" ); @@ -317,7 +306,15 @@ static inline uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1, asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4) : "memory" ); @@ -348,7 +345,15 @@ static inline uintptr_t sys_call5(unsigned int nbr, uintptr_t parm1, asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) : "memory" ); @@ -381,7 +386,15 @@ static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, asm volatile ( +#if defined (CONFIG_ARCH_USE_S_MODE) && defined (__KERNEL__) + " addi sp, sp, -16\n" /* Make room */ + " sd ra, 0(sp)\n" /* Save ra */ + " jal ra, riscv_syscall_dispatch\n" /* Dispatch (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 16\n" /* Restore sp */ +#else "ecall" +#endif :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5), "r"(r6) : "memory" ); diff --git a/arch/risc-v/src/Makefile b/arch/risc-v/src/Makefile index f598c6fd2e30f..06c2d0bf86c7f 100644 --- a/arch/risc-v/src/Makefile +++ b/arch/risc-v/src/Makefile @@ -24,10 +24,19 @@ ifeq ($(CONFIG_OPENSBI),y) include opensbi/Make.defs endif +# Kernel runs in supervisor mode or machine mode ? + +ifeq ($(CONFIG_ARCH_USE_S_MODE),y) +ARCH_CMN_MODE_DIR = supervisor +else +ARCH_CMN_MODE_DIR = machine +endif + ARCH_SRCDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip} INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)common} +INCLUDES += ${shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)common$(DELIM)$(ARCH_CMN_MODE_DIR)} INCLUDES += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)sched} ifeq ($(CONFIG_OPENSBI),y) INCLUDES += $(shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdparty$(DELIM)include) @@ -101,6 +110,7 @@ endif VPATH += chip VPATH += common +VPATH += common$(DELIM)$(ARCH_CMN_MODE_DIR) ifeq ($(CONFIG_OPENSBI),y) VPATH += opensbi endif diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/machine/riscv_exception_common.S similarity index 96% rename from arch/risc-v/src/common/riscv_exception_common.S rename to arch/risc-v/src/common/machine/riscv_exception_common.S index 4d5665ac2dc4a..8a43a16b01e8e 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/machine/riscv_exception_common.S @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/risc-v/src/common/riscv_exception_common.S + * arch/risc-v/src/common/machine/riscv_exception_common.S * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -37,14 +37,6 @@ # define REGSTORE sd #endif -#ifdef CONFIG_IRQ_NSTACKS -# define IRQ_NSTACKS CONFIG_IRQ_NSTACKS -#elif defined CONFIG_SMP -# define IRQ_NSTACKS CONFIG_SMP_NCPUS -#else -# define IRQ_NSTACKS 1 -#endif - /**************************************************************************** * Name: exception_common ****************************************************************************/ diff --git a/arch/risc-v/src/common/riscv_vectors.S b/arch/risc-v/src/common/machine/riscv_vectors.S similarity index 88% rename from arch/risc-v/src/common/riscv_vectors.S rename to arch/risc-v/src/common/machine/riscv_vectors.S index d7f0163d4412f..ac2959a3fb1df 100644 --- a/arch/risc-v/src/common/riscv_vectors.S +++ b/arch/risc-v/src/common/machine/riscv_vectors.S @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/risc-v/src/common/riscv_vectors.S + * arch/risc-v/src/common/machine/riscv_vectors.S * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -23,11 +23,15 @@ ****************************************************************************/ .section .text - .balign 4 + .balign 8 .global __trap_vec /**************************************************************************** - * Name: exception_common + * Name: __trap_vec + * + * Description: + * All M-mode exceptions and interrupts will be handled from here. + * ****************************************************************************/ __trap_vec: diff --git a/arch/risc-v/src/common/riscv_cpuindex.c b/arch/risc-v/src/common/riscv_cpuindex.c index fbf4e9face411..201fa0639a1c6 100644 --- a/arch/risc-v/src/common/riscv_cpuindex.c +++ b/arch/risc-v/src/common/riscv_cpuindex.c @@ -47,7 +47,16 @@ uintptr_t riscv_mhartid(void) { +#ifdef CONFIG_ARCH_USE_S_MODE + /* Kernel is in S-mode */ + +#error "Missing functionality..." + +#else + /* Kernel is in M-mode */ + return READ_CSR(mhartid); +#endif } /**************************************************************************** diff --git a/arch/risc-v/src/common/riscv_fpu.S b/arch/risc-v/src/common/riscv_fpu.S index ba35db263f21f..69ffecb863f6a 100644 --- a/arch/risc-v/src/common/riscv_fpu.S +++ b/arch/risc-v/src/common/riscv_fpu.S @@ -25,6 +25,7 @@ #include #include +#include #ifdef CONFIG_ARCH_FPU @@ -92,7 +93,7 @@ up_fpuconfig: li a0, FS_INITIAL - csrs mstatus, a0 + csrs CSR_STATUS, a0 csrwi fcsr, 0 ret diff --git a/arch/risc-v/src/common/riscv_getnewintctx.c b/arch/risc-v/src/common/riscv_getnewintctx.c index 04180f7abb713..713c8413883cf 100644 --- a/arch/risc-v/src/common/riscv_getnewintctx.c +++ b/arch/risc-v/src/common/riscv_getnewintctx.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "riscv_internal.h" @@ -49,23 +50,23 @@ uintptr_t riscv_get_newintctx(void) { - /* Set machine previous privilege mode to machine mode. Reegardless of + /* Set machine previous privilege mode to privileged mode. Regardless of * how NuttX is configured and of what kind of thread is being started. * That is because all threads, even user-mode threads will start in * kernel trampoline at nxtask_start() or pthread_start(). * The thread's privileges will be dropped before transitioning to - * user code. Also set machine previous interrupt enable. + * user code. Also set machine / supervisor previous interrupt enable. * * Mask the bits which should be preserved (from ISA spec) */ - uintptr_t mstatus = READ_CSR(mstatus); + uintptr_t status = READ_CSR(CSR_STATUS); - mstatus &= MSTATUS_WPRI; + status &= MSTATUS_WPRI; - return (mstatus | MSTATUS_MPPM | MSTATUS_MPIE + return (status | STATUS_PPP | STATUS_SUM | STATUS_PIE #ifdef CONFIG_ARCH_FPU - | MSTATUS_FS_INIT + | MSTATUS_FS_INIT #endif ); } diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index be7967e8ecb21..b413d754e9eec 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -32,6 +32,7 @@ # include # include # include +# include #endif /**************************************************************************** @@ -201,6 +202,7 @@ void riscv_copystate(uintptr_t *dest, uintptr_t *src); void riscv_sigdeliver(void); int riscv_swint(int irq, void *context, void *arg); +void *riscv_handle_syscall(uintptr_t *regs); uintptr_t riscv_get_newintctx(void); #ifdef CONFIG_ARCH_FPU @@ -283,6 +285,60 @@ int riscv_pause_handler(int irq, void *c, void *arg); uintptr_t riscv_mhartid(void); +#ifdef CONFIG_ARCH_USE_S_MODE +/* If kernel runs in Supervisor mode, declare proper function prototypes, + * this is because it is not possible to ecall from S mode to S mode + */ + +int riscv_saveusercontext(uintptr_t *saveregs); +void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function; +void riscv_switchcontext(uintptr_t **saveregs, uintptr_t *restoreregs); +void riscv_syscall_return(void); +void riscv_syscall_dispatch(void) noreturn_function; + +#else + +/* Context switching via system calls ***************************************/ + +/* SYS call 0: + * + * int riscv_saveusercontext(uintptr_t *saveregs); + * + * Return: + * 0: Normal Return + * 1: Context Switch Return + */ + +#define riscv_saveusercontext(saveregs) \ + sys_call1(SYS_save_context, (uintptr_t)saveregs) + +/* SYS call 1: + * + * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function; + */ + +#define riscv_fullcontextrestore(restoreregs) \ + sys_call1(SYS_restore_context, (uintptr_t)restoreregs) + +/* SYS call 2: + * + * void riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs); + */ + +#define riscv_switchcontext(saveregs, restoreregs) \ + sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs) + +#ifdef CONFIG_BUILD_KERNEL +/* SYS call 3: + * + * void riscv_syscall_return(void); + */ + +#define riscv_syscall_return() sys_call0(SYS_syscall_return) + +#endif /* CONFIG_BUILD_KERNEL */ +#endif /* CONFIG_ARCH_USE_S_MODE */ + #undef EXTERN #ifdef __cplusplus } diff --git a/arch/risc-v/src/common/riscv_schedulesigaction.c b/arch/risc-v/src/common/riscv_schedulesigaction.c index e8c5eab946a45..a68b077c2764d 100644 --- a/arch/risc-v/src/common/riscv_schedulesigaction.c +++ b/arch/risc-v/src/common/riscv_schedulesigaction.c @@ -146,12 +146,13 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * privileged thread mode. */ - tcb->xcp.sigdeliver = sigdeliver; - CURRENT_REGS[REG_EPC] = (uintptr_t)riscv_sigdeliver; - int_ctx = CURRENT_REGS[REG_INT_CTX]; - int_ctx &= ~MSTATUS_MPIE; + tcb->xcp.sigdeliver = sigdeliver; + CURRENT_REGS[REG_EPC] = (uintptr_t)riscv_sigdeliver; + + int_ctx = CURRENT_REGS[REG_INT_CTX]; + int_ctx &= ~STATUS_PIE; #ifndef CONFIG_BUILD_FLAT - int_ctx |= MSTATUS_MPPM; + int_ctx |= STATUS_PPP; #endif CURRENT_REGS[REG_INT_CTX] = int_ctx; @@ -201,7 +202,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_EPC] = (uintptr_t)riscv_sigdeliver; int_ctx = tcb->xcp.regs[REG_INT_CTX]; - int_ctx &= ~MSTATUS_MPIE; + int_ctx &= ~STATUS_PIE; tcb->xcp.regs[REG_INT_CTX] = int_ctx; @@ -312,9 +313,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_EPC] = (uintptr_t)riscv_sigdeliver; int_ctx = tcb->xcp.regs[REG_INT_CTX]; - int_ctx &= ~MSTATUS_MPIE; -#ifdef CONFIG_BUILD_PROTECTED - int_ctx |= MSTATUS_MPPM; + int_ctx &= ~STATUS_PIE; +#ifndef CONFIG_BUILD_FLAT + int_ctx |= STATUS_PPP; #endif tcb->xcp.regs[REG_INT_CTX] = int_ctx; } @@ -353,9 +354,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_EPC] = (uintptr_t)riscv_sigdeliver; int_ctx = CURRENT_REGS[REG_INT_CTX]; - int_ctx &= ~MSTATUS_MPIE; + int_ctx &= ~STATUS_PIE; #ifndef CONFIG_BUILD_FLAT - int_ctx |= MSTATUS_MPPM; + int_ctx |= STATUS_PPP; #endif CURRENT_REGS[REG_INT_CTX] = int_ctx; @@ -429,7 +430,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_EPC] = (uintptr_t)riscv_sigdeliver; int_ctx = tcb->xcp.regs[REG_INT_CTX]; - int_ctx &= ~MSTATUS_MPIE; + int_ctx &= ~STATUS_PIE; tcb->xcp.regs[REG_INT_CTX] = int_ctx; } diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index 7d14148e1ca1d..0017fafe6bffd 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -114,7 +114,7 @@ static void dispatch_syscall(void) { asm volatile ( - " addi sp, sp, -8\n" /* Create a stack frame to hold ra */ + " addi sp, sp, -16\n" /* Create a stack frame to hold ra */ " sd ra, 0(sp)\n" /* Save ra in the stack frame */ " la t0, g_stublookup\n" /* t0=The base of the stub lookup table */ " slli a0, a0, 3\n" /* a0=Offset for the stub lookup table */ @@ -122,10 +122,14 @@ static void dispatch_syscall(void) " ld t0, 0(t0)\n" /* t0=The address of the stub for this syscall */ " jalr ra, t0\n" /* Call the stub (modifies ra) */ " ld ra, 0(sp)\n" /* Restore ra */ - " addi sp, sp, 8\n" /* Destroy the stack frame */ + " addi sp, sp, 16\n" /* Destroy the stack frame */ " mv a2, a0\n" /* a2=Save return value in a0 */ " li a0, 3\n" /* a0=SYS_syscall_return (3) */ +#ifdef CONFIG_ARCH_USE_S_MODE + " j riscv_syscall_return" /* Return from the syscall */ +#else " ecall" /* Return from the syscall */ +#endif ); } #else @@ -144,7 +148,11 @@ static void dispatch_syscall(void) " addi sp, sp, 4\n" /* Destroy the stack frame */ " mv a2, a0\n" /* a2=Save return value in a0 */ " li a0, 3\n" /* a0=SYS_syscall_return (3) */ +#ifdef CONFIG_ARCH_USE_S_MODE + " j riscv_syscall_return" /* Return from the syscall */ +#else " ecall" /* Return from the syscall */ +#endif ); } #endif @@ -179,6 +187,31 @@ int riscv_swint(int irq, void *context, void *arg) riscv_registerdump(regs); #endif + /* Handle the syscall */ + + regs = riscv_handle_syscall(regs); + + /* Report what happened. That might difficult in the case of a context + * switch + */ + +#ifdef CONFIG_DEBUG_SYSCALL_INFO + if (regs != CURRENT_REGS) + { + svcinfo("SWInt Return: Context switch!\n"); + riscv_registerdump((const uintptr_t *)CURRENT_REGS); + } + else + { + svcinfo("SWInt Return: %d\n", regs[REG_A0]); + } +#endif + + return OK; +} + +void *riscv_handle_syscall(uintptr_t *regs) +{ /* Handle the SWInt according to the command in $a0 */ switch (regs[REG_A0]) @@ -196,6 +229,7 @@ int riscv_swint(int irq, void *context, void *arg) * save register space references in the saved A1 and return. */ +#ifndef CONFIG_ARCH_USE_S_MODE case SYS_save_context: { DEBUGASSERT(regs[REG_A1] != 0); @@ -253,6 +287,7 @@ int riscv_swint(int irq, void *context, void *arg) CURRENT_REGS = (uintptr_t *)regs[REG_A2]; } break; +#endif /* CONFIG_ARCH_USE_S_MODE */ /* A0=SYS_syscall_return: This is a SYSCALL return command: * @@ -352,7 +387,7 @@ int riscv_swint(int irq, void *context, void *arg) regs[REG_A0] = regs[REG_A2]; /* argc */ regs[REG_A1] = regs[REG_A3]; /* argv */ #endif - regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */ + regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */ } break; #endif @@ -384,7 +419,7 @@ int riscv_swint(int irq, void *context, void *arg) regs[REG_A0] = regs[REG_A2]; /* pthread entry */ regs[REG_A1] = regs[REG_A3]; /* arg */ - regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */ + regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */ } break; #endif @@ -423,7 +458,7 @@ int riscv_swint(int irq, void *context, void *arg) regs[REG_EPC] = (uintptr_t)ARCH_DATA_RESERVE->ar_sigtramp & ~1; #endif - regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */ + regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */ /* Change the parameter ordering to match the expectation of struct * userpace_s signal_handler. @@ -473,7 +508,7 @@ int riscv_swint(int irq, void *context, void *arg) DEBUGASSERT(rtcb->xcp.sigreturn != 0); regs[REG_EPC] = rtcb->xcp.sigreturn & ~1; - regs[REG_INT_CTX] |= MSTATUS_MPPM; /* Machine mode */ + regs[REG_INT_CTX] |= STATUS_PPP; /* Privileged mode */ rtcb->xcp.sigreturn = 0; @@ -521,7 +556,7 @@ int riscv_swint(int irq, void *context, void *arg) rtcb->xcp.syscall[index].sysreturn = regs[REG_EPC]; #ifndef CONFIG_BUILD_FLAT - rtcb->xcp.syscall[index].int_ctx = regs[REG_INT_CTX]; + rtcb->xcp.syscall[index].int_ctx = regs[REG_INT_CTX]; #endif rtcb->xcp.nsyscalls = index + 1; @@ -529,7 +564,7 @@ int riscv_swint(int irq, void *context, void *arg) regs[REG_EPC] = (uintptr_t)dispatch_syscall & ~1; #ifndef CONFIG_BUILD_FLAT - regs[REG_INT_CTX] |= MSTATUS_MPPM; /* Machine mode */ + regs[REG_INT_CTX] |= STATUS_PPP; /* Privileged mode */ #endif /* Offset A0 to account for the reserved values */ @@ -559,21 +594,5 @@ int riscv_swint(int irq, void *context, void *arg) break; } - /* Report what happened. That might difficult in the case of a context - * switch - */ - -#ifdef CONFIG_DEBUG_SYSCALL_INFO - if (regs != CURRENT_REGS) - { - svcinfo("SWInt Return: Context switch!\n"); - riscv_registerdump((const uintptr_t *)CURRENT_REGS); - } - else - { - svcinfo("SWInt Return: %d\n", regs[REG_A0]); - } -#endif - - return OK; + return regs; } diff --git a/arch/risc-v/src/common/supervisor/riscv_context.S b/arch/risc-v/src/common/supervisor/riscv_context.S new file mode 100644 index 0000000000000..f27e56fe918ae --- /dev/null +++ b/arch/risc-v/src/common/supervisor/riscv_context.S @@ -0,0 +1,234 @@ +/**************************************************************************** + * arch/risc-v/src/common/supervisor/riscv_context.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. + * + ****************************************************************************/ + +.file "riscv_context.S" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "riscv_exception_macros.S" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .globl riscv_saveusercontext + .globl riscv_fullcontextrestore + .globl riscv_switchcontext + .globl riscv_syscall_return + +/**************************************************************************** + * Name: riscv_saveusercontext + * + * Description: + * Save user context, partially destroys the caller's context + * + * C Function Prototype: + * int riscv_saveusercontext(uintptr_t *saveregs); + * + * Input Parameters: + * saveregs - Context to save + * + * Returned Value: + * 0 on context switch + * 1 on no context switch + * + * Assumptions: + * Global interrupts disabled by the caller. + * + ****************************************************************************/ + +.type riscv_saveusercontext, function + +riscv_saveusercontext: + + save_ctx a0 /* save context */ + + csrr s0, CSR_STATUS + REGSTORE s0, REG_INT_CTX(a0) /* save status */ + + REGSTORE x1, REG_EPC(a0) /* save ra to epc */ + REGSTORE sp, REG_SP(a0) /* original SP */ + +#ifdef CONFIG_ARCH_FPU + jal x1, riscv_savefpu /* FP registers */ + REGLOAD x1, REG_X1(a0) /* restore ra */ +#endif + + li s0, 1 /* return 1 (in context) */ + REGSTORE s0, REG_A0(a0) + REGLOAD s0, REG_S0(a0) /* restore s0 */ + + li a0, 0 /* return 0 (back to caller) */ + ret + +/**************************************************************************** + * Name: riscv_fullcontextrestore + * + * Description: + * Restore context + * + * C Function Prototype: + * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function; + * + * Input Parameters: + * restoreregs - Context to restore + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts disabled by the caller. + * + ****************************************************************************/ + +.type riscv_fullcontextrestore, function + +riscv_fullcontextrestore: + +#ifdef CONFIG_ARCH_FPU + jal x1, riscv_restorefpu /* FP registers */ +#endif + + mv sp, a0 /* use sp, as a0 gets wiped */ + + REGLOAD s0, REG_EPC(sp) /* restore epc */ + csrw CSR_EPC, s0 + + /* Restore status register, but don't enable interrupts yet */ + + REGLOAD s0, REG_INT_CTX(sp) /* restore status */ + li s1, STATUS_IE /* move IE -> PIE */ + and s1, s0, s1 /* if (STATUS & IE) */ + beqz s1, 1f + li s1, ~STATUS_IE /* clear IE */ + and s0, s0, s1 + li s1, STATUS_PIE /* set PIE */ + or s0, s0, s1 + +1: + csrw CSR_STATUS, s0 + + load_ctx sp + + REGLOAD sp, REG_SP(sp) /* restore original sp */ + + /* return from exception, which updates the status register */ + + sret + +/**************************************************************************** + * Name: riscv_switchcontext + * + * Description: + * Restore user context + * + * C Function Prototype: + * void riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs); + * + * Input Parameters: + * saveregs - Context to save + * restoreregs - Context to restore + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts disabled by the caller. + * + ****************************************************************************/ + +.type riscv_switchcontext, function + +riscv_switchcontext: + + /* Save old context to arg[0] */ + + save_ctx a0 /* save context */ + + REGSTORE x1, REG_EPC(a0) /* save ra to epc */ + REGSTORE sp, REG_SP(a0) /* original SP */ + + /* Set previous privilege, we are in privileged mode now */ + + csrr s0, CSR_STATUS /* read status register */ + li s1, STATUS_PPP /* set previous privilege */ + or s0, s0, s1 + li s1, ~STATUS_PIE /* clear previous interrupt enable */ + and s0, s0, s1 + REGSTORE s0, REG_INT_CTX(a0) /* store status to context */ + +#ifdef CONFIG_ARCH_FPU + jal x1, riscv_savefpu /* FP registers */ +#endif + + /* Load new context from arg[1] */ + + mv a0, a1 /* load from a1 */ + j riscv_fullcontextrestore /* restore context */ + +/**************************************************************************** + * Name: riscv_syscall_return + * + * Description: + * Return from system call to user task with user mode privileges + * + * C Function Prototype: + * void riscv_syscall_return(void); + * + * Input Parameters: + * Assumes the return value of the system call is in a0 + * + * Returned Value: + * Return value of system call is returned into contex + * + * Assumptions: + * User task is running system call in privileged mode, ready to resume + * the user task in unprivileged mode + * + ****************************************************************************/ + +.type riscv_syscall_return, function + +riscv_syscall_return: + + addi sp, sp, -XCPTCONTEXT_SIZE /* make room */ + save_ctx sp /* save current context */ + + /* Mask interrupts here, they will be re-enabled later */ + + li s0, STATUS_IE + csrc CSR_STATUS, s0 + + addi s0, sp, XCPTCONTEXT_SIZE + REGSTORE s0, REG_SP(sp) /* original SP */ + + mv a0, sp /* a0 = context */ + jal x1, riscv_handle_syscall /* run the exit function */ + + j riscv_fullcontextrestore /* resume the user task */ diff --git a/arch/risc-v/src/common/supervisor/riscv_exception_common.S b/arch/risc-v/src/common/supervisor/riscv_exception_common.S new file mode 100644 index 0000000000000..73b633aaf423c --- /dev/null +++ b/arch/risc-v/src/common/supervisor/riscv_exception_common.S @@ -0,0 +1,137 @@ +/**************************************************************************** + * arch/risc-v/src/common/supervisor/riscv_exception_common.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 "riscv_exception_macros.S" + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + +/**************************************************************************** + * Name: exception_common + * + * Description: + * Handles delegated interrupts in S-mode interrupt handler. + * + ****************************************************************************/ + + .section .text + .global exception_common + .align 8 + +exception_common: + + addi sp, sp, -XCPTCONTEXT_SIZE + save_ctx sp + + csrr s0, sstatus + REGSTORE s0, REG_INT_CTX(sp) /* sstatus */ + + addi s0, sp, XCPTCONTEXT_SIZE + REGSTORE s0, REG_X2(sp) /* original SP */ + + /* Setup arg0(exception cause), arg1(context) */ + + csrr a0, scause /* exception cause */ + csrr s0, sepc + REGSTORE s0, REG_EPC(sp) /* exception PC */ + + mv a1, sp /* context = sp */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 + + /* Offset to hartid */ + + mv s0, a0 /* save scause */ + jal x1, riscv_mhartid /* get hartid */ + + /* Switch to interrupt stack */ + +#if IRQ_NSTACKS > 1 + li t0, (CONFIG_ARCH_INTERRUPTSTACK & ~15) + mul t0, a0, t0 + la a0, g_intstacktop + sub sp, a0, t0 +#else + la sp, g_intstacktop +#endif + + mv a0, s0 /* restore scause */ + + /* Call interrupt handler in C */ + + jal x1, riscv_dispatch_irq + +#else + /* Reserve some space for CURRENT_REGS if interrupt stack disabled */ + + addi sp, sp, -XCPTCONTEXT_SIZE + + /* Call interrupt handler in C */ + + jal x1, riscv_dispatch_irq + + /* Restore sp */ + + addi sp, sp, XCPTCONTEXT_SIZE +#endif + + /* If context switch is needed, return a new sp */ + + mv sp, a0 + + REGLOAD s0, REG_EPC(sp) /* restore sepc */ + csrw sepc, s0 + + REGLOAD s0, REG_INT_CTX(sp) /* restore sstatus */ + csrw sstatus, s0 + + load_ctx sp + + REGLOAD sp, REG_SP(sp) /* restore original sp */ + + /* Return from Supervisor Interrupt */ + + sret + +/***************************************************************************** + * Name: g_intstackalloc and g_intstacktop + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK > 15 + .bss + .balign 16 + .global g_intstackalloc + .global g_intstacktop + .type g_intstackalloc, object + .type g_intstacktop, object +g_intstackalloc: + .skip (((CONFIG_ARCH_INTERRUPTSTACK * IRQ_NSTACKS) + 8) & ~15) +g_intstacktop: + .size g_intstacktop, 0 + .size g_intstackalloc, ((CONFIG_ARCH_INTERRUPTSTACK * IRQ_NSTACKS) & ~15) +#endif diff --git a/arch/risc-v/src/common/supervisor/riscv_exception_macros.S b/arch/risc-v/src/common/supervisor/riscv_exception_macros.S new file mode 100644 index 0000000000000..ec4dc78fa3f3c --- /dev/null +++ b/arch/risc-v/src/common/supervisor/riscv_exception_macros.S @@ -0,0 +1,136 @@ +/**************************************************************************** + * arch/risc-v/src/common/supervisor/riscv_exception_macros.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. + * + ****************************************************************************/ + +.file "riscv_exception_macros.S" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_ARCH_RV32 +# define REGLOAD lw +# define REGSTORE sw +#else +# define REGLOAD ld +# define REGSTORE sd +#endif + +/**************************************************************************** + * Name: save_ctx + * + * Parameter: + * in - Pointer to where the save is performed (e.g. sp) + * + * Description: + * Save the common context registers (i.e. work / temp / etc). + * + ****************************************************************************/ + +.macro save_ctx in + + REGSTORE x1, REG_X1(\in) /* ra */ +#ifdef RISCV_SAVE_GP + REGSTORE x3, REG_X3(\in) /* gp */ +#endif + REGSTORE x4, REG_X4(\in) /* tp */ + REGSTORE x5, REG_X5(\in) /* t0 */ + REGSTORE x6, REG_X6(\in) /* t1 */ + REGSTORE x7, REG_X7(\in) /* t2 */ + REGSTORE x8, REG_X8(\in) /* s0 */ + REGSTORE x9, REG_X9(\in) /* s1 */ + REGSTORE x10, REG_X10(\in) /* a0 */ + REGSTORE x11, REG_X11(\in) /* a1 */ + REGSTORE x12, REG_X12(\in) /* a2 */ + REGSTORE x13, REG_X13(\in) /* a3 */ + REGSTORE x14, REG_X14(\in) /* a4 */ + REGSTORE x15, REG_X15(\in) /* a5 */ + REGSTORE x16, REG_X16(\in) /* a6 */ + REGSTORE x17, REG_X17(\in) /* a7 */ + REGSTORE x18, REG_X18(\in) /* s2 */ + REGSTORE x19, REG_X19(\in) /* s3 */ + REGSTORE x20, REG_X20(\in) /* s4 */ + REGSTORE x21, REG_X21(\in) /* s5 */ + REGSTORE x22, REG_X22(\in) /* s6 */ + REGSTORE x23, REG_X23(\in) /* s7 */ + REGSTORE x24, REG_X24(\in) /* s8 */ + REGSTORE x25, REG_X25(\in) /* s9 */ + REGSTORE x26, REG_X26(\in) /* s10 */ + REGSTORE x27, REG_X27(\in) /* s11 */ + REGSTORE x28, REG_X28(\in) /* t3 */ + REGSTORE x29, REG_X29(\in) /* t4 */ + REGSTORE x30, REG_X30(\in) /* t5 */ + REGSTORE x31, REG_X31(\in) /* t6 */ + +.endm + +/**************************************************************************** + * Name: load_ctx + * + * Parameter: + * out - Pointer to where the load is performed (e.g. sp) + * + * Description: + * Load the common context registers (i.e. work / temp / etc). + * + ****************************************************************************/ + +.macro load_ctx out + + REGLOAD x1, REG_X1(\out) /* ra */ +#ifdef RISCV_SAVE_GP + REGLOAD x3, REG_X3(\out) /* gp */ +#endif + REGLOAD x4, REG_X4(\out) /* tp */ + REGLOAD x5, REG_X5(\out) /* t0 */ + REGLOAD x6, REG_X6(\out) /* t1 */ + REGLOAD x7, REG_X7(\out) /* t2 */ + REGLOAD x8, REG_X8(\out) /* s0 */ + REGLOAD x9, REG_X9(\out) /* s1 */ + REGLOAD x10, REG_X10(\out) /* a0 */ + REGLOAD x11, REG_X11(\out) /* a1 */ + REGLOAD x12, REG_X12(\out) /* a2 */ + REGLOAD x13, REG_X13(\out) /* a3 */ + REGLOAD x14, REG_X14(\out) /* a4 */ + REGLOAD x15, REG_X15(\out) /* a5 */ + REGLOAD x16, REG_X16(\out) /* a6 */ + REGLOAD x17, REG_X17(\out) /* a7 */ + REGLOAD x18, REG_X18(\out) /* s2 */ + REGLOAD x19, REG_X19(\out) /* s3 */ + REGLOAD x20, REG_X20(\out) /* s4 */ + REGLOAD x21, REG_X21(\out) /* s5 */ + REGLOAD x22, REG_X22(\out) /* s6 */ + REGLOAD x23, REG_X23(\out) /* s7 */ + REGLOAD x24, REG_X24(\out) /* s8 */ + REGLOAD x25, REG_X25(\out) /* s9 */ + REGLOAD x26, REG_X26(\out) /* s10 */ + REGLOAD x27, REG_X27(\out) /* s11 */ + REGLOAD x28, REG_X28(\out) /* t3 */ + REGLOAD x29, REG_X29(\out) /* t4 */ + REGLOAD x30, REG_X30(\out) /* t5 */ + REGLOAD x31, REG_X31(\out) /* t6 */ + +.endm diff --git a/arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S b/arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S new file mode 100644 index 0000000000000..348d431575808 --- /dev/null +++ b/arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.S @@ -0,0 +1,93 @@ +/**************************************************************************** + * arch/risc-v/src/common/supervisor/riscv_syscall_dispatch.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. + * + ****************************************************************************/ + +.file "riscv_syscall_dispatch.S" + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "riscv_exception_macros.S" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .globl riscv_syscall_dispatch + +/**************************************************************************** + * Name: riscv_syscall_dispatch + * + * Description: + * Dispatch syscall from kernel, return to user mode + * + * C Function Prototype: + * void riscv_syscall_dispatch(void); + * + * Input Parameters: + * Assumes the context to return is already set up + * + * Returned Value: + * Return value of system call is returned into contex + * + * Assumptions: + * User task is running in privileged mode with interrupts masked, + * ready to resume the user task in unprivileged mode with interrupts + * restored + * + ****************************************************************************/ + +.type riscv_syscall_dispatch, function + +riscv_syscall_dispatch: + + addi sp, sp, -XCPTCONTEXT_SIZE /* make room */ + save_ctx sp /* save current context */ + + REGSTORE x1, REG_EPC(sp) /* save ra to epc */ + + addi s0, sp, XCPTCONTEXT_SIZE + REGSTORE s0, REG_SP(sp) /* original SP */ + + /* Set previous privilege, we are in privileged mode now */ + + csrr s0, CSR_STATUS /* read status register */ + li s1, STATUS_PPP /* set previous privilege */ + or s0, s0, s1 + li s1, ~STATUS_PIE /* clear previous interrupt enable */ + and s0, s0, s1 + REGSTORE s0, REG_INT_CTX(sp) /* store status to context */ + +#ifdef CONFIG_ARCH_FPU + mv a0, sp + jal x1, riscv_savefpu /* FP registers */ +#endif + + mv a0, sp /* a0 = context */ + jal x1, riscv_handle_syscall /* run the syscall */ + + j riscv_fullcontextrestore /* resume the user task */ diff --git a/arch/risc-v/src/common/supervisor/riscv_vectors.S b/arch/risc-v/src/common/supervisor/riscv_vectors.S new file mode 100644 index 0000000000000..b77ff3351d182 --- /dev/null +++ b/arch/risc-v/src/common/supervisor/riscv_vectors.S @@ -0,0 +1,52 @@ +/**************************************************************************** + * arch/risc-v/src/common/supervisor/riscv_vectors.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 + ****************************************************************************/ + + .section .text + .balign 8 + .global __trap_vec + .global __irq_vec + +/**************************************************************************** + * Name: __trap_vec + * + * Description: + * All M-mode exceptions and interrupts will be handled from here. + * + ****************************************************************************/ + +__trap_vec: + j trap_vector + nop + + /**************************************************************************** + * Name: __irq_vec + * + * Description: + * All S-mode exceptions and interrupts will be handled from here. + * + ****************************************************************************/ + +__irq_vec: + j exception_common + nop diff --git a/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c b/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c index 1e420c0c78cbc..a16e6e0175d6d 100755 --- a/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c +++ b/arch/risc-v/src/mpfs/mpfs_irq_dispatch.c @@ -60,7 +60,7 @@ void *riscv_dispatch_irq(uintptr_t vector, uintptr_t *regs) if (vector < RISCV_IRQ_ECALLU || vector == RISCV_IRQ_INSTRUCTIONPF || vector == RISCV_IRQ_LOADPF || - vector == RISCV_IRQ_SROREPF || + vector == RISCV_IRQ_STOREPF || vector == RISCV_IRQ_RESERVED) { riscv_fault(irq, regs); diff --git a/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c b/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c index 3d3f02993867e..bd11c4e3b6ba1 100644 --- a/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c +++ b/boards/risc-v/bl602/bl602evb/src/bl602_ostest.c @@ -31,6 +31,8 @@ #include +#include "riscv_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/boards/risc-v/c906/smartl-c906/src/c906_ostest.c b/boards/risc-v/c906/smartl-c906/src/c906_ostest.c index f3a5c8a6e4981..dd6bc11fe8817 100644 --- a/boards/risc-v/c906/smartl-c906/src/c906_ostest.c +++ b/boards/risc-v/c906/smartl-c906/src/c906_ostest.c @@ -31,6 +31,8 @@ #include +#include "riscv_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/boards/risc-v/mpfs/common/src/mpfs_ostest.c b/boards/risc-v/mpfs/common/src/mpfs_ostest.c index 587b4415131ae..6b4e3dbfecb03 100755 --- a/boards/risc-v/mpfs/common/src/mpfs_ostest.c +++ b/boards/risc-v/mpfs/common/src/mpfs_ostest.c @@ -31,6 +31,8 @@ #include +#include "riscv_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c b/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c index d06f3e1cd9a16..4fefb06a08592 100644 --- a/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c +++ b/boards/risc-v/qemu-rv/rv-virt/src/qemu_rv_ostest.c @@ -31,6 +31,8 @@ #include +#include "riscv_internal.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ From 051e494a13f7bd8e10961cd05493baa4765f34f2 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 29 Mar 2022 16:37:19 +0300 Subject: [PATCH 2/2] RISC-V: Implement skeleton for a per CPU structure It might be useful to store things in memory per CPU. The tricky part is that all CPUs run the same code and see the same memory, so some kind of centralized access is required. For now, the structure contains the hart id. Access to the structure elements is provided via sscratch, which is unique for every hart! --- arch/risc-v/Kconfig | 4 + arch/risc-v/src/common/riscv_cpuindex.c | 3 +- arch/risc-v/src/common/riscv_percpu.c | 115 ++++++++++++++++++++++++ arch/risc-v/src/common/riscv_percpu.h | 100 +++++++++++++++++++++ 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 arch/risc-v/src/common/riscv_percpu.c create mode 100644 arch/risc-v/src/common/riscv_percpu.h diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index e2fed3613311e..095b097504f65 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -233,6 +233,10 @@ config ARCH_MPU_HAS_NAPOT bool "PMP supports NAPOT" default y if !PMP_HAS_LIMITED_FEATURES +config ARCH_CPU_COUNT + int "Amount of CPUs in SoC" + default 5 if ARCH_CHIP_MPFS + source "arch/risc-v/src/opensbi/Kconfig" source "arch/risc-v/src/common/Kconfig" diff --git a/arch/risc-v/src/common/riscv_cpuindex.c b/arch/risc-v/src/common/riscv_cpuindex.c index 201fa0639a1c6..f07c6d5be3817 100644 --- a/arch/risc-v/src/common/riscv_cpuindex.c +++ b/arch/risc-v/src/common/riscv_cpuindex.c @@ -29,6 +29,7 @@ #include #include "riscv_internal.h" +#include "riscv_percpu.h" /**************************************************************************** * Public Functions @@ -50,7 +51,7 @@ uintptr_t riscv_mhartid(void) #ifdef CONFIG_ARCH_USE_S_MODE /* Kernel is in S-mode */ -#error "Missing functionality..." + return riscv_percpu_get_hartid(); #else /* Kernel is in M-mode */ diff --git a/arch/risc-v/src/common/riscv_percpu.c b/arch/risc-v/src/common/riscv_percpu.c new file mode 100644 index 0000000000000..488e82db4bf29 --- /dev/null +++ b/arch/risc-v/src/common/riscv_percpu.c @@ -0,0 +1,115 @@ +/**************************************************************************** + * arch/risc-v/src/common/riscv_percpu.c + * + * 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 "riscv_percpu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define HART_CNT (CONFIG_ARCH_CPU_COUNT) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct riscv_percpu_s g_scratch[HART_CNT]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: riscv_percpu_init + * + * Description: + * Initialize the per CPU structures, should only be done on the boot + * hart. + * + ****************************************************************************/ + +void riscv_percpu_init(void) +{ + int i; + + for (i = 0; i < HART_CNT; i++) + { + g_scratch[i].hartid = i; + } +} + +/**************************************************************************** + * Name: riscv_percpu_get_addr + * + * Description: + * Get add a hart to the per CPU area + * + * Input Parameters: + * hartid - Hart number + * + ****************************************************************************/ + +void riscv_percpu_add_hart(uintptr_t hartid) +{ + /* Hart IDs go from 0...4 */ + + DEBUGASSERT(hartid < HART_CNT); + + /* Set the scratch register value to point to the scratch area */ + + WRITE_CSR(sscratch, &g_scratch[hartid]); + + /* Make sure it sticks */ + + __DMB(); +} + +/**************************************************************************** + * Name: riscv_percpu_get_hartid + * + * Description: + * Get harts own hartid by reading it from the per CPU area. This is safe + * to use from lower privilege modes (than M-mode). + * + * Returned Value: + * Hart id + * + ****************************************************************************/ + +uintptr_t riscv_percpu_get_hartid(void) +{ + uintptr_t scratch = READ_CSR(sscratch); + + DEBUGASSERT(scratch >= (uintptr_t) &g_scratch && + scratch <= (uintptr_t) &g_scratch + sizeof(g_scratch)); + + return ((struct riscv_percpu_s *)scratch)->hartid; +} diff --git a/arch/risc-v/src/common/riscv_percpu.h b/arch/risc-v/src/common/riscv_percpu.h new file mode 100644 index 0000000000000..4db5cc23171bd --- /dev/null +++ b/arch/risc-v/src/common/riscv_percpu.h @@ -0,0 +1,100 @@ +/**************************************************************************** + * arch/risc-v/src/common/riscv_percu.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H +#define __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H + +#include + +#include + +#ifndef __ASSEMBLY__ +# include +# include +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef __ASSEMBLY__ +#define SCRATCH_HARTID_OFFSET (0 * INT_REG_SIZE) +#else +#define SCRATCH_HARTID_OFFSET offsetof(riscv_percpu_s, hartid) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Per CPU save area. Access to this structure can be gained via the + * supervisor scratch (sscratch) register. Prior to this, every CPU that + * wishes to access this information must call riscv_percpu_add_hart() which + * will set up sscratch to point to the CPUs own area + */ + +struct riscv_percpu_s +{ + uintptr_t hartid; /* Hart ID */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: riscv_percpu_init + * + * Description: + * Initialize the per CPU structures, should only be done on the boot + * hart. + * + ****************************************************************************/ + +void riscv_percpu_init(void); + +/**************************************************************************** + * Name: riscv_percpu_get_addr + * + * Description: + * Get add a hart to the per CPU area + * + * Input Parameters: + * hartid - Hart number + * + ****************************************************************************/ + +void riscv_percpu_add_hart(uintptr_t hartid); + +/**************************************************************************** + * Name: riscv_percpu_get_hartid + * + * Description: + * Get harts own hartid by reading it from the per CPU area. This is safe + * to use from lower privilege modes than M-mode. + * + * Returned Value: + * Hart id + * + ****************************************************************************/ + +uintptr_t riscv_percpu_get_hartid(void); + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H */