summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
authorguo <[email protected]>2022-12-03 12:07:44 +0800
committerGitHub <[email protected]>2022-12-03 12:07:44 +0800
commitecf2d8215961ca7c539132b62a72df6072cc3e14 (patch)
tree59005f0f74f2593c0435059264f624c862a89f55 /libcpu
parentaaf5462c6d4ae9466a0a8cd2a4bb00cfe1fef2f2 (diff)
sync branch rt-smart. (#6641)
* Synchronize the code of the rt mart branch to the master branch. * TTY device * Add lwP code from rt-smart * Add vnode in DFS, but DFS will be re-write for rt-smart * There are three libcpu for rt-smart: * arm/cortex-a, arm/aarch64 * riscv64 Co-authored-by: Rbb666 <[email protected]> Co-authored-by: zhkag <[email protected]>
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/Kconfig58
-rw-r--r--libcpu/aarch64/common/cpuport.h10
-rw-r--r--libcpu/arm/am335x/cpuport.h23
-rw-r--r--libcpu/arm/arm926/cpuport.h13
-rw-r--r--libcpu/arm/common/backtrace.c63
-rw-r--r--libcpu/arm/cortex-a/SConscript4
-rw-r--r--libcpu/arm/cortex-a/backtrace.c545
-rw-r--r--libcpu/arm/cortex-a/backtrace.h83
-rw-r--r--libcpu/arm/cortex-a/cache.c50
-rw-r--r--libcpu/arm/cortex-a/context_gcc.S101
-rw-r--r--libcpu/arm/cortex-a/cp15_gcc.S8
-rw-r--r--libcpu/arm/cortex-a/cpuport.c (renamed from libcpu/arm/cortex-a/cpu.c)11
-rw-r--r--libcpu/arm/cortex-a/cpuport.h (renamed from libcpu/arm/cortex-a/armv7.h)38
-rw-r--r--libcpu/arm/cortex-a/gic.c6
-rw-r--r--libcpu/arm/cortex-a/interrupt.c10
-rw-r--r--libcpu/arm/cortex-a/mmu.c675
-rw-r--r--libcpu/arm/cortex-a/mmu.h66
-rw-r--r--libcpu/arm/cortex-a/pmu.c8
-rw-r--r--libcpu/arm/cortex-a/stack.c4
-rw-r--r--libcpu/arm/cortex-a/start_gcc.S579
-rw-r--r--libcpu/arm/cortex-a/trap.c274
-rw-r--r--libcpu/arm/cortex-a/vector_gcc.S6
-rw-r--r--libcpu/arm/cortex-m4/cpuport.h23
-rw-r--r--libcpu/arm/cortex-m7/cpuport.h23
-rw-r--r--libcpu/arm/s3c24x0/cpuport.h23
-rw-r--r--libcpu/arm/zynqmp-r5/cpuport.h23
-rw-r--r--libcpu/mips/gs264/cpuport.h23
-rw-r--r--libcpu/risc-v/SConscript4
-rw-r--r--libcpu/risc-v/common/context_gcc.S1
-rw-r--r--libcpu/risc-v/common/cpuport.c2
-rw-r--r--libcpu/risc-v/common/cpuport.h12
-rw-r--r--libcpu/risc-v/k210/interrupt_gcc.S1
-rw-r--r--libcpu/risc-v/k210/startup_gcc.S1
-rw-r--r--libcpu/risc-v/t-head/c906/SConscript12
-rw-r--r--libcpu/risc-v/t-head/c906/asm/sbiasm.h10
-rw-r--r--libcpu/risc-v/t-head/c906/asm/sbidef.h27
-rw-r--r--libcpu/risc-v/t-head/c906/cache.c160
-rw-r--r--libcpu/risc-v/t-head/c906/cache.h106
-rw-r--r--libcpu/risc-v/t-head/c906/context_gcc.S63
-rw-r--r--libcpu/risc-v/t-head/c906/cpuport.c127
-rw-r--r--libcpu/risc-v/t-head/c906/cpuport.h62
-rw-r--r--libcpu/risc-v/t-head/c906/encoding.h1331
-rw-r--r--libcpu/risc-v/t-head/c906/interrupt.c105
-rw-r--r--libcpu/risc-v/t-head/c906/interrupt_gcc.S114
-rw-r--r--libcpu/risc-v/t-head/c906/io.h52
-rw-r--r--libcpu/risc-v/t-head/c906/mmu.c635
-rw-r--r--libcpu/risc-v/t-head/c906/mmu.h57
-rw-r--r--libcpu/risc-v/t-head/c906/opcode.h81
-rw-r--r--libcpu/risc-v/t-head/c906/plic.c177
-rw-r--r--libcpu/risc-v/t-head/c906/plic.h57
-rw-r--r--libcpu/risc-v/t-head/c906/riscv.h29
-rw-r--r--libcpu/risc-v/t-head/c906/riscv_io.h109
-rw-r--r--libcpu/risc-v/t-head/c906/riscv_mmu.c37
-rw-r--r--libcpu/risc-v/t-head/c906/riscv_mmu.h82
-rw-r--r--libcpu/risc-v/t-head/c906/rt_interrupt.h48
-rw-r--r--libcpu/risc-v/t-head/c906/sbi.c265
-rw-r--r--libcpu/risc-v/t-head/c906/sbi.h241
-rw-r--r--libcpu/risc-v/t-head/c906/stack.h56
-rw-r--r--libcpu/risc-v/t-head/c906/stackframe.h273
-rw-r--r--libcpu/risc-v/t-head/c906/startup_gcc.S81
-rw-r--r--libcpu/risc-v/t-head/c906/symbol_analysis.c298
-rw-r--r--libcpu/risc-v/t-head/c906/symbol_analysis.h44
-rw-r--r--libcpu/risc-v/t-head/c906/syscall_c.c60
-rw-r--r--libcpu/risc-v/t-head/c906/tick.c51
-rw-r--r--libcpu/risc-v/t-head/c906/tick.h20
-rw-r--r--libcpu/risc-v/t-head/c906/trap.c265
-rw-r--r--libcpu/risc-v/virt64/backtrace.c134
-rw-r--r--libcpu/risc-v/virt64/cache.c64
-rw-r--r--libcpu/risc-v/virt64/cache.h59
-rw-r--r--libcpu/risc-v/virt64/context_gcc.S378
-rw-r--r--libcpu/risc-v/virt64/cpuport.c99
-rw-r--r--libcpu/risc-v/virt64/cpuport.h78
-rw-r--r--libcpu/risc-v/virt64/cpuport_gcc.S22
-rw-r--r--libcpu/risc-v/virt64/encoding.h1344
-rw-r--r--libcpu/risc-v/virt64/ext_context.h155
-rw-r--r--libcpu/risc-v/virt64/interrupt.c217
-rw-r--r--libcpu/risc-v/virt64/interrupt.h6
-rw-r--r--libcpu/risc-v/virt64/interrupt_gcc.S190
-rw-r--r--libcpu/risc-v/virt64/io.h52
-rw-r--r--libcpu/risc-v/virt64/mmu.c641
-rw-r--r--libcpu/risc-v/virt64/mmu.h74
-rw-r--r--libcpu/risc-v/virt64/plic.c134
-rw-r--r--libcpu/risc-v/virt64/plic.h76
-rw-r--r--libcpu/risc-v/virt64/riscv_io.h6
-rw-r--r--libcpu/risc-v/virt64/riscv_mmu.c39
-rw-r--r--libcpu/risc-v/virt64/riscv_mmu.h100
-rw-r--r--libcpu/risc-v/virt64/sbi.c263
-rw-r--r--libcpu/risc-v/virt64/sbi.h241
-rw-r--r--libcpu/risc-v/virt64/stack.h8
-rw-r--r--libcpu/risc-v/virt64/stackframe.h222
-rw-r--r--libcpu/risc-v/virt64/startup_gcc.S87
-rw-r--r--libcpu/risc-v/virt64/syscall_c.c60
-rw-r--r--libcpu/risc-v/virt64/tick.c26
-rw-r--r--libcpu/risc-v/virt64/tick.h5
-rw-r--r--libcpu/risc-v/virt64/trap.c311
-rw-r--r--libcpu/risc-v/virt64/vector_encoding.h44
96 files changed, 11848 insertions, 1193 deletions
diff --git a/libcpu/Kconfig b/libcpu/Kconfig
index 4d2f9bf013..0114d62d42 100644
--- a/libcpu/Kconfig
+++ b/libcpu/Kconfig
@@ -1,16 +1,34 @@
config ARCH_CPU_64BIT
bool
+config RT_USING_CACHE
+ bool
+ default n
+
config ARCH_CPU_BIG_ENDIAN
bool
-config ARCH_ARM
+config ARCH_ARM_BOOTWITH_FLUSH_CACHE
+ bool
+ default n
+
+config ARCH_CPU_STACK_GROWS_UPWARD
bool
+ default n
config RT_USING_CPU_FFS
bool
default n
+config ARCH_MM_MMU
+ bool
+
+config ARCH_MM_MPU
+ bool
+
+config ARCH_ARM
+ bool
+
config ARCH_ARM_CORTEX_M
bool
select ARCH_ARM
@@ -33,6 +51,7 @@ config ARCH_ARM_CORTEX_M3
config ARCH_ARM_MPU
bool
depends on ARCH_ARM
+ select ARCH_MM_MPU
config ARCH_ARM_CORTEX_M4
bool
@@ -43,6 +62,7 @@ config ARCH_ARM_CORTEX_M7
bool
select ARCH_ARM_CORTEX_M
select RT_USING_CPU_FFS
+ select RT_USING_CACHE
config ARCH_ARM_CORTEX_M33
bool
@@ -55,8 +75,33 @@ config ARCH_ARM_CORTEX_R
config ARCH_ARM_MMU
bool
+ select RT_USING_CACHE
+ select ARCH_MM_MMU
depends on ARCH_ARM
+config RT_USING_USERSPACE
+ bool "Isolated user space"
+ default n
+ depends on ARCH_MM_MMU
+
+config KERNEL_VADDR_START
+ hex "The virtural address of kernel start"
+ default 0xc0000000 if ARCH_ARM
+ default 0x80000000 if ARCH_RISCV
+ depends on RT_USING_USERSPACE
+
+config PV_OFFSET
+ hex "The offset of kernel physical address and virtural address"
+ default 0xa0000000 if ARCH_ARM
+ default 0x0 if ARCH_RISCV
+ depends on RT_USING_USERSPACE
+
+config RT_IOREMAP_LATE
+ bool "Support to create IO mapping in the kernel address space after system initlalization."
+ default n
+ depends on ARCH_ARM_CORTEX_A
+ depends on RT_USING_USERSPACE
+
config ARCH_ARM_ARM9
bool
select ARCH_ARM
@@ -104,8 +149,19 @@ config ARCH_ARM_CORTEX_A9
bool
select ARCH_ARM_CORTEX_A
+config ARCH_ARM_SECURE_MODE
+ bool "Running in secure mode [ARM Cortex-A]"
+ default n
+ depends on ARCH_ARM_CORTEX_A
+
+config RT_BACKTRACE_FUNCTION_NAME
+ bool "To show function name when backtrace."
+ default n
+ depends on ARCH_ARM_CORTEX_A
+
config ARCH_ARMV8
bool
+ select ARCH_ARM
config ARCH_MIPS
bool
diff --git a/libcpu/aarch64/common/cpuport.h b/libcpu/aarch64/common/cpuport.h
index ab398573ff..36d3ac7b65 100644
--- a/libcpu/aarch64/common/cpuport.h
+++ b/libcpu/aarch64/common/cpuport.h
@@ -20,6 +20,16 @@
#define __DSB() __asm__ volatile ("dsb 0xf":::"memory")
#define __DMB() __asm__ volatile ("dmb 0xf":::"memory")
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
rt_inline void rt_hw_isb(void)
{
__asm__ volatile ("isb":::"memory");
diff --git a/libcpu/arm/am335x/cpuport.h b/libcpu/arm/am335x/cpuport.h
new file mode 100644
index 0000000000..05bb12cf2f
--- /dev/null
+++ b/libcpu/arm/am335x/cpuport.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/arm/arm926/cpuport.h b/libcpu/arm/arm926/cpuport.h
new file mode 100644
index 0000000000..b5dae0b0e0
--- /dev/null
+++ b/libcpu/arm/arm926/cpuport.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/arm/common/backtrace.c b/libcpu/arm/common/backtrace.c
deleted file mode 100644
index bf3526703e..0000000000
--- a/libcpu/arm/common/backtrace.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2008-07-29 Bernard first version from QiuYi implementation
- */
-
-#include <rtthread.h>
-
-#ifdef __GNUC__
-/*
--->High Address,Stack Top
-PC<------|
-LR |
-IP |
-FP |
-...... |
-PC <-| |
-LR | |
-IP | |
-FP---|-- |
-...... |
-PC |
-LR |
-IP |
-FP---
--->Low Address,Stack Bottom
-*/
-void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry)
-{
- rt_uint32_t i, pc, func_entry;
-
- pc = *fp;
- rt_kprintf("[0x%x]\n", pc - 0xC);
-
- for (i = 0; i < 10; i++)
- {
- fp = (rt_uint32_t *) * (fp - 3);
- pc = *fp ;
-
- func_entry = pc - 0xC;
-
- if (func_entry <= 0x30000000) break;
-
- if (func_entry == thread_entry)
- {
- rt_kprintf("EntryPoint:0x%x\n", func_entry);
-
- break;
- }
-
- rt_kprintf("[0x%x]\n", func_entry);
- }
-}
-#else
-void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry)
-{
- /* old compiler implementation */
-}
-#endif
diff --git a/libcpu/arm/cortex-a/SConscript b/libcpu/arm/cortex-a/SConscript
index 6075a8622c..562c6ffa4f 100644
--- a/libcpu/arm/cortex-a/SConscript
+++ b/libcpu/arm/cortex-a/SConscript
@@ -7,12 +7,12 @@ Import('rtconfig')
cwd = GetCurrentDir()
src = Split('''
cache.c
-cpu.c
+cpuport.c
gtimer.c
mmu.c
pmu.c
stack.c
-
+backtrace.c
''')
CPPPATH = [cwd]
diff --git a/libcpu/arm/cortex-a/backtrace.c b/libcpu/arm/cortex-a/backtrace.c
new file mode 100644
index 0000000000..1d4d444aa9
--- /dev/null
+++ b/libcpu/arm/cortex-a/backtrace.c
@@ -0,0 +1,545 @@
+#ifndef __CHECKER__
+#if !defined (__ARM_EABI__)
+#warning Your compiler does not have EABI support.
+#warning ARM unwind is known to compile only with EABI compilers.
+#warning Change compiler or disable ARM_UNWIND option.
+#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2) && !defined(__clang__)
+#warning Your compiler is too buggy; it is known to not compile ARM unwind support.
+#warning Change compiler or disable ARM_UNWIND option.
+#endif
+#endif /* __CHECKER__ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <backtrace.h>
+
+#define DBG_TAG "BACKTRACE"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USING_USERSPACE
+#include <lwp.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+#endif
+
+rt_inline void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
+{
+ frame->fp = frame_pointer(regs);
+ frame->sp = regs->ARM_sp;
+ frame->lr = regs->ARM_lr;
+ frame->pc = regs->ARM_pc;
+}
+
+/* Dummy functions to avoid linker complaints */
+void __aeabi_unwind_cpp_pr0(void)
+{
+};
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+};
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+};
+
+struct unwind_ctrl_block {
+ unsigned long vrs[16]; /* virtual register set */
+ const unsigned long *insn; /* pointer to the current instructions word */
+ unsigned long sp_high; /* highest value of sp allowed */
+ /*
+ * 1 : check for stack overflow for each register pop.
+ * 0 : save overhead if there is plenty of stack remaining.
+ */
+ int check_each_pop;
+ int entries; /* number of entries left to interpret */
+ int byte; /* current byte number in the instructions word */
+};
+
+enum regs
+{
+#ifdef CONFIG_THUMB2_KERNEL
+ FP = 7,
+#else
+ FP = 11,
+#endif
+ SP = 13,
+ LR = 14,
+ PC = 15
+};
+
+static int core_kernel_text(unsigned long addr)
+{
+ return 1;
+}
+
+/* Convert a prel31 symbol to an absolute address */
+#define prel31_to_addr(ptr) \
+ ({ \
+ /* sign-extend to 32 bits */ \
+ long offset = (((long)*(ptr)) << 1) >> 1; \
+ (unsigned long)(ptr) + offset; \
+ })
+
+/*
+ * Binary search in the unwind index. The entries are
+ * guaranteed to be sorted in ascending order by the linker.
+ *
+ * start = first entry
+ * origin = first entry with positive offset (or stop if there is no such entry)
+ * stop - 1 = last entry
+ */
+static const struct unwind_idx *search_index(unsigned long addr,
+ const struct unwind_idx *start,
+ const struct unwind_idx *origin,
+ const struct unwind_idx *stop)
+{
+ unsigned long addr_prel31;
+
+ LOG_D("%s(%08lx, %x, %x, %x)",
+ __func__, addr, start, origin, stop);
+
+ /*
+ * only search in the section with the matching sign. This way the
+ * prel31 numbers can be compared as unsigned longs.
+ */
+ if (addr < (unsigned long)start)
+ /* negative offsets: [start; origin) */
+ stop = origin;
+ else
+ /* positive offsets: [origin; stop) */
+ start = origin;
+
+ /* prel31 for address relavive to start */
+ addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+ while (start < stop - 1)
+ {
+ const struct unwind_idx *mid = start + ((stop - start) >> 1);
+
+ /*
+ * As addr_prel31 is relative to start an offset is needed to
+ * make it relative to mid.
+ */
+ if (addr_prel31 - ((unsigned long)mid - (unsigned long)start) <
+ mid->addr_offset)
+ stop = mid;
+ else
+ {
+ /* keep addr_prel31 relative to start */
+ addr_prel31 -= ((unsigned long)mid -
+ (unsigned long)start);
+ start = mid;
+ }
+ }
+
+ if (start->addr_offset <= addr_prel31)
+ return start;
+ else
+ {
+ LOG_W("unwind: Unknown symbol address %08lx", addr);
+ return RT_NULL;
+ }
+}
+
+static const struct unwind_idx *unwind_find_origin(
+ const struct unwind_idx *start, const struct unwind_idx *stop)
+{
+ LOG_D("%s(%x, %x)", __func__, start, stop);
+ while (start < stop)
+ {
+ const struct unwind_idx *mid = start + ((stop - start) >> 1);
+
+ if (mid->addr_offset >= 0x40000000)
+ /* negative offset */
+ start = mid + 1;
+ else
+ /* positive offset */
+ stop = mid;
+ }
+ LOG_D("%s -> %x", __func__, stop);
+ return stop;
+}
+
+static const struct unwind_idx *unwind_find_idx(unsigned long addr, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
+{
+ const struct unwind_idx *idx = RT_NULL;
+
+ LOG_D("%s(%08lx)", __func__, addr);
+
+ if (core_kernel_text(addr))
+ {
+ if (!*origin_idx)
+ *origin_idx =
+ unwind_find_origin(exidx_start,
+ exidx_end);
+
+ /* main unwind table */
+ idx = search_index(addr, exidx_start,
+ *origin_idx,
+ exidx_end);
+ }
+
+ LOG_D("%s: idx = %x", __func__, idx);
+ return idx;
+}
+
+static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
+{
+ unsigned long ret;
+
+ if (ctrl->entries <= 0)
+ {
+ LOG_W("unwind: Corrupt unwind table");
+ return 0;
+ }
+
+ ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
+
+ if (ctrl->byte == 0)
+ {
+ ctrl->insn++;
+ ctrl->entries--;
+ ctrl->byte = 3;
+ }
+ else
+ ctrl->byte--;
+
+ return ret;
+}
+
+/* Before poping a register check whether it is feasible or not */
+static int unwind_pop_register(struct unwind_ctrl_block *ctrl,
+ unsigned long **vsp, unsigned int reg)
+{
+ if (ctrl->check_each_pop)
+ if (*vsp >= (unsigned long *)ctrl->sp_high)
+ return -URC_FAILURE;
+
+ ctrl->vrs[reg] = *(*vsp)++;
+ return URC_OK;
+}
+
+/* Helper functions to execute the instructions */
+static int unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_block *ctrl,
+ unsigned long mask)
+{
+ unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+ int load_sp, reg = 4;
+
+ load_sp = mask & (1 << (13 - 4));
+ while (mask)
+ {
+ if (mask & 1)
+ if (unwind_pop_register(ctrl, &vsp, reg))
+ return -URC_FAILURE;
+ mask >>= 1;
+ reg++;
+ }
+ if (!load_sp)
+ ctrl->vrs[SP] = (unsigned long)vsp;
+
+ return URC_OK;
+}
+
+static int unwind_exec_pop_r4_to_rN(struct unwind_ctrl_block *ctrl,
+ unsigned long insn)
+{
+ unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+ int reg;
+
+ /* pop R4-R[4+bbb] */
+ for (reg = 4; reg <= 4 + (insn & 7); reg++)
+ if (unwind_pop_register(ctrl, &vsp, reg))
+ return -URC_FAILURE;
+
+ if (insn & 0x8)
+ if (unwind_pop_register(ctrl, &vsp, 14))
+ return -URC_FAILURE;
+
+ ctrl->vrs[SP] = (unsigned long)vsp;
+
+ return URC_OK;
+}
+
+static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
+ unsigned long mask)
+{
+ unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
+ int reg = 0;
+
+ /* pop R0-R3 according to mask */
+ while (mask)
+ {
+ if (mask & 1)
+ if (unwind_pop_register(ctrl, &vsp, reg))
+ return -URC_FAILURE;
+ mask >>= 1;
+ reg++;
+ }
+ ctrl->vrs[SP] = (unsigned long)vsp;
+
+ return URC_OK;
+}
+
+/*
+ * Execute the current unwind instruction.
+ */
+static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
+{
+ unsigned long insn = unwind_get_byte(ctrl);
+ int ret = URC_OK;
+
+ LOG_D("%s: insn = %08lx", __func__, insn);
+
+ if ((insn & 0xc0) == 0x00)
+ ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
+ else if ((insn & 0xc0) == 0x40)
+ ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
+ else if ((insn & 0xf0) == 0x80)
+ {
+ unsigned long mask;
+
+ insn = (insn << 8) | unwind_get_byte(ctrl);
+ mask = insn & 0x0fff;
+ if (mask == 0)
+ {
+ LOG_W("unwind: 'Refuse to unwind' instruction %04lx",
+ insn);
+ return -URC_FAILURE;
+ }
+
+ ret = unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
+ if (ret)
+ goto error;
+ }
+ else if ((insn & 0xf0) == 0x90 &&
+ (insn & 0x0d) != 0x0d)
+ ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
+ else if ((insn & 0xf0) == 0xa0)
+ {
+ ret = unwind_exec_pop_r4_to_rN(ctrl, insn);
+ if (ret)
+ goto error;
+ }
+ else if (insn == 0xb0)
+ {
+ if (ctrl->vrs[PC] == 0)
+ ctrl->vrs[PC] = ctrl->vrs[LR];
+ /* no further processing */
+ ctrl->entries = 0;
+ }
+ else if (insn == 0xb1)
+ {
+ unsigned long mask = unwind_get_byte(ctrl);
+
+ if (mask == 0 || mask & 0xf0)
+ {
+ LOG_W("unwind: Spare encoding %04lx",
+ (insn << 8) | mask);
+ return -URC_FAILURE;
+ }
+
+ ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
+ if (ret)
+ goto error;
+ }
+ else if (insn == 0xb2)
+ {
+ unsigned long uleb128 = unwind_get_byte(ctrl);
+
+ ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
+ }
+ else
+ {
+ LOG_W("unwind: Unhandled instruction %02lx", insn);
+ return -URC_FAILURE;
+ }
+
+ LOG_D("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx", __func__,
+ ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
+
+error:
+ return ret;
+}
+
+#ifdef RT_BACKTRACE_FUNCTION_NAME
+static char *unwind_get_function_name(void *address)
+{
+ uint32_t flag_word = *(uint32_t *)((char*)address - 4);
+
+ if ((flag_word & 0xff000000) == 0xff000000)
+ {
+ return (char *)((char*)address - 4 - (flag_word & 0x00ffffff));
+ }
+ return RT_NULL;
+}
+#endif
+/*
+ * Unwind a single frame starting with *sp for the symbol at *pc. It
+ * updates the *pc and *sp with the new values.
+ */
+int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
+{
+ unsigned long low;
+ const struct unwind_idx *idx;
+ struct unwind_ctrl_block ctrl;
+ struct rt_thread *rt_c_thread;
+
+ /* store the highest address on the stack to avoid crossing it*/
+ low = frame->sp;
+ rt_c_thread = rt_thread_self();
+ ctrl.sp_high = (unsigned long)((char*)rt_c_thread->stack_addr + rt_c_thread->stack_size);
+
+ LOG_D("%s(pc = %08lx lr = %08lx sp = %08lx)", __func__,
+ frame->pc, frame->lr, frame->sp);
+
+ idx = unwind_find_idx(frame->pc, origin_idx, exidx_start, exidx_end);
+ if (!idx)
+ {
+ LOG_W("unwind: Index not found %08lx", frame->pc);
+ return -URC_FAILURE;
+ }
+
+#ifdef RT_BACKTRACE_FUNCTION_NAME
+ {
+ char *fun_name;
+ fun_name = unwind_get_function_name((void *)prel31_to_addr(&idx->addr_offset));
+ if (fun_name)
+ {
+ rt_kprintf("0x%08x @ %s\n", frame->pc, fun_name);
+ }
+ }
+#endif
+
+ ctrl.vrs[FP] = frame->fp;
+ ctrl.vrs[SP] = frame->sp;
+ ctrl.vrs[LR] = frame->lr;
+ ctrl.vrs[PC] = 0;
+
+ if (idx->insn == 1)
+ /* can't unwind */
+ return -URC_FAILURE;
+ else if ((idx->insn & 0x80000000) == 0)
+ /* prel31 to the unwind table */
+ ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);
+ else if ((idx->insn & 0xff000000) == 0x80000000)
+ /* only personality routine 0 supported in the index */
+ ctrl.insn = &idx->insn;
+ else
+ {
+ LOG_W("unwind: Unsupported personality routine %08lx in the index at %x",
+ idx->insn, idx);
+ return -URC_FAILURE;
+ }
+
+ /* check the personality routine */
+ if ((*ctrl.insn & 0xff000000) == 0x80000000)
+ {
+ ctrl.byte = 2;
+ ctrl.entries = 1;
+ }
+ else if ((*ctrl.insn & 0xff000000) == 0x81000000)
+ {
+ ctrl.byte = 1;
+ ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
+ }
+ else
+ {
+ LOG_W("unwind: Unsupported personality routine %08lx at %x",
+ *ctrl.insn, ctrl.insn);
+ return -URC_FAILURE;
+ }
+
+ ctrl.check_each_pop = 0;
+
+ while (ctrl.entries > 0)
+ {
+ int urc;
+ if ((ctrl.sp_high - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
+ ctrl.check_each_pop = 1;
+ urc = unwind_exec_insn(&ctrl);
+ if (urc < 0)
+ return urc;
+ if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= ctrl.sp_high)
+ return -URC_FAILURE;
+ }
+
+ if (ctrl.vrs[PC] == 0)
+ ctrl.vrs[PC] = ctrl.vrs[LR];
+
+ /* check for infinite loop */
+ if (frame->pc == ctrl.vrs[PC])
+ return -URC_FAILURE;
+
+ frame->fp = ctrl.vrs[FP];
+ frame->sp = ctrl.vrs[SP];
+ frame->lr = ctrl.vrs[LR];
+ frame->pc = ctrl.vrs[PC];
+
+ return URC_OK;
+}
+
+void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
+{
+ struct stackframe frame;
+ const struct unwind_idx *origin_idx = RT_NULL;
+
+ LOG_D("%s(regs = %x)", __func__, regs);
+
+ arm_get_current_stackframe(regs, &frame);
+
+#ifndef RT_BACKTRACE_FUNCTION_NAME
+ rt_kprintf("please use: addr2line -e rtthread.elf -a -f %08x", frame.pc);
+#endif
+ LOG_D("pc = %08x, sp = %08x", frame.pc, frame.sp);
+
+ while (1)
+ {
+ int urc;
+
+ urc = unwind_frame(&frame, &origin_idx, exidx_start, exidx_end);
+ if (urc < 0)
+ break;
+ //dump_backtrace_entry(where, frame.pc, frame.sp - 4);
+#ifndef RT_BACKTRACE_FUNCTION_NAME
+ rt_kprintf(" %08x", frame.pc);
+#endif
+ LOG_D("from: pc = %08x, frame = %08x", frame.pc, frame.sp - 4);
+ }
+ rt_kprintf("\n");
+}
+
+extern const struct unwind_idx __exidx_start[];
+extern const struct unwind_idx __exidx_end[];
+
+void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj)
+{
+ struct pt_regs e_regs;
+
+ e_regs.ARM_fp = regs->fp;
+ e_regs.ARM_sp = regs->sp;
+ e_regs.ARM_lr = regs->lr;
+ e_regs.ARM_pc = regs->pc - pc_adj;
+#ifdef RT_USING_USERSPACE
+ if (!lwp_user_accessable((void *)e_regs.ARM_pc, sizeof (void *)))
+ {
+ e_regs.ARM_pc = regs->lr - sizeof(void *);
+ }
+#endif
+ rt_kprintf("backtrace:\n");
+ unwind_backtrace(&e_regs, __exidx_start, __exidx_end);
+}
+
+void rt_backtrace(void)
+{
+ struct rt_hw_exp_stack regs;
+
+ asm volatile ("mov %0, fp":"=r"(regs.fp));
+ asm volatile ("mov %0, sp":"=r"(regs.sp));
+ asm volatile ("mov %0, lr":"=r"(regs.lr));
+ asm volatile ("mov %0, pc":"=r"(regs.pc));
+ rt_unwind(&regs, 8);
+}
+
diff --git a/libcpu/arm/cortex-a/backtrace.h b/libcpu/arm/cortex-a/backtrace.h
new file mode 100644
index 0000000000..a6ed226094
--- /dev/null
+++ b/libcpu/arm/cortex-a/backtrace.h
@@ -0,0 +1,83 @@
+#ifndef __BACKTRACE_H
+#define __BACKTRACE_H
+
+#ifndef __ASSEMBLY__
+#include <cpuport.h>
+
+/* Unwind reason code according the the ARM EABI documents */
+enum unwind_reason_code
+{
+ URC_OK = 0, /* operation completed successfully */
+ URC_CONTINUE_UNWIND = 8,
+ URC_FAILURE = 9 /* unspecified failure of some kind */
+};
+
+struct unwind_idx
+{
+ unsigned long addr_offset;
+ unsigned long insn;
+};
+
+struct unwind_table
+{
+ const struct unwind_idx *start;
+ const struct unwind_idx *origin;
+ const struct unwind_idx *stop;
+ unsigned long begin_addr;
+ unsigned long end_addr;
+};
+
+struct stackframe
+{
+ /*
+ * FP member should hold R7 when CONFIG_THUMB2_KERNEL is enabled
+ * and R11 otherwise.
+ */
+ unsigned long fp;
+ unsigned long sp;
+ unsigned long lr;
+ unsigned long pc;
+};
+
+struct pt_regs
+{
+ unsigned long uregs[18];
+};
+
+#define ARM_cpsr uregs[16]
+#define ARM_pc uregs[15]
+#define ARM_lr uregs[14]
+#define ARM_sp uregs[13]
+#define ARM_ip uregs[12]
+#define ARM_fp uregs[11]
+#define ARM_r10 uregs[10]
+#define ARM_r9 uregs[9]
+#define ARM_r8 uregs[8]
+#define ARM_r7 uregs[7]
+#define ARM_r6 uregs[6]
+#define ARM_r5 uregs[5]
+#define ARM_r4 uregs[4]
+#define ARM_r3 uregs[3]
+#define ARM_r2 uregs[2]
+#define ARM_r1 uregs[1]
+#define ARM_r0 uregs[0]
+#define ARM_ORIG_r0 uregs[17]
+
+#define instruction_pointer(regs) (regs)->ARM_pc
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define frame_pointer(regs) (regs)->ARM_r7
+#else
+#define frame_pointer(regs) (regs)->ARM_fp
+#endif
+
+int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]);
+void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]);
+
+void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj);
+void rt_backtrace(void);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __BACKTRACE_H */
+
diff --git a/libcpu/arm/cortex-a/cache.c b/libcpu/arm/cortex-a/cache.c
index a6b59182a6..c243e8e358 100644
--- a/libcpu/arm/cortex-a/cache.c
+++ b/libcpu/arm/cortex-a/cache.c
@@ -31,8 +31,8 @@ void rt_hw_cpu_icache_invalidate(void *addr, int size)
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
- start_addr &= ~(line_size-1);
- end_addr &= ~(line_size-1);
+ start_addr &= ~(line_size - 1);
+ end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r"(start_addr)); /* icimvau */
@@ -48,8 +48,8 @@ void rt_hw_cpu_dcache_invalidate(void *addr, int size)
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
- start_addr &= ~(line_size-1);
- end_addr &= ~(line_size-1);
+ start_addr &= ~(line_size - 1);
+ end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
@@ -96,8 +96,8 @@ void rt_hw_cpu_dcache_clean(void *addr, int size)
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
- start_addr &= ~(line_size-1);
- end_addr &= ~(line_size-1);
+ start_addr &= ~(line_size - 1);
+ end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
@@ -106,18 +106,19 @@ void rt_hw_cpu_dcache_clean(void *addr, int size)
asm volatile ("dsb":::"memory");
}
-void rt_hw_cpu_dcache_clean_inv(void *addr, int size)
+void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
- start_addr &= ~(line_size-1);
- end_addr &= ~(line_size-1);
+ start_addr &= ~(line_size - 1);
+ end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
- asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
+ asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
+ asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
@@ -126,15 +127,21 @@ void rt_hw_cpu_dcache_clean_inv(void *addr, int size)
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)
+ {
rt_hw_cpu_icache_invalidate(addr, size);
+ }
}
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_FLUSH)
+ {
rt_hw_cpu_dcache_clean(addr, size);
+ }
else if (ops == RT_HW_CACHE_INVALIDATE)
+ {
rt_hw_cpu_dcache_invalidate(addr, size);
+ }
}
rt_base_t rt_hw_cpu_icache_status(void)
@@ -146,3 +153,26 @@ rt_base_t rt_hw_cpu_dcache_status(void)
{
return 0;
}
+
+#ifdef RT_USING_LWP
+#define ICACHE (1<<0)
+#define DCACHE (1<<1)
+#define BCACHE (ICACHE|DCACHE)
+
+int sys_cacheflush(void *addr, int size, int cache)
+{
+ if ((size_t)addr < KERNEL_VADDR_START && (size_t)addr + size <= KERNEL_VADDR_START)
+ {
+ if ((cache & DCACHE) != 0)
+ {
+ rt_hw_cpu_dcache_clean_and_invalidate(addr, size);
+ }
+ if ((cache & ICACHE) != 0)
+ {
+ rt_hw_cpu_icache_invalidate(addr, size);
+ }
+ return 0;
+ }
+ return -1;
+}
+#endif
diff --git a/libcpu/arm/cortex-a/context_gcc.S b/libcpu/arm/cortex-a/context_gcc.S
index 768c5138e9..77ca0a7aa2 100644
--- a/libcpu/arm/cortex-a/context_gcc.S
+++ b/libcpu/arm/cortex-a/context_gcc.S
@@ -45,7 +45,20 @@ rt_hw_context_switch_to:
#ifdef RT_USING_SMP
mov r0, r1
bl rt_cpus_lock_status_restore
+#ifdef RT_USING_USERSPACE
+ bl rt_thread_self
+ bl lwp_user_setting_restore
+#endif
+#else
+#ifdef RT_USING_USERSPACE
+ bl rt_thread_self
+ mov r4, r0
+ bl lwp_mmu_switch
+ mov r0, r4
+ bl lwp_user_setting_restore
+#endif
#endif /*RT_USING_SMP*/
+
b rt_hw_context_switch_exit
.section .bss.share.isr
@@ -95,7 +108,20 @@ rt_hw_context_switch:
#ifdef RT_USING_SMP
mov r0, r2
bl rt_cpus_lock_status_restore
+#ifdef RT_USING_USERSPACE
+ bl rt_thread_self
+ bl lwp_user_setting_restore
+#endif
+#else
+#ifdef RT_USING_USERSPACE
+ bl rt_thread_self
+ mov r4, r0
+ bl lwp_mmu_switch
+ mov r0, r4
+ bl lwp_user_setting_restore
+#endif
#endif /*RT_USING_SMP*/
+
b rt_hw_context_switch_exit
/*
@@ -123,28 +149,69 @@ rt_hw_context_switch_interrupt:
* r2 :addr of to_thread's sp
* r3 :to_thread's tcb
*/
-
+#ifdef RT_USING_LWP
+ push {r0 - r3, lr}
+#ifdef RT_USING_USERSPACE
+ bl rt_thread_self
+ bl lwp_user_setting_save
+#endif
+ pop {r0 - r3, lr}
+#endif
str r0, [r1]
ldr sp, [r2]
mov r0, r3
+#ifdef RT_USING_USERSPACE
+ mov r4, r0
+#endif
bl rt_cpus_lock_status_restore
-
+#ifdef RT_USING_USERSPACE
+ mov r0, r4
+ bl lwp_user_setting_restore
+#endif
b rt_hw_context_switch_exit
#else /*RT_USING_SMP*/
- ldr r2, =rt_thread_switch_interrupt_flag
- ldr r3, [r2]
+ /* r0 :addr of from_thread's sp
+ * r1 :addr of to_thread's sp
+ * r2 :from_thread's tcb
+ * r3 :to_thread's tcb
+ */
+#ifdef RT_USING_LWP
+ /* now to_thread(r3) not used */
+ ldr ip, =rt_thread_switch_interrupt_flag
+ ldr r3, [ip]
+ cmp r3, #1
+ beq _reswitch
+ ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
+ str r0, [r3]
+ mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
+ str r3, [ip]
+#ifdef RT_USING_USERSPACE
+ push {r1, lr}
+ mov r0, r2
+ bl lwp_user_setting_save
+ pop {r1, lr}
+#endif
+_reswitch:
+ ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
+ str r1, [ip]
+ bx lr
+#else
+ /* now from_thread(r2) to_thread(r3) not used */
+ ldr ip, =rt_thread_switch_interrupt_flag
+ ldr r3, [ip]
cmp r3, #1
beq _reswitch
- ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
+ ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
+ str r0, [r3]
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
- str r0, [ip]
- str r3, [r2]
+ str r3, [ip]
_reswitch:
- ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
- str r1, [r2]
+ ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
+ str r1, [ip]
bx lr
+#endif
#endif /*RT_USING_SMP*/
.global rt_hw_context_switch_exit
@@ -178,5 +245,21 @@ rt_hw_context_switch_exit:
#endif
ldmfd sp!, {r1}
msr spsr_cxsf, r1 /* original mode */
+
+#ifdef RT_USING_LWP
+ and r1, #0x1f
+ cmp r1, #0x10
+ bne 1f
+ ldmfd sp!, {r0-r12,lr}
+ ldmfd sp!, {lr}
+ b arch_ret_to_user
+1:
+#endif
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
+#ifdef RT_USING_FPU
+.global set_fpexc
+set_fpexc:
+ vmsr fpexc, r0
+ bx lr
+#endif
diff --git a/libcpu/arm/cortex-a/cp15_gcc.S b/libcpu/arm/cortex-a/cp15_gcc.S
index 983ae522ef..dd2436ffee 100644
--- a/libcpu/arm/cortex-a/cp15_gcc.S
+++ b/libcpu/arm/cortex-a/cp15_gcc.S
@@ -8,11 +8,9 @@
* 2013-07-05 Bernard the first version
*/
-.weak rt_hw_cpu_id
-rt_hw_cpu_id:
- mrc p15, #0, r0, c0, c0, #5 @ read multiprocessor affinity register
- ldr r1, =0xFFFF03 @ Affinity mask off, leaving CPU ID field, [0:1]CPU ID, [8:15]Cluster ID Aff1, [16:23]Cluster ID Aff2
- and r0, r0, r1
+.globl rt_cpu_get_smp_id
+rt_cpu_get_smp_id:
+ mrc p15, #0, r0, c0, c0, #5
bx lr
.globl rt_cpu_vector_set_base
diff --git a/libcpu/arm/cortex-a/cpu.c b/libcpu/arm/cortex-a/cpuport.c
index 7d1a389f08..aea3b88f00 100644
--- a/libcpu/arm/cortex-a/cpu.c
+++ b/libcpu/arm/cortex-a/cpuport.c
@@ -13,6 +13,17 @@
#include <rtthread.h>
#include <board.h>
+int rt_hw_cpu_id(void)
+{
+ int cpu_id;
+ __asm__ volatile (
+ "mrc p15, 0, %0, c0, c0, 5"
+ :"=r"(cpu_id)
+ );
+ cpu_id &= 0xf;
+ return cpu_id;
+}
+
#ifdef RT_USING_SMP
void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
diff --git a/libcpu/arm/cortex-a/armv7.h b/libcpu/arm/cortex-a/cpuport.h
index 325d0ed0ae..ab68d1e311 100644
--- a/libcpu/arm/cortex-a/armv7.h
+++ b/libcpu/arm/cortex-a/cpuport.h
@@ -1,13 +1,14 @@
/*
- * Copyright (c) 2006-2021, RT-Thread Development Team
+ * Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
-#ifndef __ARMV7_H__
-#define __ARMV7_H__
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
/* the exception stack without VFP registers */
struct rt_hw_exp_stack
@@ -69,10 +70,29 @@ struct rt_hw_stack
#define E_Bit (1<<9)
#define J_Bit (1<<24)
-#define PABT_EXCEPTION 0x1
-#define DABT_EXCEPTION 0x2
-#define UND_EXCEPTION 0x3
-#define SWI_EXCEPTION 0x4
-#define RESV_EXCEPTION 0xF
-
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
#endif
+
+rt_inline void rt_hw_isb(void)
+{
+ __asm volatile ("isb":::"memory");
+}
+
+rt_inline void rt_hw_dmb(void)
+{
+ __asm volatile ("dmb":::"memory");
+}
+
+rt_inline void rt_hw_dsb(void)
+{
+ __asm volatile ("dsb":::"memory");
+}
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/arm/cortex-a/gic.c b/libcpu/arm/cortex-a/gic.c
index 5dda22530d..e65bb5413e 100644
--- a/libcpu/arm/cortex-a/gic.c
+++ b/libcpu/arm/cortex-a/gic.c
@@ -431,7 +431,11 @@ int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
- _gic_table[index].cpu_hw_base = cpu_base;
+ if (!_gic_table[index].cpu_hw_base)
+ {
+ _gic_table[index].cpu_hw_base = cpu_base;
+ }
+ cpu_base = _gic_table[index].cpu_hw_base;
GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
GIC_CPU_BINPOINT(cpu_base) = 0x7U;
diff --git a/libcpu/arm/cortex-a/interrupt.c b/libcpu/arm/cortex-a/interrupt.c
index f90f1c0094..6cf7362554 100644
--- a/libcpu/arm/cortex-a/interrupt.c
+++ b/libcpu/arm/cortex-a/interrupt.c
@@ -69,8 +69,13 @@ void rt_hw_interrupt_init(void)
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* initialize ARM GIC */
+#ifdef RT_USING_USERSPACE
+ gic_dist_base = (uint32_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_dist_base(), 0x2000, MMU_MAP_K_RW);
+ gic_cpu_base = (uint32_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_cpu_base(), 0x1000, MMU_MAP_K_RW);
+#else
gic_dist_base = platform_get_gic_dist_base();
gic_cpu_base = platform_get_gic_cpu_base();
+#endif
gic_irq_start = GIC_IRQ_START;
@@ -94,7 +99,12 @@ void rt_hw_interrupt_init(void)
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* initialize ARM GIC */
+#ifdef RT_USING_USERSPACE
+ gic_dist_base = (uint32_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_dist_base(), 0x2000, MMU_MAP_K_RW);
+#else
gic_dist_base = platform_get_gic_dist_base();
+#endif
+
gic_irq_start = GIC_IRQ_START;
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
diff --git a/libcpu/arm/cortex-a/mmu.c b/libcpu/arm/cortex-a/mmu.c
index 243fe19a0a..47f7676ace 100644
--- a/libcpu/arm/cortex-a/mmu.c
+++ b/libcpu/arm/cortex-a/mmu.c
@@ -8,13 +8,67 @@
* 2012-01-10 bernard porting to AM1808
*/
-#include <rtthread.h>
#include <rthw.h>
+#include <rtthread.h>
+
#include <board.h>
#include "cp15.h"
#include "mmu.h"
+#ifdef RT_USING_LWP
+#include <lwp_mm.h>
+#include "page.h"
+#endif
+
+/* level1 page table, each entry for 1MB memory. */
+volatile unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024)));
+
+#ifndef RT_USING_LWP
+static rt_mutex_t mm_lock = RT_NULL;
+
+void rt_mm_lock(void)
+{
+ if (rt_thread_self())
+ {
+ if (!mm_lock)
+ {
+ mm_lock = rt_mutex_create("mm_lock", RT_IPC_FLAG_FIFO);
+ }
+ if (mm_lock)
+ {
+ rt_mutex_take(mm_lock, RT_WAITING_FOREVER);
+ }
+ }
+}
+
+void rt_mm_unlock(void)
+{
+ if (rt_thread_self())
+ {
+ if (mm_lock)
+ {
+ rt_mutex_release(mm_lock);
+ }
+ }
+}
+#endif
+
+void rt_hw_cpu_tlb_invalidate(void)
+{
+ asm volatile ("mcr p15, 0, r0, c8, c7, 0\ndsb\nisb" ::: "memory");
+}
+
+unsigned long rt_hw_set_domain_register(unsigned long domain_val)
+{
+ unsigned long old_domain;
+
+ asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
+ asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
+
+ return old_domain;
+}
+
/* dump 2nd level page table */
void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb)
{
@@ -122,8 +176,6 @@ void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb)
}
}
-/* level1 page table, each entry for 1MB memory. */
-volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024)));
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
rt_uint32_t vaddrEnd,
rt_uint32_t paddrStart,
@@ -140,16 +192,6 @@ void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
}
}
-unsigned long rt_hw_set_domain_register(unsigned long domain_val)
-{
- unsigned long old_domain;
-
- asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
- asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
-
- return old_domain;
-}
-
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
{
/* set page table */
@@ -159,6 +201,8 @@ void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
mdesc->paddr_start, mdesc->attr);
mdesc++;
}
+
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void*)MMUTable, sizeof MMUTable);
}
void rt_hw_mmu_init(void)
@@ -180,3 +224,608 @@ void rt_hw_mmu_init(void)
rt_hw_cpu_dcache_enable();
}
+int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off)
+{
+ size_t l1_off, va_s, va_e;
+
+ if (!mmu_info || !vtable)
+ {
+ return -1;
+ }
+
+ va_s = (size_t)v_address;
+ va_e = (size_t)v_address + size - 1;
+
+ if ( va_e < va_s)
+ {
+ return -1;
+ }
+
+ va_s >>= ARCH_SECTION_SHIFT;
+ va_e >>= ARCH_SECTION_SHIFT;
+
+ if (va_s == 0)
+ {
+ return -1;
+ }
+
+ for (l1_off = va_s; l1_off <= va_e; l1_off++)
+ {
+ size_t v = vtable[l1_off];
+
+ if (v & ARCH_MMU_USED_MASK)
+ {
+ return -1;
+ }
+ }
+
+ mmu_info->vtable = vtable;
+ mmu_info->vstart = va_s;
+ mmu_info->vend = va_e;
+ mmu_info->pv_off = pv_off;
+
+ return 0;
+}
+
+int rt_hw_mmu_ioremap_init(rt_mmu_info *mmu_info, void* v_address, size_t size)
+{
+#ifdef RT_IOREMAP_LATE
+ size_t loop_va;
+ size_t l1_off;
+ size_t *mmu_l1, *mmu_l2;
+ size_t sections;
+
+ /* for kernel ioremap */
+ if ((size_t)v_address < KERNEL_VADDR_START)
+ {
+ return -1;
+ }
+ /* must align to section */
+ if ((size_t)v_address & ARCH_SECTION_MASK)
+ {
+ return -1;
+ }
+ /* must align to section */
+ if (size & ARCH_SECTION_MASK)
+ {
+ return -1;
+ }
+
+ loop_va = (size_t)v_address;
+ sections = (size >> ARCH_SECTION_SHIFT);
+ while (sections--)
+ {
+ l1_off = (loop_va >> ARCH_SECTION_SHIFT);
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+
+ RT_ASSERT((*mmu_l1 & ARCH_MMU_USED_MASK) == 0);
+ mmu_l2 = (size_t*)rt_pages_alloc(0);
+ if (mmu_l2)
+ {
+ rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
+
+ *mmu_l1 = (((size_t)mmu_l2 + mmu_info->pv_off) | 0x1);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
+ }
+ else
+ {
+ /* error */
+ return -1;
+ }
+
+ loop_va += ARCH_SECTION_SIZE;
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef RT_USING_LWP
+static size_t find_vaddr(rt_mmu_info *mmu_info, int pages)
+{
+ size_t l1_off, l2_off;
+ size_t *mmu_l1, *mmu_l2;
+ size_t find_off = 0;
+ size_t find_va = 0;
+ int n = 0;
+
+ if (!pages)
+ {
+ return 0;
+ }
+
+ if (!mmu_info)
+ {
+ return 0;
+ }
+
+ for (l1_off = mmu_info->vstart; l1_off <= mmu_info->vend; l1_off++)
+ {
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+ if (*mmu_l1 & ARCH_MMU_USED_MASK)
+ {
+ mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
+ for (l2_off = 0; l2_off < (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE); l2_off++)
+ {
+ if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
+ {
+ /* in use */
+ n = 0;
+ }
+ else
+ {
+ if (!n)
+ {
+ find_va = l1_off;
+ find_off = l2_off;
+ }
+ n++;
+ if (n >= pages)
+ {
+ return (find_va << ARCH_SECTION_SHIFT) + (find_off << ARCH_PAGE_SHIFT);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!n)
+ {
+ find_va = l1_off;
+ find_off = 0;
+ }
+ n += (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE);
+ if (n >= pages)
+ {
+ return (find_va << ARCH_SECTION_SHIFT) + (find_off << ARCH_PAGE_SHIFT);
+ }
+ }
+ }
+ return 0;
+}
+
+static int check_vaddr(rt_mmu_info *mmu_info, void *va, int pages)
+{
+ size_t loop_va = (size_t)va & ~ARCH_PAGE_MASK;
+ size_t l1_off, l2_off;
+ size_t *mmu_l1, *mmu_l2;
+
+ if (!pages)
+ {
+ return -1;
+ }
+
+ if (!mmu_info)
+ {
+ return -1;
+ }
+
+ l1_off = ((size_t)va >> ARCH_SECTION_SHIFT);
+ if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend)
+ {
+ return -1;
+ }
+ l1_off += ((pages << ARCH_PAGE_SHIFT) >> ARCH_SECTION_SHIFT);
+ if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend + 1)
+ {
+ return -1;
+ }
+
+ while (pages--)
+ {
+ l1_off = (loop_va >> ARCH_SECTION_SHIFT);
+ l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+
+ if (*mmu_l1 & ARCH_MMU_USED_MASK)
+ {
+ mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
+ if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
+ {
+ return -1;
+ }
+ }
+ loop_va += ARCH_PAGE_SIZE;
+ }
+ return 0;
+}
+
+static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t npages)
+{
+ size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
+ size_t l1_off, l2_off;
+ size_t *mmu_l1, *mmu_l2;
+
+ if (!mmu_info)
+ {
+ return;
+ }
+
+ while (npages--)
+ {
+ l1_off = (loop_va >> ARCH_SECTION_SHIFT);
+ if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend)
+ {
+ return;
+ }
+
+ l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+
+ if (*mmu_l1 & ARCH_MMU_USED_MASK)
+ {
+ mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
+ }
+ else
+ {
+ return;
+ }
+
+ if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
+ {
+ *(mmu_l2 + l2_off) = 0;
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
+
+ if (rt_pages_free(mmu_l2, 0))
+ {
+ *mmu_l1 = 0;
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
+ }
+ }
+ loop_va += ARCH_PAGE_SIZE;
+ }
+}
+
+static int __rt_hw_mmu_map(rt_mmu_info *mmu_info, void* v_addr, void* p_addr, size_t npages, size_t attr)
+{
+ size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
+ size_t loop_pa = (size_t)p_addr & ~ARCH_PAGE_MASK;
+ size_t l1_off, l2_off;
+ size_t *mmu_l1, *mmu_l2;
+
+ if (!mmu_info)
+ {
+ return -1;
+ }
+
+ while (npages--)
+ {
+ l1_off = (loop_va >> ARCH_SECTION_SHIFT);
+ l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+
+ if (*mmu_l1 & ARCH_MMU_USED_MASK)
+ {
+ mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
+ rt_page_ref_inc(mmu_l2, 0);
+ }
+ else
+ {
+ mmu_l2 = (size_t*)rt_pages_alloc(0);
+ if (mmu_l2)
+ {
+ rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
+
+ *mmu_l1 = (((size_t)mmu_l2 + mmu_info->pv_off) | 0x1);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
+ }
+ else
+ {
+ /* error, unmap and quit */
+ __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
+ return -1;
+ }
+ }
+
+ *(mmu_l2 + l2_off) = (loop_pa | attr);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
+
+ loop_va += ARCH_PAGE_SIZE;
+ loop_pa += ARCH_PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+void *_rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr)
+{
+ size_t pa_s, pa_e;
+ size_t vaddr;
+ int pages;
+ int ret;
+
+ if (!size)
+ {
+ return 0;
+ }
+ pa_s = (size_t)p_addr;
+ pa_e = (size_t)p_addr + size - 1;
+ pa_s >>= ARCH_PAGE_SHIFT;
+ pa_e >>= ARCH_PAGE_SHIFT;
+ pages = pa_e - pa_s + 1;
+ if (v_addr)
+ {
+ vaddr = (size_t)v_addr;
+ pa_s = (size_t)p_addr;
+ if ((vaddr & ARCH_PAGE_MASK) != (pa_s & ARCH_PAGE_MASK))
+ {
+ return 0;
+ }
+ vaddr &= ~ARCH_PAGE_MASK;
+ if (check_vaddr(mmu_info, (void*)vaddr, pages) != 0)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ vaddr = find_vaddr(mmu_info, pages);
+ }
+ if (vaddr) {
+ rt_enter_critical();
+ ret = __rt_hw_mmu_map(mmu_info, (void*)vaddr, p_addr, pages, attr);
+ if (ret == 0)
+ {
+ rt_hw_cpu_tlb_invalidate();
+ rt_exit_critical();
+ return (void*)(vaddr + ((size_t)p_addr & ARCH_PAGE_MASK));
+ }
+ rt_exit_critical();
+ }
+ return 0;
+}
+
+static int __rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void* v_addr, size_t npages, size_t attr)
+{
+ size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
+ size_t loop_pa;
+ size_t l1_off, l2_off;
+ size_t *mmu_l1, *mmu_l2;
+
+ if (!mmu_info)
+ {
+ return -1;
+ }
+
+ while (npages--)
+ {
+ loop_pa = (size_t)rt_pages_alloc(0);
+ if (!loop_pa)
+ goto err;
+
+ l1_off = (loop_va >> ARCH_SECTION_SHIFT);
+ l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+
+ if (*mmu_l1 & ARCH_MMU_USED_MASK)
+ {
+ mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
+ rt_page_ref_inc(mmu_l2, 0);
+ }
+ else
+ {
+ //mmu_l2 = (size_t*)rt_malloc_align(ARCH_PAGE_TBL_SIZE * 2, ARCH_PAGE_TBL_SIZE);
+ mmu_l2 = (size_t*)rt_pages_alloc(0);
+ if (mmu_l2)
+ {
+ rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
+
+ *mmu_l1 = (((size_t)mmu_l2 + mmu_info->pv_off) | 0x1);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
+ }
+ else
+ goto err;
+ }
+
+ loop_pa += mmu_info->pv_off;
+ *(mmu_l2 + l2_off) = (loop_pa | attr);
+ /* cache maintain */
+ rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
+
+ loop_va += ARCH_PAGE_SIZE;
+ }
+ return 0;
+err:
+ {
+ /* error, unmap and quit */
+ int i;
+ void *va, *pa;
+
+ va = (void*)((size_t)v_addr & ~ARCH_PAGE_MASK);
+ for (i = 0; i < npages; i++)
+ {
+ pa = rt_hw_mmu_v2p(mmu_info, va);
+ pa = (void*)((char*)pa - mmu_info->pv_off);
+ rt_pages_free(pa, 0);
+ va = (void*)((char*)va + ARCH_PAGE_SIZE);
+ }
+
+ __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
+ return -1;
+ }
+}
+
+void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr)
+{
+ size_t vaddr;
+ size_t offset;
+ int pages;
+ int ret;
+
+ if (!size)
+ {
+ return 0;
+ }
+
+ offset = (size_t)v_addr & ARCH_PAGE_MASK;
+ size += (offset + ARCH_PAGE_SIZE - 1);
+ pages = (size >> ARCH_PAGE_SHIFT);
+ if (v_addr)
+ {
+ vaddr = (size_t)v_addr;
+ vaddr &= ~ARCH_PAGE_MASK;
+ if (check_vaddr(mmu_info, (void*)vaddr, pages) != 0)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ vaddr = find_vaddr(mmu_info, pages);
+ }
+
+ if (vaddr)
+ {
+ rt_enter_critical();
+ ret = __rt_hw_mmu_map_auto(mmu_info, (void*)vaddr, pages, attr);
+ if (ret == 0)
+ {
+ rt_hw_cpu_tlb_invalidate();
+ rt_exit_critical();
+ return (void*)((char*)vaddr + offset);
+ }
+ rt_exit_critical();
+ }
+ return 0;
+}
+
+void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size)
+{
+ size_t va_s, va_e;
+ int pages;
+
+ va_s = (size_t)v_addr;
+ va_e = (size_t)v_addr + size - 1;
+ va_s >>= ARCH_PAGE_SHIFT;
+ va_e >>= ARCH_PAGE_SHIFT;
+ pages = va_e - va_s + 1;
+ rt_enter_critical();
+ __rt_hw_mmu_unmap(mmu_info, v_addr, pages);
+ rt_hw_cpu_tlb_invalidate();
+ rt_exit_critical();
+}
+
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr)
+{
+ void *ret;
+
+ rt_mm_lock();
+ ret = _rt_hw_mmu_map(mmu_info, v_addr, p_addr, size, attr);
+ rt_mm_unlock();
+ return ret;
+}
+
+void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr)
+{
+ void *ret;
+
+ rt_mm_lock();
+ ret = _rt_hw_mmu_map_auto(mmu_info, v_addr, size, attr);
+ rt_mm_unlock();
+ return ret;
+}
+
+void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size)
+{
+ rt_mm_lock();
+ _rt_hw_mmu_unmap(mmu_info, v_addr, size);
+ rt_mm_unlock();
+}
+
+void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr)
+{
+ size_t l1_off, l2_off;
+ size_t *mmu_l1, *mmu_l2;
+ size_t tmp;
+ size_t pa;
+
+ l1_off = (size_t)v_addr >> ARCH_SECTION_SHIFT;
+
+ if (!mmu_info)
+ {
+ return (void*)0;
+ }
+
+ mmu_l1 = (size_t*)mmu_info->vtable + l1_off;
+
+ tmp = *mmu_l1;
+
+ switch (tmp & ARCH_MMU_USED_MASK)
+ {
+ case 0: /* not used */
+ break;
+ case 1: /* page table */
+ mmu_l2 = (size_t *)((tmp & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off);
+ l2_off = (((size_t)v_addr & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
+ pa = *(mmu_l2 + l2_off);
+ if (pa & ARCH_MMU_USED_MASK)
+ {
+ if ((pa & ARCH_MMU_USED_MASK) == 1)
+ {
+ /* large page, not support */
+ break;
+ }
+ pa &= ~(ARCH_PAGE_MASK);
+ pa += ((size_t)v_addr & ARCH_PAGE_MASK);
+ return (void*)pa;
+ }
+ break;
+ case 2:
+ case 3:
+ /* section */
+ if (tmp & ARCH_TYPE_SUPERSECTION)
+ {
+ /* super section, not support */
+ break;
+ }
+ pa = (tmp & ~ARCH_SECTION_MASK);
+ pa += ((size_t)v_addr & ARCH_SECTION_MASK);
+ return (void*)pa;
+ }
+ return (void*)0;
+}
+
+void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr)
+{
+ void *ret;
+
+ rt_mm_lock();
+ ret = _rt_hw_mmu_v2p(mmu_info, v_addr);
+ rt_mm_unlock();
+ return ret;
+}
+
+void init_mm_setup(unsigned int *mtbl, unsigned int size, unsigned int pv_off)
+{
+ unsigned int va;
+
+ for (va = 0; va < 0x1000; va++)
+ {
+ unsigned int vaddr = (va << 20);
+
+ if (vaddr >= KERNEL_VADDR_START && vaddr - KERNEL_VADDR_START < size)
+ {
+ mtbl[va] = ((va << 20) + pv_off) | NORMAL_MEM;
+ }
+ else if (vaddr >= (KERNEL_VADDR_START + pv_off) && vaddr - (KERNEL_VADDR_START + pv_off) < size)
+ {
+ mtbl[va] = (va << 20) | NORMAL_MEM;
+ }
+ else
+ {
+ mtbl[va] = 0;
+ }
+ }
+}
+#endif
diff --git a/libcpu/arm/cortex-a/mmu.h b/libcpu/arm/cortex-a/mmu.h
index 5cc60a774d..0bd80dd06c 100644
--- a/libcpu/arm/cortex-a/mmu.h
+++ b/libcpu/arm/cortex-a/mmu.h
@@ -19,8 +19,14 @@
#define SHAREDEVICE (1<<2) /* shared device */
#define STRONGORDER (0<<2) /* strong ordered */
#define XN (1<<4) /* eXecute Never */
+#ifdef RT_USING_USERSPACE
+#define AP_RW (1<<10) /* supervisor=RW, user=No */
+#define AP_RO ((1<<10) |(1 << 15)) /* supervisor=RW, user=No */
+#else
#define AP_RW (3<<10) /* supervisor=RW, user=RW */
-#define AP_RO (2<<10) /* supervisor=RW, user=RO */
+#define AP_RO ((2<<10) /* supervisor=RW, user=RO */
+#endif
+
#define SHARED (1<<16) /* shareable */
#define DOMAIN_FAULT (0x0)
@@ -37,6 +43,8 @@
/* normal memory mapping type */
#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC)
+#define STRONG_ORDER_MEM (SHARED|AP_RO|XN|DESC_SEC)
+
struct mem_desc
{
rt_uint32_t vaddr_start;
@@ -45,5 +53,61 @@ struct mem_desc
rt_uint32_t attr;
};
+#define MMU_MAP_MTBL_XN (1<<0)
+#define MMU_MAP_MTBL_A (1<<1)
+#define MMU_MAP_MTBL_B (1<<2)
+#define MMU_MAP_MTBL_C (1<<3)
+#define MMU_MAP_MTBL_AP01(x) (x<<4)
+#define MMU_MAP_MTBL_TEX(x) (x<<6)
+#define MMU_MAP_MTBL_AP2(x) (x<<9)
+#define MMU_MAP_MTBL_SHARE (1<<10)
+#define MMU_MAP_MTBL_NG(x) (x<<11)
+
+#define MMU_MAP_K_RO (MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_K_RWCB (MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_K_RW (MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_K_DEVICE (MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_U_RO (MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(2)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_U_RWCB (MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_U_RW (MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE)
+#define MMU_MAP_U_DEVICE (MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE)
+
+#define ARCH_SECTION_SHIFT 20
+#define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT)
+#define ARCH_SECTION_MASK (ARCH_SECTION_SIZE - 1)
+#define ARCH_PAGE_SHIFT 12
+#define ARCH_PAGE_SIZE (1 << ARCH_PAGE_SHIFT)
+#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
+#define ARCH_PAGE_TBL_SHIFT 10
+#define ARCH_PAGE_TBL_SIZE (1 << ARCH_PAGE_TBL_SHIFT)
+#define ARCH_PAGE_TBL_MASK (ARCH_PAGE_TBL_SIZE - 1)
+
+#define ARCH_MMU_USED_MASK 3
+
+#define ARCH_TYPE_SUPERSECTION (1 << 18)
+
+#define ARCH_ADDRESS_WIDTH_BITS 32
+
+typedef struct
+{
+ size_t *vtable;
+ size_t vstart;
+ size_t vend;
+ size_t pv_off;
+} rt_mmu_info;
+
+int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off);
+int rt_hw_mmu_ioremap_init(rt_mmu_info *mmu_info, void* v_address, size_t size);
+void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size);
+
+#ifdef RT_USING_USERSPACE
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr);
+void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr);
+#else
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr);
+#endif
+
+void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size);
+void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr);
#endif
diff --git a/libcpu/arm/cortex-a/pmu.c b/libcpu/arm/cortex-a/pmu.c
index 2b9165cc8b..4b62849a1a 100644
--- a/libcpu/arm/cortex-a/pmu.c
+++ b/libcpu/arm/cortex-a/pmu.c
@@ -9,12 +9,16 @@
#include <rtthread.h>
#include "pmu.h"
+#define DBG_TAG "PMU"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
void rt_hw_pmu_dump_feature(void)
{
unsigned long reg;
reg = rt_hw_pmu_get_control();
- rt_kprintf("ARM PMU Implementor: %c, ID code: %02x, %d counters\n",
- reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f);
+ LOG_D("ARM PMU Implementor: %c, ID code: %02x, %d counters\n",
+ reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f);
RT_ASSERT(ARM_PMU_CNTER_NR == ((reg >> 11) & 0x1f));
}
diff --git a/libcpu/arm/cortex-a/stack.c b/libcpu/arm/cortex-a/stack.c
index e68b324867..875794bade 100644
--- a/libcpu/arm/cortex-a/stack.c
+++ b/libcpu/arm/cortex-a/stack.c
@@ -9,11 +9,11 @@
* 2011-10-05 Bernard add thumb mode
*/
#include <rtthread.h>
+#include <cpuport.h>
#include <board.h>
-#include <armv7.h>
/**
- * @addtogroup AM33xx
+ * @addtogroup ARM Cortex-A
*/
/*@{*/
diff --git a/libcpu/arm/cortex-a/start_gcc.S b/libcpu/arm/cortex-a/start_gcc.S
index 5916ddf957..5ddb7311a8 100644
--- a/libcpu/arm/cortex-a/start_gcc.S
+++ b/libcpu/arm/cortex-a/start_gcc.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2022, RT-Thread Development Team
+ * Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -19,40 +19,15 @@
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
-.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
-.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
+.equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */
+.equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */
-.equ UND_Stack_Size, 0x00000400
-.equ SVC_Stack_Size, 0x00000400
-.equ ABT_Stack_Size, 0x00000400
-.equ RT_FIQ_STACK_PGSZ, 0x00000000
-.equ RT_IRQ_STACK_PGSZ, 0x00000800
-.equ USR_Stack_Size, 0x00000400
-
-.equ SUB_UND_Stack_Size, 0x00000400
-.equ SUB_SVC_Stack_Size, 0x00000400
-.equ SUB_ABT_Stack_Size, 0x00000400
-.equ SUB_RT_FIQ_STACK_PGSZ, 0x00000000
-.equ SUB_RT_IRQ_STACK_PGSZ, 0x00000400
-.equ SUB_USR_Stack_Size, 0x00000400
-
-#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
- RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ)
-
-#define SUB_ISR_Stack_Size (SUB_UND_Stack_Size + SUB_SVC_Stack_Size + SUB_ABT_Stack_Size + \
- SUB_RT_FIQ_STACK_PGSZ + SUB_RT_IRQ_STACK_PGSZ)
-
-.section .bss.share.isr
-/* stack */
-.globl stack_start
-.globl stack_top
-
-.align 3
-stack_start:
-.rept ISR_Stack_Size
-.byte 0
-.endr
-stack_top:
+#ifdef RT_USING_USERSPACE
+.data
+.align 14
+init_mtbl:
+ .space 16*1024
+#endif
.text
/* reset entry */
@@ -71,15 +46,96 @@ overHyped: /* Get out of HYP mode */
adr r1, continue
msr ELR_hyp, r1
mrs r1, cpsr_all
- and r1, r1, #0x1f ;@ CPSR_MODE_MASK
- orr r1, r1, #0x13 ;@ CPSR_MODE_SUPERVISOR
+ and r1, r1, #0x1f /* CPSR_MODE_MASK */
+ orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */
+ msr SPSR_hyp, r1
+ eret
+
+continue:
+#endif
+
+#ifdef SOC_BCM283x
+ /* Suspend the other cpu cores */
+ mrc p15, 0, r0, c0, c0, 5
+ ands r0, #3
+ bne _halt
+
+ /* Disable IRQ & FIQ */
+ cpsid if
+
+ /* Check for HYP mode */
+ mrs r0, cpsr_all
+ and r0, r0, #0x1F
+ mov r8, #0x1A
+ cmp r0, r8
+ beq overHyped
+ b continue
+
+overHyped: /* Get out of HYP mode */
+ adr r1, continue
+ msr ELR_hyp, r1
+ mrs r1, cpsr_all
+ and r1, r1, #0x1f /* CPSR_MODE_MASK */
+ orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */
msr SPSR_hyp, r1
eret
continue:
+ /* set the cpu to SVC32 mode and disable interrupt */
+ mrs r0, cpsr
+ bic r0, r0, #0x1f
+ orr r0, r0, #0x13
+ msr cpsr_c, r0
+#endif
+
+ /* invalid tlb before enable mmu */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, #1
+ mcr p15, 0, r0, c1, c0, 0
+ dsb
+ isb
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0
+ mcr p15, 0, r0, c7, c5, 0 /* iciallu */
+ mcr p15, 0, r0, c7, c5, 6 /* bpiall */
+ dsb
+ isb
+
+#ifdef RT_USING_USERSPACE
+ ldr r5, =PV_OFFSET
+
+ mov r7, #0x100000
+ sub r7, #1
+ mvn r8, r7
+
+
+ ldr r9, =KERNEL_VADDR_START
+
+ ldr r6, =__bss_end
+ add r6, r7
+ and r6, r8 /* r6 end vaddr align up to 1M */
+ sub r6, r9 /* r6 is size */
+
+ ldr sp, =svc_stack_n_limit
+ add sp, r5 /* use paddr */
+
+ ldr r0, =init_mtbl
+ add r0, r5
+ mov r1, r6
+ mov r2, r5
+ bl init_mm_setup
+
+ ldr lr, =after_enable_mmu
+ ldr r0, =init_mtbl
+ add r0, r5
+ b enable_mmu
+
+after_enable_mmu:
#endif
+#ifndef SOC_BCM283x
/* set the cpu to SVC32 mode and disable interrupt */
cps #Mode_SVC
+#endif
#ifdef RT_USING_FPU
mov r4, #0xfffffff
@@ -88,41 +144,9 @@ continue:
/* disable the data alignment check */
mrc p15, 0, r1, c1, c0, 0
- bic r1, #(1<<0) /* Disable MMU */
- bic r1, #(1<<1) /* Disable Alignment fault checking */
- bic r1, #(1<<2) /* Disable data cache */
- bic r1, #(1<<11) /* Disable program flow prediction */
- bic r1, #(1<<12) /* Disable instruction cache */
- bic r1, #(3<<19) /* bit[20:19] must be zero */
+ bic r1, #(1<<1)
mcr p15, 0, r1, c1, c0, 0
- @ get cpu id, and subtract the offset from the stacks base address
- bl rt_hw_cpu_id
- mov r5, r0
-
- cmp r5, #0 @ cpu id == 0
- beq normal_setup
-
- @ cpu id > 0, stop or wait
-#ifdef RT_SMP_AUTO_BOOT
- ldr r0, =secondary_cpu_entry
- mov r1, #0
- str r1, [r0] /* clean secondary_cpu_entry */
-#endif /* RT_SMP_AUTO_BOOT */
-
-secondary_loop:
- @ cpu core 1 goes into sleep until core 0 wakeup it
- wfe
-#ifdef RT_SMP_AUTO_BOOT
- ldr r1, =secondary_cpu_entry
- ldr r0, [r1]
- cmp r0, #0
- blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */
-#endif /* RT_SMP_AUTO_BOOT */
- b secondary_loop
-
-normal_setup:
-
/* enable I cache + branch prediction */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(1<<12)
@@ -130,32 +154,53 @@ normal_setup:
mcr p15, 0, r0, c1, c0, 0
/* setup stack */
- bl stack_setup
+ bl stack_setup
/* clear .bss */
- mov r0,#0 /* get a zero */
- ldr r1,=__bss_start /* bss start */
- ldr r2,=__bss_end /* bss end */
+ mov r0,#0 /* get a zero */
+ ldr r1,=__bss_start /* bss start */
+ ldr r2,=__bss_end /* bss end */
bss_loop:
- cmp r1,r2 /* check if data to clear */
- strlo r0,[r1],#4 /* clear 4 bytes */
- blo bss_loop /* loop until done */
+ cmp r1,r2 /* check if data to clear */
+ strlo r0,[r1],#4 /* clear 4 bytes */
+ blo bss_loop /* loop until done */
#ifdef RT_USING_SMP
mrc p15, 0, r1, c1, c0, 1
mov r0, #(1<<6)
orr r1, r0
- mcr p15, 0, r1, c1, c0, 1 //enable smp
+ mcr p15, 0, r1, c1, c0, 1 /* enable smp */
#endif
-
/* initialize the mmu table and enable mmu */
ldr r0, =platform_mem_desc
ldr r1, =platform_mem_desc_size
ldr r1, [r1]
bl rt_hw_init_mmu_table
+
+#ifdef RT_USING_USERSPACE
+ ldr r0, =MMUTable /* vaddr */
+ add r0, r5 /* to paddr */
+ bl rt_hw_mmu_switch
+#else
bl rt_hw_mmu_init
+#endif
+
+ /* call C++ constructors of global objects */
+ ldr r0, =__ctors_start__
+ ldr r1, =__ctors_end__
+
+ctor_loop:
+ cmp r0, r1
+ beq ctor_end
+ ldr r2, [r0], #4
+ stmfd sp!, {r0-r1}
+ mov lr, pc
+ bx r2
+ ldmfd sp!, {r0-r1}
+ b ctor_loop
+ctor_end:
/* start RT-Thread Kernel */
ldr pc, _rtthread_startup
@@ -163,37 +208,105 @@ _rtthread_startup:
.word rtthread_startup
stack_setup:
- ldr r0, =stack_top
- @ Set the startup stack for svc
- mov sp, r0
- sub r0, r0, #SVC_Stack_Size
+#ifdef RT_USING_SMP
+ /* cpu id */
+ mrc p15, 0, r0, c0, c0, 5
+ and r0, r0, #0xf
+ add r0, r0, #1
+#else
+ mov r0, #1
+#endif
+
+ cps #Mode_UND
+ ldr r1, =und_stack_n
+ add sp, r1, r0, asl #12
- @ Enter Undefined Instruction Mode and set its Stack Pointer
- msr cpsr_c, #Mode_UND|I_Bit|F_Bit
- mov sp, r0
- sub r0, r0, #UND_Stack_Size
+ cps #Mode_IRQ
+ ldr r1, =irq_stack_n
+ add sp, r1, r0, asl #12
- @ Enter Abort Mode and set its Stack Pointer
- msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
- mov sp, r0
- sub r0, r0, #ABT_Stack_Size
+ cps #Mode_FIQ
+ ldr r1, =irq_stack_n
+ add sp, r1, r0, asl #12
- @ Enter FIQ Mode and set its Stack Pointer
- msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
- mov sp, r0
- sub r0, r0, #RT_FIQ_STACK_PGSZ
+ cps #Mode_ABT
+ ldr r1, =abt_stack_n
+ add sp, r1, r0, asl #12
- @ Enter IRQ Mode and set its Stack Pointer
- msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
- mov sp, r0
- sub r0, r0, #RT_IRQ_STACK_PGSZ
+ cps #Mode_SVC
+ ldr r1, =svc_stack_n
+ add sp, r1, r0, asl #12
- /* come back to SVC mode */
- msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
bx lr
-/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
+#ifdef RT_USING_USERSPACE
+.align 2
+.global enable_mmu
+enable_mmu:
+ orr r0, #0x18
+ mcr p15, 0, r0, c2, c0, 0 /* ttbr0 */
+
+ mov r0, #(1 << 5) /* PD1=1 */
+ mcr p15, 0, r0, c2, c0, 2 /* ttbcr */
+
+ mov r0, #1
+ mcr p15, 0, r0, c3, c0, 0 /* dacr */
+
+ /* invalid tlb before enable mmu */
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0
+ mcr p15, 0, r0, c7, c5, 0 /* iciallu */
+ mcr p15, 0, r0, c7, c5, 6 /* bpiall */
+
+ mrc p15, 0, r0, c1, c0, 0
+ orr r0, #((1 << 12) | (1 << 11)) /* instruction cache, branch prediction */
+ orr r0, #((1 << 2) | (1 << 0)) /* data cache, mmu enable */
+ mcr p15, 0, r0, c1, c0, 0
+ dsb
+ isb
+ mov pc, lr
+
+.global rt_hw_set_process_id
+rt_hw_set_process_id:
+ LSL r0, r0, #8
+ MCR p15, 0, r0, c13, c0, 1
+ mov pc, lr
+
+.global rt_hw_mmu_switch
+rt_hw_mmu_switch:
+ mov r3, #0
+ mcr p15, 0, r3, c13, c0, 1 /* set contextid = 0, for synchronization*/
+ isb
+
+ orr r0, #0x18
+ mcr p15, 0, r0, c2, c0, 0 /* ttbr0 */
+
+ isb
+ mov r1, r1, LSL #0x8
+ and r2, r2, #0xff
+ orr r1, r1, r2 /* contextid.PROCID = pid, contextid.ASID = asid*/
+ mcr p15, 0, r1, c13, c0, 1 /* set contextid = r1*/
+ isb
+
+ mcr p15, 0, r0, c7, c5, 0 /* iciallu */
+ mcr p15, 0, r0, c7, c5, 6 /* bpiall */
+
+ dsb
+ isb
+ mov pc, lr
+.global rt_hw_mmu_tbl_get
+rt_hw_mmu_tbl_get:
+ mrc p15, 0, r0, c2, c0, 0 /* ttbr0 */
+ bic r0, #0x18
+ mov pc, lr
+#endif
+
+_halt:
+ wfe
+ b _halt
+
+/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
.section .text.isr, "ax"
.align 5
.globl vector_fiq
@@ -226,7 +339,7 @@ vector_irq:
cps #Mode_IRQ
sub lr, #4
- stmfd r0!, {r1, lr} /* svc_lr, svc_pc */
+ stmfd r0!, {r1, lr} /* svc_lr, svc_pc */
stmfd r0!, {r2 - r12}
ldmfd sp!, {r1, r2} /* original r0, r1 */
stmfd r0!, {r1 - r2}
@@ -234,8 +347,8 @@ vector_irq:
stmfd r0!, {r1}
#ifdef RT_USING_LWP
- stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */
- sub r0, #8
+ stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */
+ sub r0, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
@@ -255,12 +368,13 @@ vector_irq:
/* backup r0 -> r8 */
mov r8, r0
+ cps #Mode_SVC
+ mov sp, r8
+
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
- cps #Mode_SVC
- mov sp, r8
mov r0, r8
bl rt_scheduler_do_irq_switch
@@ -273,41 +387,69 @@ vector_irq:
bl rt_hw_trap_irq
bl rt_interrupt_leave
- @ if rt_thread_switch_interrupt_flag set, jump to
- @ rt_hw_context_switch_interrupt_do and don't return
+ /* if rt_thread_switch_interrupt_flag set, jump to
+ * rt_hw_context_switch_interrupt_do and don't return */
ldr r0, =rt_thread_switch_interrupt_flag
ldr r1, [r0]
cmp r1, #1
beq rt_hw_context_switch_interrupt_do
+#ifdef RT_USING_LWP
+ ldmfd sp!, {r0-r12,lr}
+ cps #Mode_SVC
+ push {r0-r12}
+ mov r7, lr
+ cps #Mode_IRQ
+ mrs r4, spsr
+ sub r5, lr, #4
+ cps #Mode_SVC
+ and r6, r4, #0x1f
+ cmp r6, #0x10
+ bne 1f
+ msr spsr_csxf, r4
+ mov lr, r5
+ pop {r0-r12}
+ b arch_ret_to_user
+1:
+ mov lr, r7
+ cps #Mode_IRQ
+ msr spsr_csxf, r4
+ mov lr, r5
+ cps #Mode_SVC
+ pop {r0-r12}
+ cps #Mode_IRQ
+ movs pc, lr
+#else
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
+#endif
rt_hw_context_switch_interrupt_do:
- mov r1, #0 @ clear flag
+ mov r1, #0 /* clear flag */
str r1, [r0]
- mov r1, sp @ r1 point to {r0-r3} in stack
+ mov r1, sp /* r1 point to {r0-r3} in stack */
add sp, sp, #4*4
- ldmfd sp!, {r4-r12,lr}@ reload saved registers
- mrs r0, spsr @ get cpsr of interrupt thread
- sub r2, lr, #4 @ save old task's pc to r2
+ ldmfd sp!, {r4-r12,lr} /* reload saved registers */
+ mrs r0, spsr /* get cpsr of interrupt thread */
+ sub r2, lr, #4 /* save old task's pc to r2 */
- @ Switch to SVC mode with no interrupt. If the usr mode guest is
- @ interrupted, this will just switch to the stack of kernel space.
- @ save the registers in kernel space won't trigger data abort.
+ /* Switch to SVC mode with no interrupt. If the usr mode guest is
+ * interrupted, this will just switch to the stack of kernel space.
+ * save the registers in kernel space won't trigger data abort. */
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
- stmfd sp!, {r2} @ push old task's pc
- stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
- ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread
- stmfd sp!, {r1-r4} @ push old task's r0-r3
- stmfd sp!, {r0} @ push old task's cpsr
+ stmfd sp!, {r2} /* push old task's pc */
+ stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */
+ ldmfd r1, {r1-r4} /* restore r0-r3 of the interrupt thread */
+ stmfd sp!, {r1-r4} /* push old task's r0-r3 */
+ stmfd sp!, {r0} /* push old task's cpsr */
#ifdef RT_USING_LWP
- stmfd sp, {r13, r14}^ @push usr_sp, usr_lr
- sub sp, #8
+ stmfd sp, {r13, r14}^ /*push usr_sp, usr_lr */
+ sub sp, #8
#endif
+
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
@@ -323,16 +465,22 @@ rt_hw_context_switch_interrupt_do:
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
- str sp, [r5] @ store sp in preempted tasks's TCB
+ str sp, [r5] /* store sp in preempted tasks's TCB */
ldr r6, =rt_interrupt_to_thread
ldr r6, [r6]
- ldr sp, [r6] @ get new task's stack pointer
+ ldr sp, [r6] /* get new task's stack pointer */
- bl rt_interrupt_hook
+ bl rt_thread_self
+#ifdef RT_USING_USERSPACE
+ mov r4, r0
+ bl lwp_mmu_switch
+ mov r0, r4
+ bl lwp_user_setting_restore
+#endif
#ifdef RT_USING_FPU
-/* fpu context */
+ /* fpu context */
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
@@ -345,36 +493,43 @@ rt_hw_context_switch_interrupt_do:
#endif
#ifdef RT_USING_LWP
- ldmfd sp, {r13, r14}^ @pop usr_sp, usr_lr
+ ldmfd sp, {r13, r14}^ /*pop usr_sp, usr_lr */
add sp, #8
#endif
- ldmfd sp!, {r4} @ pop new task's cpsr to spsr
+ ldmfd sp!, {r4} /* pop new task's cpsr to spsr */
msr spsr_cxsf, r4
- ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
+#ifdef RT_USING_LWP
+ and r4, #0x1f
+ cmp r4, #0x10
+ bne 1f
+ ldmfd sp!, {r0-r12,lr}
+ ldmfd sp!, {lr}
+ b arch_ret_to_user
+1:
+#endif
+ /* pop new task's r0-r12,lr & pc, copy spsr to cpsr */
+ ldmfd sp!, {r0-r12,lr,pc}^
#endif
.macro push_svc_reg
- sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */
- stmia sp, {r0 - r12} @/* Calling r0-r12 */
+ sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
+ stmia sp, {r0 - r12} /* Calling r0-r12 */
mov r0, sp
- mrs r6, spsr @/* Save CPSR */
- str lr, [r0, #15*4] @/* Push PC */
- str r6, [r0, #16*4] @/* Push CPSR */
- mrs r5, cpsr @/* Save CPSR */
-
- and r4, r6, #0x1F
- cmp r4, #Mode_USR
- moveq r6, #Mode_SYS
-
- orr r6, r6, #0x80 @/* Switch to previous mode, then save SP & PC */
- msr cpsr_c, r6
- str sp, [r0, #13*4] @/* Save calling SP */
- str lr, [r0, #14*4] @/* Save calling PC */
-
- msr cpsr_c, r5 @/* Switch back to current mode */
+ add sp, sp, #17 * 4
+ mrs r6, spsr /* Save CPSR */
+ str lr, [r0, #15*4] /* Push PC */
+ str r6, [r0, #16*4] /* Push CPSR */
+ and r1, r6, #0x1f
+ cmp r1, #0x10
+ cps #Mode_SYS
+ streq sp, [r0, #13*4] /* Save calling SP */
+ streq lr, [r0, #14*4] /* Save calling PC */
+ cps #Mode_SVC
+ strne sp, [r0, #13*4] /* Save calling SP */
+ strne lr, [r0, #14*4] /* Save calling PC */
.endm
.align 5
@@ -388,9 +543,10 @@ vector_swi:
.globl vector_undef
vector_undef:
push_svc_reg
- cps #Mode_UND
bl rt_hw_trap_undef
+ cps #Mode_UND
#ifdef RT_USING_FPU
+ sub sp, sp, #17 * 4
ldr lr, [sp, #15*4]
ldmia sp, {r0 - r12}
add sp, sp, #17 * 4
@@ -402,15 +558,57 @@ vector_undef:
.globl vector_pabt
vector_pabt:
push_svc_reg
+#ifdef RT_USING_USERSPACE
+ /* cp Mode_ABT stack to SVC */
+ sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
+ mov lr, r0
+ ldmia lr, {r0 - r12}
+ stmia sp, {r0 - r12}
+ add r1, lr, #13 * 4
+ add r2, sp, #13 * 4
+ ldmia r1, {r4 - r7}
+ stmia r2, {r4 - r7}
+ mov r0, sp
+ bl rt_hw_trap_pabt
+ /* return to user */
+ ldr lr, [sp, #16*4] /* orign spsr */
+ msr spsr_cxsf, lr
+ ldr lr, [sp, #15*4] /* orign pc */
+ ldmia sp, {r0 - r12}
+ add sp, #17 * 4
+ b arch_ret_to_user
+#else
bl rt_hw_trap_pabt
b .
+#endif
.align 5
.globl vector_dabt
vector_dabt:
push_svc_reg
+#ifdef RT_USING_USERSPACE
+ /* cp Mode_ABT stack to SVC */
+ sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
+ mov lr, r0
+ ldmia lr, {r0 - r12}
+ stmia sp, {r0 - r12}
+ add r1, lr, #13 * 4
+ add r2, sp, #13 * 4
+ ldmia r1, {r4 - r7}
+ stmia r2, {r4 - r7}
+ mov r0, sp
+ bl rt_hw_trap_dabt
+ /* return to user */
+ ldr lr, [sp, #16*4] /* orign spsr */
+ msr spsr_cxsf, lr
+ ldr lr, [sp, #15*4] /* orign pc */
+ ldmia sp, {r0 - r12}
+ add sp, #17 * 4
+ b arch_ret_to_user
+#else
bl rt_hw_trap_dabt
b .
+#endif
.align 5
.globl vector_resv
@@ -420,8 +618,26 @@ vector_resv:
b .
#ifdef RT_USING_SMP
-.global secondary_cpu_start
-secondary_cpu_start:
+.global rt_hw_clz
+rt_hw_clz:
+ clz r0, r0
+ bx lr
+
+.global rt_secondary_cpu_entry
+rt_secondary_cpu_entry:
+#ifdef RT_USING_USERSPACE
+ ldr r5, =PV_OFFSET
+
+ ldr lr, =after_enable_mmu_n
+ ldr r0, =init_mtbl
+ add r0, r5
+ b enable_mmu
+
+after_enable_mmu_n:
+ ldr r0, =MMUTable
+ add r0, r5
+ bl rt_hw_mmu_switch
+#endif
#ifdef RT_USING_FPU
mov r4, #0xfffffff
@@ -431,60 +647,37 @@ secondary_cpu_start:
mrc p15, 0, r1, c1, c0, 1
mov r0, #(1<<6)
orr r1, r0
- mcr p15, 0, r1, c1, c0, 1 //enable smp
+ mcr p15, 0, r1, c1, c0, 1 /* enable smp */
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<13)
mcr p15, 0, r0, c1, c0, 0
- /* enable branch prediction */
- mrc p15, 0, r0, c1, c0, 0
- orr r0, r0, #(1<<11)
- mcr p15, 0, r0, c1, c0, 0
-
- @ get cpu id, and subtract the offset from the stacks base address
- bl rt_hw_cpu_id
- sub r5, r0, #1
-
- ldr r0, =SUB_ISR_Stack_Size
- mul r0, r0, r5 @r0 = SUB_ISR_Stack_Size * (cpuid - 1)
- ldr r1, =sub_stack_top
- sub r0, r1, r0 @r0 = sub_stack_top - (SUB_ISR_Stack_Size * (cpuid - 1))
-
- cps #Mode_SVC
- mov sp, r0
- sub r0, r0, #SUB_SVC_Stack_Size
-
- cps #Mode_UND
- mov sp, r0
- sub r0, r0, #SUB_UND_Stack_Size
-
- cps #Mode_ABT
- mov sp, r0
- sub r0, r0, #SUB_ABT_Stack_Size
-
- cps #Mode_FIQ
- mov sp, r0
- sub r0, r0, #SUB_RT_FIQ_STACK_PGSZ
-
- cps #Mode_IRQ
- mov sp, r0
- sub r0, r0, #SUB_RT_IRQ_STACK_PGSZ
-
- cps #Mode_SVC
+ bl stack_setup
/* initialize the mmu table and enable mmu */
+#ifndef RT_USING_USERSPACE
bl rt_hw_mmu_init
+#endif
- b secondary_cpu_c_start
+ b rt_hw_secondary_cpu_bsp_start
+#endif
+
+#ifndef RT_CPUS_NR
+#define RT_CPUS_NR 1
+#endif
.bss
-.align 2 //align to 2~2=4
+.align 3 /* align to 2~3=8 */
+svc_stack_n:
+ .space (RT_CPUS_NR << 12)
+svc_stack_n_limit:
-.global sub_stack_top /* used for backtrace to calculate stack top of irq mode */
+irq_stack_n:
+ .space (RT_CPUS_NR << 12)
-sub_stack_start:
- .space (SUB_ISR_Stack_Size * (RT_CPUS_NR-1))
-sub_stack_top:
+und_stack_n:
+ .space (RT_CPUS_NR << 12)
-#endif
+abt_stack_n:
+ .space (RT_CPUS_NR << 12)
diff --git a/libcpu/arm/cortex-a/trap.c b/libcpu/arm/cortex-a/trap.c
index e8b3c8f0ec..82bb6f2f78 100644
--- a/libcpu/arm/cortex-a/trap.c
+++ b/libcpu/arm/cortex-a/trap.c
@@ -11,26 +11,51 @@
#include <rtthread.h>
#include <rthw.h>
#include <board.h>
+#include <backtrace.h>
-#include "armv7.h"
#include "interrupt.h"
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
+#ifdef RT_USING_FINSH
extern long list_thread(void);
#endif
-static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#include <lwp_arch.h>
-/**
- * This function set the hook, which is invoked on fault exception handling.
- *
- * @param exception_handle the exception handling hook function.
- */
-void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
+#ifdef LWP_USING_CORE_DUMP
+#include <lwp_core_dump.h>
+#endif
+
+void sys_exit(int value);
+void check_user_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *info)
{
- rt_exception_hook = exception_handle;
+ uint32_t mode = regs->cpsr;
+
+ if ((mode & 0x1f) == 0x10)
+ {
+ rt_kprintf("%s! pc = 0x%08x\n", info, regs->pc - pc_adj);
+#ifdef LWP_USING_CORE_DUMP
+ lwp_core_dump(regs, pc_adj);
+#endif
+ sys_exit(-1);
+ }
}
+int check_user_stack(struct rt_hw_exp_stack *regs)
+{
+ void* dfar = RT_NULL;
+
+ asm volatile ("MRC p15, 0, %0, c6, c0, 0":"=r"(dfar));
+ if (arch_expand_user_stack(dfar))
+ {
+ regs->pc -= 8;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
/**
* this function will show registers of CPU
*
@@ -45,25 +70,18 @@ void rt_hw_show_register(struct rt_hw_exp_stack *regs)
rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip);
rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc);
rt_kprintf("cpsr:0x%08x\n", regs->cpsr);
- if (rt_exception_hook != RT_NULL)
+#ifdef RT_USING_USERSPACE
{
- rt_err_t result;
-
- result = rt_exception_hook(regs);
- if (result == RT_EOK) return;
+ uint32_t v;
+ asm volatile ("MRC p15, 0, %0, c5, c0, 0":"=r"(v));
+ rt_kprintf("dfsr:0x%08x\n", v);
+ asm volatile ("MRC p15, 0, %0, c2, c0, 0":"=r"(v));
+ rt_kprintf("ttbr0:0x%08x\n", v);
+ asm volatile ("MRC p15, 0, %0, c6, c0, 0":"=r"(v));
+ rt_kprintf("dfar:0x%08x\n", v);
+ rt_kprintf("0x%08x -> 0x%08x\n", v, rt_hw_mmu_v2p(&mmu_info, (void *)v));
}
-}
-
-void (*rt_trap_hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type);
-
-/**
- * This function will set a hook function to trap handler.
- *
- * @param hook the hook function
- */
-void rt_hw_trap_set_hook(void (*hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type))
-{
- rt_trap_hook = hook;
+#endif
}
/**
@@ -74,49 +92,52 @@ void rt_hw_trap_set_hook(void (*hook)(struct rt_hw_exp_stack *regs, const char *
*
* @note never invoke this function in application
*/
+#ifdef RT_USING_FPU
+void set_fpexc(rt_uint32_t val);
+#endif
void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
{
#ifdef RT_USING_FPU
{
- uint32_t val;
+ uint32_t ins;
uint32_t addr;
if (regs->cpsr & (1 << 5))
{
/* thumb mode */
addr = regs->pc - 2;
+ ins = (uint32_t)*(uint16_t *)addr;
+ if ((ins & (3 << 11)) != 0)
+ {
+ /* 32 bit ins */
+ ins <<= 16;
+ ins += *(uint16_t *)(addr + 2);
+ }
}
else
{
addr = regs->pc - 4;
+ ins = *(uint32_t *)addr;
}
- asm volatile ("vmrs %0, fpexc" : "=r"(val)::"memory");
-
- if (!(val & 0x40000000))
+ if ((ins & 0xe00) == 0xa00)
{
/* float ins */
- val = (1U << 30);
-
- asm volatile ("vmsr fpexc, %0"::"r"(val):"memory");
+ set_fpexc(1U << 30);
regs->pc = addr;
return;
}
}
#endif
-
- if (rt_trap_hook == RT_NULL)
- {
- rt_kprintf("undefined instruction:\n");
- rt_hw_show_register(regs);
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- list_thread();
+#ifdef RT_USING_LWP
+ check_user_fault(regs, 4, "User undefined instruction");
#endif
- rt_hw_cpu_shutdown();
- }
- else
- {
- rt_trap_hook(regs, "undefined instruction", UND_EXCEPTION);
- }
+ rt_unwind(regs, 4);
+ rt_kprintf("undefined instruction:\n");
+ rt_hw_show_register(regs);
+#ifdef RT_USING_FINSH
+ list_thread();
+#endif
+ rt_hw_cpu_shutdown();
}
/**
@@ -130,19 +151,12 @@ void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
*/
void rt_hw_trap_swi(struct rt_hw_exp_stack *regs)
{
- if (rt_trap_hook == RT_NULL)
- {
- rt_kprintf("software interrupt:\n");
- rt_hw_show_register(regs);
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- list_thread();
+ rt_kprintf("software interrupt:\n");
+ rt_hw_show_register(regs);
+#ifdef RT_USING_FINSH
+ list_thread();
#endif
- rt_hw_cpu_shutdown();
- }
- else
- {
- rt_trap_hook(regs, "software instruction", SWI_EXCEPTION);
- }
+ rt_hw_cpu_shutdown();
}
/**
@@ -155,19 +169,20 @@ void rt_hw_trap_swi(struct rt_hw_exp_stack *regs)
*/
void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
{
- if (rt_trap_hook == RT_NULL)
- {
- rt_kprintf("prefetch abort:\n");
- rt_hw_show_register(regs);
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- list_thread();
-#endif
- rt_hw_cpu_shutdown();
- }
- else
+#ifdef RT_USING_LWP
+ if (dbg_check_event(regs, 4))
{
- rt_trap_hook(regs, "prefetch abort", PABT_EXCEPTION);
+ return;
}
+ check_user_fault(regs, 4, "User prefetch abort");
+#endif
+ rt_unwind(regs, 4);
+ rt_kprintf("prefetch abort:\n");
+ rt_hw_show_register(regs);
+#ifdef RT_USING_FINSH
+ list_thread();
+#endif
+ rt_hw_cpu_shutdown();
}
/**
@@ -180,19 +195,24 @@ void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
*/
void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
{
- if (rt_trap_hook == RT_NULL)
+#ifdef RT_USING_LWP
+ if (dbg_check_event(regs, 8))
{
- rt_kprintf("data abort:");
- rt_hw_show_register(regs);
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- list_thread();
-#endif
- rt_hw_cpu_shutdown();
+ return;
}
- else
+ if (check_user_stack(regs))
{
- rt_trap_hook(regs, "data abort", DABT_EXCEPTION);
+ return;
}
+ check_user_fault(regs, 8, "User data abort");
+#endif
+ rt_unwind(regs, 8);
+ rt_kprintf("data abort:");
+ rt_hw_show_register(regs);
+#ifdef RT_USING_FINSH
+ list_thread();
+#endif
+ rt_hw_cpu_shutdown();
}
/**
@@ -204,32 +224,87 @@ void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
*/
void rt_hw_trap_resv(struct rt_hw_exp_stack *regs)
{
- if (rt_trap_hook == RT_NULL)
- {
- rt_kprintf("reserved trap:\n");
- rt_hw_show_register(regs);
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- list_thread();
+ rt_kprintf("reserved trap:\n");
+ rt_hw_show_register(regs);
+#ifdef RT_USING_FINSH
+ list_thread();
#endif
- rt_hw_cpu_shutdown();
- }
- else
- {
- rt_trap_hook(regs, "reserved trap", RESV_EXCEPTION);
- }
+ rt_hw_cpu_shutdown();
}
void rt_hw_trap_irq(void)
{
+#ifdef SOC_BCM283x
+ extern rt_uint8_t core_timer_flag;
void *param;
- int int_ack;
- int ir;
+ uint32_t irq;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
+ uint32_t value = 0;
+ value = IRQ_PEND_BASIC & 0x3ff;
- int_ack = rt_hw_interrupt_get_irq();
+ if(core_timer_flag != 0)
+ {
+ uint32_t cpu_id = rt_hw_cpu_id();
+ uint32_t int_source = CORE_IRQSOURCE(cpu_id);
+ if (int_source & 0x0f)
+ {
+ if (int_source & 0x08)
+ {
+ isr_func = isr_table[IRQ_ARM_TIMER].handler;
+ #ifdef RT_USING_INTERRUPT_INFO
+ isr_table[IRQ_ARM_TIMER].counter++;
+ #endif
+ if (isr_func)
+ {
+ param = isr_table[IRQ_ARM_TIMER].param;
+ isr_func(IRQ_ARM_TIMER, param);
+ }
+ }
+ }
+ }
- ir = int_ack & GIC_ACK_INTID_MASK;
+ /* local interrupt*/
+ if (value)
+ {
+ if (value & (1 << 8))
+ {
+ value = IRQ_PEND1;
+ irq = __rt_ffs(value) - 1;
+ }
+ else if (value & (1 << 9))
+ {
+ value = IRQ_PEND2;
+ irq = __rt_ffs(value) + 31;
+ }
+ else
+ {
+ value &= 0x0f;
+ irq = __rt_ffs(value) + 63;
+ }
+
+ /* get interrupt service routine */
+ isr_func = isr_table[irq].handler;
+#ifdef RT_USING_INTERRUPT_INFO
+ isr_table[irq].counter++;
+#endif
+ if (isr_func)
+ {
+ /* Interrupt for myself. */
+ param = isr_table[irq].param;
+ /* turn to interrupt service routine */
+ isr_func(irq, param);
+ }
+ }
+#else
+ void *param;
+ int ir, ir_real;
+ rt_isr_handler_t isr_func;
+ extern struct rt_irq_desc isr_table[];
+
+ ir = rt_hw_interrupt_get_irq();
+
+ ir_real = ir & 0x3ff;
if (ir == 1023)
{
/* Spurious interrupt */
@@ -237,20 +312,21 @@ void rt_hw_trap_irq(void)
}
/* get interrupt service routine */
- isr_func = isr_table[ir].handler;
+ isr_func = isr_table[ir_real].handler;
#ifdef RT_USING_INTERRUPT_INFO
- isr_table[ir].counter++;
+ isr_table[ir_real].counter++;
#endif
if (isr_func)
{
/* Interrupt for myself. */
- param = isr_table[ir].param;
+ param = isr_table[ir_real].param;
/* turn to interrupt service routine */
isr_func(ir, param);
}
/* end of interrupt */
- rt_hw_interrupt_ack(int_ack);
+ rt_hw_interrupt_ack(ir);
+#endif
}
void rt_hw_trap_fiq(void)
diff --git a/libcpu/arm/cortex-a/vector_gcc.S b/libcpu/arm/cortex-a/vector_gcc.S
index 60d3c6cf1d..eb872db71f 100644
--- a/libcpu/arm/cortex-a/vector_gcc.S
+++ b/libcpu/arm/cortex-a/vector_gcc.S
@@ -7,13 +7,19 @@
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
+
+#include "rtconfig.h"
.section .vectors, "ax"
.code 32
.globl system_vectors
system_vectors:
+#ifdef RT_USING_USERSPACE
+ b _reset
+#else
ldr pc, _vector_reset
+#endif
ldr pc, _vector_undef
ldr pc, _vector_swi
ldr pc, _vector_pabt
diff --git a/libcpu/arm/cortex-m4/cpuport.h b/libcpu/arm/cortex-m4/cpuport.h
new file mode 100644
index 0000000000..05bb12cf2f
--- /dev/null
+++ b/libcpu/arm/cortex-m4/cpuport.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/arm/cortex-m7/cpuport.h b/libcpu/arm/cortex-m7/cpuport.h
new file mode 100644
index 0000000000..05bb12cf2f
--- /dev/null
+++ b/libcpu/arm/cortex-m7/cpuport.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/arm/s3c24x0/cpuport.h b/libcpu/arm/s3c24x0/cpuport.h
new file mode 100644
index 0000000000..05bb12cf2f
--- /dev/null
+++ b/libcpu/arm/s3c24x0/cpuport.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/arm/zynqmp-r5/cpuport.h b/libcpu/arm/zynqmp-r5/cpuport.h
new file mode 100644
index 0000000000..05bb12cf2f
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/cpuport.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/mips/gs264/cpuport.h b/libcpu/mips/gs264/cpuport.h
new file mode 100644
index 0000000000..05bb12cf2f
--- /dev/null
+++ b/libcpu/mips/gs264/cpuport.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+
+#endif /*CPUPORT_H__*/
diff --git a/libcpu/risc-v/SConscript b/libcpu/risc-v/SConscript
index 6ddfe7ecb3..1a279ffe4b 100644
--- a/libcpu/risc-v/SConscript
+++ b/libcpu/risc-v/SConscript
@@ -16,6 +16,8 @@ elif rtconfig.CPU == "nuclei" :
group = group
elif rtconfig.CPU == "virt64" :
group = group
+elif rtconfig.CPU == "c906" :
+ group = group
elif rtconfig.CPU == "ch32v1" :
group = group
elif rtconfig.CPU == "ch32v3" :
@@ -26,7 +28,7 @@ else :
group = group + SConscript(os.path.join('common', 'SConscript'))
# cpu porting code files
-if rtconfig.CPU == "e9xx" :
+if rtconfig.CPU == "e9xx" or rtconfig.CPU == "c906":
group = group + SConscript(os.path.join(rtconfig.VENDOR, rtconfig.CPU, 'SConscript'))
elif rtconfig.CPU in list:
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
diff --git a/libcpu/risc-v/common/context_gcc.S b/libcpu/risc-v/common/context_gcc.S
index e5fc8536ea..e458268e11 100644
--- a/libcpu/risc-v/common/context_gcc.S
+++ b/libcpu/risc-v/common/context_gcc.S
@@ -10,6 +10,7 @@
* 2020/11/20 BalanceTWK Add FPU support
*/
+#define __ASSEMBLY__
#include "cpuport.h"
#ifdef RT_USING_SMP
diff --git a/libcpu/risc-v/common/cpuport.c b/libcpu/risc-v/common/cpuport.c
index 9e9957e66c..c35f0da6f0 100644
--- a/libcpu/risc-v/common/cpuport.c
+++ b/libcpu/risc-v/common/cpuport.c
@@ -138,7 +138,7 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
* #endif
*/
#ifndef RT_USING_SMP
-RT_WEAK void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
+RT_WEAK void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
{
if (rt_thread_switch_interrupt_flag == 0)
rt_interrupt_from_thread = from;
diff --git a/libcpu/risc-v/common/cpuport.h b/libcpu/risc-v/common/cpuport.h
index e625d9f91f..472dd6abe4 100644
--- a/libcpu/risc-v/common/cpuport.h
+++ b/libcpu/risc-v/common/cpuport.h
@@ -14,6 +14,18 @@
#include <rtconfig.h>
+#ifndef __ASSEMBLY__
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
+#endif
+#endif
+
/* bytes of register width */
#ifdef ARCH_CPU_64BIT
#define STORE sd
diff --git a/libcpu/risc-v/k210/interrupt_gcc.S b/libcpu/risc-v/k210/interrupt_gcc.S
index d695d04e4b..2e4a5c712b 100644
--- a/libcpu/risc-v/k210/interrupt_gcc.S
+++ b/libcpu/risc-v/k210/interrupt_gcc.S
@@ -9,6 +9,7 @@
* 2018/12/27 Jesven Add SMP schedule
*/
+#define __ASSEMBLY__
#include "cpuport.h"
.section .text.entry
diff --git a/libcpu/risc-v/k210/startup_gcc.S b/libcpu/risc-v/k210/startup_gcc.S
index 69f65f7f92..a860cf8dc4 100644
--- a/libcpu/risc-v/k210/startup_gcc.S
+++ b/libcpu/risc-v/k210/startup_gcc.S
@@ -9,6 +9,7 @@
* 2018/12/27 Jesven Add SMP support
*/
+#define __ASSEMBLY__
#define MSTATUS_FS 0x00006000U /* initial state of FPU */
#include <cpuport.h>
diff --git a/libcpu/risc-v/t-head/c906/SConscript b/libcpu/risc-v/t-head/c906/SConscript
new file mode 100644
index 0000000000..2f698f530a
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/SConscript
@@ -0,0 +1,12 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S')
+CPPPATH = [cwd]
+ASFLAGS = ''
+
+group = DefineGroup('cpu', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS)
+
+Return('group')
diff --git a/libcpu/risc-v/t-head/c906/asm/sbiasm.h b/libcpu/risc-v/t-head/c906/asm/sbiasm.h
new file mode 100644
index 0000000000..4639fba68c
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/asm/sbiasm.h
@@ -0,0 +1,10 @@
+#ifndef _SBI_ASM_H
+#define _SBI_ASM_H
+
+.macro SBI_CALL which
+ li a7, \which
+ ecall
+ nop
+.endm
+
+#endif /* _SBI_ASM_H */
diff --git a/libcpu/risc-v/t-head/c906/asm/sbidef.h b/libcpu/risc-v/t-head/c906/asm/sbidef.h
new file mode 100644
index 0000000000..5bcf58ade7
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/asm/sbidef.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, Xim
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+#ifndef _ASM_SBI_DEF_H
+#define _ASM_SBI_DEF_H
+
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define SBI_CONSOLE_PUTSTR 9
+
+#define SBI_SD_WRITE 10
+#define SBI_SD_READ 11
+#define SBI_NET_WRITE 12
+#define SBI_NET_READ 13
+
+#endif /* _ASM_SBI_DEF_H */
diff --git a/libcpu/risc-v/t-head/c906/cache.c b/libcpu/risc-v/t-head/c906/cache.c
new file mode 100644
index 0000000000..34f2baff34
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/cache.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-29 lizhirui first version
+ * 2021-11-05 JasonHu add c906 cache inst
+ * 2022-11-09 WangXiaoyao Support cache coherence operations;
+ * improve portability and make
+ * no assumption on undefined behavior
+ */
+
+#include <rthw.h>
+#include <rtdef.h>
+#include <board.h>
+#include <riscv.h>
+
+#include "opcode.h"
+#include "cache.h"
+
+#define L1_CACHE_BYTES (64)
+
+/**
+ * GCC version not support t-head cache flush, so we use fixed code to achieve.
+ * The following function cannot be optimized.
+ */
+static void dcache_wb_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
+static void dcache_inv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
+static void dcache_wbinv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
+static void icache_inv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
+
+#define CACHE_OP_RS1 %0
+#define CACHE_OP_RANGE(instr) \
+ { \
+ register rt_ubase_t i = start & ~(L1_CACHE_BYTES - 1); \
+ for (; i < end; i += L1_CACHE_BYTES) \
+ { \
+ __asm__ volatile(instr ::"r"(i) \
+ : "memory"); \
+ } \
+ }
+
+static void dcache_wb_range(unsigned long start, unsigned long end)
+{
+ CACHE_OP_RANGE(OPC_DCACHE_CVA(CACHE_OP_RS1));
+}
+
+static void dcache_inv_range(unsigned long start, unsigned long end)
+{
+ CACHE_OP_RANGE(OPC_DCACHE_IVA(CACHE_OP_RS1));
+}
+
+static void dcache_wbinv_range(unsigned long start, unsigned long end)
+{
+ CACHE_OP_RANGE(OPC_DCACHE_CIVA(CACHE_OP_RS1));
+}
+
+static void icache_inv_range(unsigned long start, unsigned long end)
+{
+ CACHE_OP_RANGE(OPC_ICACHE_IVA(CACHE_OP_RS1));
+}
+
+rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
+{
+ return L1_CACHE_BYTES;
+}
+
+rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
+{
+ return L1_CACHE_BYTES;
+}
+
+void rt_hw_cpu_icache_invalidate_local(void *addr, int size)
+{
+ icache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
+ rt_hw_cpu_sync_i();
+}
+
+void rt_hw_cpu_dcache_invalidate_local(void *addr, int size)
+{
+ dcache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
+ rt_hw_cpu_sync();
+}
+
+void rt_hw_cpu_dcache_clean_local(void *addr, int size)
+{
+ dcache_wb_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
+ rt_hw_cpu_sync();
+}
+
+void rt_hw_cpu_dcache_clean_invalidate_local(void *addr, int size)
+{
+ dcache_wbinv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
+ rt_hw_cpu_sync();
+}
+
+/**
+ * =====================================================
+ * Architecture Independent API
+ * =====================================================
+ */
+
+void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
+{
+ if (ops == RT_HW_CACHE_INVALIDATE)
+ {
+ rt_hw_cpu_icache_invalidate_local(addr, size);
+ }
+}
+
+void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
+{
+ if (ops == RT_HW_CACHE_FLUSH)
+ {
+ rt_hw_cpu_dcache_clean_local(addr, size);
+ }
+ else
+ {
+ rt_hw_cpu_dcache_invalidate_local(addr, size);
+ }
+}
+
+void rt_hw_sync_cache_local(void *addr, int size)
+{
+ rt_hw_cpu_dcache_clean_local(addr, size);
+ rt_hw_cpu_icache_invalidate_local(addr, size);
+}
+
+#ifdef RT_USING_LWP
+#include <lwp_arch.h>
+#define ICACHE (1 << 0)
+#define DCACHE (1 << 1)
+#define BCACHE (ICACHE | DCACHE)
+
+/**
+ * TODO moving syscall to kernel
+ */
+int sys_cacheflush(void *addr, int size, int cache)
+{
+ /* must in user space */
+ if ((size_t)addr >= USER_VADDR_START && (size_t)addr + size < USER_VADDR_TOP)
+ {
+ /**
+ * we DO NOT check argument 'cache' invalid error
+ */
+ if ((cache & DCACHE) != 0)
+ {
+ rt_hw_cpu_dcache_clean_invalidate_local(addr, size);
+ }
+ if ((cache & ICACHE) != 0)
+ {
+ rt_hw_cpu_icache_invalidate_local(addr, size);
+ }
+ return 0;
+ }
+ return -RT_ERROR;
+}
+#endif
diff --git a/libcpu/risc-v/t-head/c906/cache.h b/libcpu/risc-v/t-head/c906/cache.h
new file mode 100644
index 0000000000..c7dcac61ac
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/cache.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-05 JasonHu The first version
+ */
+
+#ifndef CACHE_H__
+#define CACHE_H__
+
+#include "opcode.h"
+
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE inline __attribute__((always_inline))
+#endif
+
+#define rt_hw_cpu_sync() __asm__ volatile(OPC_SYNC:: \
+ : "memory")
+
+#define rt_hw_cpu_sync_i() __asm__ volatile(OPC_SYNC_I:: \
+ : "memory");
+
+/**
+ * ========================================
+ * Local cpu cache maintainence operations
+ * ========================================
+ */
+
+void rt_hw_cpu_dcache_clean_local(void *addr, int size);
+void rt_hw_cpu_dcache_invalidate_local(void *addr, int size);
+void rt_hw_cpu_dcache_clean_invalidate_local(void *addr, int size);
+
+void rt_hw_cpu_icache_invalidate_local(void *addr, int size);
+
+ALWAYS_INLINE void rt_hw_cpu_dcache_clean_all_local(void)
+{
+ __asm__ volatile(OPC_DCACHE_CALL ::
+ : "memory");
+ rt_hw_cpu_sync();
+}
+
+ALWAYS_INLINE void rt_hw_cpu_dcache_invalidate_all_local(void)
+{
+ __asm__ volatile(OPC_DCACHE_IALL ::
+ : "memory");
+ rt_hw_cpu_sync();
+}
+
+ALWAYS_INLINE void rt_hw_cpu_dcache_clean_invalidate_all_local(void)
+{
+ __asm__ volatile(OPC_DCACHE_CIALL ::
+ : "memory");
+ rt_hw_cpu_sync();
+}
+
+ALWAYS_INLINE void rt_hw_cpu_icache_invalidate_all_local(void)
+{
+ __asm__ volatile(OPC_ICACHE_IALL ::
+ : "memory");
+ rt_hw_cpu_sync_i();
+}
+
+/**
+ * ========================================
+ * Multi-core cache maintainence operations
+ * ========================================
+ */
+
+#ifdef RT_USING_SMP
+#error "TODO: cache maintainence have not ported to RISC-V SMP yet"
+
+void rt_hw_cpu_dcache_clean(void *addr, int size);
+void rt_hw_cpu_dcache_invalidate(void *addr, int size);
+void rt_hw_cpu_dcache_clean_invalidate(void *addr, int size);
+
+void rt_hw_cpu_dcache_clean_all(void);
+void rt_hw_cpu_dcache_invalidate_all(void);
+void rt_hw_cpu_dcache_clean_invalidate_all(void);
+
+void rt_hw_cpu_icache_invalidate(void *addr, int size);
+void rt_hw_cpu_icache_invalidate_all(void);
+
+#else /* !RT_USING_SMP */
+
+#define rt_hw_cpu_dcache_clean rt_hw_cpu_dcache_clean_local
+#define rt_hw_cpu_dcache_invalidate rt_hw_cpu_dcache_invalidate_local
+#define rt_hw_cpu_dcache_clean_invalidate rt_hw_cpu_dcache_clean_invalidate_local
+
+#define rt_hw_cpu_dcache_clean_all rt_hw_cpu_dcache_clean_all_local
+#define rt_hw_cpu_dcache_invalidate_all rt_hw_cpu_dcache_invalidate_all_local
+#define rt_hw_cpu_dcache_clean_invalidate_all rt_hw_cpu_dcache_clean_invalidate_all_local
+
+#define rt_hw_cpu_icache_invalidate rt_hw_cpu_icache_invalidate_local
+#define rt_hw_cpu_icache_invalidate_all rt_hw_cpu_icache_invalidate_all_local
+
+#endif /* RT_USING_SMP */
+
+/**
+ * @brief Synchronize cache to Point of Coherent
+ */
+void rt_hw_sync_cache_local(void *addr, int size);
+
+#endif /* CACHE_H__ */
diff --git a/libcpu/risc-v/t-head/c906/context_gcc.S b/libcpu/risc-v/t-head/c906/context_gcc.S
new file mode 100644
index 0000000000..d121eac67d
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/context_gcc.S
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/28 Bernard The unify RISC-V porting implementation
+ * 2018/12/27 Jesven Add SMP support
+ * 2021/02/02 lizhirui Add userspace support
+ */
+
+#define __ASSEMBLY__
+#include "cpuport.h"
+#include "stackframe.h"
+
+ .globl rt_hw_context_switch_to
+rt_hw_context_switch_to:
+ LOAD sp, (a0)
+
+ la s0, rt_current_thread
+ LOAD s1, (s0)
+
+ #ifdef RT_USING_USERSPACE
+ mv a0, s1
+ jal lwp_mmu_switch
+ #endif
+
+ RESTORE_ALL
+ sret
+
+/*
+ * void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
+ *
+ * a0 --> from
+ * a1 --> to
+ */
+ .globl rt_hw_context_switch
+rt_hw_context_switch:
+ mv t2, sp
+ li t0, 0x120//set SPIE and SPP = 1
+ csrs sstatus, t0//if enter here,caller must be in system thread
+ csrw sepc, ra//return address
+ //saved from thread context
+ SAVE_ALL
+
+ STORE t2, 32 * REGBYTES(sp)//save user_sp
+
+ STORE sp, (a0)
+
+ //restore to thread context
+ LOAD sp, (a1)
+
+ la s0, rt_current_thread
+ LOAD s1, (s0)
+
+ #ifdef RT_USING_USERSPACE
+ mv a0, s1
+ jal lwp_mmu_switch
+ #endif
+
+ RESTORE_ALL
+ sret
diff --git a/libcpu/risc-v/t-head/c906/cpuport.c b/libcpu/risc-v/t-head/c906/cpuport.c
new file mode 100644
index 0000000000..592f66bfb2
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/cpuport.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/28 Bernard The unify RISC-V porting code.
+ * 2021-02-11 lizhirui add gp support
+ * 2021-11-19 JasonHu add fpu support
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "cpuport.h"
+#include "stack.h"
+
+#include <lwp_arch.h>
+
+
+/**
+ * @brief from thread used interrupt context switch
+ *
+ */
+volatile rt_ubase_t rt_interrupt_from_thread = 0;
+/**
+ * @brief to thread used interrupt context switch
+ *
+ */
+volatile rt_ubase_t rt_interrupt_to_thread = 0;
+/**
+ * @brief flag to indicate context switch in interrupt or not
+ *
+ */
+volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
+
+
+/**
+ * This function will initialize thread stack
+ *
+ * @param tentry the entry of thread
+ * @param parameter the parameter of entry
+ * @param stack_addr the beginning stack address
+ * @param texit the function will be called when thread exit
+ *
+ * @return stack address
+ */
+rt_uint8_t *rt_hw_stack_init(void *tentry,
+ void *parameter,
+ rt_uint8_t *stack_addr,
+ void *texit)
+{
+ struct rt_hw_stack_frame *frame;
+ rt_uint8_t *stk;
+ int i;
+ extern int __global_pointer$;
+
+ stk = stack_addr + sizeof(rt_ubase_t);
+ stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES);
+ stk -= sizeof(struct rt_hw_stack_frame);
+
+ frame = (struct rt_hw_stack_frame *)stk;
+
+ for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
+ {
+ ((rt_ubase_t *)frame)[i] = 0xdeadbeef;
+ }
+
+ frame->ra = (rt_ubase_t)texit;
+ frame->gp = (rt_ubase_t)&__global_pointer$;
+ frame->a0 = (rt_ubase_t)parameter;
+ frame->epc = (rt_ubase_t)tentry;
+ frame->user_sp_exc_stack = (rt_ubase_t)(((rt_ubase_t)stk) + sizeof(struct rt_hw_stack_frame));
+
+ /* force to supervisor mode(SPP=1) and set SPIE and SUM to 1 */
+#ifdef ENABLE_FPU
+ frame->sstatus = 0x00046120; /* enable FPU */
+#else
+ frame->sstatus = 0x00040120;
+#endif
+
+ return stk;
+}
+
+/*
+ * #ifdef RT_USING_SMP
+ * void rt_hw_context_switch_interrupt(void *context, rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
+ * #else
+ * void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to);
+ * #endif
+ */
+#ifndef RT_USING_SMP
+void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
+{
+ if (rt_thread_switch_interrupt_flag == 0)
+ rt_interrupt_from_thread = from;
+
+ rt_interrupt_to_thread = to;
+ rt_thread_switch_interrupt_flag = 1;
+
+ return ;
+}
+#endif /* end of RT_USING_SMP */
+
+/** shutdown CPU */
+void rt_hw_cpu_shutdown()
+{
+ rt_uint32_t level;
+ rt_kprintf("shutdown...\n");
+
+ level = rt_hw_interrupt_disable();
+ while (level)
+ {
+ RT_ASSERT(0);
+ }
+}
+
+int rt_hw_cpu_id(void)
+{
+ return 0; /* d1 has one core */
+}
+
+void rt_hw_set_process_id(int pid)
+{
+ //TODO
+}
diff --git a/libcpu/risc-v/t-head/c906/cpuport.h b/libcpu/risc-v/t-head/c906/cpuport.h
new file mode 100644
index 0000000000..ceea4ef5af
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/cpuport.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-10-03 Bernard The first version
+ */
+
+#ifndef CPUPORT_H__
+#define CPUPORT_H__
+
+#include <rtconfig.h>
+#include <opcode.h>
+
+/* bytes of register width */
+#ifdef ARCH_CPU_64BIT
+#define STORE sd
+#define LOAD ld
+#define REGBYTES 8
+#else
+// error here, not portable
+#endif
+
+/* 33 general register */
+#define CTX_GENERAL_REG_NR 33
+
+#ifdef ENABLE_FPU
+/* 32 fpu register */
+#define CTX_FPU_REG_NR 32
+#else
+#define CTX_FPU_REG_NR 0
+#endif
+
+/* all context registers */
+#define CTX_REG_NR (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR)
+
+#ifndef __ASSEMBLY__
+rt_inline void rt_hw_dsb()
+{
+ asm volatile("fence":::"memory");
+}
+
+rt_inline void rt_hw_dmb()
+{
+ asm volatile("fence":::"memory");
+}
+
+rt_inline void rt_hw_isb()
+{
+ asm volatile(OPC_FENCE_I:::"memory");
+}
+
+int rt_hw_cpu_id(void);
+
+#endif
+
+#endif
+#ifdef RISCV_U_MODE
+#define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL
+#endif
diff --git a/libcpu/risc-v/t-head/c906/encoding.h b/libcpu/risc-v/t-head/c906/encoding.h
new file mode 100644
index 0000000000..7197e6b84b
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/encoding.h
@@ -0,0 +1,1331 @@
+// See LICENSE for license details.
+
+#ifndef RISCV_CSR_ENCODING_H
+#define RISCV_CSR_ENCODING_H
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_PUM 0x00040000
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_VM 0x1F000000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000 /* Floating-point Status */
+#define SSTATUS_FS_INITIAL 0x00002000
+#define SSTATUS_FS_CLEAN 0x00004000
+#define SSTATUS_FS_DIRTY 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_PUM 0x00040000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define DCSR_XDEBUGVER (3U<<30)
+#define DCSR_NDRESET (1<<29)
+#define DCSR_FULLRESET (1<<28)
+#define DCSR_EBREAKM (1<<15)
+#define DCSR_EBREAKH (1<<14)
+#define DCSR_EBREAKS (1<<13)
+#define DCSR_EBREAKU (1<<12)
+#define DCSR_STOPCYCLE (1<<10)
+#define DCSR_STOPTIME (1<<9)
+#define DCSR_CAUSE (7<<6)
+#define DCSR_DEBUGINT (1<<5)
+#define DCSR_HALT (1<<3)
+#define DCSR_STEP (1<<2)
+#define DCSR_PRV (3<<0)
+
+#define DCSR_CAUSE_NONE 0
+#define DCSR_CAUSE_SWBP 1
+#define DCSR_CAUSE_HWBP 2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_HALT 5
+
+#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT (1<<19)
+#define MCONTROL_TIMING (1<<18)
+#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_CHAIN (1<<11)
+#define MCONTROL_MATCH (0xf<<7)
+#define MCONTROL_M (1<<6)
+#define MCONTROL_H (1<<5)
+#define MCONTROL_S (1<<4)
+#define MCONTROL_U (1<<3)
+#define MCONTROL_EXECUTE (1<<2)
+#define MCONTROL_STORE (1<<1)
+#define MCONTROL_LOAD (1<<0)
+
+#define MCONTROL_TYPE_NONE 0
+#define MCONTROL_TYPE_MATCH 2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
+#define MCONTROL_ACTION_DEBUG_MODE 1
+#define MCONTROL_ACTION_TRACE_START 2
+#define MCONTROL_ACTION_TRACE_STOP 3
+#define MCONTROL_ACTION_TRACE_EMIT 4
+
+#define MCONTROL_MATCH_EQUAL 0
+#define MCONTROL_MATCH_NAPOT 1
+#define MCONTROL_MATCH_GE 2
+#define MCONTROL_MATCH_LT 3
+#define MCONTROL_MATCH_MASK_LOW 4
+#define MCONTROL_MATCH_MASK_HIGH 5
+
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_HSIP (1 << IRQ_H_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_HTIP (1 << IRQ_H_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_HEIP (1 << IRQ_H_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP /* software interrupt */
+#define SIP_STIP MIP_STIP /* timer interrupt */
+#define SIP_SEIP MIP_SEIP /* ext interrupt */
+
+#define SIE_SSIE (1 << IRQ_S_SOFT)
+#define SIE_STIE (1 << IRQ_S_TIMER)
+#define SIE_SEIE (1 << IRQ_S_EXT)
+
+#define RISCV_XLEN 64
+
+#define SCAUSE_INTERRUPT (1UL << (RISCV_XLEN - 1))
+
+#define SCAUSE_S_SOFTWARE_INTR 1
+#define SCAUSE_S_TIMER_INTR 5
+#define SCAUSE_S_EXTERNAL_INTR 9
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define VM_MBARE 0
+#define VM_MBB 1
+#define VM_MBBID 2
+#define VM_SV32 8
+#define VM_SV39 9
+#define VM_SV48 10
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define DEFAULT_RSTVEC 0x00001000
+#define DEFAULT_NMIVEC 0x00001004
+#define DEFAULT_MTVEC 0x00001010
+#define CONFIG_STRING_ADDR 0x0000100C
+#define EXT_IO_BASE 0x40000000
+#define DRAM_BASE 0x80000000
+
+// page table entry (PTE) fields
+#define PTE_V 0x001 // Valid
+#define PTE_R 0x002 // Read
+#define PTE_W 0x004 // Write
+#define PTE_X 0x008 // Execute
+#define PTE_U 0x010 // User
+#define PTE_G 0x020 // Global
+#define PTE_A 0x040 // Accessed
+#define PTE_D 0x080 // Dirty
+#define PTE_SOFT 0x300 // Reserved for Software
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#ifdef __riscv
+
+#ifdef __riscv64
+# define MSTATUS_SD MSTATUS64_SD
+# define SSTATUS_SD SSTATUS64_SD
+# define RISCV_PGLEVEL_BITS 9
+#else
+# define MSTATUS_SD MSTATUS32_SD
+# define SSTATUS_SD SSTATUS32_SD
+# define RISCV_PGLEVEL_BITS 10
+#endif /* end of __riscv64 */
+
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
+
+#ifndef __ASSEMBLY__
+
+#ifdef __GNUC__
+
+#define read_csr(reg) ({ unsigned long __tmp; \
+ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
+ __tmp; })
+
+#define write_csr(reg, val) ({ \
+ if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
+ asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
+ else \
+ asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
+
+#define swap_csr(reg, val) ({ unsigned long __tmp; \
+ if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \
+ else \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
+ __tmp; })
+
+#define set_csr(reg, bit) ({ unsigned long __tmp; \
+ if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+ else \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+ __tmp; })
+
+#define clear_csr(reg, bit) ({ unsigned long __tmp; \
+ if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+ else \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+ __tmp; })
+
+#define rdtime() read_csr(time)
+#define rdcycle() read_csr(cycle)
+#define rdinstret() read_csr(instret)
+
+#endif /* end of __GNUC__ */
+
+#endif /* end of __ASSEMBLY__ */
+
+#endif /* end of __riscv */
+
+#endif /* end of RISCV_CSR_ENCODING_H */
+
+/* Automatically generated by parse-opcodes */
+#ifndef RISCV_ENCODING_H
+#define RISCV_ENCODING_H
+#define MATCH_BEQ 0x63
+#define MASK_BEQ 0x707f
+#define MATCH_BNE 0x1063
+#define MASK_BNE 0x707f
+#define MATCH_BLT 0x4063
+#define MASK_BLT 0x707f
+#define MATCH_BGE 0x5063
+#define MASK_BGE 0x707f
+#define MATCH_BLTU 0x6063
+#define MASK_BLTU 0x707f
+#define MATCH_BGEU 0x7063
+#define MASK_BGEU 0x707f
+#define MATCH_JALR 0x67
+#define MASK_JALR 0x707f
+#define MATCH_JAL 0x6f
+#define MASK_JAL 0x7f
+#define MATCH_LUI 0x37
+#define MASK_LUI 0x7f
+#define MATCH_AUIPC 0x17
+#define MASK_AUIPC 0x7f
+#define MATCH_ADDI 0x13
+#define MASK_ADDI 0x707f
+#define MATCH_SLLI 0x1013
+#define MASK_SLLI 0xfc00707f
+#define MATCH_SLTI 0x2013
+#define MASK_SLTI 0x707f
+#define MATCH_SLTIU 0x3013
+#define MASK_SLTIU 0x707f
+#define MATCH_XORI 0x4013
+#define MASK_XORI 0x707f
+#define MATCH_SRLI 0x5013
+#define MASK_SRLI 0xfc00707f
+#define MATCH_SRAI 0x40005013
+#define MASK_SRAI 0xfc00707f
+#define MATCH_ORI 0x6013
+#define MASK_ORI 0x707f
+#define MATCH_ANDI 0x7013
+#define MASK_ANDI 0x707f
+#define MATCH_ADD 0x33
+#define MASK_ADD 0xfe00707f
+#define MATCH_SUB 0x40000033
+#define MASK_SUB 0xfe00707f
+#define MATCH_SLL 0x1033
+#define MASK_SLL 0xfe00707f
+#define MATCH_SLT 0x2033
+#define MASK_SLT 0xfe00707f
+#define MATCH_SLTU 0x3033
+#define MASK_SLTU 0xfe00707f
+#define MATCH_XOR 0x4033
+#define MASK_XOR 0xfe00707f
+#define MATCH_SRL 0x5033
+#define MASK_SRL 0xfe00707f
+#define MATCH_SRA 0x40005033
+#define MASK_SRA 0xfe00707f
+#define MATCH_OR 0x6033
+#define MASK_OR 0xfe00707f
+#define MATCH_AND 0x7033
+#define MASK_AND 0xfe00707f
+#define MATCH_ADDIW 0x1b
+#define MASK_ADDIW 0x707f
+#define MATCH_SLLIW 0x101b
+#define MASK_SLLIW 0xfe00707f
+#define MATCH_SRLIW 0x501b
+#define MASK_SRLIW 0xfe00707f
+#define MATCH_SRAIW 0x4000501b
+#define MASK_SRAIW 0xfe00707f
+#define MATCH_ADDW 0x3b
+#define MASK_ADDW 0xfe00707f
+#define MATCH_SUBW 0x4000003b
+#define MASK_SUBW 0xfe00707f
+#define MATCH_SLLW 0x103b
+#define MASK_SLLW 0xfe00707f
+#define MATCH_SRLW 0x503b
+#define MASK_SRLW 0xfe00707f
+#define MATCH_SRAW 0x4000503b
+#define MASK_SRAW 0xfe00707f
+#define MATCH_LB 0x3
+#define MASK_LB 0x707f
+#define MATCH_LH 0x1003
+#define MASK_LH 0x707f
+#define MATCH_LW 0x2003
+#define MASK_LW 0x707f
+#define MATCH_LD 0x3003
+#define MASK_LD 0x707f
+#define MATCH_LBU 0x4003
+#define MASK_LBU 0x707f
+#define MATCH_LHU 0x5003
+#define MASK_LHU 0x707f
+#define MATCH_LWU 0x6003
+#define MASK_LWU 0x707f
+#define MATCH_SB 0x23
+#define MASK_SB 0x707f
+#define MATCH_SH 0x1023
+#define MASK_SH 0x707f
+#define MATCH_SW 0x2023
+#define MASK_SW 0x707f
+#define MATCH_SD 0x3023
+#define MASK_SD 0x707f
+#define MATCH_FENCE 0xf
+#define MASK_FENCE 0x707f
+#define MATCH_FENCE_I 0x100f
+#define MASK_FENCE_I 0x707f
+#define MATCH_MUL 0x2000033
+#define MASK_MUL 0xfe00707f
+#define MATCH_MULH 0x2001033
+#define MASK_MULH 0xfe00707f
+#define MATCH_MULHSU 0x2002033
+#define MASK_MULHSU 0xfe00707f
+#define MATCH_MULHU 0x2003033
+#define MASK_MULHU 0xfe00707f
+#define MATCH_DIV 0x2004033
+#define MASK_DIV 0xfe00707f
+#define MATCH_DIVU 0x2005033
+#define MASK_DIVU 0xfe00707f
+#define MATCH_REM 0x2006033
+#define MASK_REM 0xfe00707f
+#define MATCH_REMU 0x2007033
+#define MASK_REMU 0xfe00707f
+#define MATCH_MULW 0x200003b
+#define MASK_MULW 0xfe00707f
+#define MATCH_DIVW 0x200403b
+#define MASK_DIVW 0xfe00707f
+#define MATCH_DIVUW 0x200503b
+#define MASK_DIVUW 0xfe00707f
+#define MATCH_REMW 0x200603b
+#define MASK_REMW 0xfe00707f
+#define MATCH_REMUW 0x200703b
+#define MASK_REMUW 0xfe00707f
+#define MATCH_AMOADD_W 0x202f
+#define MASK_AMOADD_W 0xf800707f
+#define MATCH_AMOXOR_W 0x2000202f
+#define MASK_AMOXOR_W 0xf800707f
+#define MATCH_AMOOR_W 0x4000202f
+#define MASK_AMOOR_W 0xf800707f
+#define MATCH_AMOAND_W 0x6000202f
+#define MASK_AMOAND_W 0xf800707f
+#define MATCH_AMOMIN_W 0x8000202f
+#define MASK_AMOMIN_W 0xf800707f
+#define MATCH_AMOMAX_W 0xa000202f
+#define MASK_AMOMAX_W 0xf800707f
+#define MATCH_AMOMINU_W 0xc000202f
+#define MASK_AMOMINU_W 0xf800707f
+#define MATCH_AMOMAXU_W 0xe000202f
+#define MASK_AMOMAXU_W 0xf800707f
+#define MATCH_AMOSWAP_W 0x800202f
+#define MASK_AMOSWAP_W 0xf800707f
+#define MATCH_LR_W 0x1000202f
+#define MASK_LR_W 0xf9f0707f
+#define MATCH_SC_W 0x1800202f
+#define MASK_SC_W 0xf800707f
+#define MATCH_AMOADD_D 0x302f
+#define MASK_AMOADD_D 0xf800707f
+#define MATCH_AMOXOR_D 0x2000302f
+#define MASK_AMOXOR_D 0xf800707f
+#define MATCH_AMOOR_D 0x4000302f
+#define MASK_AMOOR_D 0xf800707f
+#define MATCH_AMOAND_D 0x6000302f
+#define MASK_AMOAND_D 0xf800707f
+#define MATCH_AMOMIN_D 0x8000302f
+#define MASK_AMOMIN_D 0xf800707f
+#define MATCH_AMOMAX_D 0xa000302f
+#define MASK_AMOMAX_D 0xf800707f
+#define MATCH_AMOMINU_D 0xc000302f
+#define MASK_AMOMINU_D 0xf800707f
+#define MATCH_AMOMAXU_D 0xe000302f
+#define MASK_AMOMAXU_D 0xf800707f
+#define MATCH_AMOSWAP_D 0x800302f
+#define MASK_AMOSWAP_D 0xf800707f
+#define MATCH_LR_D 0x1000302f
+#define MASK_LR_D 0xf9f0707f
+#define MATCH_SC_D 0x1800302f
+#define MASK_SC_D 0xf800707f
+#define MATCH_ECALL 0x73
+#define MASK_ECALL 0xffffffff
+#define MATCH_EBREAK 0x100073
+#define MASK_EBREAK 0xffffffff
+#define MATCH_URET 0x200073
+#define MASK_URET 0xffffffff
+#define MATCH_SRET 0x10200073
+#define MASK_SRET 0xffffffff
+#define MATCH_HRET 0x20200073
+#define MASK_HRET 0xffffffff
+#define MATCH_MRET 0x30200073
+#define MASK_MRET 0xffffffff
+#define MATCH_DRET 0x7b200073
+#define MASK_DRET 0xffffffff
+#define MATCH_SFENCE_VM 0x10400073
+#define MASK_SFENCE_VM 0xfff07fff
+#define MATCH_WFI 0x10500073
+#define MASK_WFI 0xffffffff
+#define MATCH_CSRRW 0x1073
+#define MASK_CSRRW 0x707f
+#define MATCH_CSRRS 0x2073
+#define MASK_CSRRS 0x707f
+#define MATCH_CSRRC 0x3073
+#define MASK_CSRRC 0x707f
+#define MATCH_CSRRWI 0x5073
+#define MASK_CSRRWI 0x707f
+#define MATCH_CSRRSI 0x6073
+#define MASK_CSRRSI 0x707f
+#define MATCH_CSRRCI 0x7073
+#define MASK_CSRRCI 0x707f
+#define MATCH_FADD_S 0x53
+#define MASK_FADD_S 0xfe00007f
+#define MATCH_FSUB_S 0x8000053
+#define MASK_FSUB_S 0xfe00007f
+#define MATCH_FMUL_S 0x10000053
+#define MASK_FMUL_S 0xfe00007f
+#define MATCH_FDIV_S 0x18000053
+#define MASK_FDIV_S 0xfe00007f
+#define MATCH_FSGNJ_S 0x20000053
+#define MASK_FSGNJ_S 0xfe00707f
+#define MATCH_FSGNJN_S 0x20001053
+#define MASK_FSGNJN_S 0xfe00707f
+#define MATCH_FSGNJX_S 0x20002053
+#define MASK_FSGNJX_S 0xfe00707f
+#define MATCH_FMIN_S 0x28000053
+#define MASK_FMIN_S 0xfe00707f
+#define MATCH_FMAX_S 0x28001053
+#define MASK_FMAX_S 0xfe00707f
+#define MATCH_FSQRT_S 0x58000053
+#define MASK_FSQRT_S 0xfff0007f
+#define MATCH_FADD_D 0x2000053
+#define MASK_FADD_D 0xfe00007f
+#define MATCH_FSUB_D 0xa000053
+#define MASK_FSUB_D 0xfe00007f
+#define MATCH_FMUL_D 0x12000053
+#define MASK_FMUL_D 0xfe00007f
+#define MATCH_FDIV_D 0x1a000053
+#define MASK_FDIV_D 0xfe00007f
+#define MATCH_FSGNJ_D 0x22000053
+#define MASK_FSGNJ_D 0xfe00707f
+#define MATCH_FSGNJN_D 0x22001053
+#define MASK_FSGNJN_D 0xfe00707f
+#define MATCH_FSGNJX_D 0x22002053
+#define MASK_FSGNJX_D 0xfe00707f
+#define MATCH_FMIN_D 0x2a000053
+#define MASK_FMIN_D 0xfe00707f
+#define MATCH_FMAX_D 0x2a001053
+#define MASK_FMAX_D 0xfe00707f
+#define MATCH_FCVT_S_D 0x40100053
+#define MASK_FCVT_S_D 0xfff0007f
+#define MATCH_FCVT_D_S 0x42000053
+#define MASK_FCVT_D_S 0xfff0007f
+#define MATCH_FSQRT_D 0x5a000053
+#define MASK_FSQRT_D 0xfff0007f
+#define MATCH_FLE_S 0xa0000053
+#define MASK_FLE_S 0xfe00707f
+#define MATCH_FLT_S 0xa0001053
+#define MASK_FLT_S 0xfe00707f
+#define MATCH_FEQ_S 0xa0002053
+#define MASK_FEQ_S 0xfe00707f
+#define MATCH_FLE_D 0xa2000053
+#define MASK_FLE_D 0xfe00707f
+#define MATCH_FLT_D 0xa2001053
+#define MASK_FLT_D 0xfe00707f
+#define MATCH_FEQ_D 0xa2002053
+#define MASK_FEQ_D 0xfe00707f
+#define MATCH_FCVT_W_S 0xc0000053
+#define MASK_FCVT_W_S 0xfff0007f
+#define MATCH_FCVT_WU_S 0xc0100053
+#define MASK_FCVT_WU_S 0xfff0007f
+#define MATCH_FCVT_L_S 0xc0200053
+#define MASK_FCVT_L_S 0xfff0007f
+#define MATCH_FCVT_LU_S 0xc0300053
+#define MASK_FCVT_LU_S 0xfff0007f
+#define MATCH_FMV_X_S 0xe0000053
+#define MASK_FMV_X_S 0xfff0707f
+#define MATCH_FCLASS_S 0xe0001053
+#define MASK_FCLASS_S 0xfff0707f
+#define MATCH_FCVT_W_D 0xc2000053
+#define MASK_FCVT_W_D 0xfff0007f
+#define MATCH_FCVT_WU_D 0xc2100053
+#define MASK_FCVT_WU_D 0xfff0007f
+#define MATCH_FCVT_L_D 0xc2200053
+#define MASK_FCVT_L_D 0xfff0007f
+#define MATCH_FCVT_LU_D 0xc2300053
+#define MASK_FCVT_LU_D 0xfff0007f
+#define MATCH_FMV_X_D 0xe2000053
+#define MASK_FMV_X_D 0xfff0707f
+#define MATCH_FCLASS_D 0xe2001053
+#define MASK_FCLASS_D 0xfff0707f
+#define MATCH_FCVT_S_W 0xd0000053
+#define MASK_FCVT_S_W 0xfff0007f
+#define MATCH_FCVT_S_WU 0xd0100053
+#define MASK_FCVT_S_WU 0xfff0007f
+#define MATCH_FCVT_S_L 0xd0200053
+#define MASK_FCVT_S_L 0xfff0007f
+#define MATCH_FCVT_S_LU 0xd0300053
+#define MASK_FCVT_S_LU 0xfff0007f
+#define MATCH_FMV_S_X 0xf0000053
+#define MASK_FMV_S_X 0xfff0707f
+#define MATCH_FCVT_D_W 0xd2000053
+#define MASK_FCVT_D_W 0xfff0007f
+#define MATCH_FCVT_D_WU 0xd2100053
+#define MASK_FCVT_D_WU 0xfff0007f
+#define MATCH_FCVT_D_L 0xd2200053
+#define MASK_FCVT_D_L 0xfff0007f
+#define MATCH_FCVT_D_LU 0xd2300053
+#define MASK_FCVT_D_LU 0xfff0007f
+#define MATCH_FMV_D_X 0xf2000053
+#define MASK_FMV_D_X 0xfff0707f
+#define MATCH_FLW 0x2007
+#define MASK_FLW 0x707f
+#define MATCH_FLD 0x3007
+#define MASK_FLD 0x707f
+#define MATCH_FSW 0x2027
+#define MASK_FSW 0x707f
+#define MATCH_FSD 0x3027
+#define MASK_FSD 0x707f
+#define MATCH_FMADD_S 0x43
+#define MASK_FMADD_S 0x600007f
+#define MATCH_FMSUB_S 0x47
+#define MASK_FMSUB_S 0x600007f
+#define MATCH_FNMSUB_S 0x4b
+#define MASK_FNMSUB_S 0x600007f
+#define MATCH_FNMADD_S 0x4f
+#define MASK_FNMADD_S 0x600007f
+#define MATCH_FMADD_D 0x2000043
+#define MASK_FMADD_D 0x600007f
+#define MATCH_FMSUB_D 0x2000047
+#define MASK_FMSUB_D 0x600007f
+#define MATCH_FNMSUB_D 0x200004b
+#define MASK_FNMSUB_D 0x600007f
+#define MATCH_FNMADD_D 0x200004f
+#define MASK_FNMADD_D 0x600007f
+#define MATCH_C_NOP 0x1
+#define MASK_C_NOP 0xffff
+#define MATCH_C_ADDI16SP 0x6101
+#define MASK_C_ADDI16SP 0xef83
+#define MATCH_C_JR 0x8002
+#define MASK_C_JR 0xf07f
+#define MATCH_C_JALR 0x9002
+#define MASK_C_JALR 0xf07f
+#define MATCH_C_EBREAK 0x9002
+#define MASK_C_EBREAK 0xffff
+#define MATCH_C_LD 0x6000
+#define MASK_C_LD 0xe003
+#define MATCH_C_SD 0xe000
+#define MASK_C_SD 0xe003
+#define MATCH_C_ADDIW 0x2001
+#define MASK_C_ADDIW 0xe003
+#define MATCH_C_LDSP 0x6002
+#define MASK_C_LDSP 0xe003
+#define MATCH_C_SDSP 0xe002
+#define MASK_C_SDSP 0xe003
+#define MATCH_C_ADDI4SPN 0x0
+#define MASK_C_ADDI4SPN 0xe003
+#define MATCH_C_FLD 0x2000
+#define MASK_C_FLD 0xe003
+#define MATCH_C_LW 0x4000
+#define MASK_C_LW 0xe003
+#define MATCH_C_FLW 0x6000
+#define MASK_C_FLW 0xe003
+#define MATCH_C_FSD 0xa000
+#define MASK_C_FSD 0xe003
+#define MATCH_C_SW 0xc000
+#define MASK_C_SW 0xe003
+#define MATCH_C_FSW 0xe000
+#define MASK_C_FSW 0xe003
+#define MATCH_C_ADDI 0x1
+#define MASK_C_ADDI 0xe003
+#define MATCH_C_JAL 0x2001
+#define MASK_C_JAL 0xe003
+#define MATCH_C_LI 0x4001
+#define MASK_C_LI 0xe003
+#define MATCH_C_LUI 0x6001
+#define MASK_C_LUI 0xe003
+#define MATCH_C_SRLI 0x8001
+#define MASK_C_SRLI 0xec03
+#define MATCH_C_SRAI 0x8401
+#define MASK_C_SRAI 0xec03
+#define MATCH_C_ANDI 0x8801
+#define MASK_C_ANDI 0xec03
+#define MATCH_C_SUB 0x8c01
+#define MASK_C_SUB 0xfc63
+#define MATCH_C_XOR 0x8c21
+#define MASK_C_XOR 0xfc63
+#define MATCH_C_OR 0x8c41
+#define MASK_C_OR 0xfc63
+#define MATCH_C_AND 0x8c61
+#define MASK_C_AND 0xfc63
+#define MATCH_C_SUBW 0x9c01
+#define MASK_C_SUBW 0xfc63
+#define MATCH_C_ADDW 0x9c21
+#define MASK_C_ADDW 0xfc63
+#define MATCH_C_J 0xa001
+#define MASK_C_J 0xe003
+#define MATCH_C_BEQZ 0xc001
+#define MASK_C_BEQZ 0xe003
+#define MATCH_C_BNEZ 0xe001
+#define MASK_C_BNEZ 0xe003
+#define MATCH_C_SLLI 0x2
+#define MASK_C_SLLI 0xe003
+#define MATCH_C_FLDSP 0x2002
+#define MASK_C_FLDSP 0xe003
+#define MATCH_C_LWSP 0x4002
+#define MASK_C_LWSP 0xe003
+#define MATCH_C_FLWSP 0x6002
+#define MASK_C_FLWSP 0xe003
+#define MATCH_C_MV 0x8002
+#define MASK_C_MV 0xf003
+#define MATCH_C_ADD 0x9002
+#define MASK_C_ADD 0xf003
+#define MATCH_C_FSDSP 0xa002
+#define MASK_C_FSDSP 0xe003
+#define MATCH_C_SWSP 0xc002
+#define MASK_C_SWSP 0xe003
+#define MATCH_C_FSWSP 0xe002
+#define MASK_C_FSWSP 0xe003
+#define MATCH_CUSTOM0 0xb
+#define MASK_CUSTOM0 0x707f
+#define MATCH_CUSTOM0_RS1 0x200b
+#define MASK_CUSTOM0_RS1 0x707f
+#define MATCH_CUSTOM0_RS1_RS2 0x300b
+#define MASK_CUSTOM0_RS1_RS2 0x707f
+#define MATCH_CUSTOM0_RD 0x400b
+#define MASK_CUSTOM0_RD 0x707f
+#define MATCH_CUSTOM0_RD_RS1 0x600b
+#define MASK_CUSTOM0_RD_RS1 0x707f
+#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b
+#define MASK_CUSTOM0_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM1 0x2b
+#define MASK_CUSTOM1 0x707f
+#define MATCH_CUSTOM1_RS1 0x202b
+#define MASK_CUSTOM1_RS1 0x707f
+#define MATCH_CUSTOM1_RS1_RS2 0x302b
+#define MASK_CUSTOM1_RS1_RS2 0x707f
+#define MATCH_CUSTOM1_RD 0x402b
+#define MASK_CUSTOM1_RD 0x707f
+#define MATCH_CUSTOM1_RD_RS1 0x602b
+#define MASK_CUSTOM1_RD_RS1 0x707f
+#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b
+#define MASK_CUSTOM1_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM2 0x5b
+#define MASK_CUSTOM2 0x707f
+#define MATCH_CUSTOM2_RS1 0x205b
+#define MASK_CUSTOM2_RS1 0x707f
+#define MATCH_CUSTOM2_RS1_RS2 0x305b
+#define MASK_CUSTOM2_RS1_RS2 0x707f
+#define MATCH_CUSTOM2_RD 0x405b
+#define MASK_CUSTOM2_RD 0x707f
+#define MATCH_CUSTOM2_RD_RS1 0x605b
+#define MASK_CUSTOM2_RD_RS1 0x707f
+#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b
+#define MASK_CUSTOM2_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM3 0x7b
+#define MASK_CUSTOM3 0x707f
+#define MATCH_CUSTOM3_RS1 0x207b
+#define MASK_CUSTOM3_RS1 0x707f
+#define MATCH_CUSTOM3_RS1_RS2 0x307b
+#define MASK_CUSTOM3_RS1_RS2 0x707f
+#define MATCH_CUSTOM3_RD 0x407b
+#define MASK_CUSTOM3_RD 0x707f
+#define MATCH_CUSTOM3_RD_RS1 0x607b
+#define MASK_CUSTOM3_RD_RS1 0x707f
+#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b
+#define MASK_CUSTOM3_RD_RS1_RS2 0x707f
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#define CSR_CYCLE 0xc00
+#define CSR_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_HPMCOUNTER3 0xc03
+#define CSR_HPMCOUNTER4 0xc04
+#define CSR_HPMCOUNTER5 0xc05
+#define CSR_HPMCOUNTER6 0xc06
+#define CSR_HPMCOUNTER7 0xc07
+#define CSR_HPMCOUNTER8 0xc08
+#define CSR_HPMCOUNTER9 0xc09
+#define CSR_HPMCOUNTER10 0xc0a
+#define CSR_HPMCOUNTER11 0xc0b
+#define CSR_HPMCOUNTER12 0xc0c
+#define CSR_HPMCOUNTER13 0xc0d
+#define CSR_HPMCOUNTER14 0xc0e
+#define CSR_HPMCOUNTER15 0xc0f
+#define CSR_HPMCOUNTER16 0xc10
+#define CSR_HPMCOUNTER17 0xc11
+#define CSR_HPMCOUNTER18 0xc12
+#define CSR_HPMCOUNTER19 0xc13
+#define CSR_HPMCOUNTER20 0xc14
+#define CSR_HPMCOUNTER21 0xc15
+#define CSR_HPMCOUNTER22 0xc16
+#define CSR_HPMCOUNTER23 0xc17
+#define CSR_HPMCOUNTER24 0xc18
+#define CSR_HPMCOUNTER25 0xc19
+#define CSR_HPMCOUNTER26 0xc1a
+#define CSR_HPMCOUNTER27 0xc1b
+#define CSR_HPMCOUNTER28 0xc1c
+#define CSR_HPMCOUNTER29 0xc1d
+#define CSR_HPMCOUNTER30 0xc1e
+#define CSR_HPMCOUNTER31 0xc1f
+#define CSR_SSTATUS 0x100
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_SBADADDR 0x143
+#define CSR_SIP 0x144
+#define CSR_SPTBR 0x180
+#define CSR_MSTATUS 0x300
+#define CSR_MISA 0x301
+#define CSR_MEDELEG 0x302
+#define CSR_MIDELEG 0x303
+#define CSR_MIE 0x304
+#define CSR_MTVEC 0x305
+#define CSR_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MBADADDR 0x343
+#define CSR_MIP 0x344
+#define CSR_TSELECT 0x7a0
+#define CSR_TDATA1 0x7a1
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA3 0x7a3
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+#define CSR_MCYCLE 0xb00
+#define CSR_MINSTRET 0xb02
+#define CSR_MHPMCOUNTER3 0xb03
+#define CSR_MHPMCOUNTER4 0xb04
+#define CSR_MHPMCOUNTER5 0xb05
+#define CSR_MHPMCOUNTER6 0xb06
+#define CSR_MHPMCOUNTER7 0xb07
+#define CSR_MHPMCOUNTER8 0xb08
+#define CSR_MHPMCOUNTER9 0xb09
+#define CSR_MHPMCOUNTER10 0xb0a
+#define CSR_MHPMCOUNTER11 0xb0b
+#define CSR_MHPMCOUNTER12 0xb0c
+#define CSR_MHPMCOUNTER13 0xb0d
+#define CSR_MHPMCOUNTER14 0xb0e
+#define CSR_MHPMCOUNTER15 0xb0f
+#define CSR_MHPMCOUNTER16 0xb10
+#define CSR_MHPMCOUNTER17 0xb11
+#define CSR_MHPMCOUNTER18 0xb12
+#define CSR_MHPMCOUNTER19 0xb13
+#define CSR_MHPMCOUNTER20 0xb14
+#define CSR_MHPMCOUNTER21 0xb15
+#define CSR_MHPMCOUNTER22 0xb16
+#define CSR_MHPMCOUNTER23 0xb17
+#define CSR_MHPMCOUNTER24 0xb18
+#define CSR_MHPMCOUNTER25 0xb19
+#define CSR_MHPMCOUNTER26 0xb1a
+#define CSR_MHPMCOUNTER27 0xb1b
+#define CSR_MHPMCOUNTER28 0xb1c
+#define CSR_MHPMCOUNTER29 0xb1d
+#define CSR_MHPMCOUNTER30 0xb1e
+#define CSR_MHPMCOUNTER31 0xb1f
+#define CSR_MUCOUNTEREN 0x320
+#define CSR_MSCOUNTEREN 0x321
+#define CSR_MHPMEVENT3 0x323
+#define CSR_MHPMEVENT4 0x324
+#define CSR_MHPMEVENT5 0x325
+#define CSR_MHPMEVENT6 0x326
+#define CSR_MHPMEVENT7 0x327
+#define CSR_MHPMEVENT8 0x328
+#define CSR_MHPMEVENT9 0x329
+#define CSR_MHPMEVENT10 0x32a
+#define CSR_MHPMEVENT11 0x32b
+#define CSR_MHPMEVENT12 0x32c
+#define CSR_MHPMEVENT13 0x32d
+#define CSR_MHPMEVENT14 0x32e
+#define CSR_MHPMEVENT15 0x32f
+#define CSR_MHPMEVENT16 0x330
+#define CSR_MHPMEVENT17 0x331
+#define CSR_MHPMEVENT18 0x332
+#define CSR_MHPMEVENT19 0x333
+#define CSR_MHPMEVENT20 0x334
+#define CSR_MHPMEVENT21 0x335
+#define CSR_MHPMEVENT22 0x336
+#define CSR_MHPMEVENT23 0x337
+#define CSR_MHPMEVENT24 0x338
+#define CSR_MHPMEVENT25 0x339
+#define CSR_MHPMEVENT26 0x33a
+#define CSR_MHPMEVENT27 0x33b
+#define CSR_MHPMEVENT28 0x33c
+#define CSR_MHPMEVENT29 0x33d
+#define CSR_MHPMEVENT30 0x33e
+#define CSR_MHPMEVENT31 0x33f
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CSR_HPMCOUNTER3H 0xc83
+#define CSR_HPMCOUNTER4H 0xc84
+#define CSR_HPMCOUNTER5H 0xc85
+#define CSR_HPMCOUNTER6H 0xc86
+#define CSR_HPMCOUNTER7H 0xc87
+#define CSR_HPMCOUNTER8H 0xc88
+#define CSR_HPMCOUNTER9H 0xc89
+#define CSR_HPMCOUNTER10H 0xc8a
+#define CSR_HPMCOUNTER11H 0xc8b
+#define CSR_HPMCOUNTER12H 0xc8c
+#define CSR_HPMCOUNTER13H 0xc8d
+#define CSR_HPMCOUNTER14H 0xc8e
+#define CSR_HPMCOUNTER15H 0xc8f
+#define CSR_HPMCOUNTER16H 0xc90
+#define CSR_HPMCOUNTER17H 0xc91
+#define CSR_HPMCOUNTER18H 0xc92
+#define CSR_HPMCOUNTER19H 0xc93
+#define CSR_HPMCOUNTER20H 0xc94
+#define CSR_HPMCOUNTER21H 0xc95
+#define CSR_HPMCOUNTER22H 0xc96
+#define CSR_HPMCOUNTER23H 0xc97
+#define CSR_HPMCOUNTER24H 0xc98
+#define CSR_HPMCOUNTER25H 0xc99
+#define CSR_HPMCOUNTER26H 0xc9a
+#define CSR_HPMCOUNTER27H 0xc9b
+#define CSR_HPMCOUNTER28H 0xc9c
+#define CSR_HPMCOUNTER29H 0xc9d
+#define CSR_HPMCOUNTER30H 0xc9e
+#define CSR_HPMCOUNTER31H 0xc9f
+#define CSR_MCYCLEH 0xb80
+#define CSR_MINSTRETH 0xb82
+#define CSR_MHPMCOUNTER3H 0xb83
+#define CSR_MHPMCOUNTER4H 0xb84
+#define CSR_MHPMCOUNTER5H 0xb85
+#define CSR_MHPMCOUNTER6H 0xb86
+#define CSR_MHPMCOUNTER7H 0xb87
+#define CSR_MHPMCOUNTER8H 0xb88
+#define CSR_MHPMCOUNTER9H 0xb89
+#define CSR_MHPMCOUNTER10H 0xb8a
+#define CSR_MHPMCOUNTER11H 0xb8b
+#define CSR_MHPMCOUNTER12H 0xb8c
+#define CSR_MHPMCOUNTER13H 0xb8d
+#define CSR_MHPMCOUNTER14H 0xb8e
+#define CSR_MHPMCOUNTER15H 0xb8f
+#define CSR_MHPMCOUNTER16H 0xb90
+#define CSR_MHPMCOUNTER17H 0xb91
+#define CSR_MHPMCOUNTER18H 0xb92
+#define CSR_MHPMCOUNTER19H 0xb93
+#define CSR_MHPMCOUNTER20H 0xb94
+#define CSR_MHPMCOUNTER21H 0xb95
+#define CSR_MHPMCOUNTER22H 0xb96
+#define CSR_MHPMCOUNTER23H 0xb97
+#define CSR_MHPMCOUNTER24H 0xb98
+#define CSR_MHPMCOUNTER25H 0xb99
+#define CSR_MHPMCOUNTER26H 0xb9a
+#define CSR_MHPMCOUNTER27H 0xb9b
+#define CSR_MHPMCOUNTER28H 0xb9c
+#define CSR_MHPMCOUNTER29H 0xb9d
+#define CSR_MHPMCOUNTER30H 0xb9e
+#define CSR_MHPMCOUNTER31H 0xb9f
+#define CAUSE_MISALIGNED_FETCH 0x0
+#define CAUSE_FAULT_FETCH 0x1
+#define CAUSE_ILLEGAL_INSTRUCTION 0x2
+#define CAUSE_BREAKPOINT 0x3
+#define CAUSE_MISALIGNED_LOAD 0x4
+#define CAUSE_FAULT_LOAD 0x5
+#define CAUSE_MISALIGNED_STORE 0x6
+#define CAUSE_FAULT_STORE 0x7
+#define CAUSE_USER_ECALL 0x8
+#define CAUSE_SUPERVISOR_ECALL 0x9
+#define CAUSE_HYPERVISOR_ECALL 0xa
+#define CAUSE_MACHINE_ECALL 0xb
+#endif
+#ifdef DECLARE_INSN
+DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ)
+DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
+DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
+DECLARE_INSN(bge, MATCH_BGE, MASK_BGE)
+DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
+DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU)
+DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR)
+DECLARE_INSN(jal, MATCH_JAL, MASK_JAL)
+DECLARE_INSN(lui, MATCH_LUI, MASK_LUI)
+DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC)
+DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI)
+DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI)
+DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI)
+DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU)
+DECLARE_INSN(xori, MATCH_XORI, MASK_XORI)
+DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI)
+DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI)
+DECLARE_INSN(ori, MATCH_ORI, MASK_ORI)
+DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI)
+DECLARE_INSN(add, MATCH_ADD, MASK_ADD)
+DECLARE_INSN(sub, MATCH_SUB, MASK_SUB)
+DECLARE_INSN(sll, MATCH_SLL, MASK_SLL)
+DECLARE_INSN(slt, MATCH_SLT, MASK_SLT)
+DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU)
+DECLARE_INSN(xor, MATCH_XOR, MASK_XOR)
+DECLARE_INSN(srl, MATCH_SRL, MASK_SRL)
+DECLARE_INSN(sra, MATCH_SRA, MASK_SRA)
+DECLARE_INSN(or, MATCH_OR, MASK_OR)
+DECLARE_INSN(and, MATCH_AND, MASK_AND)
+DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW)
+DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW)
+DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW)
+DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW)
+DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW)
+DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW)
+DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW)
+DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW)
+DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW)
+DECLARE_INSN(lb, MATCH_LB, MASK_LB)
+DECLARE_INSN(lh, MATCH_LH, MASK_LH)
+DECLARE_INSN(lw, MATCH_LW, MASK_LW)
+DECLARE_INSN(ld, MATCH_LD, MASK_LD)
+DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU)
+DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU)
+DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU)
+DECLARE_INSN(sb, MATCH_SB, MASK_SB)
+DECLARE_INSN(sh, MATCH_SH, MASK_SH)
+DECLARE_INSN(sw, MATCH_SW, MASK_SW)
+DECLARE_INSN(sd, MATCH_SD, MASK_SD)
+DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE)
+DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I)
+DECLARE_INSN(mul, MATCH_MUL, MASK_MUL)
+DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH)
+DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU)
+DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU)
+DECLARE_INSN(div, MATCH_DIV, MASK_DIV)
+DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU)
+DECLARE_INSN(rem, MATCH_REM, MASK_REM)
+DECLARE_INSN(remu, MATCH_REMU, MASK_REMU)
+DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW)
+DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW)
+DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW)
+DECLARE_INSN(remw, MATCH_REMW, MASK_REMW)
+DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW)
+DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W)
+DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W)
+DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W)
+DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W)
+DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W)
+DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W)
+DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W)
+DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W)
+DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W)
+DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W)
+DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W)
+DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D)
+DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D)
+DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D)
+DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D)
+DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D)
+DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D)
+DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D)
+DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D)
+DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D)
+DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D)
+DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D)
+DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL)
+DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK)
+DECLARE_INSN(uret, MATCH_URET, MASK_URET)
+DECLARE_INSN(sret, MATCH_SRET, MASK_SRET)
+DECLARE_INSN(hret, MATCH_HRET, MASK_HRET)
+DECLARE_INSN(mret, MATCH_MRET, MASK_MRET)
+DECLARE_INSN(dret, MATCH_DRET, MASK_DRET)
+DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM)
+DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI)
+DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW)
+DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS)
+DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC)
+DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI)
+DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI)
+DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI)
+DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S)
+DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S)
+DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S)
+DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S)
+DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S)
+DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S)
+DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S)
+DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S)
+DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S)
+DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S)
+DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D)
+DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D)
+DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D)
+DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D)
+DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D)
+DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D)
+DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D)
+DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D)
+DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D)
+DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D)
+DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S)
+DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D)
+DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S)
+DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S)
+DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S)
+DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D)
+DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D)
+DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D)
+DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S)
+DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S)
+DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S)
+DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S)
+DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S)
+DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S)
+DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D)
+DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D)
+DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D)
+DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D)
+DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D)
+DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D)
+DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W)
+DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU)
+DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L)
+DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU)
+DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X)
+DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W)
+DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU)
+DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L)
+DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU)
+DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X)
+DECLARE_INSN(flw, MATCH_FLW, MASK_FLW)
+DECLARE_INSN(fld, MATCH_FLD, MASK_FLD)
+DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW)
+DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD)
+DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S)
+DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S)
+DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S)
+DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S)
+DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D)
+DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D)
+DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D)
+DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D)
+DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP)
+DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP)
+DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR)
+DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR)
+DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK)
+DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD)
+DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD)
+DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW)
+DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP)
+DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP)
+DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN)
+DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD)
+DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW)
+DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW)
+DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD)
+DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW)
+DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW)
+DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI)
+DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL)
+DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI)
+DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI)
+DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI)
+DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI)
+DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI)
+DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB)
+DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR)
+DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR)
+DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND)
+DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW)
+DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW)
+DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
+DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ)
+DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ)
+DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI)
+DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP)
+DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP)
+DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP)
+DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV)
+DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
+DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP)
+DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
+DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP)
+DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0)
+DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1)
+DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2)
+DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD)
+DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1)
+DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2)
+DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1)
+DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1)
+DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2)
+DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD)
+DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1)
+DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2)
+DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2)
+DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1)
+DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2)
+DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD)
+DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1)
+DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2)
+DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3)
+DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1)
+DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2)
+DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD)
+DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1)
+DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2)
+#endif
+#ifdef DECLARE_CSR
+DECLARE_CSR(fflags, CSR_FFLAGS)
+DECLARE_CSR(frm, CSR_FRM)
+DECLARE_CSR(fcsr, CSR_FCSR)
+DECLARE_CSR(cycle, CSR_CYCLE)
+DECLARE_CSR(time, CSR_TIME)
+DECLARE_CSR(instret, CSR_INSTRET)
+DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3)
+DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4)
+DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5)
+DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6)
+DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7)
+DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8)
+DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9)
+DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10)
+DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11)
+DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12)
+DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13)
+DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14)
+DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15)
+DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16)
+DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17)
+DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18)
+DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19)
+DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20)
+DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21)
+DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22)
+DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23)
+DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24)
+DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25)
+DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26)
+DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27)
+DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28)
+DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29)
+DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30)
+DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31)
+DECLARE_CSR(sstatus, CSR_SSTATUS)
+DECLARE_CSR(sie, CSR_SIE)
+DECLARE_CSR(stvec, CSR_STVEC)
+DECLARE_CSR(sscratch, CSR_SSCRATCH)
+DECLARE_CSR(sepc, CSR_SEPC)
+DECLARE_CSR(scause, CSR_SCAUSE)
+DECLARE_CSR(sbadaddr, CSR_SBADADDR)
+DECLARE_CSR(sip, CSR_SIP)
+DECLARE_CSR(sptbr, CSR_SPTBR)
+DECLARE_CSR(mstatus, CSR_MSTATUS)
+DECLARE_CSR(misa, CSR_MISA)
+DECLARE_CSR(medeleg, CSR_MEDELEG)
+DECLARE_CSR(mideleg, CSR_MIDELEG)
+DECLARE_CSR(mie, CSR_MIE)
+DECLARE_CSR(mtvec, CSR_MTVEC)
+DECLARE_CSR(mscratch, CSR_MSCRATCH)
+DECLARE_CSR(mepc, CSR_MEPC)
+DECLARE_CSR(mcause, CSR_MCAUSE)
+DECLARE_CSR(mbadaddr, CSR_MBADADDR)
+DECLARE_CSR(mip, CSR_MIP)
+DECLARE_CSR(tselect, CSR_TSELECT)
+DECLARE_CSR(tdata1, CSR_TDATA1)
+DECLARE_CSR(tdata2, CSR_TDATA2)
+DECLARE_CSR(tdata3, CSR_TDATA3)
+DECLARE_CSR(dcsr, CSR_DCSR)
+DECLARE_CSR(dpc, CSR_DPC)
+DECLARE_CSR(dscratch, CSR_DSCRATCH)
+DECLARE_CSR(mcycle, CSR_MCYCLE)
+DECLARE_CSR(minstret, CSR_MINSTRET)
+DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3)
+DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4)
+DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5)
+DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6)
+DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7)
+DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8)
+DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9)
+DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10)
+DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11)
+DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12)
+DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13)
+DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14)
+DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15)
+DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16)
+DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17)
+DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18)
+DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19)
+DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20)
+DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21)
+DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22)
+DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23)
+DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24)
+DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25)
+DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26)
+DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27)
+DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28)
+DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29)
+DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30)
+DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31)
+DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN)
+DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN)
+DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3)
+DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4)
+DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5)
+DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6)
+DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7)
+DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8)
+DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9)
+DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10)
+DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11)
+DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12)
+DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13)
+DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14)
+DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15)
+DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16)
+DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17)
+DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18)
+DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19)
+DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20)
+DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21)
+DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22)
+DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23)
+DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24)
+DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25)
+DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26)
+DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27)
+DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28)
+DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29)
+DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30)
+DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31)
+DECLARE_CSR(mvendorid, CSR_MVENDORID)
+DECLARE_CSR(marchid, CSR_MARCHID)
+DECLARE_CSR(mimpid, CSR_MIMPID)
+DECLARE_CSR(mhartid, CSR_MHARTID)
+DECLARE_CSR(cycleh, CSR_CYCLEH)
+DECLARE_CSR(timeh, CSR_TIMEH)
+DECLARE_CSR(instreth, CSR_INSTRETH)
+DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H)
+DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H)
+DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H)
+DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H)
+DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H)
+DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H)
+DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H)
+DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H)
+DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H)
+DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H)
+DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H)
+DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H)
+DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H)
+DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H)
+DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H)
+DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H)
+DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H)
+DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H)
+DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H)
+DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H)
+DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H)
+DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H)
+DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H)
+DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H)
+DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H)
+DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H)
+DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H)
+DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H)
+DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H)
+DECLARE_CSR(mcycleh, CSR_MCYCLEH)
+DECLARE_CSR(minstreth, CSR_MINSTRETH)
+DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H)
+DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H)
+DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H)
+DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H)
+DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H)
+DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H)
+DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H)
+DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H)
+DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H)
+DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H)
+DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H)
+DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H)
+DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H)
+DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H)
+DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H)
+DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H)
+DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H)
+DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H)
+DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H)
+DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H)
+DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H)
+DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H)
+DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H)
+DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H)
+DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H)
+DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H)
+DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H)
+DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H)
+DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H)
+#endif
+#ifdef DECLARE_CAUSE
+DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH)
+DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH)
+DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION)
+DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT)
+DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD)
+DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD)
+DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE)
+DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE)
+DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL)
+DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL)
+DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL)
+DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL)
+#endif
diff --git a/libcpu/risc-v/t-head/c906/interrupt.c b/libcpu/risc-v/t-head/c906/interrupt.c
new file mode 100644
index 0000000000..1cabe67587
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/interrupt.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-10-19 JasonHu first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "rt_interrupt.h"
+#include "riscv.h"
+#include "plic.h"
+
+extern rt_uint32_t rt_interrupt_nest;
+extern rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
+extern rt_uint32_t rt_thread_switch_interrupt_flag;
+
+struct rt_irq_desc isr_table[INTERRUPTS_MAX];
+
+static void rt_hw_interrupt_handler(int vector, void *param)
+{
+ rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
+}
+
+/**
+ * This function will initialize hardware interrupt
+ */
+void rt_hw_interrupt_init(void)
+{
+ /* init interrupt controller */
+ plic_init();
+
+ rt_int32_t idx;
+
+ rt_memset(isr_table, 0x00, sizeof(isr_table));
+ for (idx = 0; idx < INTERRUPTS_MAX; idx++)
+ {
+ isr_table[idx].handler = rt_hw_interrupt_handler;
+ }
+
+ /* init interrupt nest, and context in thread sp */
+ rt_interrupt_nest = 0;
+ rt_interrupt_from_thread = 0;
+ rt_interrupt_to_thread = 0;
+ rt_thread_switch_interrupt_flag = 0;
+}
+
+/**
+ * This function will mask a interrupt.
+ * @param vector the interrupt number
+ */
+void rt_hw_interrupt_mask(int vector)
+{
+ if ((vector < 0) || (vector > IRQ_MAX_NR))
+ {
+ return;
+ }
+ plic_disable_irq(vector);
+}
+
+/**
+
+ * This function will un-mask a interrupt.
+ * @param vector the interrupt number
+ */
+void rt_hw_interrupt_umask(int vector)
+{
+ if ((vector < 0) || (vector > IRQ_MAX_NR))
+ {
+ return;
+ }
+ plic_enable_irq(vector);
+}
+
+/**
+ * This function will install a interrupt service routine to a interrupt.
+ * @param vector the interrupt number
+ * @param handler the interrupt service routine to be installed
+ * @param param the interrupt service function parameter
+ * @param name the interrupt name
+ * @return old handler
+ */
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
+ void *param, const char *name)
+{
+ rt_isr_handler_t old_handler = RT_NULL;
+ if ((vector < 0) || (vector > IRQ_MAX_NR))
+ {
+ return old_handler;
+ }
+
+ old_handler = isr_table[IRQ_OFFSET + vector].handler;
+
+#ifdef RT_USING_INTERRUPT_INFO
+ rt_strncpy(isr_table[IRQ_OFFSET + vector].name, name, RT_NAME_MAX);
+#endif /* RT_USING_INTERRUPT_INFO */
+ isr_table[IRQ_OFFSET + vector].handler = handler;
+ isr_table[IRQ_OFFSET + vector].param = param;
+
+ return old_handler;
+}
diff --git a/libcpu/risc-v/t-head/c906/interrupt_gcc.S b/libcpu/risc-v/t-head/c906/interrupt_gcc.S
new file mode 100644
index 0000000000..6b80950fea
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/interrupt_gcc.S
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/02 Bernard The first version
+ * 2018/12/27 Jesven Add SMP schedule
+ * 2021/02/02 lizhirui Add userspace support
+ * 2021/12/24 JasonHu Add user setting save/restore
+ */
+
+#define __ASSEMBLY__
+#include "cpuport.h"
+#include "encoding.h"
+#include "stackframe.h"
+
+ .section .text.entry
+ .align 2
+ .global trap_entry
+ .extern __stack_cpu0
+ .extern get_current_thread_kernel_stack_top
+trap_entry:
+ //backup sp
+ csrrw sp, sscratch, sp
+ //load interrupt stack
+ la sp, __stack_cpu0
+ //backup context
+ SAVE_ALL
+
+ RESTORE_SYS_GP
+
+ //check syscall
+ csrr t0, scause
+ li t1, 8//environment call from u-mode
+ beq t0, t1, syscall_entry
+
+ csrr a0, scause
+ csrrc a1, stval, zero
+ csrr a2, sepc
+ mv a3, sp
+
+ /* scause, stval, sepc, sp */
+ call handle_trap
+
+ /* need to switch new thread */
+ la s0, rt_thread_switch_interrupt_flag
+ lw s2, 0(s0)
+ beqz s2, spurious_interrupt
+ sw zero, 0(s0)
+
+.global rt_hw_context_switch_interrupt_do
+rt_hw_context_switch_interrupt_do:
+
+//swap to thread kernel stack
+ csrr t0, sstatus
+ andi t0, t0, 0x100
+ beqz t0, __restore_sp_from_tcb_interrupt
+
+__restore_sp_from_sscratch_interrupt:
+ csrr t0, sscratch
+ j __move_stack_context_interrupt
+
+__restore_sp_from_tcb_interrupt:
+ la s0, rt_interrupt_from_thread
+ LOAD a0, 0(s0)
+ jal rt_thread_sp_to_thread
+ jal get_thread_kernel_stack_top
+ mv t0, a0
+
+__move_stack_context_interrupt:
+ mv t1, sp//src
+ mv sp, t0//switch stack
+ addi sp, sp, -CTX_REG_NR * REGBYTES
+ //copy context
+ li s0, CTX_REG_NR//cnt
+ mv t2, sp//dst
+
+copy_context_loop_interrupt:
+ LOAD t0, 0(t1)
+ STORE t0, 0(t2)
+ addi s0, s0, -1
+ addi t1, t1, 8
+ addi t2, t2, 8
+ bnez s0, copy_context_loop_interrupt
+
+ la s0, rt_interrupt_from_thread
+ LOAD s1, 0(s0)
+ STORE sp, 0(s1)
+
+ la s0, rt_interrupt_to_thread
+ LOAD s1, 0(s0)
+ LOAD sp, 0(s1)
+
+ #ifdef RT_USING_USERSPACE
+ mv a0, s1
+ jal rt_thread_sp_to_thread
+ jal lwp_mmu_switch
+ #endif
+
+spurious_interrupt:
+ RESTORE_ALL
+ sret
+
+.global rt_hw_interrupt_enable
+rt_hw_interrupt_enable:
+ csrs sstatus, a0 /* restore to old csr */
+ jr ra
+
+.global rt_hw_interrupt_disable
+rt_hw_interrupt_disable:
+ csrrci a0, sstatus, 2 /* clear SIE */
+ jr ra
diff --git a/libcpu/risc-v/t-head/c906/io.h b/libcpu/risc-v/t-head/c906/io.h
new file mode 100644
index 0000000000..1285d5955b
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/io.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019-2020, Xim
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+#ifndef ARCH_IO_H
+#define ARCH_IO_H
+#include <rtthread.h>
+#define RISCV_FENCE(p, s) \
+ __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
+
+/* These barriers need to enforce ordering on both devices or memory. */
+#define mb() RISCV_FENCE(iorw,iorw)
+#define rmb() RISCV_FENCE(ir,ir)
+#define wmb() RISCV_FENCE(ow,ow)
+
+#define __arch_getl(a) (*(unsigned int *)(a))
+#define __arch_putl(v, a) (*(unsigned int *)(a) = (v))
+
+#define dmb() mb()
+#define __iormb() rmb()
+#define __iowmb() wmb()
+
+static inline void writel(uint32_t val, volatile void *addr)
+{
+ __iowmb();
+ __arch_putl(val, addr);
+}
+
+static inline uint32_t readl(const volatile void *addr)
+{
+ uint32_t val;
+
+ val = __arch_getl(addr);
+ __iormb();
+ return val;
+}
+
+static inline void write_reg(
+ uint32_t val, volatile void *addr, unsigned offset)
+{
+ writel(val, addr + offset);
+}
+
+static inline uint32_t read_reg(
+ const volatile void *addr, unsigned offset)
+{
+ return readl(addr + offset);
+}
+
+#endif // ARCH_IO_H
diff --git a/libcpu/risc-v/t-head/c906/mmu.c b/libcpu/risc-v/t-head/c906/mmu.c
new file mode 100644
index 0000000000..0d461bc861
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/mmu.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <board.h>
+#include "page.h"
+#include <stdlib.h>
+#include <string.h>
+#include <cache.h>
+
+#include "riscv.h"
+#include "riscv_mmu.h"
+#include "mmu.h"
+
+void *current_mmu_table = RT_NULL;
+
+static void rt_hw_cpu_tlb_invalidate()
+{
+ rt_size_t satpv = read_csr(satp);
+ write_csr(satp,satpv);
+ mmu_flush_tlb();
+}
+
+void *rt_hw_mmu_tbl_get()
+{
+ return current_mmu_table;
+}
+
+void rt_hw_mmu_switch(void *mmu_table)
+{
+ current_mmu_table = mmu_table;
+ RT_ASSERT(__CHECKALIGN(mmu_table,PAGE_OFFSET_BIT));
+ mmu_set_pagetable((rt_ubase_t)mmu_table);
+ rt_hw_cpu_dcache_clean_all();
+ rt_hw_cpu_icache_invalidate_all();
+}
+
+int rt_hw_mmu_map_init(rt_mmu_info *mmu_info,void *v_address,rt_size_t size,rt_size_t *vtable,rt_size_t pv_off)
+{
+ size_t l1_off,va_s,va_e;
+ rt_base_t level;
+
+ if((!mmu_info) || (!vtable))
+ {
+ return -1;
+ }
+
+ va_s = (rt_size_t)v_address;
+ va_e = ((rt_size_t)v_address) + size - 1;
+
+ if(va_e < va_s)
+ {
+ return -1;
+ }
+
+ //convert address to level 1 page frame id
+ va_s = GET_L1(va_s);
+ va_e = GET_L1(va_e);
+
+ if(va_s == 0)
+ {
+ return -1;
+ }
+
+ level = rt_hw_interrupt_disable();
+
+ //vtable initialization check
+ for(l1_off = va_s;l1_off <= va_e;l1_off++)
+ {
+ size_t v = vtable[l1_off];
+
+ if(v)
+ {
+ rt_hw_interrupt_enable(level);
+ return 0;
+ }
+ }
+
+ mmu_info -> vtable = vtable;
+ mmu_info -> vstart = va_s;
+ mmu_info -> vend = va_e;
+ mmu_info -> pv_off = pv_off;
+
+ rt_hw_interrupt_enable(level);
+ return 0;
+}
+
+void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info,rt_size_t vaddr_start,rt_size_t size)
+{
+ rt_size_t paddr_start = __UMASKVALUE(VPN_TO_PPN(vaddr_start,mmu_info -> pv_off),PAGE_OFFSET_MASK);
+ rt_size_t va_s = GET_L1(vaddr_start);
+ rt_size_t va_e = GET_L1(vaddr_start + size - 1);
+ rt_size_t i;
+
+ for(i = va_s;i <= va_e;i++)
+ {
+ mmu_info -> vtable[i] = COMBINEPTE(paddr_start,PAGE_ATTR_RWX | PTE_G | PTE_V | PTE_CACHE | PTE_SHARE | PTE_BUF | PTE_A | PTE_D);
+ paddr_start += L1_PAGE_SIZE;
+ }
+
+ rt_hw_cpu_tlb_invalidate();
+}
+
+//find a range of free virtual address specified by pages
+static rt_size_t find_vaddr(rt_mmu_info *mmu_info,rt_size_t pages)
+{
+ rt_size_t l1_off,l2_off,l3_off;
+ rt_size_t *mmu_l1,*mmu_l2,*mmu_l3;
+ rt_size_t find_l1 = 0,find_l2 = 0,find_l3 = 0;
+ rt_size_t n = 0;
+
+ if(!pages)
+ {
+ return 0;
+ }
+
+ if(!mmu_info)
+ {
+ return 0;
+ }
+
+ for(l1_off = mmu_info -> vstart;l1_off <= mmu_info -> vend;l1_off++)
+ {
+ mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off;
+
+ if(PTE_USED(*mmu_l1))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1),mmu_info -> pv_off);
+
+ for(l2_off = 0;l2_off < __SIZE(VPN1_BIT);l2_off++)
+ {
+ if(PTE_USED(*(mmu_l2 + l2_off)))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off)));
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)),mmu_info -> pv_off);
+
+ for(l3_off = 0;l3_off < __SIZE(VPN0_BIT);l3_off++)
+ {
+ if(PTE_USED(*(mmu_l3 + l3_off)))
+ {
+ RT_ASSERT(PAGE_IS_LEAF(*(mmu_l3 + l3_off)));
+ n = 0;//in use
+ }
+ else
+ {
+ if(!n)
+ {
+ find_l1 = l1_off;
+ find_l2 = l2_off;
+ find_l3 = l3_off;
+ }
+
+ n++;
+
+ if(n >= pages)
+ {
+ return COMBINEVADDR(find_l1,find_l2,find_l3);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(!n)
+ {
+ find_l1 = l1_off;
+ find_l2 = l2_off;
+ find_l3 = 0;
+ }
+
+ n += __SIZE(VPN0_BIT);
+
+ if(n >= pages)
+ {
+ return COMBINEVADDR(find_l1,find_l2,find_l3);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(!n)
+ {
+ find_l1 = l1_off;
+ find_l2 = 0;
+ find_l3 = 0;
+ }
+
+ n += __SIZE(VPN1_BIT);
+
+ if(n >= pages)
+ {
+ return COMBINEVADDR(find_l1,find_l2,find_l3);
+ }
+ }
+ }
+
+ return 0;
+}
+
+//check whether the range of virtual address are free
+static int check_vaddr(rt_mmu_info *mmu_info,void *va,rt_size_t pages)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)va,PAGE_OFFSET_MASK);
+ rt_size_t l1_off,l2_off,l3_off;
+ rt_size_t *mmu_l1,*mmu_l2,*mmu_l3;
+
+ if(!pages)
+ {
+ return -1;
+ }
+
+ if(!mmu_info)
+ {
+ return -1;
+ }
+
+ while(pages--)
+ {
+ l1_off = GET_L1(loop_va);
+ l2_off = GET_L2(loop_va);
+ l3_off = GET_L3(loop_va);
+ mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off;
+
+ if(PTE_USED(*mmu_l1))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1),mmu_info -> pv_off) + l2_off;
+
+ if(PTE_USED(*mmu_l2))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l2));
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l2),mmu_info -> pv_off) + l3_off;
+
+ if(PTE_USED(*mmu_l3))
+ {
+ RT_ASSERT(PAGE_IS_LEAF(*mmu_l3));
+ return -1;
+ }
+ }
+ }
+
+ loop_va += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t npages)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr,PAGE_OFFSET_MASK);
+ rt_size_t l1_off,l2_off,l3_off;
+ rt_size_t *mmu_l1,*mmu_l2,*mmu_l3;
+ rt_size_t *ref_cnt;
+
+ RT_ASSERT(mmu_info);
+
+ while(npages--)
+ {
+ l1_off = (rt_size_t)GET_L1(loop_va);
+ RT_ASSERT((l1_off >= mmu_info -> vstart) && (l1_off <= mmu_info -> vend));
+ l2_off = (rt_size_t)GET_L2(loop_va);
+ l3_off = (rt_size_t)GET_L3(loop_va);
+ mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off;
+ RT_ASSERT(PTE_USED(*mmu_l1))
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = ((rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1),mmu_info -> pv_off)) + l2_off;
+ RT_ASSERT(PTE_USED(*mmu_l2));
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l2));
+ mmu_l3 = ((rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l2),mmu_info -> pv_off)) + l3_off;
+ RT_ASSERT(PTE_USED(*mmu_l3));
+ RT_ASSERT(PAGE_IS_LEAF(*(mmu_l3)));
+ *mmu_l3 = 0;
+ rt_hw_cpu_dcache_clean(mmu_l3,sizeof(*mmu_l3));
+ mmu_l3 -= l3_off;
+ ref_cnt = mmu_l3 + __SIZE(VPN0_BIT);
+ (*ref_cnt)--;
+
+ if(!*ref_cnt)
+ {
+ //release level 3 page
+ rt_pages_free(mmu_l3,1);//entry page and ref_cnt page
+ *mmu_l2 = 0;
+ rt_hw_cpu_dcache_clean(mmu_l2,sizeof(*mmu_l2));
+ mmu_l2 -= l2_off;
+
+ ref_cnt = mmu_l2 + __SIZE(VPN1_BIT);
+ (*ref_cnt)--;
+
+ if(!*ref_cnt)
+ {
+ //release level 2 page
+ rt_pages_free(mmu_l2,1);//entry page and ref_cnt page
+ *mmu_l1 = 0;
+ rt_hw_cpu_dcache_clean(mmu_l1,sizeof(*mmu_l1));
+ }
+ }
+
+ loop_va += PAGE_SIZE;
+ }
+}
+
+static int __rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t npages,rt_size_t attr)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr,PAGE_OFFSET_MASK);
+ rt_size_t loop_pa = __UMASKVALUE((rt_size_t)p_addr,PAGE_OFFSET_MASK);
+ rt_size_t l1_off,l2_off,l3_off;
+ rt_size_t *mmu_l1,*mmu_l2,*mmu_l3;
+ rt_size_t *ref_cnt;
+ //rt_kprintf("v_addr = 0x%p,p_addr = 0x%p,npages = %lu\n",v_addr,p_addr,npages);
+
+ if(!mmu_info)
+ {
+ return -1;
+ }
+
+ while(npages--)
+ {
+ l1_off = GET_L1(loop_va);
+ l2_off = GET_L2(loop_va);
+ l3_off = GET_L3(loop_va);
+ mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off;
+
+ if(PTE_USED(*mmu_l1))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1),mmu_info -> pv_off);
+ }
+ else
+ {
+ mmu_l2 = (rt_size_t *)rt_pages_alloc(1);
+
+ if(mmu_l2)
+ {
+ rt_memset(mmu_l2,0,PAGE_SIZE * 2);
+ rt_hw_cpu_dcache_clean(mmu_l2,PAGE_SIZE * 2);
+ *mmu_l1 = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l2,mmu_info -> pv_off),PAGE_DEFAULT_ATTR_NEXT);
+ rt_hw_cpu_dcache_clean(mmu_l1,sizeof(*mmu_l1));
+ }
+ else
+ {
+ __rt_hw_mmu_unmap(mmu_info,v_addr,npages);
+ return -1;
+ }
+ }
+
+ if(PTE_USED(*(mmu_l2 + l2_off)))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off)));
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)),mmu_info -> pv_off);
+ }
+ else
+ {
+ mmu_l3 = (rt_size_t *)rt_pages_alloc(1);
+
+ if(mmu_l3)
+ {
+ rt_memset(mmu_l3,0,PAGE_SIZE * 2);
+ rt_hw_cpu_dcache_clean(mmu_l3,PAGE_SIZE * 2);
+ *(mmu_l2 + l2_off) = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l3,mmu_info -> pv_off),PAGE_DEFAULT_ATTR_NEXT);
+ rt_hw_cpu_dcache_clean(mmu_l2,sizeof(*mmu_l2));
+ ref_cnt = mmu_l2 + __SIZE(VPN1_BIT);
+ (*ref_cnt)++;
+ }
+ else
+ {
+ __rt_hw_mmu_unmap(mmu_info,v_addr,npages);
+ return -1;
+ }
+ }
+
+ RT_ASSERT(!PTE_USED(*(mmu_l3 + l3_off)));
+ ref_cnt = mmu_l3 + __SIZE(VPN0_BIT);
+ (*ref_cnt)++;
+ *(mmu_l3 + l3_off) = COMBINEPTE((rt_size_t)loop_pa,PAGE_DEFAULT_ATTR_LEAF);
+ rt_hw_cpu_dcache_clean(mmu_l3 + l3_off,sizeof(*(mmu_l3 + l3_off)));
+
+ loop_va += PAGE_SIZE;
+ loop_pa += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+void *_rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr)
+{
+ rt_size_t pa_s,pa_e;
+ rt_size_t vaddr;
+ rt_size_t pages;
+ int ret;
+
+ if(!size)
+ {
+ return 0;
+ }
+
+ pa_s = (rt_size_t)p_addr;
+ pa_e = ((rt_size_t)p_addr) + size - 1;
+ pa_s = GET_PF_ID(pa_s);
+ pa_e = GET_PF_ID(pa_e);
+ pages = pa_e - pa_s + 1;
+
+ if(v_addr)
+ {
+ vaddr = (rt_size_t)v_addr;
+ pa_s = (rt_size_t)p_addr;
+
+ if(GET_PF_OFFSET(vaddr) != GET_PF_OFFSET(pa_s))
+ {
+ return 0;
+ }
+
+ vaddr = __UMASKVALUE(vaddr,PAGE_OFFSET_MASK);
+
+ if(check_vaddr(mmu_info,(void *)vaddr,pages) != 0)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ vaddr = find_vaddr(mmu_info,pages);
+ }
+
+ if(vaddr)
+ {
+ ret = __rt_hw_mmu_map(mmu_info,(void *)vaddr,p_addr,pages,attr);
+
+ if(ret == 0)
+ {
+ rt_hw_cpu_tlb_invalidate();
+ return (void *)(vaddr | GET_PF_OFFSET((rt_size_t)p_addr));
+ }
+ }
+
+ return 0;
+}
+
+static int __rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t npages,rt_size_t attr)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr,PAGE_OFFSET_MASK);
+ rt_size_t loop_pa;
+ rt_size_t l1_off,l2_off,l3_off;
+ rt_size_t *mmu_l1,*mmu_l2,*mmu_l3;
+ rt_size_t *ref_cnt;
+ rt_size_t i;
+ void *va,*pa;
+
+ if(!mmu_info)
+ {
+ return -1;
+ }
+
+ while(npages--)
+ {
+ loop_pa = (rt_size_t)rt_pages_alloc(0);
+
+ if(!loop_pa)
+ {
+ goto err;
+ }
+
+ if(__rt_hw_mmu_map(mmu_info,(void *)loop_va,(void *)loop_pa,1,attr) < 0)
+ {
+ goto err;
+ }
+
+ loop_va += PAGE_SIZE;
+ }
+
+ return 0;
+
+ err:
+ va = (void *)__UMASKVALUE((rt_size_t)v_addr,PAGE_OFFSET_MASK);
+
+ for(i = 0;i < npages;i++)
+ {
+ pa = rt_hw_mmu_v2p(mmu_info,va);
+
+ if(pa)
+ {
+ rt_pages_free((void *)PPN_TO_VPN(pa,mmu_info -> pv_off),0);
+ }
+
+ va = (void *)((rt_uint8_t *)va + PAGE_SIZE);
+ }
+
+ __rt_hw_mmu_unmap(mmu_info,v_addr,npages);
+ return -1;
+}
+
+void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr)
+{
+ rt_size_t vaddr;
+ rt_size_t offset;
+ rt_size_t pages;
+ int ret;
+
+ if(!size)
+ {
+ return 0;
+ }
+
+ offset = GET_PF_OFFSET((rt_size_t)v_addr);
+ size += (offset + PAGE_SIZE - 1);
+ pages = size >> PAGE_OFFSET_BIT;
+
+ if(v_addr)
+ {
+ vaddr = __UMASKVALUE((rt_size_t)v_addr,PAGE_OFFSET_MASK);
+
+ if(check_vaddr(mmu_info,(void *)vaddr,pages) != 0)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ vaddr = find_vaddr(mmu_info,pages);
+ }
+
+ if(vaddr)
+ {
+ ret = __rt_hw_mmu_map_auto(mmu_info,(void *)vaddr,pages,attr);
+
+ if(ret == 0)
+ {
+ rt_hw_cpu_tlb_invalidate();
+ return (void *)(vaddr | offset);
+ }
+ }
+
+ return 0;
+}
+
+void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size)
+{
+ rt_size_t va_s,va_e;
+ rt_size_t pages;
+
+ va_s = ((rt_size_t)v_addr) >> PAGE_OFFSET_BIT;
+ va_e = (((rt_size_t)v_addr) + size - 1) >> PAGE_OFFSET_BIT;
+ pages = va_e - va_s + 1;
+ __rt_hw_mmu_unmap(mmu_info,v_addr,pages);
+ rt_hw_cpu_tlb_invalidate();
+}
+
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr)
+{
+ void *ret;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ ret = _rt_hw_mmu_map(mmu_info,v_addr,p_addr,size,attr);
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr)
+{
+ void *ret;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ ret = _rt_hw_mmu_map_auto(mmu_info,v_addr,size,attr);
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
+
+void rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size)
+{
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ _rt_hw_mmu_unmap(mmu_info,v_addr,size);
+ rt_hw_interrupt_enable(level);
+}
+
+void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr)
+{
+ rt_size_t l1_off,l2_off,l3_off;
+ rt_size_t *mmu_l1,*mmu_l2,*mmu_l3;
+ rt_size_t pa;
+
+ l1_off = GET_L1((rt_size_t)v_addr);
+ l2_off = GET_L2((rt_size_t)v_addr);
+ l3_off = GET_L3((rt_size_t)v_addr);
+
+ if(!mmu_info)
+ {
+ return RT_NULL;
+ }
+
+ mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off;
+
+ if(PTE_USED(*mmu_l1))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1),mmu_info -> pv_off);
+
+ if(PTE_USED(*(mmu_l2 + l2_off)))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off)));
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)),mmu_info -> pv_off);
+
+ if(PTE_USED(*(mmu_l3 + l3_off)))
+ {
+ RT_ASSERT(PAGE_IS_LEAF(*(mmu_l3 + l3_off)));
+ return (void *)(GET_PADDR(*(mmu_l3 + l3_off)) | GET_PF_OFFSET((rt_size_t)v_addr));
+ }
+ }
+ }
+
+ return RT_NULL;
+}
+
+void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr)
+{
+ void *ret;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ ret = _rt_hw_mmu_v2p(mmu_info,v_addr);
+ rt_hw_interrupt_enable(level);
+ return ret;
+}
diff --git a/libcpu/risc-v/t-head/c906/mmu.h b/libcpu/risc-v/t-head/c906/mmu.h
new file mode 100644
index 0000000000..09fdc494e7
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/mmu.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#ifndef __MMU_H__
+#define __MMU_H__
+
+#include "riscv.h"
+#include "riscv_mmu.h"
+struct mem_desc
+{
+ rt_size_t vaddr_start;
+ rt_size_t vaddr_end;
+ rt_size_t paddr_start;
+ rt_size_t attr;
+};
+
+#define GET_PF_ID(addr) ((addr) >> PAGE_OFFSET_BIT)
+#define GET_PF_OFFSET(addr) __MASKVALUE(addr,PAGE_OFFSET_MASK)
+#define GET_L1(addr) __PARTBIT(addr,VPN2_SHIFT,VPN2_BIT)
+#define GET_L2(addr) __PARTBIT(addr,VPN1_SHIFT,VPN1_BIT)
+#define GET_L3(addr) __PARTBIT(addr,VPN0_SHIFT,VPN0_BIT)
+#define GET_PPN(pte) (__PARTBIT(pte,PTE_PPN_SHIFT,PHYSICAL_ADDRESS_WIDTH_BITS - PTE_PPN_SHIFT))
+#define GET_PADDR(pte) (GET_PPN(pte) << PAGE_OFFSET_BIT)
+#define VPN_TO_PPN(vaddr,pv_off) (((rt_size_t)(vaddr)) + (pv_off))
+#define PPN_TO_VPN(paddr,pv_off) (((rt_size_t)(paddr)) - (pv_off))
+#define COMBINEVADDR(l1_off,l2_off,l3_off) (((l1_off) << VPN2_SHIFT) | ((l2_off) << VPN1_SHIFT) | ((l3_off) << VPN0_SHIFT))
+#define COMBINEPTE(paddr,attr) ((((paddr) >> PAGE_OFFSET_BIT) << PTE_PPN_SHIFT) | (attr))
+
+typedef struct
+{
+ size_t *vtable;
+ size_t vstart;
+ size_t vend;
+ size_t pv_off;
+}rt_mmu_info;
+
+void *rt_hw_mmu_tbl_get();
+void rt_hw_mmu_switch(void *mmu_table);
+int rt_hw_mmu_map_init(rt_mmu_info *mmu_info,void *v_address,rt_size_t size,rt_size_t *vtable,rt_size_t pv_off);
+void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info,rt_size_t vaddr_start,rt_size_t size);
+void *_rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr);
+void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr);
+void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size);
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr);
+void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr);
+void rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size);
+void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr);
+void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr);
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/opcode.h b/libcpu/risc-v/t-head/c906/opcode.h
new file mode 100644
index 0000000000..27c2f91bf8
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/opcode.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-09 WangXiaoyao Add portable asm support
+ */
+#ifndef __OPCODE_H__
+#define __OPCODE_H__
+
+/**
+ * @brief binary opcode pseudo operations
+ * Used to bypass toolchain restriction on extension ISA
+ *
+ * WARNING: Xuantie ISAs are not compatible to each other in opcode.
+ * It's painful to port this file, and should be really careful.
+ */
+
+/**
+ * @brief RISC-V instruction formats
+ */
+
+/**
+ * R type: .insn r opcode6, func3, func7, rd, rs1, rs2
+ *
+ * +-------+-----+-----+-------+----+---------+
+ * | func7 | rs2 | rs1 | func3 | rd | opcode6 |
+ * +-------+-----+-----+-------+----+---------+
+ * 31 25 20 15 12 7 0
+ */
+#define __OPC_INSN_FORMAT_R(opcode, func3, func7, rd, rs1, rs2) \
+ ".insn r "RT_STRINGIFY(opcode)","RT_STRINGIFY(func3)","RT_STRINGIFY(func7)","RT_STRINGIFY(rd)","RT_STRINGIFY(rs1)","RT_STRINGIFY(rs2)
+
+/**
+ * @brief Xuantie T-HEAD extension ISA format
+ * Compatible to Xuantie C906R2S1 user manual v06
+ */
+#define __OPC_INSN_FORMAT_CACHE(func7, rs2, rs1) \
+ __OPC_INSN_FORMAT_R(0x0b, 0x0, func7, x0, rs1, rs2)
+
+#ifdef _TOOLCHAIN_SUPP_XTHEADE_ISA_
+#define OPC_SYNC "sync"
+#define OPC_SYNC_I "sync.i"
+
+#define OPC_DCACHE_CALL "dcache.call"
+#define OPC_DCACHE_IALL "dcache.iall"
+#define OPC_DCACHE_CIALL "dcache.ciall"
+
+#define OPC_ICACHE_IALL "icache.iall"
+
+#define OPC_DCACHE_CVA(rs1) "dcache.cva "RT_STRINGIFY(rs1)
+#define OPC_DCACHE_IVA(rs1) "dcache.iva "RT_STRINGIFY(rs1)
+#define OPC_DCACHE_CIVA(rs1) "dcache.civa "RT_STRINGIFY(rs1)
+
+#define OPC_ICACHE_IVA(rs1) "icache.iva "RT_STRINGIFY(rs1)
+#else /* !_TOOLCHAIN_NOT_SUPP_THEAD_ISA_ */
+#define OPC_SYNC ".long 0x0180000B"
+#define OPC_SYNC_I ".long 0x01A0000B"
+
+#define OPC_DCACHE_CALL ".long 0x0010000B"
+#define OPC_DCACHE_IALL ".long 0x0020000B"
+#define OPC_DCACHE_CIALL ".long 0x0030000B"
+
+#define OPC_ICACHE_IALL ".long 0x0100000B"
+
+#define OPC_DCACHE_CVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x4, rs1)
+#define OPC_DCACHE_IVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x6, rs1)
+#define OPC_DCACHE_CIVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x7, rs1)
+
+#define OPC_ICACHE_IVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x16, rs1)
+#endif /* _TOOLCHAIN_NOT_SUPP_THEAD_ISA_ */
+
+#ifdef _TOOLCHAIN_SUPP_ZIFENCEI_ISA_
+#define OPC_FENCE_I "fence.i"
+#else /* !_TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
+#define OPC_FENCE_I ".long 0x0000100F"
+#endif /* _TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
+
+#endif /* __OPCODE_H__ */ \ No newline at end of file
diff --git a/libcpu/risc-v/t-head/c906/plic.c b/libcpu/risc-v/t-head/c906/plic.c
new file mode 100644
index 0000000000..796bdfc967
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/plic.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-10-19 JasonHu first version
+ * 2021-11-12 JasonHu fix bug that not intr on f133
+ */
+
+#include <rtthread.h>
+
+#include <rtdbg.h>
+
+#include "plic.h"
+#include "rt_interrupt.h"
+#include "io.h"
+#include "encoding.h"
+
+static void *c906_plic_regs = RT_NULL;
+
+struct plic_handler
+{
+ rt_bool_t present;
+ void *hart_base;
+ void *enable_base;
+};
+
+rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable);
+struct plic_handler c906_plic_handlers[C906_NR_CPUS];
+
+rt_inline void plic_irq_toggle(int hwirq, int enable)
+{
+ int cpu = 0;
+
+ /* set priority of interrupt, interrupt 0 is zero. */
+ writel(enable, c906_plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
+ struct plic_handler *handler = &c906_plic_handlers[cpu];
+
+ if (handler->present)
+ {
+ plic_toggle(handler, hwirq, enable);
+ }
+}
+
+void plic_complete(int irqno)
+{
+ int cpu = 0;
+ struct plic_handler *handler = &c906_plic_handlers[cpu];
+
+ writel(irqno, handler->hart_base + CONTEXT_CLAIM);
+}
+
+void plic_disable_irq(int irqno)
+{
+ plic_irq_toggle(irqno, 0);
+}
+
+void plic_enable_irq(int irqno)
+{
+ plic_irq_toggle(irqno, 1);
+}
+
+/*
+ * Handling an interrupt is a two-step process: first you claim the interrupt
+ * by reading the claim register, then you complete the interrupt by writing
+ * that source ID back to the same claim register. This automatically enables
+ * and disables the interrupt, so there's nothing else to do.
+ */
+void plic_handle_irq(void)
+{
+ int cpu = 0;
+ unsigned int irq;
+
+ struct plic_handler *handler = &c906_plic_handlers[cpu];
+ void *claim = handler->hart_base + CONTEXT_CLAIM;
+
+ if (c906_plic_regs == RT_NULL || !handler->present)
+ {
+ LOG_E("plic state not initialized.");
+ return;
+ }
+
+ clear_csr(sie, SIE_SEIE);
+
+ while ((irq = readl(claim)))
+ {
+ /* ID0 is diabled permantually from spec. */
+ if (irq == 0)
+ {
+ LOG_E("irq no is zero.");
+ }
+ else
+ {
+ generic_handle_irq(irq);
+ }
+ }
+ set_csr(sie, SIE_SEIE);
+}
+
+rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
+{
+ uint32_t *reg = handler->enable_base + (hwirq / 32) * sizeof(uint32_t);
+ uint32_t hwirq_mask = 1 << (hwirq % 32);
+
+ if (enable)
+ {
+ writel(readl(reg) | hwirq_mask, reg);
+ }
+ else
+ {
+ writel(readl(reg) & ~hwirq_mask, reg);
+ }
+}
+
+void plic_init(void)
+{
+ int nr_irqs;
+ int nr_context;
+ int i;
+ unsigned long hwirq;
+ int cpu = 0;
+
+ if (c906_plic_regs)
+ {
+ LOG_E("plic already initialized!");
+ return;
+ }
+
+ nr_context = C906_NR_CONTEXT;
+
+ c906_plic_regs = (void *)C906_PLIC_PHY_ADDR;
+ if (!c906_plic_regs)
+ {
+ LOG_E("fatal error, plic is reg space is null.");
+ return;
+ }
+
+ nr_irqs = C906_PLIC_NR_EXT_IRQS;
+
+ for (i = 0; i < nr_context; i ++)
+ {
+ struct plic_handler *handler;
+ uint32_t threshold = 0;
+
+ cpu = 0;
+
+ /* skip contexts other than supervisor external interrupt */
+ if (i == 0)
+ {
+ continue;
+ }
+
+ // we always use CPU0 M-mode target register.
+ handler = &c906_plic_handlers[cpu];
+ if (handler->present)
+ {
+ threshold = 0xffffffff;
+ goto done;
+ }
+
+ handler->present = RT_TRUE;
+ handler->hart_base = c906_plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
+ handler->enable_base = c906_plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
+done:
+ /* priority must be > threshold to trigger an interrupt */
+ writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
+ for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
+ {
+ plic_toggle(handler, hwirq, 0);
+ }
+ }
+
+ /* Enable supervisor external interrupts. */
+ set_csr(sie, SIE_SEIE);
+}
diff --git a/libcpu/risc-v/t-head/c906/plic.h b/libcpu/risc-v/t-head/c906/plic.h
new file mode 100644
index 0000000000..727782c11d
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/plic.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-10-19 JasonHu first version
+ */
+
+#ifndef __RISCV64_PLIC_H__
+#define __RISCV64_PLIC_H__
+
+#include <rt_interrupt.h>
+
+#define C906_PLIC_PHY_ADDR (0x10000000)
+#define C906_PLIC_NR_EXT_IRQS (IRQ_MAX_NR)
+#define C906_NR_CPUS (NR_CPUS)
+
+/* M and S mode context. */
+#define C906_NR_CONTEXT (2)
+
+#define MAX_DEVICES 1024
+#define MAX_CONTEXTS 15872
+
+/*
+ * Each interrupt source has a priority register associated with it.
+ * We always hardwire it to one in Linux.
+ */
+#define PRIORITY_BASE 0
+#define PRIORITY_PER_ID 4
+
+/*
+ * Each hart context has a vector of interrupt enable bits associated with it.
+ * There's one bit for each interrupt source.
+ */
+#define ENABLE_BASE 0x2000
+#define ENABLE_PER_HART 0x80
+
+/*
+ * Each hart context has a set of control registers associated with it. Right
+ * now there's only two: a source priority threshold over which the hart will
+ * take an interrupt, and a register to claim interrupts.
+ */
+#define CONTEXT_BASE 0x200000
+#define CONTEXT_PER_HART 0x1000
+#define CONTEXT_THRESHOLD 0x00
+#define CONTEXT_CLAIM 0x04
+
+void plic_init(void);
+void plic_enable_irq(int irqno);
+void plic_disable_irq(int irqno);
+// tell PLIC that we've served this IRQ
+void plic_complete(int irq);
+void plic_handle_irq(void);
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/riscv.h b/libcpu/risc-v/t-head/c906/riscv.h
new file mode 100644
index 0000000000..d0c0cc4b38
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/riscv.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#ifndef __RISCV_H__
+#define __RISCV_H__
+
+#include <encoding.h>
+
+#define __SIZE(bit) (1UL << (bit))
+#define __MASK(bit) (__SIZE(bit) - 1UL)
+#define __UMASK(bit) (~(__MASK(bit)))
+#define __MASKVALUE(value,maskvalue) ((value) & (maskvalue))
+#define __UMASKVALUE(value,maskvalue) ((value) & (~(maskvalue)))
+#define __CHECKUPBOUND(value,bit_count) (!(((rt_size_t)value) & (~__MASK(bit_count))))
+#define __CHECKALIGN(value,start_bit) (!(((rt_size_t)value) & (__MASK(start_bit))))
+
+#define __PARTBIT(value,start_bit,length) (((value) >> (start_bit)) & __MASK(length))
+
+#define __ALIGNUP(value,bit) (((value) + __MASK(bit)) & __UMASK(bit))
+#define __ALIGNDOWN(value,bit) ((value) & __UMASK(bit))
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/riscv_io.h b/libcpu/risc-v/t-head/c906/riscv_io.h
new file mode 100644
index 0000000000..cde0495b29
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/riscv_io.h
@@ -0,0 +1,109 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <[email protected]>
+ */
+
+#ifndef __RISCV_IO_H__
+#define __RISCV_IO_H__
+
+ static inline void __raw_writeb(rt_uint8_t val, volatile void *addr)
+ {
+ asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr));
+ }
+
+ static inline void __raw_writew(rt_uint16_t val, volatile void *addr)
+ {
+ asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr));
+ }
+
+ static inline void __raw_writel(rt_uint32_t val, volatile void *addr)
+ {
+ asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
+ }
+
+ #if __riscv_xlen != 32
+ static inline void __raw_writeq(rt_uint64_t val, volatile void *addr)
+ {
+ asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr));
+ }
+ #endif
+
+ static inline rt_uint8_t __raw_readb(const volatile void *addr)
+ {
+ rt_uint8_t val;
+
+ asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+ }
+
+ static inline rt_uint16_t __raw_readw(const volatile void *addr)
+ {
+ rt_uint16_t val;
+
+ asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+ }
+
+ static inline rt_uint32_t __raw_readl(const volatile void *addr)
+ {
+ rt_uint32_t val;
+
+ asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+ }
+
+ #if __riscv_xlen != 32
+ static inline rt_uint64_t __raw_readq(const volatile void *addr)
+ {
+ rt_uint64_t val;
+
+ asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr));
+ return val;
+ }
+ #endif
+
+ /* FIXME: These are now the same as asm-generic */
+
+ /* clang-format off */
+
+ #define __io_rbr() do {} while (0)
+ #define __io_rar() do {} while (0)
+ #define __io_rbw() do {} while (0)
+ #define __io_raw() do {} while (0)
+
+ #define readb_relaxed(c) ({ rt_uint8_t __v; __io_rbr(); __v = __raw_readb(c); __io_rar(); __v; })
+ #define readw_relaxed(c) ({ rt_uint16_t __v; __io_rbr(); __v = __raw_readw(c); __io_rar(); __v; })
+ #define readl_relaxed(c) ({ rt_uint32_t __v; __io_rbr(); __v = __raw_readl(c); __io_rar(); __v; })
+
+ #define writeb_relaxed(v,c) ({ __io_rbw(); __raw_writeb((v),(c)); __io_raw(); })
+ #define writew_relaxed(v,c) ({ __io_rbw(); __raw_writew((v),(c)); __io_raw(); })
+ #define writel_relaxed(v,c) ({ __io_rbw(); __raw_writel((v),(c)); __io_raw(); })
+
+ #if __riscv_xlen != 32
+ #define readq_relaxed(c) ({ rt_uint64_t __v; __io_rbr(); __v = __raw_readq(c); __io_rar(); __v; })
+ #define writeq_relaxed(v,c) ({ __io_rbw(); __raw_writeq((v),(c)); __io_raw(); })
+ #endif
+
+ #define __io_br() do {} while (0)
+ #define __io_ar() __asm__ __volatile__ ("fence i,r" : : : "memory");
+ #define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory");
+ #define __io_aw() do {} while (0)
+
+ #define readb(c) ({ rt_uint8_t __v; __io_br(); __v = __raw_readb(c); __io_ar(); __v; })
+ #define readw(c) ({ rt_uint16_t __v; __io_br(); __v = __raw_readw(c); __io_ar(); __v; })
+ #define readl(c) ({ rt_uint32_t __v; __io_br(); __v = __raw_readl(c); __io_ar(); __v; })
+
+ #define writeb(v,c) ({ __io_bw(); __raw_writeb((v),(c)); __io_aw(); })
+ #define writew(v,c) ({ __io_bw(); __raw_writew((v),(c)); __io_aw(); })
+ #define writel(v,c) ({ __io_bw(); __raw_writel((v),(c)); __io_aw(); })
+
+ #if __riscv_xlen != 32
+ #define readq(c) ({ rt_uint64_t __v; __io_br(); __v = __raw_readq(c); __io_ar(); __v; })
+ #define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
+ #endif
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/riscv_mmu.c b/libcpu/risc-v/t-head/c906/riscv_mmu.c
new file mode 100644
index 0000000000..9ba48e34c4
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/riscv_mmu.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include <stdint.h>
+#include <riscv.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "riscv_mmu.h"
+
+void mmu_set_pagetable(rt_ubase_t addr)
+{
+ RT_ASSERT(__CHECKALIGN(addr,PAGE_OFFSET_BIT));
+ RT_ASSERT(__CHECKUPBOUND(addr,PHYSICAL_ADDRESS_WIDTH_BITS));
+ write_csr(satp,(((size_t)8) << 60) | (addr >> PAGE_OFFSET_BIT));
+ mmu_flush_tlb();
+}
+
+void mmu_enable_user_page_access()
+{
+ set_csr(sstatus,SSTATUS_PUM);
+}
+
+void mmu_disable_user_page_access()
+{
+ clear_csr(sstatus,SSTATUS_PUM);
+}
diff --git a/libcpu/risc-v/t-head/c906/riscv_mmu.h b/libcpu/risc-v/t-head/c906/riscv_mmu.h
new file mode 100644
index 0000000000..138bd596e9
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/riscv_mmu.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ * 2021-05-03 lizhirui porting to c906
+ */
+
+#ifndef __RISCV_MMU_H__
+#define __RISCV_MMU_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+#include "riscv.h"
+
+#undef PAGE_SIZE
+
+/* C-SKY extend */
+#define PTE_SEC (1UL << 59) /* Security */
+#define PTE_SHARE (1UL << 60) /* Shareable */
+#define PTE_BUF (1UL << 61) /* Bufferable */
+#define PTE_CACHE (1UL << 62) /* Cacheable */
+#define PTE_SO (1UL << 63) /* Strong Order */
+
+#define PAGE_OFFSET_SHIFT 0
+#define PAGE_OFFSET_BIT 12
+#define PAGE_SIZE __SIZE(PAGE_OFFSET_BIT)
+#define PAGE_OFFSET_MASK __MASK(PAGE_OFFSET_BIT)
+#define VPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT)
+#define VPN0_BIT 9
+#define VPN1_SHIFT (VPN0_SHIFT + VPN0_BIT)
+#define VPN1_BIT 9
+#define VPN2_SHIFT (VPN1_SHIFT + VPN1_BIT)
+#define VPN2_BIT 9
+
+#define PPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT)
+#define PPN0_BIT 9
+#define PPN1_SHIFT (PPN0_SHIFT + PPN0_BIT)
+#define PPN1_BIT 9
+#define PPN2_SHIFT (PPN1_SHIFT + PPN1_BIT)
+#define PPN2_BIT 26
+
+#define L1_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT + VPN1_BIT)
+#define L2_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT)
+#define L3_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT)
+
+#define ARCH_ADDRESS_WIDTH_BITS 64
+
+#define PHYSICAL_ADDRESS_WIDTH_BITS 56
+
+#define PAGE_ATTR_NEXT_LEVEL (0)
+#define PAGE_ATTR_RWX (PTE_X | PTE_W | PTE_R)
+#define PAGE_ATTR_READONLY (PTE_R)
+#define PAGE_ATTR_READEXECUTE (PTE_X | PTE_R)
+
+#define PAGE_ATTR_USER (PTE_U)
+#define PAGE_ATTR_SYSTEM (0)
+
+#define PAGE_DEFAULT_ATTR_LEAF (PAGE_ATTR_RWX | PAGE_ATTR_USER | PTE_V | PTE_G | PTE_SHARE | PTE_BUF | PTE_CACHE | PTE_A | PTE_D)
+#define PAGE_DEFAULT_ATTR_NEXT (PAGE_ATTR_NEXT_LEVEL | PTE_V | PTE_G | PTE_SHARE | PTE_BUF | PTE_CACHE | PTE_A | PTE_D)
+
+#define PAGE_IS_LEAF(pte) __MASKVALUE(pte,PAGE_ATTR_RWX)
+
+#define PTE_USED(pte) __MASKVALUE(pte,PTE_V)
+
+#define mmu_flush_tlb() do{asm volatile("sfence.vma x0,x0");}while(0)
+
+//compatible to rt-smart new version
+#define MMU_MAP_K_DEVICE (PAGE_ATTR_RWX | PTE_V | PTE_G | PTE_SO | PTE_BUF | PTE_A | PTE_D)
+#define MMU_MAP_K_RWCB (PAGE_ATTR_RWX | PTE_V | PTE_G | PTE_SHARE | PTE_BUF | PTE_CACHE | PTE_A | PTE_D)
+#define ARCH_PAGE_SIZE PAGE_SIZE
+#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
+#define ARCH_PAGE_SHIFT PAGE_OFFSET_BIT
+
+void mmu_set_pagetable(rt_ubase_t addr);
+void mmu_enable_user_page_access();
+void mmu_disable_user_page_access();
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/rt_interrupt.h b/libcpu/risc-v/t-head/c906/rt_interrupt.h
new file mode 100644
index 0000000000..c55a7fc0bd
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/rt_interrupt.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-10-19 JasonHu first version
+ */
+
+#ifndef __INTERRUPT_H__
+#define __INTERRUPT_H__
+
+#include <rthw.h>
+
+#define NR_CPUS 1
+
+#define IRQ_OFFSET 16
+#define IRQ_MAX_NR 207
+#define INTERRUPTS_MAX (IRQ_OFFSET + IRQ_MAX_NR)
+
+enum {
+ EP_INSTRUCTION_ADDRESS_MISALIGNED = 0,
+ EP_INSTRUCTION_ACCESS_FAULT,
+ EP_ILLEGAL_INSTRUCTION,
+ EP_BREAKPOINT,
+ EP_LOAD_ADDRESS_MISALIGNED,
+ EP_LOAD_ACCESS_FAULT,
+ EP_STORE_ADDRESS_MISALIGNED,
+ EP_STORE_ACCESS_FAULT,
+ EP_ENVIRONMENT_CALL_U_MODE,
+ EP_ENVIRONMENT_CALL_S_MODE,
+ EP_RESERVED10,
+ EP_ENVIRONMENT_CALL_M_MODE,
+ EP_INSTRUCTION_PAGE_FAULT, /* page attr */
+ EP_LOAD_PAGE_FAULT, /* read data */
+ EP_RESERVED14,
+ EP_STORE_PAGE_FAULT, /* write data */
+};
+
+void rt_hw_interrupt_init(void);
+void rt_hw_interrupt_mask(int vector);
+void rt_hw_interrupt_umask(int vector);
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name);
+
+void generic_handle_irq(int irq);
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/sbi.c b/libcpu/risc-v/t-head/c906/sbi.c
new file mode 100644
index 0000000000..f848ec7810
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/sbi.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Bernard port from FreeBSD
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Mitchell Horne <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "sbi.h"
+#include <stdbool.h>
+#include <rtthread.h>
+
+/* SBI Implementation-Specific Definitions */
+#define OPENSBI_VERSION_MAJOR_OFFSET 16
+#define OPENSBI_VERSION_MINOR_MASK 0xFFFF
+
+unsigned long sbi_spec_version;
+unsigned long sbi_impl_id;
+unsigned long sbi_impl_version;
+
+static bool has_time_extension = false;
+static bool has_ipi_extension = false;
+static bool has_rfnc_extension = false;
+
+static struct sbi_ret
+sbi_get_spec_version(void)
+{
+ return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION));
+}
+
+static struct sbi_ret
+sbi_get_impl_id(void)
+{
+ return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID));
+}
+
+static struct sbi_ret
+sbi_get_impl_version(void)
+{
+ return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION));
+}
+
+void
+sbi_print_version(void)
+{
+ u_int major;
+ u_int minor;
+
+ /* For legacy SBI implementations. */
+ if (sbi_spec_version == 0)
+ {
+ rt_kprintf("SBI: Unknown (Legacy) Implementation\n");
+ rt_kprintf("SBI Specification Version: 0.1\n");
+ return;
+ }
+
+ switch (sbi_impl_id)
+ {
+ case (SBI_IMPL_ID_BBL):
+ rt_kprintf("SBI: Berkely Boot Loader %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_XVISOR):
+ rt_kprintf("SBI: eXtensible Versatile hypervISOR %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_KVM):
+ rt_kprintf("SBI: Kernel-based Virtual Machine %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_RUSTSBI):
+ rt_kprintf("SBI: RustSBI %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_DIOSIX):
+ rt_kprintf("SBI: Diosix %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_OPENSBI):
+ major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET;
+ minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK;
+ rt_kprintf("SBI: OpenSBI v%u.%u\n", major, minor);
+ break;
+ default:
+ rt_kprintf("SBI: Unrecognized Implementation: %lu\n", sbi_impl_id);
+ break;
+ }
+
+ major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >>
+ SBI_SPEC_VERS_MAJOR_OFFSET;
+ minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK);
+ rt_kprintf("SBI Specification Version: %u.%u\n", major, minor);
+}
+
+void
+sbi_set_timer(uint64_t val)
+{
+ struct sbi_ret ret;
+
+ /* Use the TIME legacy replacement extension, if available. */
+ if (has_time_extension)
+ {
+ ret = SBI_CALL1(SBI_EXT_ID_TIME, SBI_TIME_SET_TIMER, val);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL1(SBI_SET_TIMER, 0, val);
+ }
+}
+
+void
+sbi_send_ipi(const unsigned long *hart_mask)
+{
+ struct sbi_ret ret;
+
+ /* Use the IPI legacy replacement extension, if available. */
+ if (has_ipi_extension)
+ {
+ ret = SBI_CALL2(SBI_EXT_ID_IPI, SBI_IPI_SEND_IPI,
+ *hart_mask, 0);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL1(SBI_SEND_IPI, 0, (uint64_t)hart_mask);
+ }
+}
+
+void
+sbi_remote_fence_i(const unsigned long *hart_mask)
+{
+ struct sbi_ret ret;
+
+ /* Use the RFENCE legacy replacement extension, if available. */
+ if (has_rfnc_extension)
+ {
+ ret = SBI_CALL2(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_FENCE_I,
+ *hart_mask, 0);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL1(SBI_REMOTE_FENCE_I, 0, (uint64_t)hart_mask);
+ }
+}
+
+void
+sbi_remote_sfence_vma(const unsigned long *hart_mask, unsigned long start, unsigned long size)
+{
+ struct sbi_ret ret;
+
+ /* Use the RFENCE legacy replacement extension, if available. */
+ if (has_rfnc_extension)
+ {
+ ret = SBI_CALL4(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA,
+ *hart_mask, 0, start, size);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL3(SBI_REMOTE_SFENCE_VMA, 0, (uint64_t)hart_mask,
+ start, size);
+ }
+}
+
+void
+sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, unsigned long start, unsigned long size,
+ unsigned long asid)
+{
+ struct sbi_ret ret;
+
+ /* Use the RFENCE legacy replacement extension, if available. */
+ if (has_rfnc_extension)
+ {
+ ret = SBI_CALL5(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA_ASID,
+ *hart_mask, 0, start, size, asid);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL4(SBI_REMOTE_SFENCE_VMA_ASID, 0,
+ (uint64_t)hart_mask, start, size, asid);
+ }
+}
+
+int
+sbi_hsm_hart_start(unsigned long hart, unsigned long start_addr, unsigned long priv)
+{
+ struct sbi_ret ret;
+
+ ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr, priv);
+ return (ret.error != 0 ? (int)ret.error : 0);
+}
+
+void
+sbi_hsm_hart_stop(void)
+{
+ (void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP);
+}
+
+int
+sbi_hsm_hart_status(unsigned long hart)
+{
+ struct sbi_ret ret;
+
+ ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart);
+
+ return (ret.error != 0 ? (int)ret.error : (int)ret.value);
+}
+
+void
+sbi_init(void)
+{
+ struct sbi_ret sret;
+
+ /*
+ * Get the spec version. For legacy SBI implementations this will
+ * return an error, otherwise it is guaranteed to succeed.
+ */
+ sret = sbi_get_spec_version();
+ if (sret.error != 0)
+ {
+ /* We are running a legacy SBI implementation. */
+ sbi_spec_version = 0;
+ return;
+ }
+
+ /* Set the SBI implementation info. */
+ sbi_spec_version = sret.value;
+ sbi_impl_id = sbi_get_impl_id().value;
+ sbi_impl_version = sbi_get_impl_version().value;
+
+ /* Probe for legacy replacement extensions. */
+ if (sbi_probe_extension(SBI_EXT_ID_TIME) != 0)
+ has_time_extension = true;
+ if (sbi_probe_extension(SBI_EXT_ID_IPI) != 0)
+ has_ipi_extension = true;
+ if (sbi_probe_extension(SBI_EXT_ID_RFNC) != 0)
+ has_rfnc_extension = true;
+}
diff --git a/libcpu/risc-v/t-head/c906/sbi.h b/libcpu/risc-v/t-head/c906/sbi.h
new file mode 100644
index 0000000000..0e95ede334
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/sbi.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Bernard port from FreeBSD
+ */
+
+/*-
+ * Copyright (c) 2016-2017 Ruslan Bukin <[email protected]>
+ * All rights reserved.
+ * Copyright (c) 2019 Mitchell Horne <[email protected]>
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_SBI_H_
+#define _MACHINE_SBI_H_
+
+#include <rtdef.h>
+
+/* SBI Specification Version */
+#define SBI_SPEC_VERS_MAJOR_OFFSET 24
+#define SBI_SPEC_VERS_MAJOR_MASK (0x7F << SBI_SPEC_VERS_MAJOR_OFFSET)
+#define SBI_SPEC_VERS_MINOR_OFFSET 0
+#define SBI_SPEC_VERS_MINOR_MASK (0xFFFFFF << SBI_SPEC_VERS_MINOR_OFFSET)
+
+/* SBI Implementation IDs */
+#define SBI_IMPL_ID_BBL 0
+#define SBI_IMPL_ID_OPENSBI 1
+#define SBI_IMPL_ID_XVISOR 2
+#define SBI_IMPL_ID_KVM 3
+#define SBI_IMPL_ID_RUSTSBI 4
+#define SBI_IMPL_ID_DIOSIX 5
+
+/* SBI Error Codes */
+#define SBI_SUCCESS 0
+#define SBI_ERR_FAILURE -1
+#define SBI_ERR_NOT_SUPPORTED -2
+#define SBI_ERR_INVALID_PARAM -3
+#define SBI_ERR_DENIED -4
+#define SBI_ERR_INVALID_ADDRESS -5
+#define SBI_ERR_ALREADY_AVAILABLE -6
+
+/* SBI Base Extension */
+#define SBI_EXT_ID_BASE 0x10
+#define SBI_BASE_GET_SPEC_VERSION 0
+#define SBI_BASE_GET_IMPL_ID 1
+#define SBI_BASE_GET_IMPL_VERSION 2
+#define SBI_BASE_PROBE_EXTENSION 3
+#define SBI_BASE_GET_MVENDORID 4
+#define SBI_BASE_GET_MARCHID 5
+#define SBI_BASE_GET_MIMPID 6
+
+/* Timer (TIME) Extension */
+#define SBI_EXT_ID_TIME 0x54494D45
+#define SBI_TIME_SET_TIMER 0
+
+/* IPI (IPI) Extension */
+#define SBI_EXT_ID_IPI 0x735049
+#define SBI_IPI_SEND_IPI 0
+
+/* RFENCE (RFNC) Extension */
+#define SBI_EXT_ID_RFNC 0x52464E43
+#define SBI_RFNC_REMOTE_FENCE_I 0
+#define SBI_RFNC_REMOTE_SFENCE_VMA 1
+#define SBI_RFNC_REMOTE_SFENCE_VMA_ASID 2
+#define SBI_RFNC_REMOTE_HFENCE_GVMA_VMID 3
+#define SBI_RFNC_REMOTE_HFENCE_GVMA 4
+#define SBI_RFNC_REMOTE_HFENCE_VVMA_ASID 5
+#define SBI_RFNC_REMOTE_HFENCE_VVMA 6
+
+/* Hart State Management (HSM) Extension */
+#define SBI_EXT_ID_HSM 0x48534D
+#define SBI_HSM_HART_START 0
+#define SBI_HSM_HART_STOP 1
+#define SBI_HSM_HART_STATUS 2
+#define SBI_HSM_STATUS_STARTED 0
+#define SBI_HSM_STATUS_STOPPED 1
+#define SBI_HSM_STATUS_START_PENDING 2
+#define SBI_HSM_STATUS_STOP_PENDING 3
+
+/* Legacy Extensions */
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define SBI_CALL0(e, f) SBI_CALL5(e, f, 0, 0, 0, 0, 0)
+#define SBI_CALL1(e, f, p1) SBI_CALL5(e, f, p1, 0, 0, 0, 0)
+#define SBI_CALL2(e, f, p1, p2) SBI_CALL5(e, f, p1, p2, 0, 0, 0)
+#define SBI_CALL3(e, f, p1, p2, p3) SBI_CALL5(e, f, p1, p2, p3, 0, 0)
+#define SBI_CALL4(e, f, p1, p2, p3, p4) SBI_CALL5(e, f, p1, p2, p3, p4, 0)
+#define SBI_CALL5(e, f, p1, p2, p3, p4, p5) sbi_call(e, f, p1, p2, p3, p4, p5)
+
+/*
+ * Documentation available at
+ * https://github.com/riscv/riscv-sbi-doc/blob/master/riscv-sbi.adoc
+ */
+
+struct sbi_ret
+{
+ long error;
+ long value;
+};
+
+static __inline struct sbi_ret
+sbi_call(uint64_t arg7, uint64_t arg6, uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3, uint64_t arg4)
+{
+ struct sbi_ret ret;
+
+ register uintptr_t a0 __asm("a0") = (uintptr_t)(arg0);
+ register uintptr_t a1 __asm("a1") = (uintptr_t)(arg1);
+ register uintptr_t a2 __asm("a2") = (uintptr_t)(arg2);
+ register uintptr_t a3 __asm("a3") = (uintptr_t)(arg3);
+ register uintptr_t a4 __asm("a4") = (uintptr_t)(arg4);
+ register uintptr_t a6 __asm("a6") = (uintptr_t)(arg6);
+ register uintptr_t a7 __asm("a7") = (uintptr_t)(arg7);
+
+ __asm __volatile(\
+ "ecall" \
+ : "+r"(a0), "+r"(a1) \
+ : "r"(a2), "r"(a3), "r"(a4), "r"(a6), "r"(a7) \
+ : "memory");
+
+ ret.error = a0;
+ ret.value = a1;
+ return (ret);
+}
+
+/* Base extension functions and variables. */
+extern unsigned long sbi_spec_version;
+extern unsigned long sbi_impl_id;
+extern unsigned long sbi_impl_version;
+
+static __inline long
+sbi_probe_extension(long id)
+{
+ return (SBI_CALL1(SBI_EXT_ID_BASE, SBI_BASE_PROBE_EXTENSION, id).value);
+}
+
+/* TIME extension functions. */
+void sbi_set_timer(uint64_t val);
+
+/* IPI extension functions. */
+void sbi_send_ipi(const unsigned long *hart_mask);
+
+/* RFENCE extension functions. */
+void sbi_remote_fence_i(const unsigned long *hart_mask);
+void sbi_remote_sfence_vma(const unsigned long *hart_mask, unsigned long start, unsigned long size);
+void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, unsigned long start,
+ unsigned long size, unsigned long asid);
+
+/* Hart State Management extension functions. */
+
+/*
+ * Start execution on the specified hart at physical address start_addr. The
+ * register a0 will contain the hart's ID, and a1 will contain the value of
+ * priv.
+ */
+int sbi_hsm_hart_start(unsigned long hart, unsigned long start_addr, unsigned long priv);
+
+/*
+ * Stop execution on the current hart. Interrupts should be disabled, or this
+ * function may return.
+ */
+void sbi_hsm_hart_stop(void);
+
+/*
+ * Get the execution status of the specified hart. The status will be one of:
+ * - SBI_HSM_STATUS_STARTED
+ * - SBI_HSM_STATUS_STOPPED
+ * - SBI_HSM_STATUS_START_PENDING
+ * - SBI_HSM_STATUS_STOP_PENDING
+ */
+int sbi_hsm_hart_status(unsigned long hart);
+
+/* Legacy extension functions. */
+static __inline void
+sbi_console_putchar(int ch)
+{
+ (void)SBI_CALL1(SBI_CONSOLE_PUTCHAR, 0, ch);
+}
+
+static __inline int
+sbi_console_getchar(void)
+{
+ /*
+ * XXX: The "error" is returned here because legacy SBI functions
+ * continue to return their value in a0.
+ */
+ return (SBI_CALL0(SBI_CONSOLE_GETCHAR, 0).error);
+}
+
+static __inline void
+sbi_shutdown(void)
+{
+ (void)SBI_CALL0(SBI_SHUTDOWN, 0);
+}
+
+void sbi_print_version(void);
+void sbi_init(void);
+
+#endif /* !_MACHINE_SBI_H_ */
diff --git a/libcpu/risc-v/t-head/c906/stack.h b/libcpu/risc-v/t-head/c906/stack.h
new file mode 100644
index 0000000000..1ac507efba
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/stack.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ * 2021-11-18 JasonHu add fpu member
+ */
+
+#ifndef __STACK_H__
+#define __STACK_H__
+
+#include <rtthread.h>
+struct rt_hw_stack_frame
+{
+ rt_ubase_t epc; /* epc - epc - program counter */
+ rt_ubase_t ra; /* x1 - ra - return address for jumps */
+ rt_ubase_t sstatus; /* - supervisor status register */
+ rt_ubase_t gp; /* x3 - gp - global pointer */
+ rt_ubase_t tp; /* x4 - tp - thread pointer */
+ rt_ubase_t t0; /* x5 - t0 - temporary register 0 */
+ rt_ubase_t t1; /* x6 - t1 - temporary register 1 */
+ rt_ubase_t t2; /* x7 - t2 - temporary register 2 */
+ rt_ubase_t s0_fp; /* x8 - s0/fp - saved register 0 or frame pointer */
+ rt_ubase_t s1; /* x9 - s1 - saved register 1 */
+ rt_ubase_t a0; /* x10 - a0 - return value or function argument 0 */
+ rt_ubase_t a1; /* x11 - a1 - return value or function argument 1 */
+ rt_ubase_t a2; /* x12 - a2 - function argument 2 */
+ rt_ubase_t a3; /* x13 - a3 - function argument 3 */
+ rt_ubase_t a4; /* x14 - a4 - function argument 4 */
+ rt_ubase_t a5; /* x15 - a5 - function argument 5 */
+ rt_ubase_t a6; /* x16 - a6 - function argument 6 */
+ rt_ubase_t a7; /* x17 - s7 - function argument 7 */
+ rt_ubase_t s2; /* x18 - s2 - saved register 2 */
+ rt_ubase_t s3; /* x19 - s3 - saved register 3 */
+ rt_ubase_t s4; /* x20 - s4 - saved register 4 */
+ rt_ubase_t s5; /* x21 - s5 - saved register 5 */
+ rt_ubase_t s6; /* x22 - s6 - saved register 6 */
+ rt_ubase_t s7; /* x23 - s7 - saved register 7 */
+ rt_ubase_t s8; /* x24 - s8 - saved register 8 */
+ rt_ubase_t s9; /* x25 - s9 - saved register 9 */
+ rt_ubase_t s10; /* x26 - s10 - saved register 10 */
+ rt_ubase_t s11; /* x27 - s11 - saved register 11 */
+ rt_ubase_t t3; /* x28 - t3 - temporary register 3 */
+ rt_ubase_t t4; /* x29 - t4 - temporary register 4 */
+ rt_ubase_t t5; /* x30 - t5 - temporary register 5 */
+ rt_ubase_t t6; /* x31 - t6 - temporary register 6 */
+ rt_ubase_t user_sp_exc_stack; /* sscratch - user mode sp/exception stack */
+#ifdef ENABLE_FPU
+ rt_ubase_t f[CTX_FPU_REG_NR]; /* f0~f31 */
+#endif
+};
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/stackframe.h b/libcpu/risc-v/t-head/c906/stackframe.h
new file mode 100644
index 0000000000..1e191900b4
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/stackframe.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-02-02 lizhirui first version
+ * 2021-02-11 lizhirui fixed gp save/store bug
+ * 2021-11-18 JasonHu add fpu registers save/restore
+ */
+
+#ifndef __STACKFRAME_H__
+#define __STACKFRAME_H__
+
+#include "cpuport.h"
+#include "encoding.h"
+
+#ifdef ENABLE_FPU
+#define FPU_CTX_F0_OFF 0 /* offsetof(fpu_context_t, fpustatus.f[0]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F1_OFF 8 /* offsetof(fpu_context_t, fpustatus.f[1]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F2_OFF 16 /* offsetof(fpu_context_t, fpustatus.f[2]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F3_OFF 24 /* offsetof(fpu_context_t, fpustatus.f[3]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F4_OFF 32 /* offsetof(fpu_context_t, fpustatus.f[4]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F5_OFF 40 /* offsetof(fpu_context_t, fpustatus.f[5]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F6_OFF 48 /* offsetof(fpu_context_t, fpustatus.f[6]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F7_OFF 56 /* offsetof(fpu_context_t, fpustatus.f[7]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F8_OFF 64 /* offsetof(fpu_context_t, fpustatus.f[8]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F9_OFF 72 /* offsetof(fpu_context_t, fpustatus.f[9]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F10_OFF 80 /* offsetof(fpu_context_t, fpustatus.f[10]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F11_OFF 88 /* offsetof(fpu_context_t, fpustatus.f[11]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F12_OFF 96 /* offsetof(fpu_context_t, fpustatus.f[12]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F13_OFF 104 /* offsetof(fpu_context_t, fpustatus.f[13]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F14_OFF 112 /* offsetof(fpu_context_t, fpustatus.f[14]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F15_OFF 120 /* offsetof(fpu_context_t, fpustatus.f[15]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F16_OFF 128 /* offsetof(fpu_context_t, fpustatus.f[16]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F17_OFF 136 /* offsetof(fpu_context_t, fpustatus.f[17]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F18_OFF 144 /* offsetof(fpu_context_t, fpustatus.f[18]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F19_OFF 152 /* offsetof(fpu_context_t, fpustatus.f[19]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F20_OFF 160 /* offsetof(fpu_context_t, fpustatus.f[20]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F21_OFF 168 /* offsetof(fpu_context_t, fpustatus.f[21]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F22_OFF 176 /* offsetof(fpu_context_t, fpustatus.f[22]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F23_OFF 184 /* offsetof(fpu_context_t, fpustatus.f[23]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F24_OFF 192 /* offsetof(fpu_context_t, fpustatus.f[24]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F25_OFF 200 /* offsetof(fpu_context_t, fpustatus.f[25]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F26_OFF 208 /* offsetof(fpu_context_t, fpustatus.f[26]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F27_OFF 216 /* offsetof(fpu_context_t, fpustatus.f[27]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F28_OFF 224 /* offsetof(fpu_context_t, fpustatus.f[28]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F29_OFF 232 /* offsetof(fpu_context_t, fpustatus.f[29]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F30_OFF 240 /* offsetof(fpu_context_t, fpustatus.f[30]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F31_OFF 248 /* offsetof(fpu_context_t, fpustatus.f[31]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#endif /* ENABLE_FPU */
+
+/**
+ * The register `tp` always save/restore when context switch,
+ * we call `lwp_user_setting_save` when syscall enter,
+ * call `lwp_user_setting_restore` when syscall exit
+ * and modify context stack after `lwp_user_setting_restore` called
+ * so that the `tp` can be the correct thread area value.
+ */
+
+.macro SAVE_ALL
+
+#ifdef ENABLE_FPU
+ /* reserve float registers */
+ addi sp, sp, -CTX_FPU_REG_NR * REGBYTES
+#endif /* ENABLE_FPU */
+
+ /* save general registers */
+ addi sp, sp, -CTX_GENERAL_REG_NR * REGBYTES
+ STORE x1, 1 * REGBYTES(sp)
+
+ csrr x1, sstatus
+ STORE x1, 2 * REGBYTES(sp)
+
+ csrr x1, sepc
+ STORE x1, 0 * REGBYTES(sp)
+
+ STORE x3, 3 * REGBYTES(sp)
+ STORE x4, 4 * REGBYTES(sp) /* save tp */
+ STORE x5, 5 * REGBYTES(sp)
+ STORE x6, 6 * REGBYTES(sp)
+ STORE x7, 7 * REGBYTES(sp)
+ STORE x8, 8 * REGBYTES(sp)
+ STORE x9, 9 * REGBYTES(sp)
+ STORE x10, 10 * REGBYTES(sp)
+ STORE x11, 11 * REGBYTES(sp)
+ STORE x12, 12 * REGBYTES(sp)
+ STORE x13, 13 * REGBYTES(sp)
+ STORE x14, 14 * REGBYTES(sp)
+ STORE x15, 15 * REGBYTES(sp)
+ STORE x16, 16 * REGBYTES(sp)
+ STORE x17, 17 * REGBYTES(sp)
+ STORE x18, 18 * REGBYTES(sp)
+ STORE x19, 19 * REGBYTES(sp)
+ STORE x20, 20 * REGBYTES(sp)
+ STORE x21, 21 * REGBYTES(sp)
+ STORE x22, 22 * REGBYTES(sp)
+ STORE x23, 23 * REGBYTES(sp)
+ STORE x24, 24 * REGBYTES(sp)
+ STORE x25, 25 * REGBYTES(sp)
+ STORE x26, 26 * REGBYTES(sp)
+ STORE x27, 27 * REGBYTES(sp)
+ STORE x28, 28 * REGBYTES(sp)
+ STORE x29, 29 * REGBYTES(sp)
+ STORE x30, 30 * REGBYTES(sp)
+ STORE x31, 31 * REGBYTES(sp)
+ csrr t0, sscratch
+ STORE t0, 32 * REGBYTES(sp)
+
+#ifdef ENABLE_FPU
+ /* backup sp and adjust sp to save float registers */
+ mv t1, sp
+ addi t1, t1, CTX_GENERAL_REG_NR * REGBYTES
+
+ li t0, SSTATUS_FS
+ csrs sstatus, t0
+ fsd f0, FPU_CTX_F0_OFF(t1)
+ fsd f1, FPU_CTX_F1_OFF(t1)
+ fsd f2, FPU_CTX_F2_OFF(t1)
+ fsd f3, FPU_CTX_F3_OFF(t1)
+ fsd f4, FPU_CTX_F4_OFF(t1)
+ fsd f5, FPU_CTX_F5_OFF(t1)
+ fsd f6, FPU_CTX_F6_OFF(t1)
+ fsd f7, FPU_CTX_F7_OFF(t1)
+ fsd f8, FPU_CTX_F8_OFF(t1)
+ fsd f9, FPU_CTX_F9_OFF(t1)
+ fsd f10, FPU_CTX_F10_OFF(t1)
+ fsd f11, FPU_CTX_F11_OFF(t1)
+ fsd f12, FPU_CTX_F12_OFF(t1)
+ fsd f13, FPU_CTX_F13_OFF(t1)
+ fsd f14, FPU_CTX_F14_OFF(t1)
+ fsd f15, FPU_CTX_F15_OFF(t1)
+ fsd f16, FPU_CTX_F16_OFF(t1)
+ fsd f17, FPU_CTX_F17_OFF(t1)
+ fsd f18, FPU_CTX_F18_OFF(t1)
+ fsd f19, FPU_CTX_F19_OFF(t1)
+ fsd f20, FPU_CTX_F20_OFF(t1)
+ fsd f21, FPU_CTX_F21_OFF(t1)
+ fsd f22, FPU_CTX_F22_OFF(t1)
+ fsd f23, FPU_CTX_F23_OFF(t1)
+ fsd f24, FPU_CTX_F24_OFF(t1)
+ fsd f25, FPU_CTX_F25_OFF(t1)
+ fsd f26, FPU_CTX_F26_OFF(t1)
+ fsd f27, FPU_CTX_F27_OFF(t1)
+ fsd f28, FPU_CTX_F28_OFF(t1)
+ fsd f29, FPU_CTX_F29_OFF(t1)
+ fsd f30, FPU_CTX_F30_OFF(t1)
+ fsd f31, FPU_CTX_F31_OFF(t1)
+
+ /* clr FS domain */
+ csrc sstatus, t0
+
+ /* clean status would clr sr_sd; */
+ li t0, SSTATUS_FS_CLEAN
+ csrs sstatus, t0
+
+#endif /* ENABLE_FPU */
+
+.endm
+
+.macro RESTORE_ALL
+
+#ifdef ENABLE_FPU
+ /* restore float register */
+ mv t2, sp
+ addi t2, t2, CTX_GENERAL_REG_NR * REGBYTES /* skip all normal reg */
+
+ li t0, SSTATUS_FS
+ csrs sstatus, t0
+ fld f0, FPU_CTX_F0_OFF(t2)
+ fld f1, FPU_CTX_F1_OFF(t2)
+ fld f2, FPU_CTX_F2_OFF(t2)
+ fld f3, FPU_CTX_F3_OFF(t2)
+ fld f4, FPU_CTX_F4_OFF(t2)
+ fld f5, FPU_CTX_F5_OFF(t2)
+ fld f6, FPU_CTX_F6_OFF(t2)
+ fld f7, FPU_CTX_F7_OFF(t2)
+ fld f8, FPU_CTX_F8_OFF(t2)
+ fld f9, FPU_CTX_F9_OFF(t2)
+ fld f10, FPU_CTX_F10_OFF(t2)
+ fld f11, FPU_CTX_F11_OFF(t2)
+ fld f12, FPU_CTX_F12_OFF(t2)
+ fld f13, FPU_CTX_F13_OFF(t2)
+ fld f14, FPU_CTX_F14_OFF(t2)
+ fld f15, FPU_CTX_F15_OFF(t2)
+ fld f16, FPU_CTX_F16_OFF(t2)
+ fld f17, FPU_CTX_F17_OFF(t2)
+ fld f18, FPU_CTX_F18_OFF(t2)
+ fld f19, FPU_CTX_F19_OFF(t2)
+ fld f20, FPU_CTX_F20_OFF(t2)
+ fld f21, FPU_CTX_F21_OFF(t2)
+ fld f22, FPU_CTX_F22_OFF(t2)
+ fld f23, FPU_CTX_F23_OFF(t2)
+ fld f24, FPU_CTX_F24_OFF(t2)
+ fld f25, FPU_CTX_F25_OFF(t2)
+ fld f26, FPU_CTX_F26_OFF(t2)
+ fld f27, FPU_CTX_F27_OFF(t2)
+ fld f28, FPU_CTX_F28_OFF(t2)
+ fld f29, FPU_CTX_F29_OFF(t2)
+ fld f30, FPU_CTX_F30_OFF(t2)
+ fld f31, FPU_CTX_F31_OFF(t2)
+
+ /* clr FS domain */
+ csrc sstatus, t0
+
+ /* clean status would clr sr_sd; */
+ li t0, SSTATUS_FS_CLEAN
+ csrs sstatus, t0
+
+#endif /* ENABLE_FPU */
+
+ /* restore general register */
+
+ /* resw ra to sepc */
+ LOAD x1, 0 * REGBYTES(sp)
+ csrw sepc, x1
+
+ LOAD x1, 2 * REGBYTES(sp)
+ csrw sstatus, x1
+
+ LOAD x1, 1 * REGBYTES(sp)
+
+ LOAD x3, 3 * REGBYTES(sp)
+ LOAD x4, 4 * REGBYTES(sp) /* restore tp */
+ LOAD x5, 5 * REGBYTES(sp)
+ LOAD x6, 6 * REGBYTES(sp)
+ LOAD x7, 7 * REGBYTES(sp)
+ LOAD x8, 8 * REGBYTES(sp)
+ LOAD x9, 9 * REGBYTES(sp)
+ LOAD x10, 10 * REGBYTES(sp)
+ LOAD x11, 11 * REGBYTES(sp)
+ LOAD x12, 12 * REGBYTES(sp)
+ LOAD x13, 13 * REGBYTES(sp)
+ LOAD x14, 14 * REGBYTES(sp)
+ LOAD x15, 15 * REGBYTES(sp)
+ LOAD x16, 16 * REGBYTES(sp)
+ LOAD x17, 17 * REGBYTES(sp)
+ LOAD x18, 18 * REGBYTES(sp)
+ LOAD x19, 19 * REGBYTES(sp)
+ LOAD x20, 20 * REGBYTES(sp)
+ LOAD x21, 21 * REGBYTES(sp)
+ LOAD x22, 22 * REGBYTES(sp)
+ LOAD x23, 23 * REGBYTES(sp)
+ LOAD x24, 24 * REGBYTES(sp)
+ LOAD x25, 25 * REGBYTES(sp)
+ LOAD x26, 26 * REGBYTES(sp)
+ LOAD x27, 27 * REGBYTES(sp)
+ LOAD x28, 28 * REGBYTES(sp)
+ LOAD x29, 29 * REGBYTES(sp)
+ LOAD x30, 30 * REGBYTES(sp)
+ LOAD x31, 31 * REGBYTES(sp)
+
+ /* restore user sp */
+ LOAD sp, 32 * REGBYTES(sp)
+.endm
+
+.macro RESTORE_SYS_GP
+ .option push
+ .option norelax
+ la gp, __global_pointer$
+ .option pop
+.endm
+
+.macro OPEN_INTERRUPT
+ csrsi sstatus, 2
+.endm
+
+.macro CLOSE_INTERRUPT
+ csrci sstatus, 2
+.endm
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/startup_gcc.S b/libcpu/risc-v/t-head/c906/startup_gcc.S
new file mode 100644
index 0000000000..3760b857b3
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/startup_gcc.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/01 Bernard The first version
+ * 2018/12/27 Jesven Add SMP support
+ * 2020/6/12 Xim Port to QEMU and remove SMP support
+ */
+
+#define __ASSEMBLY__
+#define SSTATUS_FS 0x00006000U /* initial state of FPU, clear to disable */
+#include <cpuport.h>
+
+ .global _start
+ .section ".start", "ax"
+_start:
+ j 1f
+ .word 0xdeadbeef
+ .align 3
+ .global g_wake_up
+ g_wake_up:
+ .dword 1
+ .dword 0
+1:
+ csrw sie, 0
+ csrw sip, 0
+ la t0, trap_entry
+ csrw stvec, t0
+
+ li x1, 0
+ li x2, 0
+ li x3, 0
+ li x4, 0
+ li x5, 0
+ li x6, 0
+ li x7, 0
+ li x8, 0
+ li x9, 0
+ li x10,0
+ li x11,0
+ li x12,0
+ li x13,0
+ li x14,0
+ li x15,0
+ li x16,0
+ li x17,0
+ li x18,0
+ li x19,0
+ li x20,0
+ li x21,0
+ li x22,0
+ li x23,0
+ li x24,0
+ li x25,0
+ li x26,0
+ li x27,0
+ li x28,0
+ li x29,0
+ li x30,0
+ li x31,0
+
+ /* set to disable FPU */
+ li t0, SSTATUS_FS
+ csrc sstatus, t0
+ li t0, 0x40000 // SUM in sstatus
+ csrs sstatus, t0
+
+.option push
+.option norelax
+ la gp, __global_pointer$
+.option pop
+
+ // removed SMP support here
+ la sp, __stack_start__
+ li t0, __STACKSIZE__
+ add sp, sp, t0
+ csrw sscratch, sp
+ j primary_cpu_entry
diff --git a/libcpu/risc-v/t-head/c906/symbol_analysis.c b/libcpu/risc-v/t-head/c906/symbol_analysis.c
new file mode 100644
index 0000000000..83edacb1c4
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/symbol_analysis.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright lizhirui
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 lizhirui the first version
+ * 2021-05-20 lizhirui add os debug support
+ */
+
+#include <rtthread.h>
+#include "symbol_analysis.h"
+
+#define MEMORY_BASE 0x40000000
+#define MEMORY_SIZE (128 * 0x100000)
+
+extern rt_size_t _osdebug_start;
+
+static os_symtab_header *symtab_header = (os_symtab_header *)&_osdebug_start;
+
+//该函数用于在指定的表中查找某个地址对应的符号的描述结构体指针,返回值的符号遵循规则详见文档
+os_symtab_item *find_symbol_table(rt_size_t symbol_table_addr,rt_size_t symbol_num,rt_size_t address)
+{
+ rt_size_t left = 0;
+ rt_size_t right = symbol_num;
+ os_symtab_item *sym_table = (os_symtab_item *)((rt_size_t)&_osdebug_start + symbol_table_addr);
+
+ while(left < right)
+ {
+ rt_size_t mid = (left + right) >> 1;
+ //rt_kprintf("left = %d,right = %d,mid = %d\n",left,right,mid);
+
+ if(address < sym_table[mid].address)
+ {
+ right = mid;
+
+ while((right < symbol_num) && ((right - 1) >= 0) && (sym_table[right].address == sym_table[right - 1].address))
+ {
+ right--;
+ }
+ }
+ else if(address == sym_table[mid].address)
+ {
+ left = mid + 1;
+ break;
+ }
+ else
+ {
+ left = mid;
+
+ while((left >= 0) && ((left + 1) < symbol_num) && (sym_table[left].address == sym_table[left + 1].address))
+ {
+ left++;
+ }
+
+ left++;
+ }
+ }
+
+ left--;
+
+ if(left == ((rt_size_t)-1))
+ {
+ return RT_NULL;
+ }
+
+ while((left < symbol_num) && ((left - 1) >= 0) && (sym_table[left].address == sym_table[left - 1].address))
+ {
+ left--;
+ }
+
+ return &sym_table[left];
+}
+
+//该函数用于根据给定的符号指针从字符串表中找到对应的符号名指针并返回
+const char *get_symbol_name(os_symtab_item *symbol)
+{
+ return (const char *)((rt_size_t)&_osdebug_start + symtab_header -> string_table_offset + symbol -> name_offset);
+}
+
+//该函数可以根据给定的符号和地址向中断打印出标准格式的符号信息
+void print_symbol(os_symtab_item *symbol,rt_size_t address)
+{
+ rt_kprintf("<%s(0x%p)",get_symbol_name(symbol),symbol -> address);
+
+ if(symbol -> size)
+ {
+ rt_kprintf(" : 0x%x>",symbol -> size);
+ }
+ else
+ {
+ rt_kprintf(">");
+ }
+
+ if(address > symbol -> address)
+ {
+ rt_kprintf(" + 0x%x",address - symbol -> address);
+ }
+}
+
+//该函数用于打印出一个地址关联的全部符号信息
+void print_symbol_info(rt_size_t address,rt_bool_t function)
+{
+ os_symtab_item *function_symbol = find_symbol_table(symtab_header -> function_table_offset,symtab_header -> function_table_num,address);
+ os_symtab_item *object_symbol = find_symbol_table(symtab_header -> object_table_offset,symtab_header -> object_table_num,address);
+ os_symtab_item *general_symbol = find_symbol_table(symtab_header -> general_symbol_table_offset,symtab_header -> general_symbol_table_num,address);
+ const char *dot = "";
+ rt_bool_t valid = RT_FALSE;
+
+ if(function)
+ {
+ while(function_symbol != RT_NULL)
+ {
+ if((function_symbol -> address + function_symbol -> size) > address)
+ {
+ rt_kprintf(dot);
+ print_symbol(function_symbol,address);
+ dot = ",";
+ valid = RT_TRUE;
+ }
+
+ if(((rt_size_t)(function_symbol + 1)) >= (((rt_size_t)&_osdebug_start) + symtab_header -> function_table_offset + symtab_header -> function_table_num * sizeof(os_symtab_item)))
+ {
+ break;
+ }
+
+ if(function_symbol[0].address == function_symbol[1].address)
+ {
+ function_symbol++;
+ }
+
+ break;
+ }
+
+ if(!valid)
+ {
+ while(general_symbol != RT_NULL)
+ {
+ rt_kprintf(dot);
+ print_symbol(general_symbol,address);
+ dot = ",";
+ valid = RT_TRUE;
+
+ if(((rt_size_t)(general_symbol + 1)) >= (((rt_size_t)&_osdebug_start) + symtab_header -> general_symbol_table_offset + symtab_header -> general_symbol_table_num * sizeof(os_symtab_item)))
+ {
+ break;
+ }
+
+ if(general_symbol[0].address == general_symbol[1].address)
+ {
+ general_symbol++;
+ }
+
+ break;
+ }
+
+ while(object_symbol != RT_NULL)
+ {
+ if((object_symbol -> address + object_symbol -> size) > address)
+ {
+ rt_kprintf(dot);
+ print_symbol(object_symbol,address);
+ dot = ",";
+ valid = RT_TRUE;
+ }
+
+ if(((rt_size_t)(object_symbol + 1)) >= (((rt_size_t)&_osdebug_start) + symtab_header -> object_table_offset + symtab_header -> object_table_num * sizeof(os_symtab_item)))
+ {
+ break;
+ }
+
+ if(object_symbol[0].address == object_symbol[1].address)
+ {
+ object_symbol++;
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ while(object_symbol != RT_NULL)
+ {
+ if((object_symbol -> address + object_symbol -> size) > address)
+ {
+ rt_kprintf(dot);
+ print_symbol(object_symbol,address);
+ dot = ",";
+ valid = RT_TRUE;
+ }
+
+ if(((rt_size_t)(object_symbol + 1)) >= (((rt_size_t)&_osdebug_start) + symtab_header -> object_table_offset + symtab_header -> object_table_num * sizeof(os_symtab_item)))
+ {
+ break;
+ }
+
+ if(object_symbol[0].address == object_symbol[1].address)
+ {
+ object_symbol++;
+ }
+
+ break;
+ }
+
+ if(!valid)
+ {
+ while(general_symbol != RT_NULL)
+ {
+ rt_kprintf(dot);
+ print_symbol(general_symbol,address);
+ dot = ",";
+ valid = RT_TRUE;
+
+ if(((rt_size_t)(general_symbol + 1)) >= (((rt_size_t)&_osdebug_start) + symtab_header -> general_symbol_table_offset + symtab_header -> general_symbol_table_num * sizeof(os_symtab_item)))
+ {
+ break;
+ }
+
+ if(general_symbol[0].address == general_symbol[1].address)
+ {
+ general_symbol++;
+ }
+
+ break;
+ }
+
+ while(function_symbol != RT_NULL)
+ {
+ if((function_symbol -> address + function_symbol -> size) > address)
+ {
+ rt_kprintf(dot);
+ print_symbol(function_symbol,address);
+ dot = ",";
+ valid = RT_TRUE;
+ }
+
+ if(((rt_size_t)(function_symbol + 1)) >= (((rt_size_t)&_osdebug_start) + symtab_header -> function_table_offset + symtab_header -> function_table_num * sizeof(os_symtab_item)))
+ {
+ break;
+ }
+
+ if(function_symbol[0].address == function_symbol[1].address)
+ {
+ function_symbol++;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if(dot == "")
+ {
+ rt_kprintf("<Unknown Symbol>");
+ }
+}
+
+//该函数用于在出错时打印出栈跟踪信息
+void print_stacktrace(rt_size_t epc,rt_size_t fp)
+{
+ rt_kprintf("-----------------------------Dump Stacktrace----------------------------\n\n");
+ rt_size_t sp = fp;
+ rt_size_t i = 0;
+
+ rt_kprintf("address 0x%p(",epc);
+ print_symbol_info(epc,RT_TRUE);
+ rt_kprintf(")\n\n");
+
+ while(1)
+ {
+ if((sp >= MEMORY_BASE) && (sp < (MEMORY_BASE + MEMORY_SIZE)))
+ {
+ //rt_kprintf("%d: 0x%p\n",i,sp);
+ rt_size_t *stack = (rt_size_t *)(sp - sizeof(rt_size_t) * 2);
+ rt_size_t ra = stack[1];
+
+ if(!ra)
+ {
+ break;
+ }
+
+ rt_kprintf("return to 0x%p(",ra);
+ print_symbol_info(ra,RT_TRUE);
+ rt_kprintf(")\n\n");
+ //rt_kprintf("ra = 0x%p,fp = 0x%p\n",stack[1],stack[0]);
+ sp = stack[0];
+ i++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ rt_kprintf("---------------------------------Dump OK--------------------------------\n");
+}
diff --git a/libcpu/risc-v/t-head/c906/symbol_analysis.h b/libcpu/risc-v/t-head/c906/symbol_analysis.h
new file mode 100644
index 0000000000..a9db46ffd3
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/symbol_analysis.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright lizhirui
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 lizhirui the first version
+ * 2021-05-20 lizhirui add os debug support
+ */
+
+#ifndef __SYMBOL_ANALYSIS_H__
+#define __SYMBOL_ANALYSIS_H__
+
+ #include <rtthread.h>
+
+ //osdebug节区头描述结构体
+ typedef struct os_symtab_header
+ {
+ rt_size_t function_table_offset;//函数表的偏移地址(相对于节区起始地址,下同)
+ rt_size_t function_table_num;//函数表中的符号数量
+ rt_size_t object_table_offset;//对象表的偏移地址
+ rt_size_t object_table_num;//对象表中的符号数量
+ rt_size_t general_symbol_table_offset;//一般符号(指代类型虽为NONE但带有GLOBAL的符号)表的偏移地址
+ rt_size_t general_symbol_table_num;//一般符号表中的符号数量
+ rt_size_t string_table_offset;//字符串表的偏移地址
+ rt_size_t string_table_size;//字符串表的大小(字节为单位)
+ }os_symtab_header;
+
+ //符号描述结构体
+ typedef struct os_symtab_item
+ {
+ rt_size_t name_offset;//符号名称在字符串表中的偏移地址
+ rt_size_t address;//该符号所代表的地址
+ rt_size_t size;//该符号所代表的大小
+ }os_symtab_item;
+
+ os_symtab_item *find_symbol_table(rt_size_t symbol_table_addr,rt_size_t symbol_num,rt_size_t address);
+ const char *get_symbol_name(os_symtab_item *symbol);
+ void print_symbol(os_symtab_item *symbol,rt_size_t address);
+ void print_symbol_info(rt_size_t address,rt_bool_t function);
+ void print_stacktrace(rt_size_t epc,rt_size_t fp);
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/syscall_c.c b/libcpu/risc-v/t-head/c906/syscall_c.c
new file mode 100644
index 0000000000..8f27db5ffd
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/syscall_c.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-02-03 lizhirui first version
+ * 2022-11-10 WangXiaoyao Add readable syscall tracing
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#define DBG_TAG "syscall"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+#include <stdint.h>
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+
+#include "riscv_mmu.h"
+#include "stack.h"
+
+typedef rt_size_t (*syscallfunc_t)(rt_size_t, rt_size_t, rt_size_t, rt_size_t, rt_size_t, rt_size_t, rt_size_t);
+
+void syscall_handler(struct rt_hw_stack_frame *regs)
+{
+ const char *syscall_name;
+ int syscallid = regs->a7;
+
+ if (syscallid == 0)
+ {
+ LOG_E("syscall id = 0!\n");
+ while (1)
+ ;
+ }
+
+ syscallfunc_t syscallfunc = (syscallfunc_t)lwp_get_sys_api(syscallid);
+
+ if (syscallfunc == RT_NULL)
+ {
+ LOG_E("unsupported syscall!\n");
+ sys_exit(-1);
+ }
+
+#if DBG_LVL >= DBG_INFO
+ syscall_name = lwp_get_syscall_name(syscallid);
+#endif
+
+ LOG_I("[0x%lx] %s(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)", rt_thread_self(), syscall_name,
+ regs->a0, regs->a1, regs->a2, regs->a3, regs->a4, regs->a5, regs->a6);
+ regs->a0 = syscallfunc(regs->a0, regs->a1, regs->a2, regs->a3, regs->a4, regs->a5, regs->a6);
+ regs->a7 = 0;
+ regs->epc += 4; // skip ecall instruction
+ LOG_I("[0x%lx] %s ret: 0x%lx", rt_thread_self(), syscall_name, regs->a0);
+}
diff --git a/libcpu/risc-v/t-head/c906/tick.c b/libcpu/risc-v/t-head/c906/tick.c
new file mode 100644
index 0000000000..0cb3c79be3
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/tick.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/28 Bernard The unify RISC-V porting code.
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include <encoding.h>
+#include "sbi.h"
+#include "tick.h"
+
+static volatile uint64_t time_elapsed = 0;
+static volatile unsigned long tick_cycles = 0;
+
+static unsigned long tick_delta = TIMER_CLK_FREQ / RT_TICK_PER_SECOND;
+
+static uint64_t get_ticks()
+{
+ __asm__ __volatile__(
+ "rdtime %0"
+ : "=r"(time_elapsed));
+ return time_elapsed;
+}
+
+int tick_isr(void)
+{
+ rt_tick_increase();
+ sbi_set_timer(get_ticks() + tick_delta);
+ return 0;
+}
+
+/* Sets and enable the timer interrupt */
+int rt_hw_tick_init(void)
+{
+ /* Clear the Supervisor-Timer bit in SIE */
+ clear_csr(sie, SIP_STIP);
+
+ /* Set timer */
+ sbi_set_timer(get_ticks() + tick_delta);
+
+ /* Enable the Supervisor-Timer bit in SIE */
+ set_csr(sie, SIP_STIP);
+
+ return 0;
+}
diff --git a/libcpu/risc-v/t-head/c906/tick.h b/libcpu/risc-v/t-head/c906/tick.h
new file mode 100644
index 0000000000..18333ef667
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/tick.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/28 Bernard The unify RISC-V porting code.
+ */
+
+#ifndef TICK_H__
+#define TICK_H__
+
+/* timer clock is 24 MHZ */
+#define TIMER_CLK_FREQ (24000000)
+
+int tick_isr(void);
+int rt_hw_tick_init(void);
+
+#endif
diff --git a/libcpu/risc-v/t-head/c906/trap.c b/libcpu/risc-v/t-head/c906/trap.c
new file mode 100644
index 0000000000..831ea3b0a2
--- /dev/null
+++ b/libcpu/risc-v/t-head/c906/trap.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021/1/30 lizirui first version
+ * 2021/10/20 JasonHu move to trap.c
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#define DBG_LVL DBG_LOG
+#include <rtdbg.h>
+
+#include "board.h"
+#include "tick.h"
+
+#include "drv_uart.h"
+#include "encoding.h"
+#include "stack.h"
+#include "sbi.h"
+#include "riscv.h"
+
+#include "rt_interrupt.h"
+#include "plic.h"
+
+#ifdef RT_USING_USERSPACE
+ #include "riscv_mmu.h"
+ #include "mmu.h"
+ #include "page.h"
+ #include "lwp_arch.h"
+#endif
+
+void dump_regs(struct rt_hw_stack_frame *regs)
+{
+ rt_kprintf("--------------Dump Registers-----------------\n");
+
+ rt_kprintf("Function Registers:\n");
+ rt_kprintf("\tra(x1) = 0x%p(",regs->ra);
+ rt_kprintf(")\n");
+ rt_kprintf("\tuser_sp(x2) = 0x%p(",regs->user_sp_exc_stack);
+ rt_kprintf(")\n");
+ rt_kprintf("\tgp(x3) = 0x%p(",regs->gp);
+ rt_kprintf(")\n");
+ rt_kprintf("\ttp(x4) = 0x%p(",regs->tp);
+ rt_kprintf(")\n");
+ rt_kprintf("Temporary Registers:\n");
+ rt_kprintf("\tt0(x5) = 0x%p(",regs->t0);
+ rt_kprintf(")\n");
+ rt_kprintf("\tt1(x6) = 0x%p(",regs->t1);
+ rt_kprintf(")\n");
+ rt_kprintf("\tt2(x7) = 0x%p(",regs->t2);
+ rt_kprintf(")\n");
+ rt_kprintf("\tt3(x28) = 0x%p(",regs->t3);
+ rt_kprintf(")\n");
+ rt_kprintf("\tt4(x29) = 0x%p(",regs->t4);
+ rt_kprintf(")\n");
+ rt_kprintf("\tt5(x30) = 0x%p(",regs->t5);
+ rt_kprintf(")\n");
+ rt_kprintf("\tt6(x31) = 0x%p(",regs->t6);
+ rt_kprintf(")\n");
+ rt_kprintf("Saved Registers:\n");
+ rt_kprintf("\ts0/fp(x8) = 0x%p(",regs->s0_fp);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts1(x9) = 0x%p(",regs->s1);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts2(x18) = 0x%p(",regs->s2);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts3(x19) = 0x%p(",regs->s3);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts4(x20) = 0x%p(",regs->s4);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts5(x21) = 0x%p(",regs->s5);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts6(x22) = 0x%p(",regs->s6);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts7(x23) = 0x%p(",regs->s7);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts8(x24) = 0x%p(",regs->s8);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts9(x25) = 0x%p(",regs->s9);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts10(x26) = 0x%p(",regs->s10);
+ rt_kprintf(")\n");
+ rt_kprintf("\ts11(x27) = 0x%p(",regs->s11);
+ rt_kprintf(")\n");
+ rt_kprintf("Function Arguments Registers:\n");
+ rt_kprintf("\ta0(x10) = 0x%p(",regs->a0);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta1(x11) = 0x%p(",regs->a1);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta2(x12) = 0x%p(",regs->a2);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta3(x13) = 0x%p(",regs->a3);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta4(x14) = 0x%p(",regs->a4);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta5(x15) = 0x%p(",regs->a5);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta6(x16) = 0x%p(",regs->a6);
+ rt_kprintf(")\n");
+ rt_kprintf("\ta7(x17) = 0x%p(",regs->a7);
+ rt_kprintf(")\n");
+ rt_kprintf("sstatus = 0x%p\n",regs->sstatus);
+ rt_kprintf("\t%s\n",(regs->sstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
+ rt_kprintf("\t%s\n",(regs->sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
+ rt_kprintf("\t%s\n",(regs->sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
+ rt_kprintf("\t%s\n",(regs->sstatus & SSTATUS_PUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
+ rt_kprintf("\t%s\n",(regs->sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
+ rt_size_t satp_v = read_csr(satp);
+ rt_kprintf("satp = 0x%p\n",satp_v);
+
+#ifdef RT_USING_USERSPACE
+ rt_kprintf("\tCurrent Page Table(Physical) = 0x%p\n",__MASKVALUE(satp_v,__MASK(44)) << PAGE_OFFSET_BIT);
+ rt_kprintf("\tCurrent ASID = 0x%p\n",__MASKVALUE(satp_v >> 44,__MASK(16)) << PAGE_OFFSET_BIT);
+#endif
+
+ const char *mode_str = "Unknown Address Translation/Protection Mode";
+
+ switch(__MASKVALUE(satp_v >> 60,__MASK(4)))
+ {
+ case 0:
+ mode_str = "No Address Translation/Protection Mode";
+ break;
+
+ case 8:
+ mode_str = "Page-based 39-bit Virtual Addressing Mode";
+ break;
+
+ case 9:
+ mode_str = "Page-based 48-bit Virtual Addressing Mode";
+ break;
+ }
+
+ rt_kprintf("\tMode = %s\n",mode_str);
+ rt_kprintf("-----------------Dump OK---------------------\n");
+}
+
+static const char *Exception_Name[] =
+ {
+ "Instruction Address Misaligned",
+ "Instruction Access Fault",
+ "Illegal Instruction",
+ "Breakpoint",
+ "Load Address Misaligned",
+ "Load Access Fault",
+ "Store/AMO Address Misaligned",
+ "Store/AMO Access Fault",
+ "Environment call from U-mode",
+ "Environment call from S-mode",
+ "Reserved-10",
+ "Reserved-11",
+ "Instruction Page Fault",
+ "Load Page Fault",
+ "Reserved-14",
+ "Store/AMO Page Fault"
+ };
+
+static const char *Interrupt_Name[] =
+ {
+ "User Software Interrupt",
+ "Supervisor Software Interrupt",
+ "Reversed-2",
+ "Reversed-3",
+ "User Timer Interrupt",
+ "Supervisor Timer Interrupt",
+ "Reversed-6",
+ "Reversed-7",
+ "User External Interrupt",
+ "Supervisor External Interrupt",
+ "Reserved-10",
+ "Reserved-11",
+ };
+
+extern struct rt_irq_desc isr_table[];
+
+void generic_handle_irq(int irq)
+{
+ rt_isr_handler_t isr;
+ void *param;
+
+ if (irq < 0 || irq >= IRQ_MAX_NR)
+ {
+ LOG_E("bad irq number %d!\n", irq);
+ return;
+ }
+
+ if (!irq) // irq = 0 => no irq
+ {
+ LOG_W("no irq!\n");
+ return;
+ }
+ isr = isr_table[IRQ_OFFSET + irq].handler;
+ param = isr_table[IRQ_OFFSET + irq].param;
+ if (isr != RT_NULL)
+ {
+ isr(irq, param);
+ }
+ /* complete irq. */
+ plic_complete(irq);
+}
+
+/* Trap entry */
+void handle_trap(rt_size_t scause,rt_size_t stval,rt_size_t sepc,struct rt_hw_stack_frame *sp)
+{
+ rt_size_t id = __MASKVALUE(scause,__MASK(63UL));
+ const char *msg;
+
+ /* supervisor external interrupt */
+ if ((SCAUSE_INTERRUPT & scause) && SCAUSE_S_EXTERNAL_INTR == (scause & 0xff))
+ {
+ rt_interrupt_enter();
+ plic_handle_irq();
+ rt_interrupt_leave();
+ return;
+ }
+ else if ((SCAUSE_INTERRUPT | SCAUSE_S_TIMER_INTR) == scause)
+ {
+ /* supervisor timer */
+ rt_interrupt_enter();
+ tick_isr();
+ rt_interrupt_leave();
+ return;
+ }
+ else if (SCAUSE_INTERRUPT & scause)
+ {
+ if(id < sizeof(Interrupt_Name) / sizeof(const char *))
+ {
+ msg = Interrupt_Name[id];
+ }
+ else
+ {
+ msg = "Unknown Interrupt";
+ }
+ LOG_E("Unhandled Interrupt %ld:%s\n",id,msg);
+ }
+ else
+ {
+#ifdef RT_USING_USERSPACE
+ /* page fault */
+ if (id == EP_LOAD_PAGE_FAULT ||
+ id == EP_STORE_PAGE_FAULT)
+ {
+ arch_expand_user_stack((void *)stval);
+ return;
+ }
+#endif
+ if(id < sizeof(Exception_Name) / sizeof(const char *))
+ {
+ msg = Exception_Name[id];
+ }
+ else
+ {
+ msg = "Unknown Exception";
+ }
+
+ rt_kprintf("Unhandled Exception %ld:%s\n",id,msg);
+ }
+
+ rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n",scause,stval,sepc);
+ dump_regs(sp);
+ while(1);
+}
diff --git a/libcpu/risc-v/virt64/backtrace.c b/libcpu/risc-v/virt64/backtrace.c
new file mode 100644
index 0000000000..47e742b67b
--- /dev/null
+++ b/libcpu/risc-v/virt64/backtrace.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+#include <rtthread.h>
+#include <lwp_arch.h>
+
+#define TRANCE_LEVEL 20
+
+extern rt_ubase_t __text_start[];
+extern rt_ubase_t __text_end[];
+
+static char *_get_elf_name();
+
+void rt_hw_backtrace(rt_uint32_t *ffp, rt_ubase_t sepc)
+{
+ extern rt_mmu_info mmu_info;
+ rt_ubase_t *ra;
+ rt_ubase_t *fp;
+ rt_ubase_t vas, vae;
+ int i, j;
+
+ rt_kprintf("riscv64-unknown-linux-musl-addr2line -e %s -a -f", _get_elf_name(sepc));
+
+ fp = (rt_ubase_t *)ffp;
+
+ if (!fp)
+ {
+ asm volatile("mv %0, s0"
+ : "=r"(fp));
+ }
+
+ if (sepc)
+ {
+ rt_kprintf(" %p", sepc - 0x4);
+ }
+
+ if (fp > (rt_ubase_t *)USER_VADDR_START && fp < (rt_ubase_t *)USER_VADDR_TOP)
+ {
+ vas = USER_VADDR_START;
+ vae = USER_VADDR_TOP;
+ }
+ else
+ {
+ vas = (rt_ubase_t)&__text_start;
+ vae = (rt_ubase_t)&__text_end;
+ }
+
+ for (i = j = 0; i < TRANCE_LEVEL; i++)
+ {
+ if (RT_ALIGN((rt_ubase_t)fp, sizeof(void *)) != (rt_ubase_t)fp)
+ {
+ break;
+ }
+
+ ra = fp - 1;
+ if (!_rt_hw_mmu_v2p(&mmu_info, ra) || *ra < vas || *ra > vae)
+ break;
+
+ rt_kprintf(" %p", *ra - 0x04);
+
+ fp = fp - 2;
+ if (!_rt_hw_mmu_v2p(&mmu_info, fp))
+ break;
+ fp = (rt_ubase_t *)(*fp);
+ if (!fp)
+ break;
+ }
+
+ rt_kputs("\r\n");
+}
+
+static void _assert_backtrace_cb(const char *ex, const char *func, rt_size_t line)
+{
+ rt_hw_interrupt_disable();
+ rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex, func, line);
+
+ rt_hw_backtrace(0, 0);
+ rt_hw_cpu_shutdown();
+}
+
+static int rt_hw_backtrace_init(void)
+{
+ rt_assert_set_hook(_assert_backtrace_cb);
+
+ return 0;
+}
+INIT_BOARD_EXPORT(rt_hw_backtrace_init);
+
+static void backtrace_test(int args, char *argv[])
+{
+ int *p = (void *)-1;
+ init_fn_t ft = 0;
+
+ if (args < 2)
+ {
+ rt_kprintf("backtrace_test usage:backtrace_test a(assert)/m(invalid memory)/i(illegal instruction)\r\n");
+ return;
+ }
+
+ if (!rt_strcmp(argv[1], "a"))
+ {
+ rt_kprintf("Assert test:\r\n", argv[1]);
+ RT_ASSERT(0);
+ }
+ else if (!rt_strcmp(argv[1], "m"))
+ {
+ rt_kprintf("Access invalid memory:\r\n", argv[1]);
+ *p = 0;
+ }
+ else if (!rt_strcmp(argv[1], "i"))
+ {
+ rt_kprintf("Illegal instruction:\r\n", argv[1]);
+ ft();
+ }
+ else
+ {
+ rt_kprintf("Unknown cmd :%s.\r\n", argv[1]);
+ }
+}
+MSH_CMD_EXPORT(backtrace_test, backtrace test case);
+
+extern struct rt_thread *rt_current_thread;
+
+#define IN_USERSPACE (sepc > USER_VADDR_START && sepc < USER_VADDR_TOP)
+
+static char *_get_elf_name(size_t sepc)
+{
+ return IN_USERSPACE ? rt_current_thread->name : "rtthread.elf";
+}
diff --git a/libcpu/risc-v/virt64/cache.c b/libcpu/risc-v/virt64/cache.c
new file mode 100644
index 0000000000..a7f58ee0c6
--- /dev/null
+++ b/libcpu/risc-v/virt64/cache.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-29 lizhirui first version
+ */
+
+#include <rthw.h>
+#include <rtdef.h>
+#include <board.h>
+#include <riscv.h>
+#include <cache.h>
+
+rt_inline rt_uint32_t rt_cpu_icache_line_size()
+{
+ return 0;
+}
+
+rt_inline rt_uint32_t rt_cpu_dcache_line_size()
+{
+ return 0;
+}
+
+void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
+{
+ if (ops == RT_HW_CACHE_INVALIDATE)
+ {
+ rt_hw_cpu_icache_invalidate(addr, size);
+ }
+}
+
+void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
+{
+ if (ops == RT_HW_CACHE_FLUSH)
+ {
+ rt_hw_cpu_dcache_clean(addr, size);
+ }
+ else
+ {
+ rt_hw_cpu_dcache_invalidate(addr, size);
+ }
+}
+
+rt_base_t rt_hw_cpu_icache_status_local()
+{
+ return 0;
+}
+
+rt_base_t rt_hw_cpu_dcache_status()
+{
+ return 0;
+}
+
+void rt_hw_sync_cache_local(void *addr, int size)
+{
+}
+
+int sys_cacheflush(void *addr, int size, int cache)
+{
+ return 0;
+}
diff --git a/libcpu/risc-v/virt64/cache.h b/libcpu/risc-v/virt64/cache.h
new file mode 100644
index 0000000000..e343d7927f
--- /dev/null
+++ b/libcpu/risc-v/virt64/cache.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-09 RT-Thread The first version
+ */
+#ifndef __CACHE_H__
+#define __CACHE_H__
+
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE inline __attribute__((always_inline))
+#endif
+
+/**
+ * @brief These APIs may not be supported by a specified architecture
+ * But we have to include to all the cases to be 'general purpose'
+ */
+
+ALWAYS_INLINE void rt_hw_cpu_dcache_clean_local(void *addr, int size) {}
+ALWAYS_INLINE void rt_hw_cpu_dcache_invalidate_local(void *addr, int size) {}
+ALWAYS_INLINE void rt_hw_cpu_dcache_clean_invalidate_local(void *addr, int size) {}
+
+ALWAYS_INLINE void rt_hw_cpu_dcache_clean_all_local() {}
+ALWAYS_INLINE void rt_hw_cpu_dcache_invalidate_all_local(void) {}
+ALWAYS_INLINE void rt_hw_cpu_dcache_clean_invalidate_all_local(void) {}
+
+ALWAYS_INLINE void rt_hw_cpu_icache_invalidate_local(void *addr, int size) {}
+ALWAYS_INLINE void rt_hw_cpu_icache_invalidate_all_local() {}
+
+/**
+ * @brief Multi-core
+ */
+
+#define rt_hw_cpu_dcache_clean rt_hw_cpu_dcache_clean_local
+#define rt_hw_cpu_dcache_invalidate rt_hw_cpu_dcache_invalidate_local
+#define rt_hw_cpu_dcache_clean_invalidate rt_hw_cpu_dcache_clean_invalidate_local
+
+#define rt_hw_cpu_dcache_clean_all rt_hw_cpu_dcache_clean_all_local
+#define rt_hw_cpu_dcache_invalidate_all rt_hw_cpu_dcache_invalidate_all_local
+#define rt_hw_cpu_dcache_clean_invalidate_all rt_hw_cpu_dcache_clean_invalidate_all_local
+
+#define rt_hw_cpu_icache_invalidate rt_hw_cpu_icache_invalidate_local
+#define rt_hw_cpu_icache_invalidate_all rt_hw_cpu_icache_invalidate_all_local
+
+/** instruction barrier */
+void rt_hw_cpu_sync(void);
+
+/**
+ * @brief local cpu icahce & dcache synchronization
+ *
+ * @param addr
+ * @param size
+ */
+void rt_hw_sync_cache_local(void *addr, int size);
+
+#endif /* __CACHE_H__ */
diff --git a/libcpu/risc-v/virt64/context_gcc.S b/libcpu/risc-v/virt64/context_gcc.S
index 40803148df..23a0b014e9 100644
--- a/libcpu/risc-v/virt64/context_gcc.S
+++ b/libcpu/risc-v/virt64/context_gcc.S
@@ -8,300 +8,138 @@
* 2018/10/28 Bernard The unify RISC-V porting implementation
* 2018/12/27 Jesven Add SMP support
* 2021/02/02 lizhirui Add userspace support
+ * 2022/10/22 WangXiaoyao Support User mode RVV;
+ * Trimming process switch context
*/
+
#include "cpuport.h"
+#include "stackframe.h"
-#ifdef RT_USING_SMP
-#define rt_hw_interrupt_disable rt_hw_local_irq_disable
-#define rt_hw_interrupt_enable rt_hw_local_irq_enable
-#endif
+.macro PUSH_8 reg
+ addi sp, sp, -8
+ STORE \reg, (sp)
+.endm
-/*
- * rt_base_t rt_hw_interrupt_disable(void);
- */
- .globl rt_hw_interrupt_disable
-rt_hw_interrupt_disable:
-#ifdef RISCV_S_MODE
- csrrci a0, sstatus, 2
-#else
- csrrci a0, mstatus, 8
-#endif
- ret
+.macro POP_8 reg
+ LOAD \reg, (sp)
+ addi sp, sp, 8
+.endm
-/*
- * void rt_hw_interrupt_enable(rt_base_t level);
- */
- .globl rt_hw_interrupt_enable
-rt_hw_interrupt_enable:
- csrw SRC_XSTATUS, a0
- ret
+.macro RESERVE_CONTEXT
+ PUSH_8 tp
+ PUSH_8 ra
+ PUSH_8 s0
+ PUSH_8 s1
+ PUSH_8 s2
+ PUSH_8 s3
+ PUSH_8 s4
+ PUSH_8 s5
+ PUSH_8 s6
+ PUSH_8 s7
+ PUSH_8 s8
+ PUSH_8 s9
+ PUSH_8 s10
+ PUSH_8 s11
+ csrr s11, sstatus
+ li s10, (SSTATUS_SPP)
+ or s11, s11, s10
+ PUSH_8 s11
+.endm
+
+.macro RESTORE_CONTEXT
+ POP_8 s11
+ csrw sstatus, s11
+ POP_8 s11
+ POP_8 s10
+ POP_8 s9
+ POP_8 s8
+ POP_8 s7
+ POP_8 s6
+ POP_8 s5
+ POP_8 s4
+ POP_8 s3
+ POP_8 s2
+ POP_8 s1
+ POP_8 s0
+ POP_8 ra
+ POP_8 tp
+ csrw sepc, ra
+.endm
/*
- * #ifdef RT_USING_SMP
- * void rt_hw_context_switch_to(rt_ubase_t to, stuct rt_thread *to_thread);
- * #else
* void rt_hw_context_switch_to(rt_ubase_t to);
- * #endif
- * a0 --> to
- * a1 --> to_thread
+ *
+ * a0 --> to SP pointer
*/
- .globl rt_hw_context_switch_to
+.globl rt_hw_context_switch_to
rt_hw_context_switch_to:
LOAD sp, (a0)
-#ifdef RT_USING_SMP
- mv a0, a1
- call rt_cpus_lock_status_restore
-#endif
- LOAD a0, 2 * REGBYTES(sp)
- csrw SRC_XSTATUS, a0
- j rt_hw_context_switch_exit
+ la s0, rt_current_thread
+ LOAD s1, (s0)
+
+ #ifdef RT_USING_USERSPACE
+ mv a0, s1
+ jal lwp_mmu_switch
+ #endif
+
+ RESTORE_CONTEXT
+ sret
/*
- * #ifdef RT_USING_SMP
- * void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
- * #else
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
- * #endif
*
- * a0 --> from
- * a1 --> to
- * a2 --> to_thread
+ * a0 --> from SP pointer
+ * a1 --> to SP pointer
+ *
+ * It should only be used on local interrupt disable
*/
- .globl rt_hw_context_switch
+.globl rt_hw_context_switch
rt_hw_context_switch:
- /* saved from thread context
- * x1/ra -> sp(0)
- * x1/ra -> sp(1)
- * mstatus.mie -> sp(2)
- * x(i) -> sp(i-4)
- */
-#ifdef ARCH_RISCV_FPU
- addi sp, sp, -32 * FREGBYTES
-
- FSTORE f0, 0 * FREGBYTES(sp)
- FSTORE f1, 1 * FREGBYTES(sp)
- FSTORE f2, 2 * FREGBYTES(sp)
- FSTORE f3, 3 * FREGBYTES(sp)
- FSTORE f4, 4 * FREGBYTES(sp)
- FSTORE f5, 5 * FREGBYTES(sp)
- FSTORE f6, 6 * FREGBYTES(sp)
- FSTORE f7, 7 * FREGBYTES(sp)
- FSTORE f8, 8 * FREGBYTES(sp)
- FSTORE f9, 9 * FREGBYTES(sp)
- FSTORE f10, 10 * FREGBYTES(sp)
- FSTORE f11, 11 * FREGBYTES(sp)
- FSTORE f12, 12 * FREGBYTES(sp)
- FSTORE f13, 13 * FREGBYTES(sp)
- FSTORE f14, 14 * FREGBYTES(sp)
- FSTORE f15, 15 * FREGBYTES(sp)
- FSTORE f16, 16 * FREGBYTES(sp)
- FSTORE f17, 17 * FREGBYTES(sp)
- FSTORE f18, 18 * FREGBYTES(sp)
- FSTORE f19, 19 * FREGBYTES(sp)
- FSTORE f20, 20 * FREGBYTES(sp)
- FSTORE f21, 21 * FREGBYTES(sp)
- FSTORE f22, 22 * FREGBYTES(sp)
- FSTORE f23, 23 * FREGBYTES(sp)
- FSTORE f24, 24 * FREGBYTES(sp)
- FSTORE f25, 25 * FREGBYTES(sp)
- FSTORE f26, 26 * FREGBYTES(sp)
- FSTORE f27, 27 * FREGBYTES(sp)
- FSTORE f28, 28 * FREGBYTES(sp)
- FSTORE f29, 29 * FREGBYTES(sp)
- FSTORE f30, 30 * FREGBYTES(sp)
- FSTORE f31, 31 * FREGBYTES(sp)
-
-#endif
- addi sp, sp, -32 * REGBYTES
- STORE sp, (a0)
+ RESERVE_CONTEXT
+ STORE sp, (a0)
- STORE x1, 0 * REGBYTES(sp)
- STORE x1, 1 * REGBYTES(sp)
+ // restore to thread SP
+ LOAD sp, (a1)
+ // restore Address Space
+ la s0, rt_current_thread
+ LOAD s1, (s0)
- csrr a0, SRC_XSTATUS
-#ifdef RISCV_S_MODE
- andi a0, a0, 2
- beqz a0, save_spie
- li a0, 0x20
-save_spie:
- STORE a0, 2 * REGBYTES(sp)
-#else
- andi a0, a0, 8
- beqz a0, save_mpie
- li a0, 0x80
-save_mpie:
- STORE a0, 2 * REGBYTES(sp)
-#endif
+ #ifdef RT_USING_USERSPACE
+ mv a0, s1
+ jal lwp_mmu_switch
+ #endif
- STORE x4, 4 * REGBYTES(sp)
- STORE x5, 5 * REGBYTES(sp)
- STORE x6, 6 * REGBYTES(sp)
- STORE x7, 7 * REGBYTES(sp)
- STORE x8, 8 * REGBYTES(sp)
- STORE x9, 9 * REGBYTES(sp)
- STORE x10, 10 * REGBYTES(sp)
- STORE x11, 11 * REGBYTES(sp)
- STORE x12, 12 * REGBYTES(sp)
- STORE x13, 13 * REGBYTES(sp)
- STORE x14, 14 * REGBYTES(sp)
- STORE x15, 15 * REGBYTES(sp)
- STORE x16, 16 * REGBYTES(sp)
- STORE x17, 17 * REGBYTES(sp)
- STORE x18, 18 * REGBYTES(sp)
- STORE x19, 19 * REGBYTES(sp)
- STORE x20, 20 * REGBYTES(sp)
- STORE x21, 21 * REGBYTES(sp)
- STORE x22, 22 * REGBYTES(sp)
- STORE x23, 23 * REGBYTES(sp)
- STORE x24, 24 * REGBYTES(sp)
- STORE x25, 25 * REGBYTES(sp)
- STORE x26, 26 * REGBYTES(sp)
- STORE x27, 27 * REGBYTES(sp)
- STORE x28, 28 * REGBYTES(sp)
- STORE x29, 29 * REGBYTES(sp)
- STORE x30, 30 * REGBYTES(sp)
- STORE x31, 31 * REGBYTES(sp)
+ RESTORE_CONTEXT
+ sret
- /* restore to thread context
- * sp(0) -> epc;
- * sp(1) -> ra;
- * sp(i) -> x(i+2)
- */
- LOAD sp, (a1)
-
-#ifdef RT_USING_SMP
- mv a0, a2
- call rt_cpus_lock_status_restore
-#endif /*RT_USING_SMP*/
-
- j rt_hw_context_switch_exit
-
-#ifdef RT_USING_SMP
-/*
- * void rt_hw_context_switch_interrupt(void *context, rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
- *
- * a0 --> context
- * a1 --> from
- * a2 --> to
- * a3 --> to_thread
+#ifdef ENABLE_VECTOR
+/**
+ * @param a0 pointer to frame bottom
*/
- .globl rt_hw_context_switch_interrupt
-rt_hw_context_switch_interrupt:
-
- STORE a0, 0(a1)
-
- LOAD sp, 0(a2)
- move a0, a3
- call rt_cpus_lock_status_restore
-
- j rt_hw_context_switch_exit
-
-#endif
-
-.global rt_hw_context_switch_exit
-rt_hw_context_switch_exit:
-#ifdef RT_USING_SMP
-#ifdef RT_USING_SIGNALS
- mv a0, sp
-
- csrr t0, mhartid
- /* switch interrupt stack of current cpu */
- la sp, __stack_start__
- addi t1, t0, 1
- li t2, __STACKSIZE__
- mul t1, t1, t2
- add sp, sp, t1 /* sp = (cpuid + 1) * __STACKSIZE__ + __stack_start__ */
-
- call rt_signal_check
- mv sp, a0
-#endif
-#endif
- /* resw ra to mepc */
- LOAD a0, 0 * REGBYTES(sp)
- csrw SRC_XEPC, a0
-
- LOAD x1, 1 * REGBYTES(sp)
-
-#ifdef RISCV_S_MODE
- li t0, 0x00000120
- csrw sstatus, t0
- LOAD a0, 2 * REGBYTES(sp)
- csrs sstatus, a0
-#else
- li t0, 0x00007800
- csrw mstatus, t0
- LOAD a0, 2 * REGBYTES(sp)
- csrs mstatus, a0
-#endif
-
- LOAD x4, 4 * REGBYTES(sp)
- LOAD x5, 5 * REGBYTES(sp)
- LOAD x6, 6 * REGBYTES(sp)
- LOAD x7, 7 * REGBYTES(sp)
- LOAD x8, 8 * REGBYTES(sp)
- LOAD x9, 9 * REGBYTES(sp)
- LOAD x10, 10 * REGBYTES(sp)
- LOAD x11, 11 * REGBYTES(sp)
- LOAD x12, 12 * REGBYTES(sp)
- LOAD x13, 13 * REGBYTES(sp)
- LOAD x14, 14 * REGBYTES(sp)
- LOAD x15, 15 * REGBYTES(sp)
- LOAD x16, 16 * REGBYTES(sp)
- LOAD x17, 17 * REGBYTES(sp)
- LOAD x18, 18 * REGBYTES(sp)
- LOAD x19, 19 * REGBYTES(sp)
- LOAD x20, 20 * REGBYTES(sp)
- LOAD x21, 21 * REGBYTES(sp)
- LOAD x22, 22 * REGBYTES(sp)
- LOAD x23, 23 * REGBYTES(sp)
- LOAD x24, 24 * REGBYTES(sp)
- LOAD x25, 25 * REGBYTES(sp)
- LOAD x26, 26 * REGBYTES(sp)
- LOAD x27, 27 * REGBYTES(sp)
- LOAD x28, 28 * REGBYTES(sp)
- LOAD x29, 29 * REGBYTES(sp)
- LOAD x30, 30 * REGBYTES(sp)
- LOAD x31, 31 * REGBYTES(sp)
-
- addi sp, sp, 32 * REGBYTES
+.global rt_hw_vector_ctx_save
+rt_hw_vector_ctx_save:
+ SAVE_VECTOR a0
+ ret
-#ifdef ARCH_RISCV_FPU
- FLOAD f0, 0 * FREGBYTES(sp)
- FLOAD f1, 1 * FREGBYTES(sp)
- FLOAD f2, 2 * FREGBYTES(sp)
- FLOAD f3, 3 * FREGBYTES(sp)
- FLOAD f4, 4 * FREGBYTES(sp)
- FLOAD f5, 5 * FREGBYTES(sp)
- FLOAD f6, 6 * FREGBYTES(sp)
- FLOAD f7, 7 * FREGBYTES(sp)
- FLOAD f8, 8 * FREGBYTES(sp)
- FLOAD f9, 9 * FREGBYTES(sp)
- FLOAD f10, 10 * FREGBYTES(sp)
- FLOAD f11, 11 * FREGBYTES(sp)
- FLOAD f12, 12 * FREGBYTES(sp)
- FLOAD f13, 13 * FREGBYTES(sp)
- FLOAD f14, 14 * FREGBYTES(sp)
- FLOAD f15, 15 * FREGBYTES(sp)
- FLOAD f16, 16 * FREGBYTES(sp)
- FLOAD f17, 17 * FREGBYTES(sp)
- FLOAD f18, 18 * FREGBYTES(sp)
- FLOAD f19, 19 * FREGBYTES(sp)
- FLOAD f20, 20 * FREGBYTES(sp)
- FLOAD f21, 21 * FREGBYTES(sp)
- FLOAD f22, 22 * FREGBYTES(sp)
- FLOAD f23, 23 * FREGBYTES(sp)
- FLOAD f24, 24 * FREGBYTES(sp)
- FLOAD f25, 25 * FREGBYTES(sp)
- FLOAD f26, 26 * FREGBYTES(sp)
- FLOAD f27, 27 * FREGBYTES(sp)
- FLOAD f28, 28 * FREGBYTES(sp)
- FLOAD f29, 29 * FREGBYTES(sp)
- FLOAD f30, 30 * FREGBYTES(sp)
- FLOAD f31, 31 * FREGBYTES(sp)
+/**
+ * @param a0 pointer to frame bottom
+ */
+.global rt_hw_vector_ctx_restore
+rt_hw_vector_ctx_restore:
+ RESTORE_VECTOR a0
+ ret
- addi sp, sp, 32 * FREGBYTES
-#endif
+.global rt_hw_disable_vector
+rt_hw_disable_vector:
+ li t0, SSTATUS_VS
+ csrc sstatus, t0
+ ret
- XRET
+.global rt_hw_enable_vector
+rt_hw_enable_vector:
+ li t0, SSTATUS_VS
+ csrs sstatus, t0
+ ret
+#endif /* ENABLE_VECTOR */
diff --git a/libcpu/risc-v/virt64/cpuport.c b/libcpu/risc-v/virt64/cpuport.c
index 26360bd18a..8325259bce 100644
--- a/libcpu/risc-v/virt64/cpuport.c
+++ b/libcpu/risc-v/virt64/cpuport.c
@@ -9,33 +9,60 @@
* 2021-02-11 lizhirui add gp support
*/
-#include <stddef.h>
#include <rthw.h>
#include <rtthread.h>
#include "cpuport.h"
#include "stack.h"
+#include "sbi.h"
+
+#include <lwp_arch.h>
+
+#define K_SSTATUS_DEFAULT (SSTATUS_SPP | SSTATUS_SPIE | SSTATUS_SUM | SSTATUS_FS)
/**
* @brief from thread used interrupt context switch
*
*/
-volatile rt_ubase_t rt_interrupt_from_thread = 0;
+volatile rt_ubase_t rt_interrupt_from_thread = 0;
/**
* @brief to thread used interrupt context switch
*
*/
-volatile rt_ubase_t rt_interrupt_to_thread = 0;
+volatile rt_ubase_t rt_interrupt_to_thread = 0;
/**
* @brief flag to indicate context switch in interrupt or not
*
*/
volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
+void *_rt_hw_stack_init(rt_ubase_t *sp, rt_ubase_t ra, rt_ubase_t sstatus)
+{
+ (*--sp) = 0; /* tp */
+ (*--sp) = ra; /* ra */
+ (*--sp) = 0; /* s0(fp) */
+ (*--sp) = 0; /* s1 */
+ (*--sp) = 0; /* s2 */
+ (*--sp) = 0; /* s3 */
+ (*--sp) = 0; /* s4 */
+ (*--sp) = 0; /* s5 */
+ (*--sp) = 0; /* s6 */
+ (*--sp) = 0; /* s7 */
+ (*--sp) = 0; /* s8 */
+ (*--sp) = 0; /* s9 */
+ (*--sp) = 0; /* s10 */
+ (*--sp) = 0; /* s11 */
+ (*--sp) = sstatus; /* sstatus */
+
+ return (void *)sp;
+}
/**
- * This function will initialize thread stack
+ * This function will initialize thread stack, we assuming
+ * when scheduler restore this new thread, context will restore
+ * an entry to user first application
*
+ * s0-s11, ra, sstatus, a0
* @param tentry the entry of thread
* @param parameter the parameter of entry
* @param stack_addr the beginning stack address
@@ -43,40 +70,22 @@ volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
*
* @return stack address
*/
-rt_uint8_t *rt_hw_stack_init(void *tentry,
- void *parameter,
+rt_uint8_t *rt_hw_stack_init(void *tentry,
+ void *parameter,
rt_uint8_t *stack_addr,
- void *texit)
+ void *texit)
{
- struct rt_hw_stack_frame *frame;
- rt_uint8_t *stk;
- int i;
- extern int __global_pointer$;
-
- stk = stack_addr + sizeof(rt_ubase_t);
- stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES);
- stk -= sizeof(struct rt_hw_stack_frame);
+ rt_ubase_t *sp = (rt_ubase_t *)stack_addr;
+ // we use a strict alignment requirement for Q extension
+ sp = (rt_ubase_t *)RT_ALIGN_DOWN((rt_ubase_t)sp, 16);
- frame = (struct rt_hw_stack_frame *)stk;
+ (*--sp) = (rt_ubase_t)tentry;
+ (*--sp) = (rt_ubase_t)parameter;
+ (*--sp) = (rt_ubase_t)texit;
- for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
- {
- ((rt_ubase_t *)frame)[i] = 0xdeadbeef;
- }
-
- frame->ra = (rt_ubase_t)texit;
- frame->gp = (rt_ubase_t)&__global_pointer$;
- frame->a0 = (rt_ubase_t)parameter;
- frame->epc = (rt_ubase_t)tentry;
- frame->user_sp_exc_stack = (rt_ubase_t)(((rt_ubase_t)stk) + sizeof(struct rt_hw_stack_frame));
-
-#ifndef RISCV_S_MODE
- frame->xstatus = 0x00007880;
-#else
- frame->xstatus = 0x00040120;
-#endif
-
- return stk;
+ /* compatible to RESTORE_CONTEXT */
+ extern void _rt_thread_entry(void);
+ return (rt_uint8_t *)_rt_hw_stack_init(sp, (rt_ubase_t)_rt_thread_entry, K_SSTATUS_DEFAULT);
}
/*
@@ -87,7 +96,7 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
* #endif
*/
#ifndef RT_USING_SMP
-void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
+void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
{
if (rt_thread_switch_interrupt_flag == 0)
rt_interrupt_from_thread = from;
@@ -95,29 +104,25 @@ void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
rt_interrupt_to_thread = to;
rt_thread_switch_interrupt_flag = 1;
- return ;
+ return;
}
#endif /* end of RT_USING_SMP */
/** shutdown CPU */
void rt_hw_cpu_shutdown()
{
- rt_base_t level;
+ rt_uint32_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
- while (level)
- {
- RT_ASSERT(0);
- }
-}
-rt_thread_t rt_thread_sp_to_thread(void *spmember_addr)
-{
- return (rt_thread_t)(((rt_ubase_t)spmember_addr) - (offsetof(struct rt_thread,sp)));
+ sbi_shutdown();
+
+ while (1)
+ ;
}
-void *get_thread_kernel_stack_top(rt_thread_t thread)
+void rt_hw_set_process_id(int pid)
{
- return (void *)(((rt_size_t)thread -> stack_addr) + ((rt_size_t)thread -> stack_size));
+ // TODO
}
diff --git a/libcpu/risc-v/virt64/cpuport.h b/libcpu/risc-v/virt64/cpuport.h
index fa0776b509..3dde250bc3 100644
--- a/libcpu/risc-v/virt64/cpuport.h
+++ b/libcpu/risc-v/virt64/cpuport.h
@@ -20,36 +20,64 @@
#define REGBYTES 8
#else
// error here, not portable
+#error "Not supported XLEN"
#endif
-#ifdef RISCV_U_MODE
-#define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL
+/* 33 general register */
+#define CTX_GENERAL_REG_NR 33
+
+#ifdef ENABLE_FPU
+/* 32 fpu register */
+#define CTX_FPU_REG_NR 32
+#else
+#define CTX_FPU_REG_NR 0
#endif
-#ifdef RISCV_S_MODE
-//csr in s-mode
-// M/U/S Interrupt Registers
-#define SRC_XIE sie
-#define SRC_XIP sip
-#define SRC_XTVEC stvec
-#define SRC_XSTATUS sstatus
-#define SRC_XSCRATCH sscratch
-#define SRC_XEPC sepc
-#define SRC_XCAUSE scause
-#define SRC_XTVAL stval
-#define XRET sret
+#ifdef ENABLE_VECTOR
+
+#if defined(ARCH_VECTOR_VLEN_128)
+#define CTX_VECTOR_REGS 64
+#elif defined(ARCH_VECTOR_VLEN_256)
+#define CTX_VECTOR_REGS 128
+#endif
+
+#define CTX_VECTOR_REG_NR (CTX_VECTOR_REGS + 4)
#else
-//csr in m-mode
-// M/U/S Interrupt Registers
-#define SRC_XIE mie
-#define SRC_XIP mip
-#define SRC_XTVEC mtvec
-#define SRC_XSTATUS mstatus
-#define SRC_XSCRATCH mscratch
-#define SRC_XEPC mepc
-#define SRC_XCAUSE mcause
-#define SRC_XTVAL mtval
-#define XRET mret
+#define CTX_VECTOR_REG_NR 0
+#endif
+
+/* all context registers */
+#define CTX_REG_NR (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR + CTX_VECTOR_REG_NR)
+
+#ifdef RT_USING_SMP
+typedef union {
+ unsigned long slock;
+ struct __arch_tickets {
+ unsigned short owner;
+ unsigned short next;
+ } tickets;
+} rt_hw_spinlock_t;
#endif
+#ifndef __ASSEMBLY__
+rt_inline void rt_hw_dsb()
+{
+ asm volatile("fence":::"memory");
+}
+
+rt_inline void rt_hw_dmb()
+{
+ asm volatile("fence":::"memory");
+}
+
+rt_inline void rt_hw_isb()
+{
+ asm volatile(".long 0x0000100F":::"memory");
+}
+
+#endif
+
+#endif
+#ifdef RISCV_U_MODE
+#define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL
#endif
diff --git a/libcpu/risc-v/virt64/cpuport_gcc.S b/libcpu/risc-v/virt64/cpuport_gcc.S
new file mode 100644
index 0000000000..cb636c9a4f
--- /dev/null
+++ b/libcpu/risc-v/virt64/cpuport_gcc.S
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-19 RT-Thread the first version
+ */
+
+#include "cpuport.h"
+#include "stackframe.h"
+
+.global _rt_thread_entry
+_rt_thread_entry:
+ LOAD ra, (sp) /* texit */
+ addi sp, sp, 8
+ LOAD a0, (sp) /* parameter */
+ addi sp, sp, 8
+ LOAD t0, (sp) /* tentry */
+ addi sp, sp, 8
+ jr t0
diff --git a/libcpu/risc-v/virt64/encoding.h b/libcpu/risc-v/virt64/encoding.h
new file mode 100644
index 0000000000..2616b86461
--- /dev/null
+++ b/libcpu/risc-v/virt64/encoding.h
@@ -0,0 +1,1344 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+// See LICENSE for license details.
+
+#ifndef RISCV_CSR_ENCODING_H
+#define RISCV_CSR_ENCODING_H
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_VS 0x00000600
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_PUM 0x00040000
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_VM 0x1F000000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000 /* Floating-point Status */
+#define SSTATUS_FS_INITIAL 0x00002000
+#define SSTATUS_FS_CLEAN 0x00004000
+#define SSTATUS_FS_DIRTY 0x00006000
+#define SSTATUS_VS 0x00000600 /* Vector Status */
+#define SSTATUS_VS_INITIAL 0x00000200
+#define SSTATUS_VS_CLEAN 0x00000400
+#define SSTATUS_VS_DIRTY 0x00000600
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_SUM 0x00040000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define DCSR_XDEBUGVER (3U<<30)
+#define DCSR_NDRESET (1<<29)
+#define DCSR_FULLRESET (1<<28)
+#define DCSR_EBREAKM (1<<15)
+#define DCSR_EBREAKH (1<<14)
+#define DCSR_EBREAKS (1<<13)
+#define DCSR_EBREAKU (1<<12)
+#define DCSR_STOPCYCLE (1<<10)
+#define DCSR_STOPTIME (1<<9)
+#define DCSR_CAUSE (7<<6)
+#define DCSR_DEBUGINT (1<<5)
+#define DCSR_HALT (1<<3)
+#define DCSR_STEP (1<<2)
+#define DCSR_PRV (3<<0)
+
+#define DCSR_CAUSE_NONE 0
+#define DCSR_CAUSE_SWBP 1
+#define DCSR_CAUSE_HWBP 2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_HALT 5
+
+#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT (1<<19)
+#define MCONTROL_TIMING (1<<18)
+#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_CHAIN (1<<11)
+#define MCONTROL_MATCH (0xf<<7)
+#define MCONTROL_M (1<<6)
+#define MCONTROL_H (1<<5)
+#define MCONTROL_S (1<<4)
+#define MCONTROL_U (1<<3)
+#define MCONTROL_EXECUTE (1<<2)
+#define MCONTROL_STORE (1<<1)
+#define MCONTROL_LOAD (1<<0)
+
+#define MCONTROL_TYPE_NONE 0
+#define MCONTROL_TYPE_MATCH 2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
+#define MCONTROL_ACTION_DEBUG_MODE 1
+#define MCONTROL_ACTION_TRACE_START 2
+#define MCONTROL_ACTION_TRACE_STOP 3
+#define MCONTROL_ACTION_TRACE_EMIT 4
+
+#define MCONTROL_MATCH_EQUAL 0
+#define MCONTROL_MATCH_NAPOT 1
+#define MCONTROL_MATCH_GE 2
+#define MCONTROL_MATCH_LT 3
+#define MCONTROL_MATCH_MASK_LOW 4
+#define MCONTROL_MATCH_MASK_HIGH 5
+
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_HSIP (1 << IRQ_H_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_HTIP (1 << IRQ_H_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_HEIP (1 << IRQ_H_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP /* software interrupt */
+#define SIP_STIP MIP_STIP /* timer interrupt */
+#define SIP_SEIP MIP_SEIP /* ext interrupt */
+
+#define SIE_SSIE (1 << IRQ_S_SOFT)
+#define SIE_STIE (1 << IRQ_S_TIMER)
+#define SIE_SEIE (1 << IRQ_S_EXT)
+
+#define RISCV_XLEN 64
+
+#define SCAUSE_INTERRUPT (1UL << (RISCV_XLEN - 1))
+
+#define SCAUSE_S_SOFTWARE_INTR 1
+#define SCAUSE_S_TIMER_INTR 5
+#define SCAUSE_S_EXTERNAL_INTR 9
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define VM_MBARE 0
+#define VM_MBB 1
+#define VM_MBBID 2
+#define VM_SV32 8
+#define VM_SV39 9
+#define VM_SV48 10
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define DEFAULT_RSTVEC 0x00001000
+#define DEFAULT_NMIVEC 0x00001004
+#define DEFAULT_MTVEC 0x00001010
+#define CONFIG_STRING_ADDR 0x0000100C
+#define EXT_IO_BASE 0x40000000
+#define DRAM_BASE 0x80000000
+
+// page table entry (PTE) fields
+#define PTE_V 0x001 // Valid
+#define PTE_R 0x002 // Read
+#define PTE_W 0x004 // Write
+#define PTE_X 0x008 // Execute
+#define PTE_U 0x010 // User
+#define PTE_G 0x020 // Global
+#define PTE_A 0x040 // Accessed
+#define PTE_D 0x080 // Dirty
+#define PTE_SOFT 0x300 // Reserved for Software
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#ifdef __riscv
+
+#ifdef __riscv64
+# define MSTATUS_SD MSTATUS64_SD
+# define SSTATUS_SD SSTATUS64_SD
+# define RISCV_PGLEVEL_BITS 9
+#else
+# define MSTATUS_SD MSTATUS32_SD
+# define SSTATUS_SD SSTATUS32_SD
+# define RISCV_PGLEVEL_BITS 10
+#endif /* end of __riscv64 */
+
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
+
+#ifndef __ASSEMBLY__
+
+#ifdef __GNUC__
+
+#define read_csr(reg) ({ unsigned long __tmp; \
+ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
+ __tmp; })
+
+#define write_csr(reg, val) ({ \
+ if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
+ asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
+ else \
+ asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
+
+#define swap_csr(reg, val) ({ unsigned long __tmp; \
+ if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \
+ else \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
+ __tmp; })
+
+#define set_csr(reg, bit) ({ unsigned long __tmp; \
+ if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+ else \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+ __tmp; })
+
+#define clear_csr(reg, bit) ({ unsigned long __tmp; \
+ if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
+ else \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
+ __tmp; })
+
+#define rdtime() read_csr(time)
+#define rdcycle() read_csr(cycle)
+#define rdinstret() read_csr(instret)
+
+#endif /* end of __GNUC__ */
+
+#endif /* end of __ASSEMBLY__ */
+
+#endif /* end of __riscv */
+
+#endif /* end of RISCV_CSR_ENCODING_H */
+
+/* Automatically generated by parse-opcodes */
+#ifndef RISCV_ENCODING_H
+#define RISCV_ENCODING_H
+#define MATCH_BEQ 0x63
+#define MASK_BEQ 0x707f
+#define MATCH_BNE 0x1063
+#define MASK_BNE 0x707f
+#define MATCH_BLT 0x4063
+#define MASK_BLT 0x707f
+#define MATCH_BGE 0x5063
+#define MASK_BGE 0x707f
+#define MATCH_BLTU 0x6063
+#define MASK_BLTU 0x707f
+#define MATCH_BGEU 0x7063
+#define MASK_BGEU 0x707f
+#define MATCH_JALR 0x67
+#define MASK_JALR 0x707f
+#define MATCH_JAL 0x6f
+#define MASK_JAL 0x7f
+#define MATCH_LUI 0x37
+#define MASK_LUI 0x7f
+#define MATCH_AUIPC 0x17
+#define MASK_AUIPC 0x7f
+#define MATCH_ADDI 0x13
+#define MASK_ADDI 0x707f
+#define MATCH_SLLI 0x1013
+#define MASK_SLLI 0xfc00707f
+#define MATCH_SLTI 0x2013
+#define MASK_SLTI 0x707f
+#define MATCH_SLTIU 0x3013
+#define MASK_SLTIU 0x707f
+#define MATCH_XORI 0x4013
+#define MASK_XORI 0x707f
+#define MATCH_SRLI 0x5013
+#define MASK_SRLI 0xfc00707f
+#define MATCH_SRAI 0x40005013
+#define MASK_SRAI 0xfc00707f
+#define MATCH_ORI 0x6013
+#define MASK_ORI 0x707f
+#define MATCH_ANDI 0x7013
+#define MASK_ANDI 0x707f
+#define MATCH_ADD 0x33
+#define MASK_ADD 0xfe00707f
+#define MATCH_SUB 0x40000033
+#define MASK_SUB 0xfe00707f
+#define MATCH_SLL 0x1033
+#define MASK_SLL 0xfe00707f
+#define MATCH_SLT 0x2033
+#define MASK_SLT 0xfe00707f
+#define MATCH_SLTU 0x3033
+#define MASK_SLTU 0xfe00707f
+#define MATCH_XOR 0x4033
+#define MASK_XOR 0xfe00707f
+#define MATCH_SRL 0x5033
+#define MASK_SRL 0xfe00707f
+#define MATCH_SRA 0x40005033
+#define MASK_SRA 0xfe00707f
+#define MATCH_OR 0x6033
+#define MASK_OR 0xfe00707f
+#define MATCH_AND 0x7033
+#define MASK_AND 0xfe00707f
+#define MATCH_ADDIW 0x1b
+#define MASK_ADDIW 0x707f
+#define MATCH_SLLIW 0x101b
+#define MASK_SLLIW 0xfe00707f
+#define MATCH_SRLIW 0x501b
+#define MASK_SRLIW 0xfe00707f
+#define MATCH_SRAIW 0x4000501b
+#define MASK_SRAIW 0xfe00707f
+#define MATCH_ADDW 0x3b
+#define MASK_ADDW 0xfe00707f
+#define MATCH_SUBW 0x4000003b
+#define MASK_SUBW 0xfe00707f
+#define MATCH_SLLW 0x103b
+#define MASK_SLLW 0xfe00707f
+#define MATCH_SRLW 0x503b
+#define MASK_SRLW 0xfe00707f
+#define MATCH_SRAW 0x4000503b
+#define MASK_SRAW 0xfe00707f
+#define MATCH_LB 0x3
+#define MASK_LB 0x707f
+#define MATCH_LH 0x1003
+#define MASK_LH 0x707f
+#define MATCH_LW 0x2003
+#define MASK_LW 0x707f
+#define MATCH_LD 0x3003
+#define MASK_LD 0x707f
+#define MATCH_LBU 0x4003
+#define MASK_LBU 0x707f
+#define MATCH_LHU 0x5003
+#define MASK_LHU 0x707f
+#define MATCH_LWU 0x6003
+#define MASK_LWU 0x707f
+#define MATCH_SB 0x23
+#define MASK_SB 0x707f
+#define MATCH_SH 0x1023
+#define MASK_SH 0x707f
+#define MATCH_SW 0x2023
+#define MASK_SW 0x707f
+#define MATCH_SD 0x3023
+#define MASK_SD 0x707f
+#define MATCH_FENCE 0xf
+#define MASK_FENCE 0x707f
+#define MATCH_FENCE_I 0x100f
+#define MASK_FENCE_I 0x707f
+#define MATCH_MUL 0x2000033
+#define MASK_MUL 0xfe00707f
+#define MATCH_MULH 0x2001033
+#define MASK_MULH 0xfe00707f
+#define MATCH_MULHSU 0x2002033
+#define MASK_MULHSU 0xfe00707f
+#define MATCH_MULHU 0x2003033
+#define MASK_MULHU 0xfe00707f
+#define MATCH_DIV 0x2004033
+#define MASK_DIV 0xfe00707f
+#define MATCH_DIVU 0x2005033
+#define MASK_DIVU 0xfe00707f
+#define MATCH_REM 0x2006033
+#define MASK_REM 0xfe00707f
+#define MATCH_REMU 0x2007033
+#define MASK_REMU 0xfe00707f
+#define MATCH_MULW 0x200003b
+#define MASK_MULW 0xfe00707f
+#define MATCH_DIVW 0x200403b
+#define MASK_DIVW 0xfe00707f
+#define MATCH_DIVUW 0x200503b
+#define MASK_DIVUW 0xfe00707f
+#define MATCH_REMW 0x200603b
+#define MASK_REMW 0xfe00707f
+#define MATCH_REMUW 0x200703b
+#define MASK_REMUW 0xfe00707f
+#define MATCH_AMOADD_W 0x202f
+#define MASK_AMOADD_W 0xf800707f
+#define MATCH_AMOXOR_W 0x2000202f
+#define MASK_AMOXOR_W 0xf800707f
+#define MATCH_AMOOR_W 0x4000202f
+#define MASK_AMOOR_W 0xf800707f
+#define MATCH_AMOAND_W 0x6000202f
+#define MASK_AMOAND_W 0xf800707f
+#define MATCH_AMOMIN_W 0x8000202f
+#define MASK_AMOMIN_W 0xf800707f
+#define MATCH_AMOMAX_W 0xa000202f
+#define MASK_AMOMAX_W 0xf800707f
+#define MATCH_AMOMINU_W 0xc000202f
+#define MASK_AMOMINU_W 0xf800707f
+#define MATCH_AMOMAXU_W 0xe000202f
+#define MASK_AMOMAXU_W 0xf800707f
+#define MATCH_AMOSWAP_W 0x800202f
+#define MASK_AMOSWAP_W 0xf800707f
+#define MATCH_LR_W 0x1000202f
+#define MASK_LR_W 0xf9f0707f
+#define MATCH_SC_W 0x1800202f
+#define MASK_SC_W 0xf800707f
+#define MATCH_AMOADD_D 0x302f
+#define MASK_AMOADD_D 0xf800707f
+#define MATCH_AMOXOR_D 0x2000302f
+#define MASK_AMOXOR_D 0xf800707f
+#define MATCH_AMOOR_D 0x4000302f
+#define MASK_AMOOR_D 0xf800707f
+#define MATCH_AMOAND_D 0x6000302f
+#define MASK_AMOAND_D 0xf800707f
+#define MATCH_AMOMIN_D 0x8000302f
+#define MASK_AMOMIN_D 0xf800707f
+#define MATCH_AMOMAX_D 0xa000302f
+#define MASK_AMOMAX_D 0xf800707f
+#define MATCH_AMOMINU_D 0xc000302f
+#define MASK_AMOMINU_D 0xf800707f
+#define MATCH_AMOMAXU_D 0xe000302f
+#define MASK_AMOMAXU_D 0xf800707f
+#define MATCH_AMOSWAP_D 0x800302f
+#define MASK_AMOSWAP_D 0xf800707f
+#define MATCH_LR_D 0x1000302f
+#define MASK_LR_D 0xf9f0707f
+#define MATCH_SC_D 0x1800302f
+#define MASK_SC_D 0xf800707f
+#define MATCH_ECALL 0x73
+#define MASK_ECALL 0xffffffff
+#define MATCH_EBREAK 0x100073
+#define MASK_EBREAK 0xffffffff
+#define MATCH_URET 0x200073
+#define MASK_URET 0xffffffff
+#define MATCH_SRET 0x10200073
+#define MASK_SRET 0xffffffff
+#define MATCH_HRET 0x20200073
+#define MASK_HRET 0xffffffff
+#define MATCH_MRET 0x30200073
+#define MASK_MRET 0xffffffff
+#define MATCH_DRET 0x7b200073
+#define MASK_DRET 0xffffffff
+#define MATCH_SFENCE_VM 0x10400073
+#define MASK_SFENCE_VM 0xfff07fff
+#define MATCH_WFI 0x10500073
+#define MASK_WFI 0xffffffff
+#define MATCH_CSRRW 0x1073
+#define MASK_CSRRW 0x707f
+#define MATCH_CSRRS 0x2073
+#define MASK_CSRRS 0x707f
+#define MATCH_CSRRC 0x3073
+#define MASK_CSRRC 0x707f
+#define MATCH_CSRRWI 0x5073
+#define MASK_CSRRWI 0x707f
+#define MATCH_CSRRSI 0x6073
+#define MASK_CSRRSI 0x707f
+#define MATCH_CSRRCI 0x7073
+#define MASK_CSRRCI 0x707f
+#define MATCH_FADD_S 0x53
+#define MASK_FADD_S 0xfe00007f
+#define MATCH_FSUB_S 0x8000053
+#define MASK_FSUB_S 0xfe00007f
+#define MATCH_FMUL_S 0x10000053
+#define MASK_FMUL_S 0xfe00007f
+#define MATCH_FDIV_S 0x18000053
+#define MASK_FDIV_S 0xfe00007f
+#define MATCH_FSGNJ_S 0x20000053
+#define MASK_FSGNJ_S 0xfe00707f
+#define MATCH_FSGNJN_S 0x20001053
+#define MASK_FSGNJN_S 0xfe00707f
+#define MATCH_FSGNJX_S 0x20002053
+#define MASK_FSGNJX_S 0xfe00707f
+#define MATCH_FMIN_S 0x28000053
+#define MASK_FMIN_S 0xfe00707f
+#define MATCH_FMAX_S 0x28001053
+#define MASK_FMAX_S 0xfe00707f
+#define MATCH_FSQRT_S 0x58000053
+#define MASK_FSQRT_S 0xfff0007f
+#define MATCH_FADD_D 0x2000053
+#define MASK_FADD_D 0xfe00007f
+#define MATCH_FSUB_D 0xa000053
+#define MASK_FSUB_D 0xfe00007f
+#define MATCH_FMUL_D 0x12000053
+#define MASK_FMUL_D 0xfe00007f
+#define MATCH_FDIV_D 0x1a000053
+#define MASK_FDIV_D 0xfe00007f
+#define MATCH_FSGNJ_D 0x22000053
+#define MASK_FSGNJ_D 0xfe00707f
+#define MATCH_FSGNJN_D 0x22001053
+#define MASK_FSGNJN_D 0xfe00707f
+#define MATCH_FSGNJX_D 0x22002053
+#define MASK_FSGNJX_D 0xfe00707f
+#define MATCH_FMIN_D 0x2a000053
+#define MASK_FMIN_D 0xfe00707f
+#define MATCH_FMAX_D 0x2a001053
+#define MASK_FMAX_D 0xfe00707f
+#define MATCH_FCVT_S_D 0x40100053
+#define MASK_FCVT_S_D 0xfff0007f
+#define MATCH_FCVT_D_S 0x42000053
+#define MASK_FCVT_D_S 0xfff0007f
+#define MATCH_FSQRT_D 0x5a000053
+#define MASK_FSQRT_D 0xfff0007f
+#define MATCH_FLE_S 0xa0000053
+#define MASK_FLE_S 0xfe00707f
+#define MATCH_FLT_S 0xa0001053
+#define MASK_FLT_S 0xfe00707f
+#define MATCH_FEQ_S 0xa0002053
+#define MASK_FEQ_S 0xfe00707f
+#define MATCH_FLE_D 0xa2000053
+#define MASK_FLE_D 0xfe00707f
+#define MATCH_FLT_D 0xa2001053
+#define MASK_FLT_D 0xfe00707f
+#define MATCH_FEQ_D 0xa2002053
+#define MASK_FEQ_D 0xfe00707f
+#define MATCH_FCVT_W_S 0xc0000053
+#define MASK_FCVT_W_S 0xfff0007f
+#define MATCH_FCVT_WU_S 0xc0100053
+#define MASK_FCVT_WU_S 0xfff0007f
+#define MATCH_FCVT_L_S 0xc0200053
+#define MASK_FCVT_L_S 0xfff0007f
+#define MATCH_FCVT_LU_S 0xc0300053
+#define MASK_FCVT_LU_S 0xfff0007f
+#define MATCH_FMV_X_S 0xe0000053
+#define MASK_FMV_X_S 0xfff0707f
+#define MATCH_FCLASS_S 0xe0001053
+#define MASK_FCLASS_S 0xfff0707f
+#define MATCH_FCVT_W_D 0xc2000053
+#define MASK_FCVT_W_D 0xfff0007f
+#define MATCH_FCVT_WU_D 0xc2100053
+#define MASK_FCVT_WU_D 0xfff0007f
+#define MATCH_FCVT_L_D 0xc2200053
+#define MASK_FCVT_L_D 0xfff0007f
+#define MATCH_FCVT_LU_D 0xc2300053
+#define MASK_FCVT_LU_D 0xfff0007f
+#define MATCH_FMV_X_D 0xe2000053
+#define MASK_FMV_X_D 0xfff0707f
+#define MATCH_FCLASS_D 0xe2001053
+#define MASK_FCLASS_D 0xfff0707f
+#define MATCH_FCVT_S_W 0xd0000053
+#define MASK_FCVT_S_W 0xfff0007f
+#define MATCH_FCVT_S_WU 0xd0100053
+#define MASK_FCVT_S_WU 0xfff0007f
+#define MATCH_FCVT_S_L 0xd0200053
+#define MASK_FCVT_S_L 0xfff0007f
+#define MATCH_FCVT_S_LU 0xd0300053
+#define MASK_FCVT_S_LU 0xfff0007f
+#define MATCH_FMV_S_X 0xf0000053
+#define MASK_FMV_S_X 0xfff0707f
+#define MATCH_FCVT_D_W 0xd2000053
+#define MASK_FCVT_D_W 0xfff0007f
+#define MATCH_FCVT_D_WU 0xd2100053
+#define MASK_FCVT_D_WU 0xfff0007f
+#define MATCH_FCVT_D_L 0xd2200053
+#define MASK_FCVT_D_L 0xfff0007f
+#define MATCH_FCVT_D_LU 0xd2300053
+#define MASK_FCVT_D_LU 0xfff0007f
+#define MATCH_FMV_D_X 0xf2000053
+#define MASK_FMV_D_X 0xfff0707f
+#define MATCH_FLW 0x2007
+#define MASK_FLW 0x707f
+#define MATCH_FLD 0x3007
+#define MASK_FLD 0x707f
+#define MATCH_FSW 0x2027
+#define MASK_FSW 0x707f
+#define MATCH_FSD 0x3027
+#define MASK_FSD 0x707f
+#define MATCH_FMADD_S 0x43
+#define MASK_FMADD_S 0x600007f
+#define MATCH_FMSUB_S 0x47
+#define MASK_FMSUB_S 0x600007f
+#define MATCH_FNMSUB_S 0x4b
+#define MASK_FNMSUB_S 0x600007f
+#define MATCH_FNMADD_S 0x4f
+#define MASK_FNMADD_S 0x600007f
+#define MATCH_FMADD_D 0x2000043
+#define MASK_FMADD_D 0x600007f
+#define MATCH_FMSUB_D 0x2000047
+#define MASK_FMSUB_D 0x600007f
+#define MATCH_FNMSUB_D 0x200004b
+#define MASK_FNMSUB_D 0x600007f
+#define MATCH_FNMADD_D 0x200004f
+#define MASK_FNMADD_D 0x600007f
+#define MATCH_C_NOP 0x1
+#define MASK_C_NOP 0xffff
+#define MATCH_C_ADDI16SP 0x6101
+#define MASK_C_ADDI16SP 0xef83
+#define MATCH_C_JR 0x8002
+#define MASK_C_JR 0xf07f
+#define MATCH_C_JALR 0x9002
+#define MASK_C_JALR 0xf07f
+#define MATCH_C_EBREAK 0x9002
+#define MASK_C_EBREAK 0xffff
+#define MATCH_C_LD 0x6000
+#define MASK_C_LD 0xe003
+#define MATCH_C_SD 0xe000
+#define MASK_C_SD 0xe003
+#define MATCH_C_ADDIW 0x2001
+#define MASK_C_ADDIW 0xe003
+#define MATCH_C_LDSP 0x6002
+#define MASK_C_LDSP 0xe003
+#define MATCH_C_SDSP 0xe002
+#define MASK_C_SDSP 0xe003
+#define MATCH_C_ADDI4SPN 0x0
+#define MASK_C_ADDI4SPN 0xe003
+#define MATCH_C_FLD 0x2000
+#define MASK_C_FLD 0xe003
+#define MATCH_C_LW 0x4000
+#define MASK_C_LW 0xe003
+#define MATCH_C_FLW 0x6000
+#define MASK_C_FLW 0xe003
+#define MATCH_C_FSD 0xa000
+#define MASK_C_FSD 0xe003
+#define MATCH_C_SW 0xc000
+#define MASK_C_SW 0xe003
+#define MATCH_C_FSW 0xe000
+#define MASK_C_FSW 0xe003
+#define MATCH_C_ADDI 0x1
+#define MASK_C_ADDI 0xe003
+#define MATCH_C_JAL 0x2001
+#define MASK_C_JAL 0xe003
+#define MATCH_C_LI 0x4001
+#define MASK_C_LI 0xe003
+#define MATCH_C_LUI 0x6001
+#define MASK_C_LUI 0xe003
+#define MATCH_C_SRLI 0x8001
+#define MASK_C_SRLI 0xec03
+#define MATCH_C_SRAI 0x8401
+#define MASK_C_SRAI 0xec03
+#define MATCH_C_ANDI 0x8801
+#define MASK_C_ANDI 0xec03
+#define MATCH_C_SUB 0x8c01
+#define MASK_C_SUB 0xfc63
+#define MATCH_C_XOR 0x8c21
+#define MASK_C_XOR 0xfc63
+#define MATCH_C_OR 0x8c41
+#define MASK_C_OR 0xfc63
+#define MATCH_C_AND 0x8c61
+#define MASK_C_AND 0xfc63
+#define MATCH_C_SUBW 0x9c01
+#define MASK_C_SUBW 0xfc63
+#define MATCH_C_ADDW 0x9c21
+#define MASK_C_ADDW 0xfc63
+#define MATCH_C_J 0xa001
+#define MASK_C_J 0xe003
+#define MATCH_C_BEQZ 0xc001
+#define MASK_C_BEQZ 0xe003
+#define MATCH_C_BNEZ 0xe001
+#define MASK_C_BNEZ 0xe003
+#define MATCH_C_SLLI 0x2
+#define MASK_C_SLLI 0xe003
+#define MATCH_C_FLDSP 0x2002
+#define MASK_C_FLDSP 0xe003
+#define MATCH_C_LWSP 0x4002
+#define MASK_C_LWSP 0xe003
+#define MATCH_C_FLWSP 0x6002
+#define MASK_C_FLWSP 0xe003
+#define MATCH_C_MV 0x8002
+#define MASK_C_MV 0xf003
+#define MATCH_C_ADD 0x9002
+#define MASK_C_ADD 0xf003
+#define MATCH_C_FSDSP 0xa002
+#define MASK_C_FSDSP 0xe003
+#define MATCH_C_SWSP 0xc002
+#define MASK_C_SWSP 0xe003
+#define MATCH_C_FSWSP 0xe002
+#define MASK_C_FSWSP 0xe003
+#define MATCH_CUSTOM0 0xb
+#define MASK_CUSTOM0 0x707f
+#define MATCH_CUSTOM0_RS1 0x200b
+#define MASK_CUSTOM0_RS1 0x707f
+#define MATCH_CUSTOM0_RS1_RS2 0x300b
+#define MASK_CUSTOM0_RS1_RS2 0x707f
+#define MATCH_CUSTOM0_RD 0x400b
+#define MASK_CUSTOM0_RD 0x707f
+#define MATCH_CUSTOM0_RD_RS1 0x600b
+#define MASK_CUSTOM0_RD_RS1 0x707f
+#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b
+#define MASK_CUSTOM0_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM1 0x2b
+#define MASK_CUSTOM1 0x707f
+#define MATCH_CUSTOM1_RS1 0x202b
+#define MASK_CUSTOM1_RS1 0x707f
+#define MATCH_CUSTOM1_RS1_RS2 0x302b
+#define MASK_CUSTOM1_RS1_RS2 0x707f
+#define MATCH_CUSTOM1_RD 0x402b
+#define MASK_CUSTOM1_RD 0x707f
+#define MATCH_CUSTOM1_RD_RS1 0x602b
+#define MASK_CUSTOM1_RD_RS1 0x707f
+#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b
+#define MASK_CUSTOM1_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM2 0x5b
+#define MASK_CUSTOM2 0x707f
+#define MATCH_CUSTOM2_RS1 0x205b
+#define MASK_CUSTOM2_RS1 0x707f
+#define MATCH_CUSTOM2_RS1_RS2 0x305b
+#define MASK_CUSTOM2_RS1_RS2 0x707f
+#define MATCH_CUSTOM2_RD 0x405b
+#define MASK_CUSTOM2_RD 0x707f
+#define MATCH_CUSTOM2_RD_RS1 0x605b
+#define MASK_CUSTOM2_RD_RS1 0x707f
+#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b
+#define MASK_CUSTOM2_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM3 0x7b
+#define MASK_CUSTOM3 0x707f
+#define MATCH_CUSTOM3_RS1 0x207b
+#define MASK_CUSTOM3_RS1 0x707f
+#define MATCH_CUSTOM3_RS1_RS2 0x307b
+#define MASK_CUSTOM3_RS1_RS2 0x707f
+#define MATCH_CUSTOM3_RD 0x407b
+#define MASK_CUSTOM3_RD 0x707f
+#define MATCH_CUSTOM3_RD_RS1 0x607b
+#define MASK_CUSTOM3_RD_RS1 0x707f
+#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b
+#define MASK_CUSTOM3_RD_RS1_RS2 0x707f
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#define CSR_CYCLE 0xc00
+#define CSR_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_HPMCOUNTER3 0xc03
+#define CSR_HPMCOUNTER4 0xc04
+#define CSR_HPMCOUNTER5 0xc05
+#define CSR_HPMCOUNTER6 0xc06
+#define CSR_HPMCOUNTER7 0xc07
+#define CSR_HPMCOUNTER8 0xc08
+#define CSR_HPMCOUNTER9 0xc09
+#define CSR_HPMCOUNTER10 0xc0a
+#define CSR_HPMCOUNTER11 0xc0b
+#define CSR_HPMCOUNTER12 0xc0c
+#define CSR_HPMCOUNTER13 0xc0d
+#define CSR_HPMCOUNTER14 0xc0e
+#define CSR_HPMCOUNTER15 0xc0f
+#define CSR_HPMCOUNTER16 0xc10
+#define CSR_HPMCOUNTER17 0xc11
+#define CSR_HPMCOUNTER18 0xc12
+#define CSR_HPMCOUNTER19 0xc13
+#define CSR_HPMCOUNTER20 0xc14
+#define CSR_HPMCOUNTER21 0xc15
+#define CSR_HPMCOUNTER22 0xc16
+#define CSR_HPMCOUNTER23 0xc17
+#define CSR_HPMCOUNTER24 0xc18
+#define CSR_HPMCOUNTER25 0xc19
+#define CSR_HPMCOUNTER26 0xc1a
+#define CSR_HPMCOUNTER27 0xc1b
+#define CSR_HPMCOUNTER28 0xc1c
+#define CSR_HPMCOUNTER29 0xc1d
+#define CSR_HPMCOUNTER30 0xc1e
+#define CSR_HPMCOUNTER31 0xc1f
+#define CSR_SSTATUS 0x100
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_SBADADDR 0x143
+#define CSR_SIP 0x144
+#define CSR_SPTBR 0x180
+#define CSR_MSTATUS 0x300
+#define CSR_MISA 0x301
+#define CSR_MEDELEG 0x302
+#define CSR_MIDELEG 0x303
+#define CSR_MIE 0x304
+#define CSR_MTVEC 0x305
+#define CSR_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MBADADDR 0x343
+#define CSR_MIP 0x344
+#define CSR_TSELECT 0x7a0
+#define CSR_TDATA1 0x7a1
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA3 0x7a3
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+#define CSR_MCYCLE 0xb00
+#define CSR_MINSTRET 0xb02
+#define CSR_MHPMCOUNTER3 0xb03
+#define CSR_MHPMCOUNTER4 0xb04
+#define CSR_MHPMCOUNTER5 0xb05
+#define CSR_MHPMCOUNTER6 0xb06
+#define CSR_MHPMCOUNTER7 0xb07
+#define CSR_MHPMCOUNTER8 0xb08
+#define CSR_MHPMCOUNTER9 0xb09
+#define CSR_MHPMCOUNTER10 0xb0a
+#define CSR_MHPMCOUNTER11 0xb0b
+#define CSR_MHPMCOUNTER12 0xb0c
+#define CSR_MHPMCOUNTER13 0xb0d
+#define CSR_MHPMCOUNTER14 0xb0e
+#define CSR_MHPMCOUNTER15 0xb0f
+#define CSR_MHPMCOUNTER16 0xb10
+#define CSR_MHPMCOUNTER17 0xb11
+#define CSR_MHPMCOUNTER18 0xb12
+#define CSR_MHPMCOUNTER19 0xb13
+#define CSR_MHPMCOUNTER20 0xb14
+#define CSR_MHPMCOUNTER21 0xb15
+#define CSR_MHPMCOUNTER22 0xb16
+#define CSR_MHPMCOUNTER23 0xb17
+#define CSR_MHPMCOUNTER24 0xb18
+#define CSR_MHPMCOUNTER25 0xb19
+#define CSR_MHPMCOUNTER26 0xb1a
+#define CSR_MHPMCOUNTER27 0xb1b
+#define CSR_MHPMCOUNTER28 0xb1c
+#define CSR_MHPMCOUNTER29 0xb1d
+#define CSR_MHPMCOUNTER30 0xb1e
+#define CSR_MHPMCOUNTER31 0xb1f
+#define CSR_MUCOUNTEREN 0x320
+#define CSR_MSCOUNTEREN 0x321
+#define CSR_MHPMEVENT3 0x323
+#define CSR_MHPMEVENT4 0x324
+#define CSR_MHPMEVENT5 0x325
+#define CSR_MHPMEVENT6 0x326
+#define CSR_MHPMEVENT7 0x327
+#define CSR_MHPMEVENT8 0x328
+#define CSR_MHPMEVENT9 0x329
+#define CSR_MHPMEVENT10 0x32a
+#define CSR_MHPMEVENT11 0x32b
+#define CSR_MHPMEVENT12 0x32c
+#define CSR_MHPMEVENT13 0x32d
+#define CSR_MHPMEVENT14 0x32e
+#define CSR_MHPMEVENT15 0x32f
+#define CSR_MHPMEVENT16 0x330
+#define CSR_MHPMEVENT17 0x331
+#define CSR_MHPMEVENT18 0x332
+#define CSR_MHPMEVENT19 0x333
+#define CSR_MHPMEVENT20 0x334
+#define CSR_MHPMEVENT21 0x335
+#define CSR_MHPMEVENT22 0x336
+#define CSR_MHPMEVENT23 0x337
+#define CSR_MHPMEVENT24 0x338
+#define CSR_MHPMEVENT25 0x339
+#define CSR_MHPMEVENT26 0x33a
+#define CSR_MHPMEVENT27 0x33b
+#define CSR_MHPMEVENT28 0x33c
+#define CSR_MHPMEVENT29 0x33d
+#define CSR_MHPMEVENT30 0x33e
+#define CSR_MHPMEVENT31 0x33f
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CSR_HPMCOUNTER3H 0xc83
+#define CSR_HPMCOUNTER4H 0xc84
+#define CSR_HPMCOUNTER5H 0xc85
+#define CSR_HPMCOUNTER6H 0xc86
+#define CSR_HPMCOUNTER7H 0xc87
+#define CSR_HPMCOUNTER8H 0xc88
+#define CSR_HPMCOUNTER9H 0xc89
+#define CSR_HPMCOUNTER10H 0xc8a
+#define CSR_HPMCOUNTER11H 0xc8b
+#define CSR_HPMCOUNTER12H 0xc8c
+#define CSR_HPMCOUNTER13H 0xc8d
+#define CSR_HPMCOUNTER14H 0xc8e
+#define CSR_HPMCOUNTER15H 0xc8f
+#define CSR_HPMCOUNTER16H 0xc90
+#define CSR_HPMCOUNTER17H 0xc91
+#define CSR_HPMCOUNTER18H 0xc92
+#define CSR_HPMCOUNTER19H 0xc93
+#define CSR_HPMCOUNTER20H 0xc94
+#define CSR_HPMCOUNTER21H 0xc95
+#define CSR_HPMCOUNTER22H 0xc96
+#define CSR_HPMCOUNTER23H 0xc97
+#define CSR_HPMCOUNTER24H 0xc98
+#define CSR_HPMCOUNTER25H 0xc99
+#define CSR_HPMCOUNTER26H 0xc9a
+#define CSR_HPMCOUNTER27H 0xc9b
+#define CSR_HPMCOUNTER28H 0xc9c
+#define CSR_HPMCOUNTER29H 0xc9d
+#define CSR_HPMCOUNTER30H 0xc9e
+#define CSR_HPMCOUNTER31H 0xc9f
+#define CSR_MCYCLEH 0xb80
+#define CSR_MINSTRETH 0xb82
+#define CSR_MHPMCOUNTER3H 0xb83
+#define CSR_MHPMCOUNTER4H 0xb84
+#define CSR_MHPMCOUNTER5H 0xb85
+#define CSR_MHPMCOUNTER6H 0xb86
+#define CSR_MHPMCOUNTER7H 0xb87
+#define CSR_MHPMCOUNTER8H 0xb88
+#define CSR_MHPMCOUNTER9H 0xb89
+#define CSR_MHPMCOUNTER10H 0xb8a
+#define CSR_MHPMCOUNTER11H 0xb8b
+#define CSR_MHPMCOUNTER12H 0xb8c
+#define CSR_MHPMCOUNTER13H 0xb8d
+#define CSR_MHPMCOUNTER14H 0xb8e
+#define CSR_MHPMCOUNTER15H 0xb8f
+#define CSR_MHPMCOUNTER16H 0xb90
+#define CSR_MHPMCOUNTER17H 0xb91
+#define CSR_MHPMCOUNTER18H 0xb92
+#define CSR_MHPMCOUNTER19H 0xb93
+#define CSR_MHPMCOUNTER20H 0xb94
+#define CSR_MHPMCOUNTER21H 0xb95
+#define CSR_MHPMCOUNTER22H 0xb96
+#define CSR_MHPMCOUNTER23H 0xb97
+#define CSR_MHPMCOUNTER24H 0xb98
+#define CSR_MHPMCOUNTER25H 0xb99
+#define CSR_MHPMCOUNTER26H 0xb9a
+#define CSR_MHPMCOUNTER27H 0xb9b
+#define CSR_MHPMCOUNTER28H 0xb9c
+#define CSR_MHPMCOUNTER29H 0xb9d
+#define CSR_MHPMCOUNTER30H 0xb9e
+#define CSR_MHPMCOUNTER31H 0xb9f
+#define CAUSE_MISALIGNED_FETCH 0x0
+#define CAUSE_FAULT_FETCH 0x1
+#define CAUSE_ILLEGAL_INSTRUCTION 0x2
+#define CAUSE_BREAKPOINT 0x3
+#define CAUSE_MISALIGNED_LOAD 0x4
+#define CAUSE_FAULT_LOAD 0x5
+#define CAUSE_MISALIGNED_STORE 0x6
+#define CAUSE_FAULT_STORE 0x7
+#define CAUSE_USER_ECALL 0x8
+#define CAUSE_SUPERVISOR_ECALL 0x9
+#define CAUSE_HYPERVISOR_ECALL 0xa
+#define CAUSE_MACHINE_ECALL 0xb
+#endif
+#ifdef DECLARE_INSN
+DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ)
+DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
+DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
+DECLARE_INSN(bge, MATCH_BGE, MASK_BGE)
+DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
+DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU)
+DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR)
+DECLARE_INSN(jal, MATCH_JAL, MASK_JAL)
+DECLARE_INSN(lui, MATCH_LUI, MASK_LUI)
+DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC)
+DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI)
+DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI)
+DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI)
+DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU)
+DECLARE_INSN(xori, MATCH_XORI, MASK_XORI)
+DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI)
+DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI)
+DECLARE_INSN(ori, MATCH_ORI, MASK_ORI)
+DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI)
+DECLARE_INSN(add, MATCH_ADD, MASK_ADD)
+DECLARE_INSN(sub, MATCH_SUB, MASK_SUB)
+DECLARE_INSN(sll, MATCH_SLL, MASK_SLL)
+DECLARE_INSN(slt, MATCH_SLT, MASK_SLT)
+DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU)
+DECLARE_INSN(xor, MATCH_XOR, MASK_XOR)
+DECLARE_INSN(srl, MATCH_SRL, MASK_SRL)
+DECLARE_INSN(sra, MATCH_SRA, MASK_SRA)
+DECLARE_INSN(or, MATCH_OR, MASK_OR)
+DECLARE_INSN(and, MATCH_AND, MASK_AND)
+DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW)
+DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW)
+DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW)
+DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW)
+DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW)
+DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW)
+DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW)
+DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW)
+DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW)
+DECLARE_INSN(lb, MATCH_LB, MASK_LB)
+DECLARE_INSN(lh, MATCH_LH, MASK_LH)
+DECLARE_INSN(lw, MATCH_LW, MASK_LW)
+DECLARE_INSN(ld, MATCH_LD, MASK_LD)
+DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU)
+DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU)
+DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU)
+DECLARE_INSN(sb, MATCH_SB, MASK_SB)
+DECLARE_INSN(sh, MATCH_SH, MASK_SH)
+DECLARE_INSN(sw, MATCH_SW, MASK_SW)
+DECLARE_INSN(sd, MATCH_SD, MASK_SD)
+DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE)
+DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I)
+DECLARE_INSN(mul, MATCH_MUL, MASK_MUL)
+DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH)
+DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU)
+DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU)
+DECLARE_INSN(div, MATCH_DIV, MASK_DIV)
+DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU)
+DECLARE_INSN(rem, MATCH_REM, MASK_REM)
+DECLARE_INSN(remu, MATCH_REMU, MASK_REMU)
+DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW)
+DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW)
+DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW)
+DECLARE_INSN(remw, MATCH_REMW, MASK_REMW)
+DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW)
+DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W)
+DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W)
+DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W)
+DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W)
+DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W)
+DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W)
+DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W)
+DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W)
+DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W)
+DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W)
+DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W)
+DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D)
+DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D)
+DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D)
+DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D)
+DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D)
+DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D)
+DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D)
+DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D)
+DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D)
+DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D)
+DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D)
+DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL)
+DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK)
+DECLARE_INSN(uret, MATCH_URET, MASK_URET)
+DECLARE_INSN(sret, MATCH_SRET, MASK_SRET)
+DECLARE_INSN(hret, MATCH_HRET, MASK_HRET)
+DECLARE_INSN(mret, MATCH_MRET, MASK_MRET)
+DECLARE_INSN(dret, MATCH_DRET, MASK_DRET)
+DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM)
+DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI)
+DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW)
+DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS)
+DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC)
+DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI)
+DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI)
+DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI)
+DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S)
+DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S)
+DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S)
+DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S)
+DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S)
+DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S)
+DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S)
+DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S)
+DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S)
+DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S)
+DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D)
+DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D)
+DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D)
+DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D)
+DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D)
+DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D)
+DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D)
+DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D)
+DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D)
+DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D)
+DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S)
+DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D)
+DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S)
+DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S)
+DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S)
+DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D)
+DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D)
+DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D)
+DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S)
+DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S)
+DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S)
+DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S)
+DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S)
+DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S)
+DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D)
+DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D)
+DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D)
+DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D)
+DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D)
+DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D)
+DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W)
+DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU)
+DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L)
+DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU)
+DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X)
+DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W)
+DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU)
+DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L)
+DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU)
+DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X)
+DECLARE_INSN(flw, MATCH_FLW, MASK_FLW)
+DECLARE_INSN(fld, MATCH_FLD, MASK_FLD)
+DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW)
+DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD)
+DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S)
+DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S)
+DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S)
+DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S)
+DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D)
+DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D)
+DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D)
+DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D)
+DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP)
+DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP)
+DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR)
+DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR)
+DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK)
+DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD)
+DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD)
+DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW)
+DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP)
+DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP)
+DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN)
+DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD)
+DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW)
+DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW)
+DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD)
+DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW)
+DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW)
+DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI)
+DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL)
+DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI)
+DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI)
+DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI)
+DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI)
+DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI)
+DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB)
+DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR)
+DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR)
+DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND)
+DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW)
+DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW)
+DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
+DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ)
+DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ)
+DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI)
+DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP)
+DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP)
+DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP)
+DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV)
+DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
+DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP)
+DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
+DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP)
+DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0)
+DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1)
+DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2)
+DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD)
+DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1)
+DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2)
+DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1)
+DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1)
+DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2)
+DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD)
+DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1)
+DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2)
+DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2)
+DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1)
+DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2)
+DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD)
+DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1)
+DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2)
+DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3)
+DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1)
+DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2)
+DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD)
+DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1)
+DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2)
+#endif
+#ifdef DECLARE_CSR
+DECLARE_CSR(fflags, CSR_FFLAGS)
+DECLARE_CSR(frm, CSR_FRM)
+DECLARE_CSR(fcsr, CSR_FCSR)
+DECLARE_CSR(cycle, CSR_CYCLE)
+DECLARE_CSR(time, CSR_TIME)
+DECLARE_CSR(instret, CSR_INSTRET)
+DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3)
+DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4)
+DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5)
+DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6)
+DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7)
+DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8)
+DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9)
+DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10)
+DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11)
+DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12)
+DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13)
+DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14)
+DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15)
+DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16)
+DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17)
+DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18)
+DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19)
+DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20)
+DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21)
+DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22)
+DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23)
+DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24)
+DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25)
+DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26)
+DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27)
+DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28)
+DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29)
+DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30)
+DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31)
+DECLARE_CSR(sstatus, CSR_SSTATUS)
+DECLARE_CSR(sie, CSR_SIE)
+DECLARE_CSR(stvec, CSR_STVEC)
+DECLARE_CSR(sscratch, CSR_SSCRATCH)
+DECLARE_CSR(sepc, CSR_SEPC)
+DECLARE_CSR(scause, CSR_SCAUSE)
+DECLARE_CSR(sbadaddr, CSR_SBADADDR)
+DECLARE_CSR(sip, CSR_SIP)
+DECLARE_CSR(sptbr, CSR_SPTBR)
+DECLARE_CSR(mstatus, CSR_MSTATUS)
+DECLARE_CSR(misa, CSR_MISA)
+DECLARE_CSR(medeleg, CSR_MEDELEG)
+DECLARE_CSR(mideleg, CSR_MIDELEG)
+DECLARE_CSR(mie, CSR_MIE)
+DECLARE_CSR(mtvec, CSR_MTVEC)
+DECLARE_CSR(mscratch, CSR_MSCRATCH)
+DECLARE_CSR(mepc, CSR_MEPC)
+DECLARE_CSR(mcause, CSR_MCAUSE)
+DECLARE_CSR(mbadaddr, CSR_MBADADDR)
+DECLARE_CSR(mip, CSR_MIP)
+DECLARE_CSR(tselect, CSR_TSELECT)
+DECLARE_CSR(tdata1, CSR_TDATA1)
+DECLARE_CSR(tdata2, CSR_TDATA2)
+DECLARE_CSR(tdata3, CSR_TDATA3)
+DECLARE_CSR(dcsr, CSR_DCSR)
+DECLARE_CSR(dpc, CSR_DPC)
+DECLARE_CSR(dscratch, CSR_DSCRATCH)
+DECLARE_CSR(mcycle, CSR_MCYCLE)
+DECLARE_CSR(minstret, CSR_MINSTRET)
+DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3)
+DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4)
+DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5)
+DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6)
+DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7)
+DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8)
+DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9)
+DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10)
+DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11)
+DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12)
+DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13)
+DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14)
+DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15)
+DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16)
+DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17)
+DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18)
+DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19)
+DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20)
+DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21)
+DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22)
+DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23)
+DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24)
+DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25)
+DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26)
+DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27)
+DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28)
+DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29)
+DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30)
+DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31)
+DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN)
+DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN)
+DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3)
+DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4)
+DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5)
+DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6)
+DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7)
+DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8)
+DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9)
+DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10)
+DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11)
+DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12)
+DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13)
+DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14)
+DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15)
+DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16)
+DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17)
+DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18)
+DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19)
+DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20)
+DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21)
+DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22)
+DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23)
+DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24)
+DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25)
+DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26)
+DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27)
+DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28)
+DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29)
+DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30)
+DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31)
+DECLARE_CSR(mvendorid, CSR_MVENDORID)
+DECLARE_CSR(marchid, CSR_MARCHID)
+DECLARE_CSR(mimpid, CSR_MIMPID)
+DECLARE_CSR(mhartid, CSR_MHARTID)
+DECLARE_CSR(cycleh, CSR_CYCLEH)
+DECLARE_CSR(timeh, CSR_TIMEH)
+DECLARE_CSR(instreth, CSR_INSTRETH)
+DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H)
+DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H)
+DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H)
+DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H)
+DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H)
+DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H)
+DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H)
+DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H)
+DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H)
+DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H)
+DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H)
+DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H)
+DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H)
+DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H)
+DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H)
+DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H)
+DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H)
+DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H)
+DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H)
+DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H)
+DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H)
+DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H)
+DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H)
+DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H)
+DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H)
+DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H)
+DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H)
+DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H)
+DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H)
+DECLARE_CSR(mcycleh, CSR_MCYCLEH)
+DECLARE_CSR(minstreth, CSR_MINSTRETH)
+DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H)
+DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H)
+DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H)
+DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H)
+DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H)
+DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H)
+DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H)
+DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H)
+DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H)
+DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H)
+DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H)
+DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H)
+DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H)
+DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H)
+DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H)
+DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H)
+DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H)
+DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H)
+DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H)
+DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H)
+DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H)
+DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H)
+DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H)
+DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H)
+DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H)
+DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H)
+DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H)
+DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H)
+DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H)
+#endif
+#ifdef DECLARE_CAUSE
+DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH)
+DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH)
+DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION)
+DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT)
+DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD)
+DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD)
+DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE)
+DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE)
+DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL)
+DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL)
+DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL)
+DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL)
+#endif
diff --git a/libcpu/risc-v/virt64/ext_context.h b/libcpu/risc-v/virt64/ext_context.h
new file mode 100644
index 0000000000..ac757dddb6
--- /dev/null
+++ b/libcpu/risc-v/virt64/ext_context.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-10 RT-Thread the first version,
+ * compatible to riscv-v-spec-1.0
+ */
+#ifndef __EXT_CONTEXT_H__
+#define __EXT_CONTEXT_H__
+
+#ifdef __ASSEMBLY__
+
+/**
+ * extension context maintenance
+ */
+
+#include "cpuport.h"
+#include "encoding.h"
+#include "vector_encoding.h"
+
+/**
+ * ==================================
+ * FPU EXTENSION
+ * ==================================
+ */
+
+#ifdef ENABLE_FPU
+#define FPU_CTX_F0_OFF 0 /* offsetof(fpu_context_t, fpustatus.f[0]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F1_OFF 8 /* offsetof(fpu_context_t, fpustatus.f[1]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F2_OFF 16 /* offsetof(fpu_context_t, fpustatus.f[2]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F3_OFF 24 /* offsetof(fpu_context_t, fpustatus.f[3]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F4_OFF 32 /* offsetof(fpu_context_t, fpustatus.f[4]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F5_OFF 40 /* offsetof(fpu_context_t, fpustatus.f[5]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F6_OFF 48 /* offsetof(fpu_context_t, fpustatus.f[6]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F7_OFF 56 /* offsetof(fpu_context_t, fpustatus.f[7]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F8_OFF 64 /* offsetof(fpu_context_t, fpustatus.f[8]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F9_OFF 72 /* offsetof(fpu_context_t, fpustatus.f[9]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F10_OFF 80 /* offsetof(fpu_context_t, fpustatus.f[10]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F11_OFF 88 /* offsetof(fpu_context_t, fpustatus.f[11]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F12_OFF 96 /* offsetof(fpu_context_t, fpustatus.f[12]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F13_OFF 104 /* offsetof(fpu_context_t, fpustatus.f[13]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F14_OFF 112 /* offsetof(fpu_context_t, fpustatus.f[14]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F15_OFF 120 /* offsetof(fpu_context_t, fpustatus.f[15]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F16_OFF 128 /* offsetof(fpu_context_t, fpustatus.f[16]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F17_OFF 136 /* offsetof(fpu_context_t, fpustatus.f[17]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F18_OFF 144 /* offsetof(fpu_context_t, fpustatus.f[18]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F19_OFF 152 /* offsetof(fpu_context_t, fpustatus.f[19]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F20_OFF 160 /* offsetof(fpu_context_t, fpustatus.f[20]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F21_OFF 168 /* offsetof(fpu_context_t, fpustatus.f[21]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F22_OFF 176 /* offsetof(fpu_context_t, fpustatus.f[22]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F23_OFF 184 /* offsetof(fpu_context_t, fpustatus.f[23]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F24_OFF 192 /* offsetof(fpu_context_t, fpustatus.f[24]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F25_OFF 200 /* offsetof(fpu_context_t, fpustatus.f[25]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F26_OFF 208 /* offsetof(fpu_context_t, fpustatus.f[26]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F27_OFF 216 /* offsetof(fpu_context_t, fpustatus.f[27]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F28_OFF 224 /* offsetof(fpu_context_t, fpustatus.f[28]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F29_OFF 232 /* offsetof(fpu_context_t, fpustatus.f[29]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F30_OFF 240 /* offsetof(fpu_context_t, fpustatus.f[30]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#define FPU_CTX_F31_OFF 248 /* offsetof(fpu_context_t, fpustatus.f[31]) - offsetof(fpu_context_t, fpustatus.f[0]) */
+#endif /* ENABLE_FPU */
+
+/**
+ * ==================================
+ * VECTOR EXTENSION
+ * ==================================
+ */
+
+#ifdef ENABLE_VECTOR
+
+#define VEC_FRAME_VSTART (0 * REGBYTES)
+#define VEC_FRAME_VTYPE (1 * REGBYTES)
+#define VEC_FRAME_VL (2 * REGBYTES)
+#define VEC_FRAME_VCSR (3 * REGBYTES)
+#define VEC_FRAME_V0 (4 * REGBYTES)
+
+.macro GET_VEC_FRAME_LEN, xreg
+ csrr \xreg, vlenb
+ slli \xreg, \xreg, 5
+ addi \xreg, \xreg, 4 * REGBYTES
+.endm
+
+/**
+ * @brief save vector extension hardware state
+ *
+ * @param dst register storing bottom of storage block
+ *
+ */
+.macro SAVE_VECTOR, dst
+ mv t1, \dst
+
+ csrr t0, vstart
+ STORE t0, VEC_FRAME_VSTART(t1)
+ csrr t0, vtype
+ STORE t0, VEC_FRAME_VTYPE(t1)
+ csrr t0, vl
+ STORE t0, VEC_FRAME_VL(t1)
+ csrr t0, vcsr
+ STORE t0, VEC_FRAME_VCSR(t1)
+
+ addi t1, t1, VEC_FRAME_V0
+
+ // config vector setting,
+ // t2 is updated to length of a vector group in bytes
+ VEC_CONFIG_SETVLI(t2, x0, VEC_IMM_SEW_8, VEC_IMM_LMUL_8)
+
+ vse8.v v0, (t1)
+ add t1, t1, t2
+ vse8.v v8, (t1)
+ add t1, t1, t2
+ vse8.v v16, (t1)
+ add t1, t1, t2
+ vse8.v v24, (t1)
+.endm
+
+/**
+ * @brief restore vector extension hardware states
+ *
+ * @param dst register storing bottom of storage block
+ *
+ */
+.macro RESTORE_VECTOR, dst
+ // restore vector registers first since it will modify vector states
+ mv t0, \dst
+ addi t1, t0, VEC_FRAME_V0
+
+ VEC_CONFIG_SETVLI(t2, x0, VEC_IMM_SEW_8, VEC_IMM_LMUL_8)
+
+ vle8.v v0, (t1)
+ add t1, t1, t2
+ vle8.v v8, (t1)
+ add t1, t1, t2
+ vle8.v v16, (t1)
+ add t1, t1, t2
+ vle8.v v24, (t1)
+
+ mv t1, t0
+
+ LOAD t0, VEC_FRAME_VSTART(t1)
+ csrw vstart, t0
+ LOAD t0, VEC_FRAME_VCSR(t1)
+ csrw vcsr, t0
+
+ LOAD t0, VEC_FRAME_VTYPE(t1)
+ LOAD t3, VEC_FRAME_VL(t1)
+ VEC_CONFIG_SET_VL_VTYPE(t3, t0)
+.endm
+
+#endif /* ENABLE_VECTOR */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __EXT_CONTEXT_H__ */ \ No newline at end of file
diff --git a/libcpu/risc-v/virt64/interrupt.c b/libcpu/risc-v/virt64/interrupt.c
index f2869fc441..e6c9ea3777 100644
--- a/libcpu/risc-v/virt64/interrupt.c
+++ b/libcpu/risc-v/virt64/interrupt.c
@@ -8,15 +8,15 @@
* 2018/10/01 Bernard The first version
* 2018/12/27 Jesven Change irq enable/disable to cpu0
*/
-#include "tick.h"
#include <plic.h>
+#include <mmu.h>
+#include <lwp_arch.h>
+#include "tick.h"
#include "encoding.h"
#include "riscv.h"
#include "interrupt.h"
-#define MAX_HANDLERS 128
-
-static struct rt_irq_desc irq_desc[MAX_HANDLERS];
+struct rt_irq_desc irq_desc[MAX_HANDLERS];
static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
{
@@ -24,20 +24,6 @@ static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
return RT_NULL;
}
-int rt_hw_clint_ipi_enable(void)
-{
- /* Set the Machine-Software bit in MIE */
- set_csr(mie, MIP_MSIP);
- return 0;
-}
-
-int rt_hw_clint_ipi_disable(void)
-{
- /* Clear the Machine-Software bit in MIE */
- clear_csr(mie, MIP_MSIP);
- return 0;
-}
-
int rt_hw_plic_irq_enable(int irq_number)
{
plic_irq_enable(irq_number);
@@ -51,35 +37,6 @@ int rt_hw_plic_irq_disable(int irq_number)
}
/**
- * This function will initialize hardware interrupt
- */
-void rt_hw_interrupt_init(void)
-{
- int idx = 0;
- /* init exceptions table */
- for (idx = 0; idx < MAX_HANDLERS; idx++)
- {
- irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
- irq_desc[idx].param = RT_NULL;
-#ifdef RT_USING_INTERRUPT_INFO
- rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
- irq_desc[idx].counter = 0;
-#endif
- }
-
- plic_set_threshold(0);
-}
-
-/**
- * This function will mask a interrupt.
- * @param vector the interrupt number
- */
-void rt_hw_interrupt_mask(int vector)
-{
- rt_hw_plic_irq_disable(vector);
-}
-
-/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
@@ -118,161 +75,21 @@ rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
return old_handler;
}
-RT_WEAK
-void plic_irq_handle(int irq)
+void rt_hw_interrupt_init()
{
- rt_kprintf("UN-handled interrupt %d occurred!!!\n", irq);
- return ;
-}
-
-void dump_regs(struct rt_hw_stack_frame *regs)
-{
- rt_kprintf("--------------Dump Registers-----------------\n");
-
- rt_kprintf("Function Registers:\n");
- rt_kprintf("\tra(x1) = 0x%p\tuser_sp = 0x%p\n",regs -> ra,regs -> user_sp_exc_stack);
- rt_kprintf("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n",regs -> gp,regs -> tp);
- rt_kprintf("Temporary Registers:\n");
- rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n",regs -> t0,regs -> t1);
- rt_kprintf("\tt2(x7) = 0x%p\n",regs -> t2);
- rt_kprintf("\tt3(x28) = 0x%p\tt4(x29) = 0x%p\n",regs -> t3,regs -> t4);
- rt_kprintf("\tt5(x30) = 0x%p\tt6(x31) = 0x%p\n",regs -> t5,regs -> t6);
- rt_kprintf("Saved Registers:\n");
- rt_kprintf("\ts0/fp(x8) = 0x%p\ts1(x9) = 0x%p\n",regs -> s0_fp,regs -> s1);
- rt_kprintf("\ts2(x18) = 0x%p\ts3(x19) = 0x%p\n",regs -> s2,regs -> s3);
- rt_kprintf("\ts4(x20) = 0x%p\ts5(x21) = 0x%p\n",regs -> s4,regs -> s5);
- rt_kprintf("\ts6(x22) = 0x%p\ts7(x23) = 0x%p\n",regs -> s6,regs -> s7);
- rt_kprintf("\ts8(x24) = 0x%p\ts9(x25) = 0x%p\n",regs -> s8,regs -> s9);
- rt_kprintf("\ts10(x26) = 0x%p\ts11(x27) = 0x%p\n",regs -> s10,regs -> s11);
- rt_kprintf("Function Arguments Registers:\n");
- rt_kprintf("\ta0(x10) = 0x%p\ta1(x11) = 0x%p\n",regs -> a0,regs -> a1);
- rt_kprintf("\ta2(x12) = 0x%p\ta3(x13) = 0x%p\n",regs -> a2,regs -> a3);
- rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n",regs -> a4,regs -> a5);
- rt_kprintf("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n",regs -> a6,regs -> a7);
- rt_kprintf("xstatus = 0x%p\n",regs -> xstatus);
- rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
- rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
- rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
- rt_kprintf("\t%s\n",(regs -> xstatus & SSTATUS_PUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
- rt_kprintf("\t%s\n",(regs -> xstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
- rt_size_t satp_v = read_csr(satp);
- rt_kprintf("satp = 0x%p\n",satp_v);
- const char *mode_str = "Unknown Address Translation/Protection Mode";
-
- switch(__MASKVALUE(satp_v >> 60,__MASK(4)))
- {
- case 0:
- mode_str = "No Address Translation/Protection Mode";
- break;
-
- case 8:
- mode_str = "Page-based 39-bit Virtual Addressing Mode";
- break;
-
- case 9:
- mode_str = "Page-based 48-bit Virtual Addressing Mode";
- break;
- }
-
- rt_kprintf("\tMode = %s\n",mode_str);
- rt_kprintf("-----------------Dump OK---------------------\n");
-}
-
-void handle_trap(rt_size_t xcause,rt_size_t xtval,rt_size_t xepc,struct rt_hw_stack_frame *sp)
-{
- int cause = (xcause & 0xFFFFFFFF);
- int plic_irq = 0;
-
- if (xcause & (1UL << 63))
- {
- switch (cause)
- {
- case IRQ_M_SOFT:
- {
-
- }
- break;
- case IRQ_M_TIMER:
- tick_isr();
- break;
- case IRQ_S_TIMER:
- tick_isr();
- break;
-
- case IRQ_S_EXT:
- plic_irq = plic_claim();
- plic_complete(plic_irq);
- irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
- break;
-
- case IRQ_M_EXT:
- plic_irq = plic_claim();
- plic_complete(plic_irq);
- irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
- break;
- }
- }
- else
+ /* Enable machine external interrupts. */
+ // set_csr(sie, SIP_SEIP);
+ int idx = 0;
+ /* init exceptions table */
+ for (idx = 0; idx < MAX_HANDLERS; idx++)
{
- rt_thread_t tid;
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- extern long list_thread();
-#endif
- rt_hw_interrupt_disable();
-
- rt_kprintf("xcause = %08x,xtval = %08x,xepc = %08x\n", xcause, xtval, xepc);
- tid = rt_thread_self();
- rt_kprintf("\nException:\n");
- switch (cause)
- {
- case CAUSE_MISALIGNED_FETCH:
- rt_kprintf("Instruction address misaligned");
- break;
- case CAUSE_FAULT_FETCH:
- rt_kprintf("Instruction access fault");
- break;
- case CAUSE_ILLEGAL_INSTRUCTION:
- rt_kprintf("Illegal instruction");
- break;
- case CAUSE_BREAKPOINT:
- rt_kprintf("Breakpoint");
- break;
- case CAUSE_MISALIGNED_LOAD:
- rt_kprintf("Load address misaligned");
- break;
- case CAUSE_FAULT_LOAD:
- rt_kprintf("Load access fault");
- break;
- case CAUSE_MISALIGNED_STORE:
- rt_kprintf("Store address misaligned");
- break;
- case CAUSE_FAULT_STORE:
- rt_kprintf("Store access fault");
- break;
- case CAUSE_USER_ECALL:
- rt_kprintf("Environment call from U-mode");
- break;
- case CAUSE_SUPERVISOR_ECALL:
- rt_kprintf("Environment call from S-mode");
- break;
- case CAUSE_HYPERVISOR_ECALL:
- rt_kprintf("Environment call from H-mode");
- break;
- case CAUSE_MACHINE_ECALL:
- rt_kprintf("Environment call from M-mode");
- break;
- default:
- rt_kprintf("Uknown exception : %08lX", cause);
- break;
- }
- rt_kprintf("\n");
- dump_regs(sp);
- rt_kprintf("exception pc => 0x%08x\n", xepc);
- rt_kprintf("current thread: %.*s\n", RT_NAME_MAX, tid->name);
-#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
- list_thread();
+ irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
+ irq_desc[idx].param = RT_NULL;
+#ifdef RT_USING_INTERRUPT_INFO
+ rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
+ irq_desc[idx].counter = 0;
#endif
- while(1);
}
- rt_hw_interrupt_enable(0);
+
+ plic_set_threshold(0);
}
diff --git a/libcpu/risc-v/virt64/interrupt.h b/libcpu/risc-v/virt64/interrupt.h
index e49f0215bf..a4bf7eb0a0 100644
--- a/libcpu/risc-v/virt64/interrupt.h
+++ b/libcpu/risc-v/virt64/interrupt.h
@@ -11,11 +11,13 @@
#ifndef INTERRUPT_H__
#define INTERRUPT_H__
+#define MAX_HANDLERS 128
+
#include <rthw.h>
#include "stack.h"
-int rt_hw_clint_ipi_enable(void);
-int rt_hw_clint_ipi_disable(void);
+// int rt_hw_clint_ipi_enable(void);
+// int rt_hw_clint_ipi_disable(void);
int rt_hw_plic_irq_enable(int irq_number);
int rt_hw_plic_irq_disable(int irq_number);
void rt_hw_interrupt_init(void);
diff --git a/libcpu/risc-v/virt64/interrupt_gcc.S b/libcpu/risc-v/virt64/interrupt_gcc.S
index d9b7a06d98..6cc26731f1 100644
--- a/libcpu/risc-v/virt64/interrupt_gcc.S
+++ b/libcpu/risc-v/virt64/interrupt_gcc.S
@@ -8,145 +8,83 @@
* 2018/10/02 Bernard The first version
* 2018/12/27 Jesven Add SMP schedule
* 2021/02/02 lizhirui Add userspace support
+ * 2021/12/24 JasonHu Add user setting save/restore
+ * 2022/10/22 WangXiaoyao Support kernel mode RVV;
+ * Rewrite trap handling routine
*/
#include "cpuport.h"
+#include "encoding.h"
+#include "stackframe.h"
- .section .text.entry
- .align 2
- .global trap_entry
+ .align 2
+ .global trap_entry
+ .global debug_check_sp
trap_entry:
-#ifdef ARCH_RISCV_FPU
- addi sp, sp, -32 * FREGBYTES
+ // distingush exception from kernel or user
+ csrrw sp, sscratch, sp
+ bnez sp, _save_context
- FSTORE f0, 0 * FREGBYTES(sp)
- FSTORE f1, 1 * FREGBYTES(sp)
- FSTORE f2, 2 * FREGBYTES(sp)
- FSTORE f3, 3 * FREGBYTES(sp)
- FSTORE f4, 4 * FREGBYTES(sp)
- FSTORE f5, 5 * FREGBYTES(sp)
- FSTORE f6, 6 * FREGBYTES(sp)
- FSTORE f7, 7 * FREGBYTES(sp)
- FSTORE f8, 8 * FREGBYTES(sp)
- FSTORE f9, 9 * FREGBYTES(sp)
- FSTORE f10, 10 * FREGBYTES(sp)
- FSTORE f11, 11 * FREGBYTES(sp)
- FSTORE f12, 12 * FREGBYTES(sp)
- FSTORE f13, 13 * FREGBYTES(sp)
- FSTORE f14, 14 * FREGBYTES(sp)
- FSTORE f15, 15 * FREGBYTES(sp)
- FSTORE f16, 16 * FREGBYTES(sp)
- FSTORE f17, 17 * FREGBYTES(sp)
- FSTORE f18, 18 * FREGBYTES(sp)
- FSTORE f19, 19 * FREGBYTES(sp)
- FSTORE f20, 20 * FREGBYTES(sp)
- FSTORE f21, 21 * FREGBYTES(sp)
- FSTORE f22, 22 * FREGBYTES(sp)
- FSTORE f23, 23 * FREGBYTES(sp)
- FSTORE f24, 24 * FREGBYTES(sp)
- FSTORE f25, 25 * FREGBYTES(sp)
- FSTORE f26, 26 * FREGBYTES(sp)
- FSTORE f27, 27 * FREGBYTES(sp)
- FSTORE f28, 28 * FREGBYTES(sp)
- FSTORE f29, 29 * FREGBYTES(sp)
- FSTORE f30, 30 * FREGBYTES(sp)
- FSTORE f31, 31 * FREGBYTES(sp)
+ // BE REALLY careful with sscratch,
+ // if it's wrong, we could looping here forever
+ // or accessing random memory and seeing things totally
+ // messy after a long time and don't even know why
+_from_kernel:
+ csrr sp, sscratch
+ j _save_context
-#endif
+_save_context:
+ SAVE_ALL
+ // clear sscratch to say 'now in kernel mode'
+ csrw sscratch, zero
- /* save thread context to thread stack */
- addi sp, sp, -32 * REGBYTES
+ RESTORE_SYS_GP
- STORE x1, 1 * REGBYTES(sp)
+ // now we are ready to enter interrupt / excepiton handler
+_distinguish_syscall:
+ csrr t0, scause
+ // TODO swap 8 with config macro name
+ li t1, 8
+ beq t0, t1, syscall_entry
+ // syscall never return here
- csrr x1, SRC_XSTATUS
- STORE x1, 2 * REGBYTES(sp)
+_handle_interrupt_and_exception:
+ mv a0, t0
+ csrrc a1, stval, zero
+ csrr a2, sepc
+ // sp as exception frame pointer
+ mv a3, sp
+ call handle_trap
- csrr x1, SRC_XEPC
- STORE x1, 0 * REGBYTES(sp)
+_interrupt_exit:
+ la s0, rt_thread_switch_interrupt_flag
+ lw s2, 0(s0)
+ beqz s2, _resume_execution
+ sw zero, 0(s0)
- STORE x4, 4 * REGBYTES(sp)
- STORE x5, 5 * REGBYTES(sp)
- STORE x6, 6 * REGBYTES(sp)
- STORE x7, 7 * REGBYTES(sp)
- STORE x8, 8 * REGBYTES(sp)
- STORE x9, 9 * REGBYTES(sp)
- STORE x10, 10 * REGBYTES(sp)
- STORE x11, 11 * REGBYTES(sp)
- STORE x12, 12 * REGBYTES(sp)
- STORE x13, 13 * REGBYTES(sp)
- STORE x14, 14 * REGBYTES(sp)
- STORE x15, 15 * REGBYTES(sp)
- STORE x16, 16 * REGBYTES(sp)
- STORE x17, 17 * REGBYTES(sp)
- STORE x18, 18 * REGBYTES(sp)
- STORE x19, 19 * REGBYTES(sp)
- STORE x20, 20 * REGBYTES(sp)
- STORE x21, 21 * REGBYTES(sp)
- STORE x22, 22 * REGBYTES(sp)
- STORE x23, 23 * REGBYTES(sp)
- STORE x24, 24 * REGBYTES(sp)
- STORE x25, 25 * REGBYTES(sp)
- STORE x26, 26 * REGBYTES(sp)
- STORE x27, 27 * REGBYTES(sp)
- STORE x28, 28 * REGBYTES(sp)
- STORE x29, 29 * REGBYTES(sp)
- STORE x30, 30 * REGBYTES(sp)
- STORE x31, 31 * REGBYTES(sp)
+_context_switch:
+ la t0, rt_interrupt_from_thread
+ LOAD a0, 0(t0)
+ la t0, rt_interrupt_to_thread
+ LOAD a1, 0(t0)
+ jal rt_hw_context_switch
- /* switch to interrupt stack */
- move s0, sp
+_resume_execution:
+ LOAD t0, FRAME_OFF_SSTATUS(sp)
+ andi t0, t0, SSTATUS_SPP
+ beqz t0, arch_ret_to_user
-#ifndef RISCV_S_MODE
- /* get cpu id */
- csrr t0, mhartid
-#else
- li t0, 0
-#endif
+_resume_kernel:
+ RESTORE_ALL
+ csrw sscratch, zero
+ sret
- /* switch interrupt stack of current cpu */
- la sp, __stack_start__
- addi t1, t0, 1
- li t2, __STACKSIZE__
- mul t1, t1, t2
- add sp, sp, t1 /* sp = (cpuid + 1) * __STACKSIZE__ + __stack_start__ */
+.global rt_hw_interrupt_enable
+rt_hw_interrupt_enable:
+ csrs sstatus, a0 /* restore to old csr */
+ jr ra
- /* handle interrupt */
- call rt_interrupt_enter
- csrr a0, SRC_XCAUSE
- csrr a1, SRC_XTVAL
- csrr a2, SRC_XEPC
- mv a3, s0
- call handle_trap
- call rt_interrupt_leave
-
-#ifdef RT_USING_SMP
- /* s0 --> sp */
- mv sp, s0
- mv a0, s0
- call rt_scheduler_do_irq_switch
- tail rt_hw_context_switch_exit
-
-#else
-
- /* switch to from_thread stack */
- move sp, s0
-
- /* need to switch new thread */
- la s0, rt_thread_switch_interrupt_flag
- lw s2, 0(s0)
- beqz s2, spurious_interrupt
- sw zero, 0(s0)
-
- la s0, rt_interrupt_from_thread
- LOAD s1, 0(s0)
- STORE sp, 0(s1)
-
- la s0, rt_interrupt_to_thread
- LOAD s1, 0(s0)
- LOAD sp, 0(s1)
-
-#endif
-
-spurious_interrupt:
- tail rt_hw_context_switch_exit
+.global rt_hw_interrupt_disable
+rt_hw_interrupt_disable:
+ csrrci a0, sstatus, 2 /* clear SIE */
+ jr ra
diff --git a/libcpu/risc-v/virt64/io.h b/libcpu/risc-v/virt64/io.h
new file mode 100644
index 0000000000..1285d5955b
--- /dev/null
+++ b/libcpu/risc-v/virt64/io.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019-2020, Xim
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+#ifndef ARCH_IO_H
+#define ARCH_IO_H
+#include <rtthread.h>
+#define RISCV_FENCE(p, s) \
+ __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
+
+/* These barriers need to enforce ordering on both devices or memory. */
+#define mb() RISCV_FENCE(iorw,iorw)
+#define rmb() RISCV_FENCE(ir,ir)
+#define wmb() RISCV_FENCE(ow,ow)
+
+#define __arch_getl(a) (*(unsigned int *)(a))
+#define __arch_putl(v, a) (*(unsigned int *)(a) = (v))
+
+#define dmb() mb()
+#define __iormb() rmb()
+#define __iowmb() wmb()
+
+static inline void writel(uint32_t val, volatile void *addr)
+{
+ __iowmb();
+ __arch_putl(val, addr);
+}
+
+static inline uint32_t readl(const volatile void *addr)
+{
+ uint32_t val;
+
+ val = __arch_getl(addr);
+ __iormb();
+ return val;
+}
+
+static inline void write_reg(
+ uint32_t val, volatile void *addr, unsigned offset)
+{
+ writel(val, addr + offset);
+}
+
+static inline uint32_t read_reg(
+ const volatile void *addr, unsigned offset)
+{
+ return readl(addr + offset);
+}
+
+#endif // ARCH_IO_H
diff --git a/libcpu/risc-v/virt64/mmu.c b/libcpu/risc-v/virt64/mmu.c
new file mode 100644
index 0000000000..92bac7cf52
--- /dev/null
+++ b/libcpu/risc-v/virt64/mmu.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <board.h>
+#include <page.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lwp_mm.h>
+#include <cache.h>
+
+#define DBG_TAG "mmu"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "riscv.h"
+#include "riscv_mmu.h"
+#include "mmu.h"
+
+void *current_mmu_table = RT_NULL;
+
+volatile rt_ubase_t MMUTable[__SIZE(VPN2_BIT)] __attribute__((aligned(4 * 1024)));
+
+static void rt_hw_cpu_tlb_invalidate()
+{
+ rt_size_t satpv = read_csr(satp);
+ write_csr(satp, satpv);
+ mmu_flush_tlb();
+}
+
+void *rt_hw_mmu_tbl_get()
+{
+ return current_mmu_table;
+}
+
+void rt_hw_mmu_switch(void *mmu_table)
+{
+ current_mmu_table = mmu_table;
+ RT_ASSERT(__CHECKALIGN(mmu_table, PAGE_OFFSET_BIT));
+ mmu_set_pagetable((rt_ubase_t)mmu_table);
+ rt_hw_cpu_dcache_clean_all();
+ rt_hw_cpu_icache_invalidate_all();
+}
+
+int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void *v_address, rt_size_t size, rt_size_t *vtable, rt_size_t pv_off)
+{
+ size_t l1_off, va_s, va_e;
+ rt_base_t level;
+
+ if ((!mmu_info) || (!vtable))
+ {
+ return -1;
+ }
+
+ va_s = (rt_size_t)v_address;
+ va_e = ((rt_size_t)v_address) + size - 1;
+
+ if (va_e < va_s)
+ {
+ return -1;
+ }
+
+ // convert address to PPN2 index
+ va_s = GET_L1(va_s);
+ va_e = GET_L1(va_e);
+
+ if (va_s == 0)
+ {
+ return -1;
+ }
+
+ rt_mm_lock();
+
+ // vtable initialization check
+ for (l1_off = va_s; l1_off <= va_e; l1_off++)
+ {
+ size_t v = vtable[l1_off];
+
+ if (v)
+ {
+ rt_mm_unlock();
+ return -1;
+ }
+ }
+
+ rt_mm_unlock();
+ mmu_info->vtable = vtable;
+ mmu_info->vstart = va_s;
+ mmu_info->vend = va_e;
+ mmu_info->pv_off = pv_off;
+
+ return 0;
+}
+
+void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info, rt_size_t vaddr_start, rt_size_t size)
+{
+ rt_size_t paddr_start = __UMASKVALUE(VPN_TO_PPN(vaddr_start, mmu_info->pv_off), PAGE_OFFSET_MASK);
+ rt_size_t va_s = GET_L1(vaddr_start);
+ rt_size_t va_e = GET_L1(vaddr_start + size - 1);
+ rt_size_t i;
+
+ for (i = va_s; i <= va_e; i++)
+ {
+ mmu_info->vtable[i] = COMBINEPTE(paddr_start, PAGE_ATTR_RWX | PTE_G | PTE_V);
+ paddr_start += L1_PAGE_SIZE;
+ }
+
+ rt_hw_cpu_tlb_invalidate();
+}
+
+// find a range of free virtual address specified by pages
+static size_t find_vaddr(rt_mmu_info *mmu_info, int pages)
+{
+ size_t loop_pages;
+ size_t va;
+ size_t find_va = 0;
+ int n = 0;
+ size_t i;
+
+ if (!pages || !mmu_info)
+ {
+ return 0;
+ }
+
+ loop_pages = (mmu_info->vend - mmu_info->vstart) ? (mmu_info->vend - mmu_info->vstart) : 1;
+ loop_pages <<= (ARCH_INDEX_WIDTH * 2);
+ va = mmu_info->vstart;
+ va <<= (ARCH_PAGE_SHIFT + ARCH_INDEX_WIDTH * 2);
+
+ for (i = 0; i < loop_pages; i++, va += ARCH_PAGE_SIZE)
+ {
+ if (_rt_hw_mmu_v2p(mmu_info, (void *)va))
+ {
+ n = 0;
+ find_va = 0;
+ continue;
+ }
+ if (!find_va)
+ {
+ find_va = va;
+ }
+ n++;
+ if (n >= pages)
+ {
+ return find_va;
+ }
+ }
+ return 0;
+}
+
+// check whether the range of virtual address are free
+static int check_vaddr(rt_mmu_info *mmu_info, void *va, rt_size_t pages)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)va, PAGE_OFFSET_MASK);
+ rt_size_t l1_off, l2_off, l3_off;
+ rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
+
+ if (!pages)
+ {
+ return -1;
+ }
+
+ if (!mmu_info)
+ {
+ return -1;
+ }
+
+ while (pages--)
+ {
+ l1_off = GET_L1(loop_va);
+ l2_off = GET_L2(loop_va);
+ l3_off = GET_L3(loop_va);
+ mmu_l1 = ((rt_size_t *)mmu_info->vtable) + l1_off;
+
+ if (PTE_USED(*mmu_l1))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), mmu_info->pv_off) + l2_off;
+
+ if (PTE_USED(*mmu_l2))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l2));
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l2), mmu_info->pv_off) + l3_off;
+
+ if (PTE_USED(*mmu_l3))
+ {
+ RT_ASSERT(PAGE_IS_LEAF(*mmu_l3));
+ return -1;
+ }
+ }
+ }
+
+ loop_va += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t npages)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
+ rt_size_t l1_off, l2_off, l3_off;
+ rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
+
+ RT_ASSERT(mmu_info);
+
+ while (npages--)
+ {
+ l1_off = (rt_size_t)GET_L1(loop_va);
+ RT_ASSERT((l1_off >= mmu_info->vstart) && (l1_off <= mmu_info->vend));
+ l2_off = (rt_size_t)GET_L2(loop_va);
+ l3_off = (rt_size_t)GET_L3(loop_va);
+
+ mmu_l1 = ((rt_size_t *)mmu_info->vtable) + l1_off;
+ RT_ASSERT(PTE_USED(*mmu_l1))
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = ((rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), mmu_info->pv_off)) + l2_off;
+ RT_ASSERT(PTE_USED(*mmu_l2));
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l2));
+ mmu_l3 = ((rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l2), mmu_info->pv_off)) + l3_off;
+ RT_ASSERT(PTE_USED(*mmu_l3));
+ RT_ASSERT(PAGE_IS_LEAF(*(mmu_l3)));
+
+ *mmu_l3 = 0;
+ rt_hw_cpu_dcache_clean(mmu_l3, sizeof(*mmu_l3));
+
+ // decrease reference from leaf page to l3 page
+ mmu_l3 -= l3_off;
+ rt_pages_free(mmu_l3, 0);
+ int free = rt_page_ref_get(mmu_l3, 0);
+
+ if (free == 1)
+ {
+ // free l3 page
+ rt_pages_free(mmu_l3, 0);
+
+ *mmu_l2 = 0;
+ rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2));
+
+ // decrease reference from l3 page to l2 page
+ mmu_l2 -= l2_off;
+ rt_pages_free(mmu_l2, 0);
+
+ free = rt_page_ref_get(mmu_l2, 0);
+ if (free == 1)
+ {
+ // free l3 page
+ rt_pages_free(mmu_l2, 0);
+ // reset PTE in l1
+ *mmu_l1 = 0;
+ rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1));
+ }
+ }
+
+ loop_va += PAGE_SIZE;
+ }
+}
+
+static int _mmu_map_one_page(rt_mmu_info *mmu_info, size_t va, size_t pa, size_t attr)
+{
+ rt_size_t l1_off, l2_off, l3_off;
+ rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
+
+ l1_off = GET_L1(va);
+ l2_off = GET_L2(va);
+ l3_off = GET_L3(va);
+
+ mmu_l1 = ((rt_size_t *)mmu_info->vtable) + l1_off;
+
+ if (PTE_USED(*mmu_l1))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), mmu_info->pv_off);
+ }
+ else
+ {
+ mmu_l2 = (rt_size_t *)rt_pages_alloc(0);
+
+ if (mmu_l2)
+ {
+ rt_memset(mmu_l2, 0, PAGE_SIZE);
+ rt_hw_cpu_dcache_clean(mmu_l2, PAGE_SIZE);
+ *mmu_l1 = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l2, mmu_info->pv_off), PAGE_DEFAULT_ATTR_NEXT);
+ rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1));
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ if (PTE_USED(*(mmu_l2 + l2_off)))
+ {
+ RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off)));
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)), mmu_info->pv_off);
+ }
+ else
+ {
+ mmu_l3 = (rt_size_t *)rt_pages_alloc(0);
+
+ if (mmu_l3)
+ {
+ rt_memset(mmu_l3, 0, PAGE_SIZE);
+ rt_hw_cpu_dcache_clean(mmu_l3, PAGE_SIZE);
+ *(mmu_l2 + l2_off) = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l3, mmu_info->pv_off), PAGE_DEFAULT_ATTR_NEXT);
+ rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2));
+ // declares a reference to parent page table
+ rt_page_ref_inc((void *)mmu_l2, 0);
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ RT_ASSERT(!PTE_USED(*(mmu_l3 + l3_off)));
+ // declares a reference to parent page table
+ rt_page_ref_inc((void *)mmu_l3, 0);
+ *(mmu_l3 + l3_off) = COMBINEPTE((rt_size_t)pa, attr);
+ rt_hw_cpu_dcache_clean(mmu_l3 + l3_off, sizeof(*(mmu_l3 + l3_off)));
+ return 0;
+}
+
+static int __rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t npages, rt_size_t attr)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
+ rt_size_t loop_pa = __UMASKVALUE((rt_size_t)p_addr, PAGE_OFFSET_MASK);
+
+ if (!mmu_info)
+ {
+ return -1;
+ }
+
+ while (npages--)
+ {
+ if (_mmu_map_one_page(mmu_info, loop_va, loop_pa, attr) != 0)
+ {
+ __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
+ return -1;
+ }
+
+ loop_va += PAGE_SIZE;
+ loop_pa += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+void *_rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t size, rt_size_t attr)
+{
+ rt_size_t pa_s, pa_e;
+ rt_size_t vaddr;
+ rt_size_t pages;
+ int ret;
+
+ if (!size)
+ {
+ return 0;
+ }
+
+ pa_s = (rt_size_t)p_addr;
+ pa_e = ((rt_size_t)p_addr) + size - 1;
+ pa_s = GET_PF_ID(pa_s);
+ pa_e = GET_PF_ID(pa_e);
+ pages = pa_e - pa_s + 1;
+
+ if (v_addr)
+ {
+ vaddr = (rt_size_t)v_addr;
+ pa_s = (rt_size_t)p_addr;
+
+ if (GET_PF_OFFSET(vaddr) != GET_PF_OFFSET(pa_s))
+ {
+ return 0;
+ }
+
+ vaddr = __UMASKVALUE(vaddr, PAGE_OFFSET_MASK);
+
+ if (check_vaddr(mmu_info, (void *)vaddr, pages) != 0)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ vaddr = find_vaddr(mmu_info, pages);
+ }
+
+ if (vaddr)
+ {
+ ret = __rt_hw_mmu_map(mmu_info, (void *)vaddr, p_addr, pages, attr);
+
+ if (ret == 0)
+ {
+ rt_hw_cpu_tlb_invalidate();
+ return (void *)(vaddr | GET_PF_OFFSET((rt_size_t)p_addr));
+ }
+ }
+
+ return 0;
+}
+
+static int __rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, rt_size_t npages, rt_size_t attr)
+{
+ rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
+ rt_size_t loop_pa;
+ rt_size_t l1_off, l2_off, l3_off;
+ rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
+ rt_size_t *ref_cnt;
+ rt_size_t i;
+ void *va, *pa;
+
+ if (!mmu_info)
+ {
+ return -1;
+ }
+
+ while (npages--)
+ {
+ loop_pa = (rt_size_t)rt_pages_alloc(0);
+
+ if (!loop_pa)
+ {
+ goto err;
+ }
+
+ if (__rt_hw_mmu_map(mmu_info, (void *)loop_va, (void *)loop_pa, 1, attr) < 0)
+ {
+ goto err;
+ }
+
+ loop_va += PAGE_SIZE;
+ }
+
+ return 0;
+
+err:
+ va = (void *)__UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
+
+ for (i = 0; i < npages; i++)
+ {
+ pa = rt_hw_mmu_v2p(mmu_info, va);
+
+ if (pa)
+ {
+ rt_pages_free((void *)PPN_TO_VPN(pa, mmu_info->pv_off), 0);
+ }
+
+ va = (void *)((rt_uint8_t *)va + PAGE_SIZE);
+ }
+
+ __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
+ return -1;
+}
+
+void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size, rt_size_t attr)
+{
+ rt_size_t vaddr;
+ rt_size_t offset;
+ rt_size_t pages;
+ int ret;
+
+ if (!size)
+ {
+ return 0;
+ }
+
+ offset = GET_PF_OFFSET((rt_size_t)v_addr);
+ size += (offset + PAGE_SIZE - 1);
+ pages = size >> PAGE_OFFSET_BIT;
+
+ if (v_addr)
+ {
+ vaddr = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
+
+ if (check_vaddr(mmu_info, (void *)vaddr, pages) != 0)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ vaddr = find_vaddr(mmu_info, pages);
+ }
+
+ if (vaddr)
+ {
+ ret = __rt_hw_mmu_map_auto(mmu_info, (void *)vaddr, pages, attr);
+
+ if (ret == 0)
+ {
+ rt_hw_cpu_tlb_invalidate();
+ return (void *)(vaddr | offset);
+ }
+ }
+
+ return 0;
+}
+
+void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size)
+{
+ rt_size_t va_s, va_e;
+ rt_size_t pages;
+
+ va_s = ((rt_size_t)v_addr) >> PAGE_OFFSET_BIT;
+ va_e = (((rt_size_t)v_addr) + size - 1) >> PAGE_OFFSET_BIT;
+ pages = va_e - va_s + 1;
+ __rt_hw_mmu_unmap(mmu_info, v_addr, pages);
+ rt_hw_cpu_tlb_invalidate();
+}
+
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t size, rt_size_t attr)
+{
+ void *ret;
+ rt_base_t level;
+
+ rt_mm_lock();
+ ret = _rt_hw_mmu_map(mmu_info, v_addr, p_addr, size, attr);
+ rt_mm_unlock();
+ return ret;
+}
+
+void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size, rt_size_t attr)
+{
+ void *ret;
+ rt_base_t level;
+
+ rt_mm_lock();
+ ret = _rt_hw_mmu_map_auto(mmu_info, v_addr, size, attr);
+ rt_mm_unlock();
+ return ret;
+}
+
+void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size)
+{
+ rt_base_t level;
+
+ rt_mm_lock();
+ _rt_hw_mmu_unmap(mmu_info, v_addr, size);
+ rt_mm_unlock();
+}
+
+void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void *v_addr)
+{
+ rt_size_t l1_off, l2_off, l3_off;
+ rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
+ rt_size_t pa;
+
+ l1_off = GET_L1((rt_size_t)v_addr);
+ l2_off = GET_L2((rt_size_t)v_addr);
+ l3_off = GET_L3((rt_size_t)v_addr);
+
+ if (!mmu_info)
+ {
+ return RT_NULL;
+ }
+
+ mmu_l1 = ((rt_size_t *)mmu_info->vtable) + l1_off;
+
+ if (PTE_USED(*mmu_l1))
+ {
+ if (*mmu_l1 & PTE_XWR_MASK)
+ return (void *)(GET_PADDR(*mmu_l1) | ((rt_size_t)v_addr & ((1 << 30) - 1)));
+
+ mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), mmu_info->pv_off);
+
+ if (PTE_USED(*(mmu_l2 + l2_off)))
+ {
+ if (*(mmu_l2 + l2_off) & PTE_XWR_MASK)
+ return (void *)(GET_PADDR(*(mmu_l2 + l2_off)) | ((rt_size_t)v_addr & ((1 << 21) - 1)));
+
+ mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)), mmu_info->pv_off);
+
+ if (PTE_USED(*(mmu_l3 + l3_off)))
+ {
+ return (void *)(GET_PADDR(*(mmu_l3 + l3_off)) | GET_PF_OFFSET((rt_size_t)v_addr));
+ }
+ }
+ }
+
+ return RT_NULL;
+}
+
+void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void *v_addr)
+{
+ void *ret;
+ rt_base_t level;
+
+ rt_mm_lock();
+ ret = _rt_hw_mmu_v2p(mmu_info, v_addr);
+ rt_mm_unlock();
+ return ret;
+}
+
+/**
+ * @brief setup Page Table for kernel space. It's a fixed map
+ * and all mappings cannot be changed after initialization.
+ *
+ * Memory region in struct mem_desc must be page aligned,
+ * otherwise is a failure and no report will be
+ * returned.
+ *
+ * @param mmu_info
+ * @param mdesc
+ * @param desc_nr
+ */
+void rt_hw_mmu_setup(rt_mmu_info *mmu_info, struct mem_desc *mdesc, int desc_nr)
+{
+ void *err;
+ for (size_t i = 0; i < desc_nr; i++)
+ {
+ size_t attr;
+ switch (mdesc->attr)
+ {
+ case NORMAL_MEM:
+ attr = MMU_MAP_K_RWCB;
+ break;
+ case NORMAL_NOCACHE_MEM:
+ attr = MMU_MAP_K_RWCB;
+ break;
+ case DEVICE_MEM:
+ attr = MMU_MAP_K_DEVICE;
+ break;
+ default:
+ attr = MMU_MAP_K_DEVICE;
+ }
+ err = _rt_hw_mmu_map(mmu_info, (void *)mdesc->vaddr_start, (void *)mdesc->paddr_start,
+ mdesc->vaddr_end - mdesc->vaddr_start + 1, attr);
+ mdesc++;
+ }
+
+ rt_hw_mmu_switch((void *)MMUTable);
+}
diff --git a/libcpu/risc-v/virt64/mmu.h b/libcpu/risc-v/virt64/mmu.h
new file mode 100644
index 0000000000..086ad1edb9
--- /dev/null
+++ b/libcpu/risc-v/virt64/mmu.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#ifndef __MMU_H__
+#define __MMU_H__
+
+#include "riscv.h"
+#include "riscv_mmu.h"
+
+/* RAM, Flash, or ROM */
+#define NORMAL_MEM 0
+/* normal nocache memory mapping type */
+#define NORMAL_NOCACHE_MEM 1
+/* MMIO region */
+#define DEVICE_MEM 2
+
+struct mem_desc
+{
+ rt_size_t vaddr_start;
+ rt_size_t vaddr_end;
+ rt_size_t paddr_start;
+ rt_size_t attr;
+};
+
+#define GET_PF_ID(addr) ((addr) >> PAGE_OFFSET_BIT)
+#define GET_PF_OFFSET(addr) __MASKVALUE(addr, PAGE_OFFSET_MASK)
+#define GET_L1(addr) __PARTBIT(addr, VPN2_SHIFT, VPN2_BIT)
+#define GET_L2(addr) __PARTBIT(addr, VPN1_SHIFT, VPN1_BIT)
+#define GET_L3(addr) __PARTBIT(addr, VPN0_SHIFT, VPN0_BIT)
+#define GET_PPN(pte) (__PARTBIT(pte, PTE_PPN_SHIFT, PHYSICAL_ADDRESS_WIDTH_BITS - PTE_PPN_SHIFT))
+#define GET_PADDR(pte) (GET_PPN(pte) << PAGE_OFFSET_BIT)
+#define VPN_TO_PPN(vaddr, pv_off) (((rt_size_t)(vaddr)) + (pv_off))
+#define PPN_TO_VPN(paddr, pv_off) (((rt_size_t)(paddr)) - (pv_off))
+#define COMBINEVADDR(l1_off, l2_off, l3_off) (((l1_off) << VPN2_SHIFT) | ((l2_off) << VPN1_SHIFT) | ((l3_off) << VPN0_SHIFT))
+#define COMBINEPTE(paddr, attr) ((((paddr) >> PAGE_OFFSET_BIT) << PTE_PPN_SHIFT) | (attr))
+
+typedef struct
+{
+ size_t *vtable;
+ size_t vstart;
+ size_t vend;
+ size_t pv_off;
+} rt_mmu_info;
+
+void *rt_hw_mmu_tbl_get();
+void rt_hw_mmu_switch(void *mmu_table);
+int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void *v_address, rt_size_t size, rt_size_t *vtable, rt_size_t pv_off);
+void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info, rt_size_t vaddr_start, rt_size_t size);
+void *_rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t size, rt_size_t attr);
+void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size, rt_size_t attr);
+void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size);
+void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t size, rt_size_t attr);
+void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size, rt_size_t attr);
+void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t size);
+void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void *v_addr);
+void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void *v_addr);
+
+void rt_hw_mmu_setup(rt_mmu_info *mmu_info, struct mem_desc *mdesc, int desc_nr);
+
+#define ARCH_ADDRESS_WIDTH_BITS 64
+
+#define MMU_MAP_ERROR_VANOTALIGN -1
+#define MMU_MAP_ERROR_PANOTALIGN -2
+#define MMU_MAP_ERROR_NOPAGE -3
+#define MMU_MAP_ERROR_CONFLICT -4
+
+#endif
diff --git a/libcpu/risc-v/virt64/plic.c b/libcpu/risc-v/virt64/plic.c
new file mode 100644
index 0000000000..05167549d2
--- /dev/null
+++ b/libcpu/risc-v/virt64/plic.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-20 bigmagic first version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+#include <stdint.h>
+#include "plic.h"
+#include <riscv_io.h>
+#include "encoding.h"
+
+#include <riscv.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+* Each PLIC interrupt source can be assigned a priority by writing
+* to its 32-bit memory-mapped priority register.
+* The QEMU-virt (the same as FU540-C000) supports 7 levels of priority.
+* A priority value of 0 is reserved to mean "never interrupt" and
+* effectively disables the interrupt.
+* Priority 1 is the lowest active priority, and priority 7 is the highest.
+* Ties between global interrupts of the same priority are broken by
+* the Interrupt ID; interrupts with the lowest ID have the highest
+* effective priority.
+*/
+void plic_set_priority(int irq, int priority)
+{
+ *(uint32_t*)PLIC_PRIORITY(irq) = priority;
+}
+
+/*
+* Each global interrupt can be enabled by setting the corresponding
+* bit in the enables registers.
+*/
+void plic_irq_enable(int irq)
+{
+ int hart = __raw_hartid();
+ *(uint32_t*)PLIC_ENABLE(hart) = ((*(uint32_t*)PLIC_ENABLE(hart)) | (1 << irq));
+#ifdef RISCV_S_MODE
+ set_csr(sie, read_csr(sie) | MIP_SEIP);
+#else
+ set_csr(mie, read_csr(mie) | MIP_MEIP);
+#endif
+}
+
+void plic_irq_disable(int irq)
+{
+ int hart = __raw_hartid();
+ *(uint32_t*)PLIC_ENABLE(hart) = (((*(uint32_t*)PLIC_ENABLE(hart)) & (~(1 << irq))));
+}
+
+/*
+* PLIC will mask all interrupts of a priority less than or equal to threshold.
+* Maximum threshold is 7.
+* For example, a threshold value of zero permits all interrupts with
+* non-zero priority, whereas a value of 7 masks all interrupts.
+* Notice, the threshold is global for PLIC, not for each interrupt source.
+*/
+void plic_set_threshold(int threshold)
+{
+ int hart = __raw_hartid();
+ *(uint32_t*)PLIC_THRESHOLD(hart) = threshold;
+}
+
+/*
+ * DESCRIPTION:
+ * Query the PLIC what interrupt we should serve.
+ * Perform an interrupt claim by reading the claim register, which
+ * returns the ID of the highest-priority pending interrupt or zero if there
+ * is no pending interrupt.
+ * A successful claim also atomically clears the corresponding pending bit
+ * on the interrupt source.
+ * RETURN VALUE:
+ * the ID of the highest-priority pending interrupt or zero if there
+ * is no pending interrupt.
+ */
+int plic_claim(void)
+{
+ int hart = __raw_hartid();
+ int irq = *(uint32_t*)PLIC_CLAIM(hart);
+ return irq;
+}
+
+/*
+ * DESCRIPTION:
+ * Writing the interrupt ID it received from the claim (irq) to the
+ * complete register would signal the PLIC we've served this IRQ.
+ * The PLIC does not check whether the completion ID is the same as the
+ * last claim ID for that target. If the completion ID does not match an
+ * interrupt source that is currently enabled for the target, the completion
+ * is silently ignored.
+ * RETURN VALUE: none
+ */
+void plic_complete(int irq)
+{
+ int hart = __raw_hartid();
+ *(uint32_t*)PLIC_COMPLETE(hart) = irq;
+}
+
+void plic_set_ie(rt_uint32_t word_index, rt_uint32_t val)
+{
+ volatile void *plic_ie = (void *)(rt_size_t)(PLIC_BASE_ADDR + PLIC_ENABLE_BASE + word_index * 4);
+ writel(val, plic_ie);
+}
+
+void plic_init()
+{
+ int i;
+
+ plic_set_threshold(0);
+
+ for(i = 0;i < 128;i++)
+ {
+ plic_set_priority(i,7);
+ }
+
+ plic_set_ie(0,0xffffffff);
+ plic_set_ie(1,0xffffffff);
+ plic_set_ie(2,0xffffffff);
+ plic_set_ie(3,0xffffffff);
+
+ rt_uint64_t addr;
+
+ for(addr = 0xC001000;addr <= 0xC1F1F80;addr += 4)
+ {
+ *((rt_uint32_t *)addr) = 0xffffffff;
+ }
+}
diff --git a/libcpu/risc-v/virt64/plic.h b/libcpu/risc-v/virt64/plic.h
new file mode 100644
index 0000000000..b1509f1fd1
--- /dev/null
+++ b/libcpu/risc-v/virt64/plic.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-20 bigmagic first version
+ * 2021-10-20 bernard fix s-mode issue
+ */
+
+#ifndef __PLIC_H__
+#define __PLIC_H__
+
+#include <rtconfig.h>
+#include <rthw.h>
+
+/*
+ * This machine puts platform-level interrupt controller (PLIC) here.
+ * Here only list PLIC registers in Machine mode.
+ *
+ */
+
+#define PLIC_PRIORITY_BASE 0x0
+#define PLIC_PENDING_BASE 0x1000
+#define PLIC_ENABLE_BASE 0x2000
+#define PLIC_CONTEXT_BASE 0x200000
+
+#define PLIC_BASE_ADDR 0xC000000
+
+#define VIRT_PLIC_BASE 0x0c000000L
+
+#define PLIC_PRIORITY_OFFSET (0x0)
+#define PLIC_PENDING_OFFSET (0x1000)
+
+#define PLIC_ENABLE_STRIDE 0x80
+#define PLIC_CONTEXT_STRIDE 0x1000
+
+#ifndef RISCV_S_MODE
+#define PLIC_MENABLE_OFFSET (0x2000)
+#define PLIC_MTHRESHOLD_OFFSET (0x200000)
+#define PLIC_MCLAIM_OFFSET (0x200004)
+#define PLIC_MCOMPLETE_OFFSET (0x200004)
+
+#define PLIC_ENABLE(hart) (VIRT_PLIC_BASE + PLIC_MENABLE_OFFSET + (hart * 2) * PLIC_ENABLE_STRIDE)
+#define PLIC_THRESHOLD(hart) (VIRT_PLIC_BASE + PLIC_MTHRESHOLD_OFFSET + (hart * 2) * PLIC_CONTEXT_STRIDE)
+#define PLIC_CLAIM(hart) (VIRT_PLIC_BASE + PLIC_MCLAIM_OFFSET + (hart * 2) * PLIC_CONTEXT_STRIDE)
+#define PLIC_COMPLETE(hart) (VIRT_PLIC_BASE + PLIC_MCOMPLETE_OFFSET + (hart * 2) * PLIC_CONTEXT_STRIDE)
+
+#else
+#define PLIC_SENABLE_OFFSET (0x2000 + PLIC_ENABLE_STRIDE)
+#define PLIC_STHRESHOLD_OFFSET (0x200000 + PLIC_CONTEXT_STRIDE)
+#define PLIC_SCLAIM_OFFSET (0x200004 + PLIC_CONTEXT_STRIDE)
+#define PLIC_SCOMPLETE_OFFSET (0x200004 + PLIC_CONTEXT_STRIDE)
+
+#define PLIC_ENABLE(hart) (VIRT_PLIC_BASE + PLIC_SENABLE_OFFSET + (hart * 2) * PLIC_ENABLE_STRIDE)
+#define PLIC_THRESHOLD(hart) (VIRT_PLIC_BASE + PLIC_STHRESHOLD_OFFSET + (hart * 2) * PLIC_CONTEXT_STRIDE)
+#define PLIC_CLAIM(hart) (VIRT_PLIC_BASE + PLIC_SCLAIM_OFFSET + (hart * 2) * PLIC_CONTEXT_STRIDE)
+#define PLIC_COMPLETE(hart) (VIRT_PLIC_BASE + PLIC_SCOMPLETE_OFFSET + (hart * 2) * PLIC_CONTEXT_STRIDE)
+#endif
+
+#define PLIC_PRIORITY(id) (VIRT_PLIC_BASE + PLIC_PRIORITY_OFFSET + (id) * 4)
+#define PLIC_PENDING(id) (VIRT_PLIC_BASE + PLIC_PENDING_OFFSET + ((id) / 32))
+
+void plic_set_priority(int irq, int priority);
+void plic_irq_enable(int irq);
+void plic_irq_disable(int irq);
+void plic_set_threshold(int mthreshold);
+int plic_claim(void);
+void plic_complete(int irq);
+
+void plic_set_thresh(rt_uint32_t val);
+void plic_set_ie(rt_uint32_t word_index,rt_uint32_t val);
+void plic_init();
+
+#endif
diff --git a/libcpu/risc-v/virt64/riscv_io.h b/libcpu/risc-v/virt64/riscv_io.h
index 7dcc98f70a..b92e24e4c9 100644
--- a/libcpu/risc-v/virt64/riscv_io.h
+++ b/libcpu/risc-v/virt64/riscv_io.h
@@ -12,14 +12,8 @@
static inline uint32_t __raw_hartid(void)
{
-#ifdef RISCV_S_MODE
extern int boot_hartid;
return boot_hartid;
-#else
- uint32_t x;
- asm volatile("csrr %0, mhartid" : "=r" (x) );
- return x;
-#endif
}
static inline void __raw_writeb(rt_uint8_t val, volatile void *addr)
diff --git a/libcpu/risc-v/virt64/riscv_mmu.c b/libcpu/risc-v/virt64/riscv_mmu.c
new file mode 100644
index 0000000000..e79ca8b37b
--- /dev/null
+++ b/libcpu/risc-v/virt64/riscv_mmu.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include <stdint.h>
+#include <riscv.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "riscv_mmu.h"
+
+void mmu_set_pagetable(rt_ubase_t addr)
+{
+ RT_ASSERT(__CHECKALIGN(addr, PAGE_OFFSET_BIT));
+ RT_ASSERT(__CHECKUPBOUND(addr, PHYSICAL_ADDRESS_WIDTH_BITS));
+
+ mmu_flush_tlb();
+ write_csr(satp, (((size_t)SATP_MODE) << SATP_MODE_OFFSET) | (addr >> PAGE_OFFSET_BIT));
+ mmu_flush_tlb();
+}
+
+void mmu_enable_user_page_access()
+{
+ set_csr(sstatus, SSTATUS_SUM);
+}
+
+void mmu_disable_user_page_access()
+{
+ clear_csr(sstatus, SSTATUS_SUM);
+}
diff --git a/libcpu/risc-v/virt64/riscv_mmu.h b/libcpu/risc-v/virt64/riscv_mmu.h
new file mode 100644
index 0000000000..04c4201aab
--- /dev/null
+++ b/libcpu/risc-v/virt64/riscv_mmu.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ */
+
+#ifndef __RISCV_MMU_H__
+#define __RISCV_MMU_H__
+
+#include <rtthread.h>
+#include <rthw.h>
+#include "riscv.h"
+
+#undef PAGE_SIZE
+
+#define PAGE_OFFSET_SHIFT 0
+#define PAGE_OFFSET_BIT 12
+#define PAGE_SIZE __SIZE(PAGE_OFFSET_BIT)
+#define PAGE_OFFSET_MASK __MASK(PAGE_OFFSET_BIT)
+#define VPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT)
+#define VPN0_BIT 9
+#define VPN1_SHIFT (VPN0_SHIFT + VPN0_BIT)
+#define VPN1_BIT 9
+#define VPN2_SHIFT (VPN1_SHIFT + VPN1_BIT)
+#define VPN2_BIT 9
+
+#define PPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT)
+#define PPN0_BIT 9
+#define PPN1_SHIFT (PPN0_SHIFT + PPN0_BIT)
+#define PPN1_BIT 9
+#define PPN2_SHIFT (PPN1_SHIFT + PPN1_BIT)
+#define PPN2_BIT 26
+
+#define L1_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT + VPN1_BIT)
+#define L2_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT)
+#define L3_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT)
+
+#define ARCH_ADDRESS_WIDTH_BITS 64
+
+#define PHYSICAL_ADDRESS_WIDTH_BITS 56
+
+#define PAGE_ATTR_NEXT_LEVEL (0)
+#define PAGE_ATTR_RWX (PTE_X | PTE_W | PTE_R)
+#define PAGE_ATTR_READONLY (PTE_R)
+#define PAGE_ATTR_READEXECUTE (PTE_X | PTE_R)
+
+#define PAGE_ATTR_USER (PTE_U)
+#define PAGE_ATTR_SYSTEM (0)
+
+#define PAGE_DEFAULT_ATTR_LEAF (PAGE_ATTR_RWX | PAGE_ATTR_USER | PTE_V | PTE_G)
+#define PAGE_DEFAULT_ATTR_NEXT (PAGE_ATTR_NEXT_LEVEL | PTE_V | PTE_G)
+
+#define PAGE_IS_LEAF(pte) __MASKVALUE(pte, PAGE_ATTR_RWX)
+
+#define PTE_USED(pte) __MASKVALUE(pte, PTE_V)
+
+/**
+ * encoding of SATP (Supervisor Address Translation and Protection register)
+ */
+#define SATP_MODE_OFFSET 60
+#define SATP_MODE_BARE 0
+#define SATP_MODE_SV39 8
+#define SATP_MODE_SV48 9
+#define SATP_MODE_SV57 10
+#define SATP_MODE_SV64 11
+
+#define ARCH_VA_WIDTH 39
+#define SATP_MODE SATP_MODE_SV39
+
+#define mmu_flush_tlb() \
+ do \
+ { \
+ asm volatile("sfence.vma x0,x0"); \
+ } while (0)
+
+
+#define MMU_MAP_K_DEVICE (PTE_G | PTE_W | PTE_R | PTE_V)
+#define MMU_MAP_K_RWCB (PTE_G | PTE_X | PTE_W | PTE_R | PTE_V)
+#define MMU_MAP_U_RWCB (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V)
+#define MMU_MAP_U_RWCB_XN (PTE_U | PTE_W | PTE_R | PTE_V)
+#define MMU_MAP_U_RW (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V)
+
+#define PTE_XWR_MASK 0xe
+
+#define ARCH_PAGE_SIZE PAGE_SIZE
+#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
+#define ARCH_PAGE_SHIFT PAGE_OFFSET_BIT
+#define ARCH_INDEX_WIDTH 9
+#define ARCH_INDEX_SIZE (1ul << ARCH_INDEX_WIDTH)
+#define ARCH_INDEX_MASK (ARCH_INDEX_SIZE - 1)
+
+void mmu_set_pagetable(rt_ubase_t addr);
+void mmu_enable_user_page_access();
+void mmu_disable_user_page_access();
+
+#endif
diff --git a/libcpu/risc-v/virt64/sbi.c b/libcpu/risc-v/virt64/sbi.c
new file mode 100644
index 0000000000..5dd021df8a
--- /dev/null
+++ b/libcpu/risc-v/virt64/sbi.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Bernard port from FreeBSD
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Mitchell Horne <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "sbi.h"
+#include <stdbool.h>
+#include <rtthread.h>
+
+/* SBI Implementation-Specific Definitions */
+#define OPENSBI_VERSION_MAJOR_OFFSET 16
+#define OPENSBI_VERSION_MINOR_MASK 0xFFFF
+
+unsigned long sbi_spec_version;
+unsigned long sbi_impl_id;
+unsigned long sbi_impl_version;
+
+static bool has_time_extension = false;
+static bool has_ipi_extension = false;
+static bool has_rfnc_extension = false;
+
+static struct sbi_ret
+sbi_get_spec_version(void)
+{
+ return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION));
+}
+
+static struct sbi_ret
+sbi_get_impl_id(void)
+{
+ return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID));
+}
+
+static struct sbi_ret
+sbi_get_impl_version(void)
+{
+ return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION));
+}
+
+void sbi_print_version(void)
+{
+ u_int major;
+ u_int minor;
+
+ /* For legacy SBI implementations. */
+ if (sbi_spec_version == 0)
+ {
+ rt_kprintf("SBI: Unknown (Legacy) Implementation\n");
+ rt_kprintf("SBI Specification Version: 0.1\n");
+ return;
+ }
+
+ switch (sbi_impl_id)
+ {
+ case (SBI_IMPL_ID_BBL):
+ rt_kprintf("SBI: Berkely Boot Loader %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_XVISOR):
+ rt_kprintf("SBI: eXtensible Versatile hypervISOR %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_KVM):
+ rt_kprintf("SBI: Kernel-based Virtual Machine %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_RUSTSBI):
+ rt_kprintf("SBI: RustSBI %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_DIOSIX):
+ rt_kprintf("SBI: Diosix %lu\n", sbi_impl_version);
+ break;
+ case (SBI_IMPL_ID_OPENSBI):
+ major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET;
+ minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK;
+ rt_kprintf("SBI: OpenSBI v%u.%u\n", major, minor);
+ break;
+ default:
+ rt_kprintf("SBI: Unrecognized Implementation: %lu\n", sbi_impl_id);
+ break;
+ }
+
+ major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >>
+ SBI_SPEC_VERS_MAJOR_OFFSET;
+ minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK);
+ rt_kprintf("SBI Specification Version: %u.%u\n", major, minor);
+}
+
+void sbi_set_timer(uint64_t val)
+{
+ struct sbi_ret ret;
+
+ /* Use the TIME legacy replacement extension, if available. */
+ if (has_time_extension)
+ {
+ ret = SBI_CALL1(SBI_EXT_ID_TIME, SBI_TIME_SET_TIMER, val);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL1(SBI_SET_TIMER, 0, val);
+ }
+}
+
+void sbi_send_ipi(const unsigned long *hart_mask)
+{
+ struct sbi_ret ret;
+
+ /* Use the IPI legacy replacement extension, if available. */
+ if (has_ipi_extension)
+ {
+ ret = SBI_CALL2(SBI_EXT_ID_IPI, SBI_IPI_SEND_IPI,
+ *hart_mask, 0);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL1(SBI_SEND_IPI, 0, (uint64_t)hart_mask);
+ }
+}
+
+void sbi_remote_fence_i(const unsigned long *hart_mask)
+{
+ struct sbi_ret ret;
+
+ /* Use the RFENCE legacy replacement extension, if available. */
+ if (has_rfnc_extension)
+ {
+ ret = SBI_CALL2(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_FENCE_I,
+ *hart_mask, 0);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL1(SBI_REMOTE_FENCE_I, 0, (uint64_t)hart_mask);
+ }
+}
+
+void sbi_remote_sfence_vma(const unsigned long *hart_mask, unsigned long start, unsigned long size)
+{
+ struct sbi_ret ret;
+
+ /* Use the RFENCE legacy replacement extension, if available. */
+ if (has_rfnc_extension)
+ {
+ ret = SBI_CALL4(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA,
+ *hart_mask, 0, start, size);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL3(SBI_REMOTE_SFENCE_VMA, 0, (uint64_t)hart_mask,
+ start, size);
+ }
+}
+
+void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, unsigned long start, unsigned long size,
+ unsigned long asid)
+{
+ struct sbi_ret ret;
+
+ /* Use the RFENCE legacy replacement extension, if available. */
+ if (has_rfnc_extension)
+ {
+ ret = SBI_CALL5(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA_ASID,
+ *hart_mask, 0, start, size, asid);
+ RT_ASSERT(ret.error == SBI_SUCCESS);
+ }
+ else
+ {
+ (void)SBI_CALL4(SBI_REMOTE_SFENCE_VMA_ASID, 0,
+ (uint64_t)hart_mask, start, size, asid);
+ }
+}
+
+int sbi_hsm_hart_start(unsigned long hart, unsigned long start_addr, unsigned long priv)
+{
+ struct sbi_ret ret;
+
+ ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr, priv);
+ return (ret.error != 0 ? (int)ret.error : 0);
+}
+
+void sbi_hsm_hart_stop(void)
+{
+ (void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP);
+}
+
+int sbi_hsm_hart_status(unsigned long hart)
+{
+ struct sbi_ret ret;
+
+ ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart);
+
+ return (ret.error != 0 ? (int)ret.error : (int)ret.value);
+}
+
+void sbi_init(void)
+{
+ struct sbi_ret sret;
+
+ /*
+ * Get the spec version. For legacy SBI implementations this will
+ * return an error, otherwise it is guaranteed to succeed.
+ */
+ sret = sbi_get_spec_version();
+ if (sret.error != 0)
+ {
+ /* We are running a legacy SBI implementation. */
+ sbi_spec_version = 0;
+ return;
+ }
+
+ /* Set the SBI implementation info. */
+ sbi_spec_version = sret.value;
+ sbi_impl_id = sbi_get_impl_id().value;
+ sbi_impl_version = sbi_get_impl_version().value;
+
+ /* Probe for legacy replacement extensions. */
+ if (sbi_probe_extension(SBI_EXT_ID_TIME) != 0)
+ has_time_extension = true;
+ if (sbi_probe_extension(SBI_EXT_ID_IPI) != 0)
+ has_ipi_extension = true;
+ if (sbi_probe_extension(SBI_EXT_ID_RFNC) != 0)
+ has_rfnc_extension = true;
+}
+
+void rt_hw_console_output(const char *str)
+{
+ while (*str)
+ {
+ sbi_console_putchar(*str++);
+ }
+}
diff --git a/libcpu/risc-v/virt64/sbi.h b/libcpu/risc-v/virt64/sbi.h
new file mode 100644
index 0000000000..0e95ede334
--- /dev/null
+++ b/libcpu/risc-v/virt64/sbi.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-18 Bernard port from FreeBSD
+ */
+
+/*-
+ * Copyright (c) 2016-2017 Ruslan Bukin <[email protected]>
+ * All rights reserved.
+ * Copyright (c) 2019 Mitchell Horne <[email protected]>
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_SBI_H_
+#define _MACHINE_SBI_H_
+
+#include <rtdef.h>
+
+/* SBI Specification Version */
+#define SBI_SPEC_VERS_MAJOR_OFFSET 24
+#define SBI_SPEC_VERS_MAJOR_MASK (0x7F << SBI_SPEC_VERS_MAJOR_OFFSET)
+#define SBI_SPEC_VERS_MINOR_OFFSET 0
+#define SBI_SPEC_VERS_MINOR_MASK (0xFFFFFF << SBI_SPEC_VERS_MINOR_OFFSET)
+
+/* SBI Implementation IDs */
+#define SBI_IMPL_ID_BBL 0
+#define SBI_IMPL_ID_OPENSBI 1
+#define SBI_IMPL_ID_XVISOR 2
+#define SBI_IMPL_ID_KVM 3
+#define SBI_IMPL_ID_RUSTSBI 4
+#define SBI_IMPL_ID_DIOSIX 5
+
+/* SBI Error Codes */
+#define SBI_SUCCESS 0
+#define SBI_ERR_FAILURE -1
+#define SBI_ERR_NOT_SUPPORTED -2
+#define SBI_ERR_INVALID_PARAM -3
+#define SBI_ERR_DENIED -4
+#define SBI_ERR_INVALID_ADDRESS -5
+#define SBI_ERR_ALREADY_AVAILABLE -6
+
+/* SBI Base Extension */
+#define SBI_EXT_ID_BASE 0x10
+#define SBI_BASE_GET_SPEC_VERSION 0
+#define SBI_BASE_GET_IMPL_ID 1
+#define SBI_BASE_GET_IMPL_VERSION 2
+#define SBI_BASE_PROBE_EXTENSION 3
+#define SBI_BASE_GET_MVENDORID 4
+#define SBI_BASE_GET_MARCHID 5
+#define SBI_BASE_GET_MIMPID 6
+
+/* Timer (TIME) Extension */
+#define SBI_EXT_ID_TIME 0x54494D45
+#define SBI_TIME_SET_TIMER 0
+
+/* IPI (IPI) Extension */
+#define SBI_EXT_ID_IPI 0x735049
+#define SBI_IPI_SEND_IPI 0
+
+/* RFENCE (RFNC) Extension */
+#define SBI_EXT_ID_RFNC 0x52464E43
+#define SBI_RFNC_REMOTE_FENCE_I 0
+#define SBI_RFNC_REMOTE_SFENCE_VMA 1
+#define SBI_RFNC_REMOTE_SFENCE_VMA_ASID 2
+#define SBI_RFNC_REMOTE_HFENCE_GVMA_VMID 3
+#define SBI_RFNC_REMOTE_HFENCE_GVMA 4
+#define SBI_RFNC_REMOTE_HFENCE_VVMA_ASID 5
+#define SBI_RFNC_REMOTE_HFENCE_VVMA 6
+
+/* Hart State Management (HSM) Extension */
+#define SBI_EXT_ID_HSM 0x48534D
+#define SBI_HSM_HART_START 0
+#define SBI_HSM_HART_STOP 1
+#define SBI_HSM_HART_STATUS 2
+#define SBI_HSM_STATUS_STARTED 0
+#define SBI_HSM_STATUS_STOPPED 1
+#define SBI_HSM_STATUS_START_PENDING 2
+#define SBI_HSM_STATUS_STOP_PENDING 3
+
+/* Legacy Extensions */
+#define SBI_SET_TIMER 0
+#define SBI_CONSOLE_PUTCHAR 1
+#define SBI_CONSOLE_GETCHAR 2
+#define SBI_CLEAR_IPI 3
+#define SBI_SEND_IPI 4
+#define SBI_REMOTE_FENCE_I 5
+#define SBI_REMOTE_SFENCE_VMA 6
+#define SBI_REMOTE_SFENCE_VMA_ASID 7
+#define SBI_SHUTDOWN 8
+
+#define SBI_CALL0(e, f) SBI_CALL5(e, f, 0, 0, 0, 0, 0)
+#define SBI_CALL1(e, f, p1) SBI_CALL5(e, f, p1, 0, 0, 0, 0)
+#define SBI_CALL2(e, f, p1, p2) SBI_CALL5(e, f, p1, p2, 0, 0, 0)
+#define SBI_CALL3(e, f, p1, p2, p3) SBI_CALL5(e, f, p1, p2, p3, 0, 0)
+#define SBI_CALL4(e, f, p1, p2, p3, p4) SBI_CALL5(e, f, p1, p2, p3, p4, 0)
+#define SBI_CALL5(e, f, p1, p2, p3, p4, p5) sbi_call(e, f, p1, p2, p3, p4, p5)
+
+/*
+ * Documentation available at
+ * https://github.com/riscv/riscv-sbi-doc/blob/master/riscv-sbi.adoc
+ */
+
+struct sbi_ret
+{
+ long error;
+ long value;
+};
+
+static __inline struct sbi_ret
+sbi_call(uint64_t arg7, uint64_t arg6, uint64_t arg0, uint64_t arg1,
+ uint64_t arg2, uint64_t arg3, uint64_t arg4)
+{
+ struct sbi_ret ret;
+
+ register uintptr_t a0 __asm("a0") = (uintptr_t)(arg0);
+ register uintptr_t a1 __asm("a1") = (uintptr_t)(arg1);
+ register uintptr_t a2 __asm("a2") = (uintptr_t)(arg2);
+ register uintptr_t a3 __asm("a3") = (uintptr_t)(arg3);
+ register uintptr_t a4 __asm("a4") = (uintptr_t)(arg4);
+ register uintptr_t a6 __asm("a6") = (uintptr_t)(arg6);
+ register uintptr_t a7 __asm("a7") = (uintptr_t)(arg7);
+
+ __asm __volatile(\
+ "ecall" \
+ : "+r"(a0), "+r"(a1) \
+ : "r"(a2), "r"(a3), "r"(a4), "r"(a6), "r"(a7) \
+ : "memory");
+
+ ret.error = a0;
+ ret.value = a1;
+ return (ret);
+}
+
+/* Base extension functions and variables. */
+extern unsigned long sbi_spec_version;
+extern unsigned long sbi_impl_id;
+extern unsigned long sbi_impl_version;
+
+static __inline long
+sbi_probe_extension(long id)
+{
+ return (SBI_CALL1(SBI_EXT_ID_BASE, SBI_BASE_PROBE_EXTENSION, id).value);
+}
+
+/* TIME extension functions. */
+void sbi_set_timer(uint64_t val);
+
+/* IPI extension functions. */
+void sbi_send_ipi(const unsigned long *hart_mask);
+
+/* RFENCE extension functions. */
+void sbi_remote_fence_i(const unsigned long *hart_mask);
+void sbi_remote_sfence_vma(const unsigned long *hart_mask, unsigned long start, unsigned long size);
+void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, unsigned long start,
+ unsigned long size, unsigned long asid);
+
+/* Hart State Management extension functions. */
+
+/*
+ * Start execution on the specified hart at physical address start_addr. The
+ * register a0 will contain the hart's ID, and a1 will contain the value of
+ * priv.
+ */
+int sbi_hsm_hart_start(unsigned long hart, unsigned long start_addr, unsigned long priv);
+
+/*
+ * Stop execution on the current hart. Interrupts should be disabled, or this
+ * function may return.
+ */
+void sbi_hsm_hart_stop(void);
+
+/*
+ * Get the execution status of the specified hart. The status will be one of:
+ * - SBI_HSM_STATUS_STARTED
+ * - SBI_HSM_STATUS_STOPPED
+ * - SBI_HSM_STATUS_START_PENDING
+ * - SBI_HSM_STATUS_STOP_PENDING
+ */
+int sbi_hsm_hart_status(unsigned long hart);
+
+/* Legacy extension functions. */
+static __inline void
+sbi_console_putchar(int ch)
+{
+ (void)SBI_CALL1(SBI_CONSOLE_PUTCHAR, 0, ch);
+}
+
+static __inline int
+sbi_console_getchar(void)
+{
+ /*
+ * XXX: The "error" is returned here because legacy SBI functions
+ * continue to return their value in a0.
+ */
+ return (SBI_CALL0(SBI_CONSOLE_GETCHAR, 0).error);
+}
+
+static __inline void
+sbi_shutdown(void)
+{
+ (void)SBI_CALL0(SBI_SHUTDOWN, 0);
+}
+
+void sbi_print_version(void);
+void sbi_init(void);
+
+#endif /* !_MACHINE_SBI_H_ */
diff --git a/libcpu/risc-v/virt64/stack.h b/libcpu/risc-v/virt64/stack.h
index 09179238ea..d619d3fd35 100644
--- a/libcpu/risc-v/virt64/stack.h
+++ b/libcpu/risc-v/virt64/stack.h
@@ -16,7 +16,7 @@ struct rt_hw_stack_frame
{
rt_ubase_t epc; /* epc - epc - program counter */
rt_ubase_t ra; /* x1 - ra - return address for jumps */
- rt_ubase_t xstatus; /* - supervisor/machine/user status register */
+ rt_ubase_t sstatus; /* - supervisor status register */
rt_ubase_t gp; /* x3 - gp - global pointer */
rt_ubase_t tp; /* x4 - tp - thread pointer */
rt_ubase_t t0; /* x5 - t0 - temporary register 0 */
@@ -47,6 +47,12 @@ struct rt_hw_stack_frame
rt_ubase_t t5; /* x30 - t5 - temporary register 5 */
rt_ubase_t t6; /* x31 - t6 - temporary register 6 */
rt_ubase_t user_sp_exc_stack; /* sscratch - user mode sp/exception stack */
+#ifdef ENABLE_FPU
+ rt_ubase_t f[CTX_FPU_REG_NR]; /* f0~f31 */
+#endif
+#ifdef ENABLE_VECTOR
+ rt_ubase_t v[CTX_VECTOR_REG_NR];
+#endif
};
#endif
diff --git a/libcpu/risc-v/virt64/stackframe.h b/libcpu/risc-v/virt64/stackframe.h
index eb4e4f9d86..5b546f01f9 100644
--- a/libcpu/risc-v/virt64/stackframe.h
+++ b/libcpu/risc-v/virt64/stackframe.h
@@ -7,26 +7,45 @@
* Date Author Notes
* 2021-02-02 lizhirui first version
* 2021-02-11 lizhirui fixed gp save/store bug
+ * 2021-11-18 JasonHu add fpu registers save/restore
+ * 2022/10/22 WangXiaoyao Support kernel mode RVV;
*/
#ifndef __STACKFRAME_H__
#define __STACKFRAME_H__
#include "cpuport.h"
+#include "encoding.h"
+#include "ext_context.h"
+
+#define BYTES(idx) ((idx) * REGBYTES)
+#define FRAME_OFF_SSTATUS BYTES(2)
+
+#ifdef __ASSEMBLY__
.macro SAVE_ALL
- addi sp, sp, -33 * REGBYTES
+#ifdef ENABLE_FPU
+ /* reserve float registers */
+ addi sp, sp, -CTX_FPU_REG_NR * REGBYTES
+#endif /* ENABLE_FPU */
+#ifdef ENABLE_VECTOR
+ /* reserve float registers */
+ addi sp, sp, -CTX_VECTOR_REG_NR * REGBYTES
+#endif /* ENABLE_VECTOR */
+
+ /* save general registers */
+ addi sp, sp, -CTX_GENERAL_REG_NR * REGBYTES
STORE x1, 1 * REGBYTES(sp)
- csrr x1, SRC_XSTATUS
- STORE x1, 2 * REGBYTES(sp)
+ csrr x1, sstatus
+ STORE x1, FRAME_OFF_SSTATUS(sp)
- csrr x1, SRC_XEPC
- STORE x1, 0 * REGBYTES(sp)
+ csrr x1, sepc
+ STORE x1, 0 * REGBYTES(sp)
STORE x3, 3 * REGBYTES(sp)
- STORE x4, 4 * REGBYTES(sp)
+ STORE x4, 4 * REGBYTES(sp) /* save tp */
STORE x5, 5 * REGBYTES(sp)
STORE x6, 6 * REGBYTES(sp)
STORE x7, 7 * REGBYTES(sp)
@@ -54,65 +73,154 @@
STORE x29, 29 * REGBYTES(sp)
STORE x30, 30 * REGBYTES(sp)
STORE x31, 31 * REGBYTES(sp)
- csrr t0, SRC_XSCRATCH
+ csrr t0, sscratch
STORE t0, 32 * REGBYTES(sp)
-.endm
-.macro RESTORE_ALL_ONLY
- /* resw ra to sepc */
- LOAD x1, 0 * REGBYTES(sp)
- csrw SRC_XEPC, x1
+#ifdef ENABLE_FPU
+ /* backup sp and adjust sp to save float registers */
+ mv t1, sp
+ addi t1, t1, CTX_GENERAL_REG_NR * REGBYTES
- LOAD x1, 2 * REGBYTES(sp)
- csrw SRC_XSTATUS, x1
+ li t0, SSTATUS_FS
+ csrs sstatus, t0
+ fsd f0, FPU_CTX_F0_OFF(t1)
+ fsd f1, FPU_CTX_F1_OFF(t1)
+ fsd f2, FPU_CTX_F2_OFF(t1)
+ fsd f3, FPU_CTX_F3_OFF(t1)
+ fsd f4, FPU_CTX_F4_OFF(t1)
+ fsd f5, FPU_CTX_F5_OFF(t1)
+ fsd f6, FPU_CTX_F6_OFF(t1)
+ fsd f7, FPU_CTX_F7_OFF(t1)
+ fsd f8, FPU_CTX_F8_OFF(t1)
+ fsd f9, FPU_CTX_F9_OFF(t1)
+ fsd f10, FPU_CTX_F10_OFF(t1)
+ fsd f11, FPU_CTX_F11_OFF(t1)
+ fsd f12, FPU_CTX_F12_OFF(t1)
+ fsd f13, FPU_CTX_F13_OFF(t1)
+ fsd f14, FPU_CTX_F14_OFF(t1)
+ fsd f15, FPU_CTX_F15_OFF(t1)
+ fsd f16, FPU_CTX_F16_OFF(t1)
+ fsd f17, FPU_CTX_F17_OFF(t1)
+ fsd f18, FPU_CTX_F18_OFF(t1)
+ fsd f19, FPU_CTX_F19_OFF(t1)
+ fsd f20, FPU_CTX_F20_OFF(t1)
+ fsd f21, FPU_CTX_F21_OFF(t1)
+ fsd f22, FPU_CTX_F22_OFF(t1)
+ fsd f23, FPU_CTX_F23_OFF(t1)
+ fsd f24, FPU_CTX_F24_OFF(t1)
+ fsd f25, FPU_CTX_F25_OFF(t1)
+ fsd f26, FPU_CTX_F26_OFF(t1)
+ fsd f27, FPU_CTX_F27_OFF(t1)
+ fsd f28, FPU_CTX_F28_OFF(t1)
+ fsd f29, FPU_CTX_F29_OFF(t1)
+ fsd f30, FPU_CTX_F30_OFF(t1)
+ fsd f31, FPU_CTX_F31_OFF(t1)
- LOAD x1, 1 * REGBYTES(sp)
+ /* clr FS domain */
+ csrc sstatus, t0
- LOAD x3, 3 * REGBYTES(sp)
- LOAD x4, 4 * REGBYTES(sp)
- LOAD x5, 5 * REGBYTES(sp)
- LOAD x6, 6 * REGBYTES(sp)
- LOAD x7, 7 * REGBYTES(sp)
- LOAD x8, 8 * REGBYTES(sp)
- LOAD x9, 9 * REGBYTES(sp)
- LOAD x10, 10 * REGBYTES(sp)
- LOAD x11, 11 * REGBYTES(sp)
- LOAD x12, 12 * REGBYTES(sp)
- LOAD x13, 13 * REGBYTES(sp)
- LOAD x14, 14 * REGBYTES(sp)
- LOAD x15, 15 * REGBYTES(sp)
- LOAD x16, 16 * REGBYTES(sp)
- LOAD x17, 17 * REGBYTES(sp)
- LOAD x18, 18 * REGBYTES(sp)
- LOAD x19, 19 * REGBYTES(sp)
- LOAD x20, 20 * REGBYTES(sp)
- LOAD x21, 21 * REGBYTES(sp)
- LOAD x22, 22 * REGBYTES(sp)
- LOAD x23, 23 * REGBYTES(sp)
- LOAD x24, 24 * REGBYTES(sp)
- LOAD x25, 25 * REGBYTES(sp)
- LOAD x26, 26 * REGBYTES(sp)
- LOAD x27, 27 * REGBYTES(sp)
- LOAD x28, 28 * REGBYTES(sp)
- LOAD x29, 29 * REGBYTES(sp)
- LOAD x30, 30 * REGBYTES(sp)
- LOAD x31, 31 * REGBYTES(sp)
+ /* clean status would clr sr_sd; */
+ li t0, SSTATUS_FS_CLEAN
+ csrs sstatus, t0
- addi sp, sp, 33 * REGBYTES
+#endif /* ENABLE_FPU */
+
+#ifdef ENABLE_VECTOR
+ csrr t0, sstatus
+ andi t0, t0, SSTATUS_VS
+ beqz t0, 0f
+
+ /* push vector frame */
+ addi t1, sp, (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR) * REGBYTES
+
+ SAVE_VECTOR t1
+0:
+#endif /* ENABLE_VECTOR */
.endm
+/**
+ * @brief Restore All General Registers, for interrupt handling
+ *
+ */
.macro RESTORE_ALL
- /* resw ra to sepc */
- LOAD x1, 0 * REGBYTES(sp)
- csrw SRC_XEPC, x1
+
+#ifdef ENABLE_VECTOR
+ // skip on close
+ ld t0, 2 * REGBYTES(sp)
+ // cannot use vector on initial
+ andi t0, t0, SSTATUS_VS_CLEAN
+ beqz t0, 0f
+
+ /* push vector frame */
+ addi t1, sp, (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR) * REGBYTES
+
+ RESTORE_VECTOR t1
+0:
+#endif /* ENABLE_VECTOR */
+
+#ifdef ENABLE_FPU
+ /* restore float register */
+ addi t2, sp, CTX_GENERAL_REG_NR * REGBYTES
+
+ li t0, SSTATUS_FS
+ csrs sstatus, t0
+ fld f0, FPU_CTX_F0_OFF(t2)
+ fld f1, FPU_CTX_F1_OFF(t2)
+ fld f2, FPU_CTX_F2_OFF(t2)
+ fld f3, FPU_CTX_F3_OFF(t2)
+ fld f4, FPU_CTX_F4_OFF(t2)
+ fld f5, FPU_CTX_F5_OFF(t2)
+ fld f6, FPU_CTX_F6_OFF(t2)
+ fld f7, FPU_CTX_F7_OFF(t2)
+ fld f8, FPU_CTX_F8_OFF(t2)
+ fld f9, FPU_CTX_F9_OFF(t2)
+ fld f10, FPU_CTX_F10_OFF(t2)
+ fld f11, FPU_CTX_F11_OFF(t2)
+ fld f12, FPU_CTX_F12_OFF(t2)
+ fld f13, FPU_CTX_F13_OFF(t2)
+ fld f14, FPU_CTX_F14_OFF(t2)
+ fld f15, FPU_CTX_F15_OFF(t2)
+ fld f16, FPU_CTX_F16_OFF(t2)
+ fld f17, FPU_CTX_F17_OFF(t2)
+ fld f18, FPU_CTX_F18_OFF(t2)
+ fld f19, FPU_CTX_F19_OFF(t2)
+ fld f20, FPU_CTX_F20_OFF(t2)
+ fld f21, FPU_CTX_F21_OFF(t2)
+ fld f22, FPU_CTX_F22_OFF(t2)
+ fld f23, FPU_CTX_F23_OFF(t2)
+ fld f24, FPU_CTX_F24_OFF(t2)
+ fld f25, FPU_CTX_F25_OFF(t2)
+ fld f26, FPU_CTX_F26_OFF(t2)
+ fld f27, FPU_CTX_F27_OFF(t2)
+ fld f28, FPU_CTX_F28_OFF(t2)
+ fld f29, FPU_CTX_F29_OFF(t2)
+ fld f30, FPU_CTX_F30_OFF(t2)
+ fld f31, FPU_CTX_F31_OFF(t2)
+
+ /* clr FS domain */
+ csrc sstatus, t0
+
+ /* clean status would clr sr_sd; */
+ li t0, SSTATUS_FS_CLEAN
+ csrs sstatus, t0
+
+#endif /* ENABLE_FPU */
+
+ /* restore general register */
+ addi t0, sp, CTX_REG_NR * REGBYTES
+ csrw sscratch, t0
+
+ /* resw ra to sepc */
+ LOAD x1, 0 * REGBYTES(sp)
+ csrw sepc, x1
LOAD x1, 2 * REGBYTES(sp)
- csrw SRC_XSTATUS, x1
+ csrw sstatus, x1
LOAD x1, 1 * REGBYTES(sp)
LOAD x3, 3 * REGBYTES(sp)
- LOAD x4, 4 * REGBYTES(sp)
+ LOAD x4, 4 * REGBYTES(sp) /* restore tp */
LOAD x5, 5 * REGBYTES(sp)
LOAD x6, 6 * REGBYTES(sp)
LOAD x7, 7 * REGBYTES(sp)
@@ -141,7 +249,7 @@
LOAD x30, 30 * REGBYTES(sp)
LOAD x31, 31 * REGBYTES(sp)
- //restore user sp
+ /* restore user sp */
LOAD sp, 32 * REGBYTES(sp)
.endm
@@ -152,4 +260,14 @@
.option pop
.endm
-#endif
+.macro OPEN_INTERRUPT
+ csrsi sstatus, 2
+.endm
+
+.macro CLOSE_INTERRUPT
+ csrci sstatus, 2
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __STACKFRAME_H__ */
diff --git a/libcpu/risc-v/virt64/startup_gcc.S b/libcpu/risc-v/virt64/startup_gcc.S
index 9c12b6dd44..700f31181d 100644
--- a/libcpu/risc-v/virt64/startup_gcc.S
+++ b/libcpu/risc-v/virt64/startup_gcc.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2022, RT-Thread Development Team
+ * Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -10,56 +10,85 @@
* 2020/6/12 Xim Port to QEMU and remove SMP support
*/
-#define XSTATUS_FS (3 << 13) /* initial state of FPU, clear to disable */
-#define XSTATUS_PUM (1 << 18)
+#define SSTATUS_FS 0x00006000U /* initial state of FPU, clear to disable */
#include <cpuport.h>
boot_hartid: .int
.global boot_hartid
- .global _start
+ .global _start
.section ".start", "ax"
_start:
-#ifdef RISCV_S_MODE
+ j 1f
+ .word 0xdeadbeef
+ .align 3
+ .global g_wake_up
+ g_wake_up:
+ .dword 1
+ .dword 0
+1:
# save hartid
la t0, boot_hartid # global varible rt_boot_hartid
mv t1, a0 # get hartid in S-mode frome a0 register
sw t1, (t0) # store t1 register low 4 bits in memory address which is stored in t0
-#else
- # setup stacks per hart
- csrr t0, mhartid # read current hart id
- slli t0, t0, 10 # shift left the hart id by 1024
-
- # park harts with id != 0
- csrr a0, mhartid # read current hart id
- bnez a0, park # if we're not on the hart 0
-#endif
-
- csrw SRC_XIE, 0 # clear Interrupt Registers
- csrw SRC_XIP, 0
+ # clear Interrupt Registers
+ csrw sie, 0
+ csrw sip, 0
+ # set Trap Vector Base Address Register
la t0, trap_entry
- csrw SRC_XTVEC, t0 # set Trap Vector Base Address Register
+ csrw stvec, t0
+
+ li x1, 0
+ li x2, 0
+ li x3, 0
+ li x4, 0
+ li x5, 0
+ li x6, 0
+ li x7, 0
+ li x8, 0
+ li x9, 0
+ li x10,0
+ li x11,0
+ li x12,0
+ li x13,0
+ li x14,0
+ li x15,0
+ li x16,0
+ li x17,0
+ li x18,0
+ li x19,0
+ li x20,0
+ li x21,0
+ li x22,0
+ li x23,0
+ li x24,0
+ li x25,0
+ li x26,0
+ li x27,0
+ li x28,0
+ li x29,0
+ li x30,0
+ li x31,0
/* set to disable FPU */
- li t0, XSTATUS_FS # close fpu
- csrc SRC_XSTATUS, t0
-#ifdef RISCV_S_MODE
- li t0, XSTATUS_PUM # PUM has no effect
- csrs SRC_XSTATUS, t0
-#endif
+ li t0, SSTATUS_FS
+ csrc sstatus, t0
+ li t0, 0x40000 // SUM in sstatus
+ csrs sstatus, t0
.option push
.option norelax
la gp, __global_pointer$
.option pop
+ // removed SMP support here
la sp, __stack_start__
li t0, __STACKSIZE__
add sp, sp, t0
- csrw SRC_XSCRATCH, sp
- j primary_cpu_entry
-park:
- wfi
- j park
+ /**
+ * sscratch is always zero on kernel mode
+ */
+ csrw sscratch, zero
+ j primary_cpu_entry
diff --git a/libcpu/risc-v/virt64/syscall_c.c b/libcpu/risc-v/virt64/syscall_c.c
new file mode 100644
index 0000000000..8f27db5ffd
--- /dev/null
+++ b/libcpu/risc-v/virt64/syscall_c.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-02-03 lizhirui first version
+ * 2022-11-10 WangXiaoyao Add readable syscall tracing
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#define DBG_TAG "syscall"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+#include <stdint.h>
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+
+#include "riscv_mmu.h"
+#include "stack.h"
+
+typedef rt_size_t (*syscallfunc_t)(rt_size_t, rt_size_t, rt_size_t, rt_size_t, rt_size_t, rt_size_t, rt_size_t);
+
+void syscall_handler(struct rt_hw_stack_frame *regs)
+{
+ const char *syscall_name;
+ int syscallid = regs->a7;
+
+ if (syscallid == 0)
+ {
+ LOG_E("syscall id = 0!\n");
+ while (1)
+ ;
+ }
+
+ syscallfunc_t syscallfunc = (syscallfunc_t)lwp_get_sys_api(syscallid);
+
+ if (syscallfunc == RT_NULL)
+ {
+ LOG_E("unsupported syscall!\n");
+ sys_exit(-1);
+ }
+
+#if DBG_LVL >= DBG_INFO
+ syscall_name = lwp_get_syscall_name(syscallid);
+#endif
+
+ LOG_I("[0x%lx] %s(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)", rt_thread_self(), syscall_name,
+ regs->a0, regs->a1, regs->a2, regs->a3, regs->a4, regs->a5, regs->a6);
+ regs->a0 = syscallfunc(regs->a0, regs->a1, regs->a2, regs->a3, regs->a4, regs->a5, regs->a6);
+ regs->a7 = 0;
+ regs->epc += 4; // skip ecall instruction
+ LOG_I("[0x%lx] %s ret: 0x%lx", rt_thread_self(), syscall_name, regs->a0);
+}
diff --git a/libcpu/risc-v/virt64/tick.c b/libcpu/risc-v/virt64/tick.c
index 53f555da9d..8fdbe0809f 100644
--- a/libcpu/risc-v/virt64/tick.c
+++ b/libcpu/risc-v/virt64/tick.c
@@ -11,12 +11,8 @@
#include <rthw.h>
#include <rtthread.h>
-#include "sbi.h"
-#include "tick.h"
-#include <riscv_io.h>
#include <encoding.h>
-
-#define VIRT_CLINT_TIMEBASE_FREQ (10000000)
+#include "sbi.h"
static volatile uint64_t time_elapsed = 0;
static volatile unsigned long tick_cycles = 0;
@@ -31,13 +27,11 @@ static uint64_t get_ticks()
int tick_isr(void)
{
- int tick_cycles = VIRT_CLINT_TIMEBASE_FREQ / RT_TICK_PER_SECOND;
+ // uint64_t core_id = current_coreid();
+ int tick_cycles = 40000;
+ // clint->mtimecmp[core_id] += tick_cycles;
rt_tick_increase();
-#ifdef RISCV_S_MODE
sbi_set_timer(get_ticks() + tick_cycles);
-#else
- *(uint64_t*)CLINT_MTIMECMP(__raw_hartid()) = *(uint64_t*)CLINT_MTIME + tick_cycles;
-#endif
return 0;
}
@@ -45,9 +39,10 @@ int tick_isr(void)
/* Sets and enable the timer interrupt */
int rt_hw_tick_init(void)
{
- unsigned long interval = VIRT_CLINT_TIMEBASE_FREQ / RT_TICK_PER_SECOND;
+ /* Read core id */
+ // unsigned long core_id = current_coreid();
+ unsigned long interval = 1000/RT_TICK_PER_SECOND;
-#ifdef RISCV_S_MODE
/* Clear the Supervisor-Timer bit in SIE */
clear_csr(sie, SIP_STIP);
@@ -59,11 +54,6 @@ int rt_hw_tick_init(void)
/* Enable the Supervisor-Timer bit in SIE */
set_csr(sie, SIP_STIP);
-#else
- clear_csr(mie, MIP_MTIP);
- clear_csr(mip, MIP_MTIP);
- *(uint64_t*)CLINT_MTIMECMP(__raw_hartid()) = *(uint64_t*)CLINT_MTIME + interval;
- set_csr(mie, MIP_MTIP);
-#endif
+
return 0;
}
diff --git a/libcpu/risc-v/virt64/tick.h b/libcpu/risc-v/virt64/tick.h
index c5a55cf16f..0bfd6f62e8 100644
--- a/libcpu/risc-v/virt64/tick.h
+++ b/libcpu/risc-v/virt64/tick.h
@@ -11,11 +11,6 @@
#ifndef TICK_H__
#define TICK_H__
-//ask the CLINT for a timer interrupt.
-#define CLINT (0x2000000L)
-#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 4*(hartid))
-#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
-
int tick_isr(void);
int rt_hw_tick_init(void);
diff --git a/libcpu/risc-v/virt64/trap.c b/libcpu/risc-v/virt64/trap.c
new file mode 100644
index 0000000000..35392559d6
--- /dev/null
+++ b/libcpu/risc-v/virt64/trap.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "encoding.h"
+#include "stack.h"
+#include "sbi.h"
+#include "riscv.h"
+#include "tick.h"
+#include "plic.h"
+#include "lwp_arch.h"
+
+void dump_regs(struct rt_hw_stack_frame *regs)
+{
+ rt_kprintf("--------------Dump Registers-----------------\n");
+
+ rt_kprintf("Function Registers:\n");
+ rt_kprintf("\tra(x1) = 0x%p\tuser_sp = 0x%p\n", regs->ra, regs->user_sp_exc_stack);
+ rt_kprintf("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n", regs->gp, regs->tp);
+ rt_kprintf("Temporary Registers:\n");
+ rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1);
+ rt_kprintf("\tt2(x7) = 0x%p\n", regs->t2);
+ rt_kprintf("\tt3(x28) = 0x%p\tt4(x29) = 0x%p\n", regs->t3, regs->t4);
+ rt_kprintf("\tt5(x30) = 0x%p\tt6(x31) = 0x%p\n", regs->t5, regs->t6);
+ rt_kprintf("Saved Registers:\n");
+ rt_kprintf("\ts0/fp(x8) = 0x%p\ts1(x9) = 0x%p\n", regs->s0_fp, regs->s1);
+ rt_kprintf("\ts2(x18) = 0x%p\ts3(x19) = 0x%p\n", regs->s2, regs->s3);
+ rt_kprintf("\ts4(x20) = 0x%p\ts5(x21) = 0x%p\n", regs->s4, regs->s5);
+ rt_kprintf("\ts6(x22) = 0x%p\ts7(x23) = 0x%p\n", regs->s6, regs->s7);
+ rt_kprintf("\ts8(x24) = 0x%p\ts9(x25) = 0x%p\n", regs->s8, regs->s9);
+ rt_kprintf("\ts10(x26) = 0x%p\ts11(x27) = 0x%p\n", regs->s10, regs->s11);
+ rt_kprintf("Function Arguments Registers:\n");
+ rt_kprintf("\ta0(x10) = 0x%p\ta1(x11) = 0x%p\n", regs->a0, regs->a1);
+ rt_kprintf("\ta2(x12) = 0x%p\ta3(x13) = 0x%p\n", regs->a2, regs->a3);
+ rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n", regs->a4, regs->a5);
+ rt_kprintf("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n", regs->a6, regs->a7);
+ rt_kprintf("sstatus = 0x%p\n", regs->sstatus);
+ rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
+ rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
+ rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
+ rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
+ rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
+ rt_size_t satp_v = read_csr(satp);
+ rt_kprintf("satp = 0x%p\n", satp_v);
+ rt_kprintf("\tCurrent Page Table(Physical) = 0x%p\n", __MASKVALUE(satp_v, __MASK(44)) << PAGE_OFFSET_BIT);
+ rt_kprintf("\tCurrent ASID = 0x%p\n", __MASKVALUE(satp_v >> 44, __MASK(16)) << PAGE_OFFSET_BIT);
+ const char *mode_str = "Unknown Address Translation/Protection Mode";
+
+ switch (__MASKVALUE(satp_v >> 60, __MASK(4)))
+ {
+ case 0:
+ mode_str = "No Address Translation/Protection Mode";
+ break;
+
+ case 8:
+ mode_str = "Page-based 39-bit Virtual Addressing Mode";
+ break;
+
+ case 9:
+ mode_str = "Page-based 48-bit Virtual Addressing Mode";
+ break;
+ }
+
+ rt_kprintf("\tMode = %s\n", mode_str);
+ rt_kprintf("-----------------Dump OK---------------------\n");
+}
+
+static const char *Exception_Name[] =
+ {
+ "Instruction Address Misaligned",
+ "Instruction Access Fault",
+ "Illegal Instruction",
+ "Breakpoint",
+ "Load Address Misaligned",
+ "Load Access Fault",
+ "Store/AMO Address Misaligned",
+ "Store/AMO Access Fault",
+ "Environment call from U-mode",
+ "Environment call from S-mode",
+ "Reserved-10",
+ "Reserved-11",
+ "Instruction Page Fault",
+ "Load Page Fault",
+ "Reserved-14",
+ "Store/AMO Page Fault"};
+
+static const char *Interrupt_Name[] =
+ {
+ "User Software Interrupt",
+ "Supervisor Software Interrupt",
+ "Reversed-2",
+ "Reversed-3",
+ "User Timer Interrupt",
+ "Supervisor Timer Interrupt",
+ "Reversed-6",
+ "Reversed-7",
+ "User External Interrupt",
+ "Supervisor External Interrupt",
+ "Reserved-10",
+ "Reserved-11",
+};
+
+enum
+{
+ EP_INSTRUCTION_ADDRESS_MISALIGNED = 0,
+ EP_INSTRUCTION_ACCESS_FAULT,
+ EP_ILLEGAL_INSTRUCTION,
+ EP_BREAKPOINT,
+ EP_LOAD_ADDRESS_MISALIGNED,
+ EP_LOAD_ACCESS_FAULT,
+ EP_STORE_ADDRESS_MISALIGNED,
+ EP_STORE_ACCESS_FAULT,
+ EP_ENVIRONMENT_CALL_U_MODE,
+ EP_ENVIRONMENT_CALL_S_MODE,
+ EP_RESERVED10,
+ EP_ENVIRONMENT_CALL_M_MODE,
+ EP_INSTRUCTION_PAGE_FAULT, /* page attr */
+ EP_LOAD_PAGE_FAULT, /* read data */
+ EP_RESERVED14,
+ EP_STORE_PAGE_FAULT, /* write data */
+};
+
+extern struct rt_irq_desc irq_desc[];
+
+#include "rtdbg.h"
+#include "encoding.h"
+void sys_exit(int value);
+
+static const char *get_exception_msg(int id)
+{
+ const char *msg;
+ if (id < sizeof(Exception_Name) / sizeof(const char *))
+ {
+ msg = Exception_Name[id];
+ }
+ else
+ {
+ msg = "Unknown Exception";
+ }
+ return msg;
+}
+
+void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp)
+{
+ rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
+
+#ifdef RT_USING_USERSPACE
+ /* user page fault */
+ if (id == EP_LOAD_PAGE_FAULT ||
+ id == EP_STORE_PAGE_FAULT)
+ {
+ if (arch_expand_user_stack((void *)stval))
+ {
+ return;
+ }
+ }
+#endif
+ LOG_E("[FATAL ERROR] Exception %ld:%s\n", id, get_exception_msg(id));
+ LOG_E("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
+ dump_regs(sp);
+
+ rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc);
+
+ LOG_E("User Fault, killing thread: %s", rt_thread_self()->name);
+ sys_exit(-1);
+}
+
+static void vector_enable(struct rt_hw_stack_frame *sp)
+{
+ sp->sstatus |= SSTATUS_VS_INITIAL;
+}
+
+/**
+ * detect V/D support, and do not distinguish V/D instruction
+ */
+static int illegal_inst_recoverable(rt_ubase_t stval, struct rt_hw_stack_frame *sp)
+{
+ // first 7 bits is opcode
+ int opcode = stval & 0x7f;
+ int csr = (stval & 0xFFF00000) >> 20;
+ // ref riscv-v-spec-1.0, [Vector Instruction Formats]
+ int width = ((stval & 0x7000) >> 12) - 1;
+ int flag = 0;
+
+ switch (opcode)
+ {
+ case 0x57: // V
+ case 0x27: // scalar FLOAT
+ case 0x07:
+ case 0x73: // CSR
+ flag = 1;
+ break;
+ }
+
+ if (flag)
+ {
+ vector_enable(sp);
+ }
+
+ return flag;
+}
+
+static void handle_nested_trap_panic(
+ rt_size_t cause,
+ rt_size_t tval,
+ rt_size_t epc,
+ struct rt_hw_stack_frame *eframe)
+{
+ LOG_E("\n-------- [SEVER ERROR] --------");
+ LOG_E("Nested trap detected");
+ LOG_E("scause:0x%p,stval:0x%p,sepc:0x%p\n", cause, tval, epc);
+ dump_regs(eframe);
+ rt_hw_cpu_shutdown();
+}
+
+#ifndef RT_USING_SMP
+static volatile int nested = 0;
+#define ENTER_TRAP \
+ nested += 1
+#define EXIT_TRAP \
+ nested -= 1
+#define CHECK_NESTED_PANIC(cause, tval, epc, eframe) \
+ if (nested != 1) \
+ handle_nested_trap_panic(cause, tval, epc, eframe)
+#endif /* RT_USING_SMP */
+
+/* Trap entry */
+void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp)
+{
+ ENTER_TRAP;
+ rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
+ const char *msg;
+
+ /* supervisor external interrupt */
+ if (scause == (uint64_t)(0x8000000000000005))
+ {
+ rt_interrupt_enter();
+ tick_isr();
+ rt_interrupt_leave();
+ }
+ else if (scause == (uint64_t)(0x8000000000000009))
+ {
+ rt_interrupt_enter();
+ int plic_irq = plic_claim();
+ plic_complete(plic_irq);
+ irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
+ rt_interrupt_leave();
+ }
+ else
+ {
+ // trap cannot nested when handling another trap / interrupt
+ CHECK_NESTED_PANIC(scause, stval, sepc, sp);
+ rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
+ const char *msg;
+
+ if (scause >> 63)
+ {
+ if (id < sizeof(Interrupt_Name) / sizeof(const char *))
+ {
+ msg = Interrupt_Name[id];
+ }
+ else
+ {
+ msg = "Unknown Interrupt";
+ }
+
+ rt_kprintf("Unhandled Interrupt %ld:%s\n", id, msg);
+ }
+ else
+ {
+#ifdef ENABLE_VECTOR
+ if (scause == 0x2)
+ {
+ if (!(sp->sstatus & SSTATUS_VS) && illegal_inst_recoverable(stval, sp))
+ goto _exit;
+ }
+#endif /* ENABLE_VECTOR */
+ if (!(sp->sstatus & 0x100))
+ {
+ handle_user(scause, stval, sepc, sp);
+ // if handle_user() return here, jump to u mode then
+ goto _exit;
+ }
+
+ // handle kernel exception:
+ rt_kprintf("Unhandled Exception %ld:%s\n", id, get_exception_msg(id));
+ }
+
+ rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
+ dump_regs(sp);
+ rt_kprintf("--------------Thread list--------------\n");
+ rt_kprintf("current thread: %s\n", rt_thread_self()->name);
+
+ extern struct rt_thread *rt_current_thread;
+ rt_kprintf("--------------Backtrace--------------\n");
+ rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc);
+
+ while (1)
+ ;
+ }
+_exit:
+ EXIT_TRAP;
+ return ;
+}
diff --git a/libcpu/risc-v/virt64/vector_encoding.h b/libcpu/risc-v/virt64/vector_encoding.h
new file mode 100644
index 0000000000..5445843f06
--- /dev/null
+++ b/libcpu/risc-v/virt64/vector_encoding.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-10 RT-Thread the first version,
+ * compatible to riscv-v-spec-1.0
+ */
+
+#ifndef __VECTOR_ENCODING_H__
+#define __VECTOR_ENCODING_H__
+
+/**
+ * assembler names used for vset{i}vli vtypei immediate
+ */
+
+#define VEC_IMM_SEW_8 e8
+#define VEC_IMM_SEW_16 e16
+#define VEC_IMM_SEW_32 e32
+#define VEC_IMM_SEW_64 e64
+/* group setting, encoding by multiplier */
+#define VEC_IMM_LMUL_F8 mf8
+#define VEC_IMM_LMUL_F4 mf4
+#define VEC_IMM_LMUL_F2 mf2
+#define VEC_IMM_LMUL_1 m1
+#define VEC_IMM_LMUL_2 m2
+#define VEC_IMM_LMUL_4 m4
+#define VEC_IMM_LMUL_8 m8
+/* TAIL & MASK agnostic bits */
+#define VEC_IMM_TAIL_AGNOSTIC ta
+#define VEC_IMM_MASK_AGNOSTIC ma
+#define VEC_IMM_TAMA VEC_IMM_TAIL_AGNOSTIC, VEC_IMM_MASK_AGNOSTIC
+#define VEC_IMM_TAMU VEC_IMM_TAIL_AGNOSTIC
+#define VEC_IMM_TUMA VEC_IMM_MASK_AGNOSTIC
+
+/**
+ * configuration setting instruction
+ */
+#define VEC_CONFIG_SETVLI(xVl, xAvl, vtype...) vsetvli xVl, xAvl, ##vtype
+#define VEC_CONFIG_SET_VL_VTYPE(xVl, xVtype) vsetvl x0, xVl, xVtype
+
+#endif /* __VECTOR_ENCODING_H__ */ \ No newline at end of file