summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/privilege.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/privilege.c')
-rw-r--r--FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/privilege.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/privilege.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/privilege.c
new file mode 100644
index 000000000..42bdf6e0d
--- /dev/null
+++ b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/privilege.c
@@ -0,0 +1,57 @@
+/* Copyright 2019 SiFive, Inc */
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <stddef.h>
+
+#include <metal/privilege.h>
+
+#define METAL_MSTATUS_MIE_OFFSET 3
+#define METAL_MSTATUS_MPIE_OFFSET 7
+#define METAL_MSTATUS_SIE_OFFSET 1
+#define METAL_MSTATUS_SPIE_OFFSET 5
+#define METAL_MSTATUS_UIE_OFFSET 0
+#define METAL_MSTATUS_UPIE_OFFSET 4
+
+#define METAL_MSTATUS_MPP_OFFSET 11
+#define METAL_MSTATUS_MPP_MASK 3
+
+void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
+ struct metal_register_file regfile,
+ metal_privilege_entry_point_t entry_point)
+{
+ uintptr_t mstatus;
+ asm volatile("csrr %0, mstatus" : "=r" (mstatus));
+
+ /* Set xPIE bits based on current xIE bits */
+ if(mstatus && (1 << METAL_MSTATUS_MIE_OFFSET)) {
+ mstatus |= (1 << METAL_MSTATUS_MPIE_OFFSET);
+ } else {
+ mstatus &= ~(1 << METAL_MSTATUS_MPIE_OFFSET);
+ }
+ if(mstatus && (1 << METAL_MSTATUS_SIE_OFFSET)) {
+ mstatus |= (1 << METAL_MSTATUS_SPIE_OFFSET);
+ } else {
+ mstatus &= ~(1 << METAL_MSTATUS_SPIE_OFFSET);
+ }
+ if(mstatus && (1 << METAL_MSTATUS_UIE_OFFSET)) {
+ mstatus |= (1 << METAL_MSTATUS_UPIE_OFFSET);
+ } else {
+ mstatus &= ~(1 << METAL_MSTATUS_UPIE_OFFSET);
+ }
+
+ /* Set MPP to the requested privilege mode */
+ mstatus &= ~(METAL_MSTATUS_MPP_MASK << METAL_MSTATUS_MPP_OFFSET);
+ mstatus |= (mode << METAL_MSTATUS_MPP_OFFSET);
+
+ asm volatile("csrw mstatus, %0" :: "r" (mstatus));
+
+ /* Set the entry point in MEPC */
+ asm volatile("csrw mepc, %0" :: "r" (entry_point));
+
+ /* Set the register file */
+ asm volatile("mv ra, %0" :: "r" (regfile.ra));
+ asm volatile("mv sp, %0" :: "r" (regfile.sp));
+
+ asm volatile("mret");
+}
+