summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/Kconfig21
-rw-r--r--libcpu/arm/cortex-a/cpu.c17
-rw-r--r--libcpu/arm/zynqmp-r5/cache.c291
-rw-r--r--libcpu/arm/zynqmp-r5/start_gcc.S4
-rw-r--r--libcpu/arm/zynqmp-r5/xil_mmu.h54
-rw-r--r--libcpu/arm/zynqmp-r5/xil_mpu.c637
-rw-r--r--libcpu/arm/zynqmp-r5/xil_mpu.h129
-rw-r--r--libcpu/risc-v/SConscript2
-rw-r--r--libcpu/risc-v/virt64/SConscript14
-rw-r--r--libcpu/risc-v/virt64/context_gcc.S307
-rw-r--r--libcpu/risc-v/virt64/cpuport.c123
-rw-r--r--libcpu/risc-v/virt64/cpuport.h55
-rw-r--r--libcpu/risc-v/virt64/interrupt.c274
-rw-r--r--libcpu/risc-v/virt64/interrupt.h27
-rw-r--r--libcpu/risc-v/virt64/interrupt_gcc.S151
-rw-r--r--libcpu/risc-v/virt64/riscv.h29
-rw-r--r--libcpu/risc-v/virt64/riscv_io.h137
-rw-r--r--libcpu/risc-v/virt64/stack.h52
-rw-r--r--libcpu/risc-v/virt64/stackframe.h155
-rw-r--r--libcpu/risc-v/virt64/startup_gcc.S57
-rw-r--r--libcpu/risc-v/virt64/tick.c69
-rw-r--r--libcpu/risc-v/virt64/tick.h22
22 files changed, 2588 insertions, 39 deletions
diff --git a/libcpu/Kconfig b/libcpu/Kconfig
index bb54b487c7..d0fa40d1bd 100644
--- a/libcpu/Kconfig
+++ b/libcpu/Kconfig
@@ -57,25 +57,24 @@ config ARCH_ARM_ARM11
config ARCH_ARM_CORTEX_A
bool
select ARCH_ARM
+ select RT_USING_CPU_FFS
if ARCH_ARM_CORTEX_A
config RT_SMP_AUTO_BOOT
bool
default n
- choice
- prompt "GIC controller selection"
- default RT_USING_GIC_V2
-
- config RT_USING_GIC_V2
- bool " Gic version 2 "
+ config RT_USING_GIC_V2
+ bool
+ default n
- config RT_USING_GIC_V3
- bool " Gic version 3 "
+ config RT_USING_GIC_V3
+ bool
+ default n
- config RT_NO_USING_GIC
- bool " GIC controller is not used "
- endchoice
+ config RT_NO_USING_GIC
+ bool
+ default y if !RT_USING_GIC_V2 && !RT_USING_GIC_V3
endif
config ARCH_ARM_CORTEX_A5
diff --git a/libcpu/arm/cortex-a/cpu.c b/libcpu/arm/cortex-a/cpu.c
index 7367bddd9f..c95c58a13c 100644
--- a/libcpu/arm/cortex-a/cpu.c
+++ b/libcpu/arm/cortex-a/cpu.c
@@ -75,4 +75,21 @@ RT_WEAK void rt_hw_cpu_shutdown()
}
}
+#ifdef RT_USING_CPU_FFS
+/**
+ * This function finds the first bit set (beginning with the least significant bit)
+ * in value and return the index of that bit.
+ *
+ * Bits are numbered starting at 1 (the least significant bit). A return value of
+ * zero from any of these functions means that the argument was zero.
+ *
+ * @return return the index of the first bit set. If value is 0, then this function
+ * shall return 0.
+ */
+int __rt_ffs(int value)
+{
+ return __builtin_ffs(value);
+}
+#endif
+
/*@}*/
diff --git a/libcpu/arm/zynqmp-r5/cache.c b/libcpu/arm/zynqmp-r5/cache.c
index d6e7cd2d6d..6053b2fe47 100644
--- a/libcpu/arm/zynqmp-r5/cache.c
+++ b/libcpu/arm/zynqmp-r5/cache.c
@@ -1,11 +1,13 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2021 WangHuachen. All rights reserved.
+ * SPDX-License-Identifier: MIT
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
+ * 2021-05-10 WangHuachen add more functions
*/
#include <rthw.h>
#include <rtdef.h>
@@ -44,41 +46,77 @@ typedef rt_uint32_t u32;
XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param))
#endif
+void Xil_DCacheEnable(void);
+void Xil_DCacheDisable(void);
+void Xil_DCacheInvalidate(void);
+void Xil_DCacheInvalidateRange(INTPTR adr, u32 len);
+void Xil_DCacheFlush(void);
+void Xil_DCacheFlushRange(INTPTR adr, u32 len);
+void Xil_DCacheInvalidateLine(INTPTR adr);
+void Xil_DCacheFlushLine(INTPTR adr);
+void Xil_DCacheStoreLine(INTPTR adr);
+void Xil_ICacheEnable(void);
+void Xil_ICacheDisable(void);
+void Xil_ICacheInvalidate(void);
+void Xil_ICacheInvalidateRange(INTPTR adr, u32 len);
+void Xil_ICacheInvalidateLine(INTPTR adr);
-void Xil_ICacheInvalidateRange(INTPTR adr, u32 len)
+void Xil_DCacheEnable(void)
+{
+ register u32 CtrlReg;
+
+ /* enable caches only if they are disabled */
+#if defined (__GNUC__)
+ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
+#endif
+ if ((CtrlReg & XREG_CP15_CONTROL_C_BIT)==0x00000000U) {
+ /* invalidate the Data cache */
+ Xil_DCacheInvalidate();
+
+ /* enable the Data cache */
+ CtrlReg |= (XREG_CP15_CONTROL_C_BIT);
+
+ mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
+ }
+}
+
+void Xil_DCacheDisable(void)
+{
+ register u32 CtrlReg;
+
+ /* clean and invalidate the Data cache */
+ Xil_DCacheFlush();
+
+ /* disable the Data cache */
+#if defined (__GNUC__)
+ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
+#endif
+
+ CtrlReg &= ~(XREG_CP15_CONTROL_C_BIT);
+
+ mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
+}
+
+void Xil_DCacheInvalidate(void)
{
- u32 LocalAddr = adr;
- const u32 cacheline = 32U;
- u32 end;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
- if (len != 0x00000000U) {
- /* Back the starting address up to the start of a cache line
- * perform cache operations until adr+len
- */
- end = LocalAddr + len;
- LocalAddr = LocalAddr & ~(cacheline - 1U);
- /* Select cache L0 I-cache in CSSR */
- mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
-
- while (LocalAddr < end) {
-
- /* Invalidate L1 I-cache line */
- asm_inval_ic_line_mva_pou(LocalAddr);
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
- LocalAddr += cacheline;
- }
- }
+ /*invalidate all D cache*/
+ mtcp(XREG_CP15_INVAL_DC_ALL, 0);
- /* Wait for invalidate to complete */
- dsb();
mtcpsr(currmask);
}
-void Xil_DCacheFlushLine(INTPTR adr)
+void Xil_DCacheInvalidateLine(INTPTR adr)
{
u32 currmask;
@@ -86,11 +124,11 @@ void Xil_DCacheFlushLine(INTPTR adr)
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
+ mtcp(XREG_CP15_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
- mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
-
- /* Wait for flush to complete */
+ /* Wait for invalidate to complete */
dsb();
+
mtcpsr(currmask);
}
@@ -135,6 +173,79 @@ void Xil_DCacheInvalidateRange(INTPTR adr, u32 len)
mtcpsr(currmask);
}
+void Xil_DCacheFlush(void)
+{
+ register u32 CsidReg, C7Reg;
+ u32 CacheSize, LineSize, NumWays;
+ u32 Way, WayIndex, Set, SetIndex, NumSet;
+ u32 currmask;
+
+ currmask = mfcpsr();
+ mtcpsr(currmask | IRQ_FIQ_MASK);
+
+ /* Select cache level 0 and D cache in CSSR */
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
+
+#if defined (__GNUC__)
+ CsidReg = mfcp(XREG_CP15_CACHE_SIZE_ID);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_CACHE_SIZE_ID,CsidReg);
+#endif
+ /* Determine Cache Size */
+
+ CacheSize = (CsidReg >> 13U) & 0x000001FFU;
+ CacheSize += 0x00000001U;
+ CacheSize *= (u32)128; /* to get number of bytes */
+
+ /* Number of Ways */
+ NumWays = (CsidReg & 0x000003ffU) >> 3U;
+ NumWays += 0x00000001U;
+
+ /* Get the cacheline size, way size, index size from csidr */
+ LineSize = (CsidReg & 0x00000007U) + 0x00000004U;
+
+ NumSet = CacheSize/NumWays;
+ NumSet /= (0x00000001U << LineSize);
+
+ Way = 0U;
+ Set = 0U;
+
+ /* Invalidate all the cachelines */
+ for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) {
+ for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) {
+ C7Reg = Way | Set;
+ /* Flush by Set/Way */
+ asm_clean_inval_dc_line_sw(C7Reg);
+
+ Set += (0x00000001U << LineSize);
+ }
+ Set = 0U;
+ Way += 0x40000000U;
+ }
+
+ /* Wait for flush to complete */
+ dsb();
+ mtcpsr(currmask);
+
+ mtcpsr(currmask);
+}
+
+void Xil_DCacheFlushLine(INTPTR adr)
+{
+ u32 currmask;
+
+ currmask = mfcpsr();
+ mtcpsr(currmask | IRQ_FIQ_MASK);
+
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
+
+ mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
+
+ /* Wait for flush to complete */
+ dsb();
+ mtcpsr(currmask);
+}
+
void Xil_DCacheFlushRange(INTPTR adr, u32 len)
{
u32 LocalAddr = adr;
@@ -163,6 +274,130 @@ void Xil_DCacheFlushRange(INTPTR adr, u32 len)
mtcpsr(currmask);
}
+void Xil_DCacheStoreLine(INTPTR adr)
+{
+ u32 currmask;
+
+ currmask = mfcpsr();
+ mtcpsr(currmask | IRQ_FIQ_MASK);
+
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
+ mtcp(XREG_CP15_CLEAN_DC_LINE_MVA_POC, (adr & (~0x1F)));
+
+ /* Wait for store to complete */
+ dsb();
+ isb();
+
+ mtcpsr(currmask);
+}
+
+void Xil_ICacheEnable(void)
+{
+ register u32 CtrlReg;
+
+ /* enable caches only if they are disabled */
+#if defined (__GNUC__)
+ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
+#endif
+ if ((CtrlReg & XREG_CP15_CONTROL_I_BIT)==0x00000000U) {
+ /* invalidate the instruction cache */
+ mtcp(XREG_CP15_INVAL_IC_POU, 0);
+
+ /* enable the instruction cache */
+ CtrlReg |= (XREG_CP15_CONTROL_I_BIT);
+
+ mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
+ }
+}
+
+void Xil_ICacheDisable(void)
+{
+ register u32 CtrlReg;
+
+ dsb();
+
+ /* invalidate the instruction cache */
+ mtcp(XREG_CP15_INVAL_IC_POU, 0);
+
+ /* disable the instruction cache */
+#if defined (__GNUC__)
+ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
+#endif
+
+ CtrlReg &= ~(XREG_CP15_CONTROL_I_BIT);
+
+ mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
+}
+
+void Xil_ICacheInvalidate(void)
+{
+ u32 currmask;
+
+ currmask = mfcpsr();
+ mtcpsr(currmask | IRQ_FIQ_MASK);
+
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 1);
+
+ /* invalidate the instruction cache */
+ mtcp(XREG_CP15_INVAL_IC_POU, 0);
+
+ /* Wait for invalidate to complete */
+ dsb();
+ mtcpsr(currmask);
+}
+
+void Xil_ICacheInvalidateLine(INTPTR adr)
+{
+ u32 currmask;
+
+ currmask = mfcpsr();
+ mtcpsr(currmask | IRQ_FIQ_MASK);
+
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 1);
+ mtcp(XREG_CP15_INVAL_IC_LINE_MVA_POU, (adr & (~0x1F)));
+
+ /* Wait for invalidate to complete */
+ dsb();
+ mtcpsr(currmask);
+}
+
+void Xil_ICacheInvalidateRange(INTPTR adr, u32 len)
+{
+ u32 LocalAddr = adr;
+ const u32 cacheline = 32U;
+ u32 end;
+ u32 currmask;
+
+ currmask = mfcpsr();
+ mtcpsr(currmask | IRQ_FIQ_MASK);
+ if (len != 0x00000000U) {
+ /* Back the starting address up to the start of a cache line
+ * perform cache operations until adr+len
+ */
+ end = LocalAddr + len;
+ LocalAddr = LocalAddr & ~(cacheline - 1U);
+
+ /* Select cache L0 I-cache in CSSR */
+ mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
+
+ while (LocalAddr < end) {
+
+ /* Invalidate L1 I-cache line */
+ asm_inval_ic_line_mva_pou(LocalAddr);
+
+ LocalAddr += cacheline;
+ }
+ }
+
+ /* Wait for invalidate to complete */
+ dsb();
+ mtcpsr(currmask);
+}
+
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)
diff --git a/libcpu/arm/zynqmp-r5/start_gcc.S b/libcpu/arm/zynqmp-r5/start_gcc.S
index faea0022be..7e99c9e82b 100644
--- a/libcpu/arm/zynqmp-r5/start_gcc.S
+++ b/libcpu/arm/zynqmp-r5/start_gcc.S
@@ -6,6 +6,9 @@
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
+ * 2021-05-11 WangHuachen Added call to Xil_InitializeExistingMPURegConfig to
+ * initialize the MPU configuration table with the MPU
+ * configurations already set in Init_Mpu function.
*/
.equ Mode_USR, 0x10
@@ -234,6 +237,7 @@ ctor_loop:
b ctor_loop
ctor_end:
+ bl Xil_InitializeExistingMPURegConfig /* Initialize MPU config */
/* start RT-Thread Kernel */
ldr pc, _entry
diff --git a/libcpu/arm/zynqmp-r5/xil_mmu.h b/libcpu/arm/zynqmp-r5/xil_mmu.h
new file mode 100644
index 0000000000..99e019c6f5
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/xil_mmu.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+* Copyright (c) 2015 - 2020 Xilinx, Inc. All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+* @file xil_mmu.h
+* This file only includes xil_mpu.h which contains Xil_SetTlbAttributes API
+* defined for MPU in R5. R5 does not have mmu and for usage of similar API
+* the file has been created.
+*
+*
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- ---------------------------------------------------
+* 5.0 pkp 2/12/15 Initial version
+* </pre>
+*
+* @note
+*
+* None.
+*
+******************************************************************************/
+
+#ifndef XIL_MMU_H
+#define XIL_MMU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/***************************** Include Files *********************************/
+
+#include "xil_mpu.h"
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/**************************** Type Definitions *******************************/
+
+/************************** Constant Definitions *****************************/
+
+/************************** Variable Definitions *****************************/
+
+/************************** Function Prototypes ******************************/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XIL_MMU_H */
diff --git a/libcpu/arm/zynqmp-r5/xil_mpu.c b/libcpu/arm/zynqmp-r5/xil_mpu.c
new file mode 100644
index 0000000000..9ab94a488b
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/xil_mpu.c
@@ -0,0 +1,637 @@
+/******************************************************************************
+*
+* Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
+* Copyright (C) 2021 WangHuachen. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+*
+*
+******************************************************************************/
+/*****************************************************************************/
+/**
+* @file xil_mpu.c
+*
+* This file provides APIs for enabling/disabling MPU and setting the memory
+* attributes for sections, in the MPU translation table.
+*
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- ---------------------------------------------------
+* 5.00 pkp 02/10/14 Initial version
+* 6.2 mus 01/27/17 Updated to support IAR compiler
+* 6.4 asa 08/16/17 Added many APIs for MPU access to make MPU usage
+* user-friendly. The APIs added are: Xil_UpdateMPUConfig,
+* Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
+* Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
+* Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
+* Xil_InitializeExistingMPURegConfig.
+* Added a new array of structure of type XMpuConfig to
+* represent the MPU configuration table.
+* 6.8 aru 07/02/18 Returned the pointer instead of address
+* of that pointer in Xil_MemMap().
+* </pre>
+*
+*
+******************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xil_cache.h"
+#include "xpseudo_asm_gcc.h"
+#include "xil_types.h"
+#include "xil_mpu.h"
+// #include "xdebug.h"
+#include "xreg_cortexr5.h"
+#include "xstatus.h"
+
+#include <rtthread.h>
+#define DBG_TAG "xil_mpu"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+extern void Xil_DCacheFlush(void);
+extern void Xil_ICacheInvalidate(void);
+extern void Xil_DCacheDisable(void);
+extern void Xil_ICacheDisable(void);
+extern void Xil_DCacheEnable(void);
+extern void Xil_ICacheEnable(void);
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/**************************** Type Definitions *******************************/
+
+/************************** Constant Definitions *****************************/
+#define MPU_REGION_SIZE_MIN 0x20
+/************************** Variable Definitions *****************************/
+
+static const struct {
+ u64 size;
+ unsigned int encoding;
+}region_size[] = {
+ { 0x20, REGION_32B },
+ { 0x40, REGION_64B },
+ { 0x80, REGION_128B },
+ { 0x100, REGION_256B },
+ { 0x200, REGION_512B },
+ { 0x400, REGION_1K },
+ { 0x800, REGION_2K },
+ { 0x1000, REGION_4K },
+ { 0x2000, REGION_8K },
+ { 0x4000, REGION_16K },
+ { 0x8000, REGION_32K },
+ { 0x10000, REGION_64K },
+ { 0x20000, REGION_128K },
+ { 0x40000, REGION_256K },
+ { 0x80000, REGION_512K },
+ { 0x100000, REGION_1M },
+ { 0x200000, REGION_2M },
+ { 0x400000, REGION_4M },
+ { 0x800000, REGION_8M },
+ { 0x1000000, REGION_16M },
+ { 0x2000000, REGION_32M },
+ { 0x4000000, REGION_64M },
+ { 0x8000000, REGION_128M },
+ { 0x10000000, REGION_256M },
+ { 0x20000000, REGION_512M },
+ { 0x40000000, REGION_1G },
+ { 0x80000000, REGION_2G },
+ { 0x100000000, REGION_4G },
+};
+
+XMpu_Config Mpu_Config;
+
+/************************** Function Prototypes ******************************/
+void Xil_InitializeExistingMPURegConfig(void);
+/*****************************************************************************/
+/**
+* @brief This function sets the memory attributes for a section covering
+* 1MB, of memory in the translation table.
+*
+* @param Addr: 32-bit address for which memory attributes need to be set.
+* @param attrib: Attribute for the given memory region.
+* @return None.
+*
+*
+******************************************************************************/
+void Xil_SetTlbAttributes(INTPTR addr, u32 attrib)
+{
+ INTPTR Localaddr = addr;
+ Localaddr &= (~(0xFFFFFU));
+ /* Setting the MPU region with given attribute with 1MB size */
+ Xil_SetMPURegion(Localaddr, 0x100000, attrib);
+}
+
+/*****************************************************************************/
+/**
+* @brief Set the memory attributes for a section of memory in the
+* translation table.
+*
+* @param Addr: 32-bit address for which memory attributes need to be set..
+* @param size: size is the size of the region.
+* @param attrib: Attribute for the given memory region.
+* @return None.
+*
+*
+******************************************************************************/
+u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib)
+{
+ u32 Regionsize = 0;
+ INTPTR Localaddr = addr;
+ u32 NextAvailableMemRegion;
+ unsigned int i;
+
+ NextAvailableMemRegion = Xil_GetNextMPURegion();
+ if (NextAvailableMemRegion == 0xFF) {
+ LOG_E("No regions available\r\n");
+ return XST_FAILURE;
+ }
+
+ Xil_DCacheFlush();
+ Xil_ICacheInvalidate();
+
+ mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,NextAvailableMemRegion);
+ isb();
+
+ /* Lookup the size. */
+ for (i = 0; i < sizeof region_size / sizeof region_size[0]; i++) {
+ if (size <= region_size[i].size) {
+ Regionsize = region_size[i].encoding;
+ break;
+ }
+ }
+
+ Localaddr &= ~(region_size[i].size - 1);
+
+ Regionsize <<= 1;
+ Regionsize |= REGION_EN;
+ dsb();
+ mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr); /* Set base address of a region */
+ mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib); /* Set the control attribute */
+ mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize); /* set the region size and enable it*/
+ dsb();
+ isb();
+ Xil_UpdateMPUConfig(NextAvailableMemRegion, Localaddr, Regionsize, attrib);
+ return XST_SUCCESS;
+}
+/*****************************************************************************/
+/**
+* @brief Enable MPU for Cortex R5 processor. This function invalidates I
+* cache and flush the D Caches, and then enables the MPU.
+*
+*
+* @param None.
+* @return None.
+*
+******************************************************************************/
+void Xil_EnableMPU(void)
+{
+ u32 CtrlReg, Reg;
+ s32 DCacheStatus=0, ICacheStatus=0;
+ /* enable caches only if they are disabled */
+#if defined (__GNUC__)
+ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
+#endif
+ if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
+ DCacheStatus=1;
+ }
+ if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
+ ICacheStatus=1;
+ }
+
+ if(DCacheStatus != 0) {
+ Xil_DCacheDisable();
+ }
+ if(ICacheStatus != 0){
+ Xil_ICacheDisable();
+ }
+#if defined (__GNUC__)
+ Reg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,Reg);
+#endif
+ Reg |= 0x00000001U;
+ dsb();
+ mtcp(XREG_CP15_SYS_CONTROL, Reg);
+ isb();
+ /* enable caches only if they are disabled in routine*/
+ if(DCacheStatus != 0) {
+ Xil_DCacheEnable();
+ }
+ if(ICacheStatus != 0) {
+ Xil_ICacheEnable();
+ }
+}
+
+/*****************************************************************************/
+/**
+* @brief Disable MPU for Cortex R5 processors. This function invalidates I
+* cache and flush the D Caches, and then disabes the MPU.
+*
+* @param None.
+*
+* @return None.
+*
+******************************************************************************/
+void Xil_DisableMPU(void)
+{
+ u32 CtrlReg, Reg;
+ s32 DCacheStatus=0, ICacheStatus=0;
+ /* enable caches only if they are disabled */
+
+#if defined (__GNUC__)
+ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
+#endif
+ if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
+ DCacheStatus=1;
+ }
+ if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
+ ICacheStatus=1;
+ }
+
+ if(DCacheStatus != 0) {
+ Xil_DCacheDisable();
+ }
+ if(ICacheStatus != 0){
+ Xil_ICacheDisable();
+ }
+
+ mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0);
+#if defined (__GNUC__)
+ Reg = mfcp(XREG_CP15_SYS_CONTROL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_SYS_CONTROL,Reg);
+#endif
+ Reg &= ~(0x00000001U);
+ dsb();
+ mtcp(XREG_CP15_SYS_CONTROL, Reg);
+ isb();
+ /* enable caches only if they are disabled in routine*/
+ if(DCacheStatus != 0) {
+ Xil_DCacheEnable();
+ }
+ if(ICacheStatus != 0) {
+ Xil_ICacheEnable();
+ }
+}
+
+/*****************************************************************************/
+/**
+* @brief Update the MPU configuration for the requested region number in
+* the global MPU configuration table.
+*
+* @param reg_num: The requested region number to be updated information for.
+* @param address: 32 bit address for start of the region.
+* @param size: Requested size of the region.
+* @param attrib: Attribute for the corresponding region.
+* @return XST_FAILURE: When the requested region number if 16 or more.
+* XST_SUCCESS: When the MPU configuration table is updated.
+*
+*
+******************************************************************************/
+u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib)
+{
+ u32 ReturnVal = XST_SUCCESS;
+ u32 Tempsize = size;
+ u32 Index;
+
+ if (reg_num >= MAX_POSSIBLE_MPU_REGS) {
+ LOG_E("Invalid region number\r\n");
+ ReturnVal = XST_FAILURE;
+ goto exit;
+ }
+
+ if (size & REGION_EN) {
+ Mpu_Config[reg_num].RegionStatus = MPU_REG_ENABLED;
+ Mpu_Config[reg_num].BaseAddress = address;
+ Tempsize &= (~REGION_EN);
+ Tempsize >>= 1;
+ /* Lookup the size. */
+ for (Index = 0; Index <
+ sizeof region_size / sizeof region_size[0]; Index++) {
+ if (Tempsize <= region_size[Index].encoding) {
+ Mpu_Config[reg_num].Size = region_size[Index].size;
+ break;
+ }
+ }
+ Mpu_Config[reg_num].Attribute = attrib;
+ } else {
+ Mpu_Config[reg_num].RegionStatus = 0U;
+ Mpu_Config[reg_num].BaseAddress = 0U;
+ Mpu_Config[reg_num].Size = 0U;
+ Mpu_Config[reg_num].Attribute = 0U;
+ }
+
+exit:
+ return ReturnVal;
+}
+
+/*****************************************************************************/
+/**
+* @brief The MPU configuration table is passed to the caller.
+*
+* @param mpuconfig: This is of type XMpu_Config which is an array of
+* 16 entries of type structure representing the MPU config table
+* @return none
+*
+*
+******************************************************************************/
+void Xil_GetMPUConfig (XMpu_Config mpuconfig) {
+ u32 Index = 0U;
+
+ while (Index < MAX_POSSIBLE_MPU_REGS) {
+ mpuconfig[Index].RegionStatus = Mpu_Config[Index].RegionStatus;
+ mpuconfig[Index].BaseAddress = Mpu_Config[Index].BaseAddress;
+ mpuconfig[Index].Attribute = Mpu_Config[Index].Attribute;
+ mpuconfig[Index].Size = Mpu_Config[Index].Size;
+ Index++;
+ }
+}
+
+/*****************************************************************************/
+/**
+* @brief Returns the total number of free MPU regions available.
+*
+* @param none
+* @return Number of free regions available to users
+*
+*
+******************************************************************************/
+u32 Xil_GetNumOfFreeRegions (void) {
+ u32 Index = 0U;
+ int NumofFreeRegs = 0U;
+
+ while (Index < MAX_POSSIBLE_MPU_REGS) {
+ if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
+ NumofFreeRegs++;
+ }
+ Index++;
+ }
+ return NumofFreeRegs;
+}
+
+/*****************************************************************************/
+/**
+* @brief Returns the total number of free MPU regions available in the form
+* of a mask. A bit of 1 in the returned 16 bit value represents the
+* corresponding region number to be available.
+* For example, if this function returns 0xC0000, this would mean, the
+* regions 14 and 15 are available to users.
+*
+* @param none
+* @return The free region mask as a 16 bit value
+*
+*
+******************************************************************************/
+u16 Xil_GetMPUFreeRegMask (void) {
+ u32 Index = 0U;
+ u16 FreeRegMask = 0U;
+
+ while (Index < MAX_POSSIBLE_MPU_REGS) {
+ if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
+ FreeRegMask |= (1U << Index);
+ }
+ Index++;
+ }
+ return FreeRegMask;
+}
+
+/*****************************************************************************/
+/**
+* @brief Disables the corresponding region number as passed by the user.
+*
+* @param reg_num: The region number to be disabled
+* @return XST_SUCCESS: If the region could be disabled successfully
+* XST_FAILURE: If the requested region number is 16 or more.
+*
+*
+******************************************************************************/
+u32 Xil_DisableMPURegionByRegNum (u32 reg_num) {
+ u32 Temp = 0U;
+ u32 ReturnVal = XST_FAILURE;
+
+ if (reg_num >= 16U) {
+ LOG_E("Invalid region number\r\n");
+ goto exit1;
+ }
+ Xil_DCacheFlush();
+ Xil_ICacheInvalidate();
+
+ mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
+#if defined (__GNUC__)
+ Temp = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
+#endif
+ Temp &= (~REGION_EN);
+ dsb();
+ mtcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
+ dsb();
+ isb();
+ Xil_UpdateMPUConfig(reg_num, 0U, 0U, 0U);
+ ReturnVal = XST_SUCCESS;
+
+exit1:
+ return ReturnVal;
+}
+
+/*****************************************************************************/
+/**
+* @brief Enables the corresponding region number as passed by the user.
+*
+* @param reg_num: The region number to be enabled
+* @param address: 32 bit address for start of the region.
+* @param size: Requested size of the region.
+* @param attrib: Attribute for the corresponding region.
+* @return XST_SUCCESS: If the region could be created successfully
+* XST_FAILURE: If the requested region number is 16 or more.
+*
+*
+******************************************************************************/
+u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib)
+{
+ u32 ReturnVal = XST_SUCCESS;
+ INTPTR Localaddr = addr;
+ u32 Regionsize = 0;
+ u32 Index;
+
+ if (reg_num >= 16U) {
+ LOG_E("Invalid region number\r\n");
+ ReturnVal = XST_FAILURE;
+ goto exit2;
+ }
+
+ if (Mpu_Config[reg_num].RegionStatus == MPU_REG_ENABLED) {
+ LOG_E("Region already enabled\r\n");
+ ReturnVal = XST_FAILURE;
+ goto exit2;
+ }
+
+ Xil_DCacheFlush();
+ Xil_ICacheInvalidate();
+ mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
+ isb();
+
+ /* Lookup the size. */
+ for (Index = 0; Index <
+ sizeof region_size / sizeof region_size[0]; Index++) {
+ if (size <= region_size[Index].size) {
+ Regionsize = region_size[Index].encoding;
+ break;
+ }
+ }
+
+ Localaddr &= ~(region_size[Index].size - 1);
+ Regionsize <<= 1;
+ Regionsize |= REGION_EN;
+ dsb();
+ mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr);
+ mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib);
+ mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize);
+ dsb();
+ isb();
+ Xil_UpdateMPUConfig(reg_num, Localaddr, Regionsize, attrib);
+exit2:
+ return ReturnVal;
+
+}
+
+/*****************************************************************************/
+/**
+* @brief Initializes the MPU configuration table that are setup in the
+* R5 boot code in the Init_Mpu function called before C main.
+*
+* @param none
+* @return none
+*
+*
+******************************************************************************/
+void Xil_InitializeExistingMPURegConfig(void)
+{
+ u32 Index = 0U;
+ u32 Index1 = 0U;
+ u32 MPURegSize;
+ INTPTR MPURegBA;
+ u32 MPURegAttrib;
+ u32 Tempsize;
+
+ while (Index < MAX_POSSIBLE_MPU_REGS) {
+ mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,Index);
+#if defined (__GNUC__)
+ MPURegSize = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
+ MPURegBA = mfcp(XREG_CP15_MPU_REG_BASEADDR);
+ MPURegAttrib = mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL);
+#elif defined (__ICCARM__)
+ mfcp(XREG_CP15_MPU_REG_SIZE_EN,MPURegSize);
+ mfcp(XREG_CP15_MPU_REG_BASEADDR, MPURegBA);
+ mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL, MPURegAttrib);
+#endif
+ if (MPURegSize & REGION_EN) {
+ Mpu_Config[Index].RegionStatus = MPU_REG_ENABLED;
+ Mpu_Config[Index].BaseAddress = MPURegBA;
+ Mpu_Config[Index].Attribute = MPURegAttrib;
+ Tempsize = MPURegSize & (~REGION_EN);
+ Tempsize >>= 1;
+ for (Index1 = 0; Index1 <
+ (sizeof (region_size) / sizeof (region_size[0])); Index1++) {
+ if (Tempsize <= region_size[Index1].encoding) {
+ Mpu_Config[Index].Size = region_size[Index1].size;
+ break;
+ }
+ }
+ }
+ Index++;
+ }
+}
+
+/*****************************************************************************/
+/**
+* @brief Returns the next available free MPU region
+*
+* @param none
+* @return The free MPU region available
+*
+*
+******************************************************************************/
+u32 Xil_GetNextMPURegion(void)
+{
+ u32 Index = 0U;
+ u32 NextAvailableReg = 0xFF;
+ while (Index < MAX_POSSIBLE_MPU_REGS) {
+ if (Mpu_Config[Index].RegionStatus != MPU_REG_ENABLED) {
+ NextAvailableReg = Index;
+ break;
+ }
+ Index++;
+ }
+ return NextAvailableReg;
+}
+
+/*****************************************************************************/
+/**
+* @brief Memory mapping for Cortex r5.
+*
+* @param Physaddr is base physical address at which to start mapping.
+* NULL in Physaddr masks possible mapping errors.
+* @param size of region to be mapped.
+* @param flags used to set translation table.
+*
+* @return Physaddr on success, NULL on error. Ambiguous if Physaddr==NULL
+*
+* @note: u32overflow() is defined for readability and (for __GNUC__) to
+* - force the type of the check to be the same as the first argument
+* - hide the otherwise unused third argument of the builtin
+* - improve safety by choosing the explicit _uadd_ version.
+* Consider __builtin_add_overflow_p() when available.
+* Use an alternative (less optimal?) for compilers w/o the builtin.
+*
+******************************************************************************/
+#ifdef __GNUC__
+#define u32overflow(a, b) ({typeof(a) s; __builtin_uadd_overflow(a, b, &s); })
+#else
+#define u32overflow(a, b) ((a) > ((a) + (b)))
+#endif /* __GNUC__ */
+void *Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags)
+{
+ size_t Regionsize = MPU_REGION_SIZE_MIN;
+ UINTPTR Basephysaddr = 0, end = Physaddr + size;
+
+ if (!flags)
+ return (void *)Physaddr;
+ if (u32overflow(Physaddr, size))
+ return NULL;
+ for ( ; Regionsize != 0; Regionsize <<= 1) {
+ if (Regionsize >= size) {
+ Basephysaddr = Physaddr & ~(Regionsize - 1);
+ if (u32overflow(Basephysaddr, Regionsize))
+ break;
+ if ((Basephysaddr + Regionsize) >= end)
+ return Xil_SetMPURegion(Basephysaddr,
+ Regionsize, flags) == XST_SUCCESS ?
+ (void *)Physaddr : NULL;
+ }
+ }
+ return NULL;
+}
diff --git a/libcpu/arm/zynqmp-r5/xil_mpu.h b/libcpu/arm/zynqmp-r5/xil_mpu.h
new file mode 100644
index 0000000000..1afa6f76f7
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/xil_mpu.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+*
+* Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*
+*
+*
+******************************************************************************/
+/*****************************************************************************/
+/**
+* @file xil_mmu.h
+*
+* @addtogroup r5_mpu_apis Cortex R5 Processor MPU specific APIs
+*
+* MPU functions provides access to MPU operations such as enable MPU, disable
+* MPU and set attribute for section of memory.
+* Boot code invokes Init_MPU function to configure the MPU. A total of 10 MPU
+* regions are allocated with another 6 being free for users. Overview of the
+* memory attributes for different MPU regions is as given below,
+*
+*| | Memory Range | Attributes of MPURegion |
+*|-----------------------|-------------------------|-----------------------------|
+*| DDR | 0x00000000 - 0x7FFFFFFF | Normal write-back Cacheable |
+*| PL | 0x80000000 - 0xBFFFFFFF | Strongly Ordered |
+*| QSPI | 0xC0000000 - 0xDFFFFFFF | Device Memory |
+*| PCIe | 0xE0000000 - 0xEFFFFFFF | Device Memory |
+*| STM_CORESIGHT | 0xF8000000 - 0xF8FFFFFF | Device Memory |
+*| RPU_R5_GIC | 0xF9000000 - 0xF90FFFFF | Device memory |
+*| FPS | 0xFD000000 - 0xFDFFFFFF | Device Memory |
+*| LPS | 0xFE000000 - 0xFFFFFFFF | Device Memory |
+*| OCM | 0xFFFC0000 - 0xFFFFFFFF | Normal write-back Cacheable |
+*
+*
+* @note
+* For a system where DDR is less than 2GB, region after DDR and before PL is
+* marked as undefined in translation table. Memory range 0xFE000000-0xFEFFFFFF is
+* allocated for upper LPS slaves, where as memory region 0xFF000000-0xFFFFFFFF is
+* allocated for lower LPS slaves.
+*
+* @{
+* <pre>
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- ---------------------------------------------------
+* 5.00 pkp 02/10/14 Initial version
+* 6.4 asa 08/16/17 Added many APIs for MPU access to make MPU usage
+* user-friendly. The APIs added are: Xil_UpdateMPUConfig,
+* Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
+* Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
+* Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
+* Xil_InitializeExistingMPURegConfig.
+* Added a new array of structure of type XMpuConfig to
+* represent the MPU configuration table.
+* </pre>
+*
+
+*
+*
+******************************************************************************/
+
+#ifndef XIL_MPU_H
+#define XIL_MPU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#include "xil_types.h"
+/***************************** Include Files *********************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+#define MPU_REG_DISABLED 0U
+#define MPU_REG_ENABLED 1U
+#define MAX_POSSIBLE_MPU_REGS 16U
+/**************************** Type Definitions *******************************/
+struct XMpuConfig{
+ u32 RegionStatus; /* Enabled or disabled */
+ INTPTR BaseAddress;/* MPU region base address */
+ u64 Size; /* MPU region size address */
+ u32 Attribute; /* MPU region size attribute */
+};
+
+typedef struct XMpuConfig XMpu_Config[MAX_POSSIBLE_MPU_REGS];
+
+extern XMpu_Config Mpu_Config;
+/************************** Constant Definitions *****************************/
+
+/************************** Variable Definitions *****************************/
+
+/************************** Function Prototypes ******************************/
+
+void Xil_SetTlbAttributes(INTPTR Addr, u32 attrib);
+void Xil_EnableMPU(void);
+void Xil_DisableMPU(void);
+u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib);
+u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib);
+void Xil_GetMPUConfig (XMpu_Config mpuconfig);
+u32 Xil_GetNumOfFreeRegions (void);
+u32 Xil_GetNextMPURegion(void);
+u32 Xil_DisableMPURegionByRegNum (u32 reg_num);
+u16 Xil_GetMPUFreeRegMask (void);
+u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib);
+void* Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XIL_MPU_H */
+/**
+* @} End of "addtogroup r5_mpu_apis".
+*/
diff --git a/libcpu/risc-v/SConscript b/libcpu/risc-v/SConscript
index dece8b0423..18b4c2005d 100644
--- a/libcpu/risc-v/SConscript
+++ b/libcpu/risc-v/SConscript
@@ -14,6 +14,8 @@ if rtconfig.CPU == "e906" :
group = group
elif rtconfig.CPU == "nuclei" :
group = group
+elif rtconfig.CPU == "virt64" :
+ group = group
else :
group = group + SConscript(os.path.join(cwd, 'common', 'SConscript'))
diff --git a/libcpu/risc-v/virt64/SConscript b/libcpu/risc-v/virt64/SConscript
new file mode 100644
index 0000000000..b0ae20ba02
--- /dev/null
+++ b/libcpu/risc-v/virt64/SConscript
@@ -0,0 +1,14 @@
+# RT-Thread building script for component
+
+from building import *
+
+Import('rtconfig')
+
+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/virt64/context_gcc.S b/libcpu/risc-v/virt64/context_gcc.S
new file mode 100644
index 0000000000..40803148df
--- /dev/null
+++ b/libcpu/risc-v/virt64/context_gcc.S
@@ -0,0 +1,307 @@
+/*
+ * 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
+ */
+#include "cpuport.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
+
+/*
+ * 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
+
+/*
+ * void rt_hw_interrupt_enable(rt_base_t level);
+ */
+ .globl rt_hw_interrupt_enable
+rt_hw_interrupt_enable:
+ csrw SRC_XSTATUS, a0
+ ret
+
+/*
+ * #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
+ */
+ .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
+
+/*
+ * #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
+ */
+ .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)
+
+ STORE x1, 0 * REGBYTES(sp)
+ STORE x1, 1 * REGBYTES(sp)
+
+
+ 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
+
+ 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 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
+ */
+ .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
+
+#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)
+
+ addi sp, sp, 32 * FREGBYTES
+#endif
+
+ XRET
diff --git a/libcpu/risc-v/virt64/cpuport.c b/libcpu/risc-v/virt64/cpuport.c
new file mode 100644
index 0000000000..33cab19488
--- /dev/null
+++ b/libcpu/risc-v/virt64/cpuport.c
@@ -0,0 +1,123 @@
+/*
+ * 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
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "cpuport.h"
+#include "stack.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));
+
+#ifndef RISCV_S_MODE
+ frame->xstatus = 0x00007880;
+#else
+ frame->xstatus = 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)
+{
+ 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);
+ }
+}
+
+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)));
+}
+
+void *get_thread_kernel_stack_top(rt_thread_t thread)
+{
+ return (void *)(((rt_size_t)thread -> stack_addr) + ((rt_size_t)thread -> stack_size));
+}
diff --git a/libcpu/risc-v/virt64/cpuport.h b/libcpu/risc-v/virt64/cpuport.h
new file mode 100644
index 0000000000..fa0776b509
--- /dev/null
+++ b/libcpu/risc-v/virt64/cpuport.h
@@ -0,0 +1,55 @@
+/*
+ * 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>
+
+/* bytes of register width */
+#ifdef ARCH_CPU_64BIT
+#define STORE sd
+#define LOAD ld
+#define REGBYTES 8
+#else
+// error here, not portable
+#endif
+
+#ifdef RISCV_U_MODE
+#define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL
+#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
+#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
+#endif
+
+#endif
diff --git a/libcpu/risc-v/virt64/interrupt.c b/libcpu/risc-v/virt64/interrupt.c
new file mode 100644
index 0000000000..7916be8f6f
--- /dev/null
+++ b/libcpu/risc-v/virt64/interrupt.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2006-2021, 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 Change irq enable/disable to cpu0
+ */
+#include "tick.h"
+#include <plic.h>
+#include "encoding.h"
+#include "riscv.h"
+#include "interrupt.h"
+
+#define CPU_NUM 2
+#define MAX_HANDLERS 128
+
+static struct rt_irq_desc irq_desc[MAX_HANDLERS];
+
+static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
+{
+ rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
+ 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);
+ return 0;
+}
+
+int rt_hw_plic_irq_disable(int irq_number)
+{
+ plic_irq_disable(irq_number);
+ return 0;
+}
+
+/**
+ * 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++)
+ {
+ //rt_hw_interrupt_mask(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
+ }
+}
+
+/**
+ * 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
+ */
+void rt_hw_interrupt_umask(int vector)
+{
+ plic_set_priority(vector, 1);
+ plic_set_threshold(0);
+ rt_hw_plic_irq_enable(vector);
+}
+
+/**
+ * This function will install a interrupt service routine to a interrupt.
+ * @param vector the interrupt number
+ * @param new_handler the interrupt service routine to be installed
+ * @param old_handler the old interrupt service routine
+ */
+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 < MAX_HANDLERS)
+ {
+ old_handler = irq_desc[vector].handler;
+ if (handler != RT_NULL)
+ {
+ irq_desc[vector].handler = (rt_isr_handler_t)handler;
+ irq_desc[vector].param = param;
+#ifdef RT_USING_INTERRUPT_INFO
+ rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
+ irq_desc[vector].counter = 0;
+#endif
+ }
+ }
+
+ return old_handler;
+}
+
+RT_WEAK
+void plic_irq_handle(int irq)
+{
+ 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
+ {
+ rt_thread_t tid;
+ extern long list_thread();
+
+ 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);
+#ifdef RT_USING_FINSH
+ list_thread();
+#endif
+ while(1);
+ }
+ rt_hw_interrupt_enable(0);
+}
diff --git a/libcpu/risc-v/virt64/interrupt.h b/libcpu/risc-v/virt64/interrupt.h
new file mode 100644
index 0000000000..e49f0215bf
--- /dev/null
+++ b/libcpu/risc-v/virt64/interrupt.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-20 bigmagic The first version
+ */
+
+#ifndef INTERRUPT_H__
+#define INTERRUPT_H__
+
+#include <rthw.h>
+#include "stack.h"
+
+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);
+void rt_hw_interrupt_mask(int vector);
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
+ void *param, const char *name);
+void handle_trap(rt_size_t xcause,rt_size_t xtval,rt_size_t xepc,struct rt_hw_stack_frame *sp);
+
+#endif
diff --git a/libcpu/risc-v/virt64/interrupt_gcc.S b/libcpu/risc-v/virt64/interrupt_gcc.S
new file mode 100644
index 0000000000..730fa10d61
--- /dev/null
+++ b/libcpu/risc-v/virt64/interrupt_gcc.S
@@ -0,0 +1,151 @@
+/*
+ * 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
+ */
+
+#include "cpuport.h"
+
+ .section .text.entry
+ .align 2
+ .global trap_entry
+trap_entry:
+#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
+
+ /* save thread context to thread stack */
+ addi sp, sp, -32 * REGBYTES
+
+ STORE x1, 1 * REGBYTES(sp)
+
+ csrr x1, SRC_XSTATUS
+ STORE x1, 2 * REGBYTES(sp)
+
+ csrr x1, SRC_XEPC
+ STORE x1, 0 * REGBYTES(sp)
+
+ 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)
+
+ /* switch to interrupt stack */
+ move s0, sp
+
+#ifndef RISCV_S_MODE
+ /* get cpu id */
+ csrr t0, mhartid
+#else
+ li t0, 0
+#endif
+
+ /* 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__ */
+
+ /* handle interrupt */
+ call rt_interrupt_enter
+ csrr a0, SRC_XCAUSE
+ csrr a1, SRC_XEPC
+ mv a2, 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
diff --git a/libcpu/risc-v/virt64/riscv.h b/libcpu/risc-v/virt64/riscv.h
new file mode 100644
index 0000000000..d0c0cc4b38
--- /dev/null
+++ b/libcpu/risc-v/virt64/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/virt64/riscv_io.h b/libcpu/risc-v/virt64/riscv_io.h
new file mode 100644
index 0000000000..391d7f5a41
--- /dev/null
+++ b/libcpu/risc-v/virt64/riscv_io.h
@@ -0,0 +1,137 @@
+/*
+ * 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__
+
+// which hart (core) is this?
+static inline uint32_t r_mhartid()
+{
+#ifndef RISCV_S_MODE
+ uint32_t x;
+ asm volatile("csrr %0, mhartid" : "=r" (x) );
+ return x;
+#else
+ return 0;
+#endif
+}
+
+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/virt64/stack.h b/libcpu/risc-v/virt64/stack.h
new file mode 100644
index 0000000000..09179238ea
--- /dev/null
+++ b/libcpu/risc-v/virt64/stack.h
@@ -0,0 +1,52 @@
+/*
+ * 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 __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 xstatus; /* - supervisor/machine/user 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 */
+};
+
+#endif
diff --git a/libcpu/risc-v/virt64/stackframe.h b/libcpu/risc-v/virt64/stackframe.h
new file mode 100644
index 0000000000..eb4e4f9d86
--- /dev/null
+++ b/libcpu/risc-v/virt64/stackframe.h
@@ -0,0 +1,155 @@
+/*
+ * 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
+ */
+
+#ifndef __STACKFRAME_H__
+#define __STACKFRAME_H__
+
+#include "cpuport.h"
+
+.macro SAVE_ALL
+ addi sp, sp, -33 * REGBYTES
+
+ STORE x1, 1 * REGBYTES(sp)
+
+ csrr x1, SRC_XSTATUS
+ STORE x1, 2 * REGBYTES(sp)
+
+ csrr x1, SRC_XEPC
+ STORE x1, 0 * REGBYTES(sp)
+
+ STORE x3, 3 * REGBYTES(sp)
+ 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)
+ csrr t0, SRC_XSCRATCH
+ STORE t0, 32 * REGBYTES(sp)
+.endm
+
+.macro RESTORE_ALL_ONLY
+ /* resw ra to sepc */
+ LOAD x1, 0 * REGBYTES(sp)
+ csrw SRC_XEPC, x1
+
+ LOAD x1, 2 * REGBYTES(sp)
+ csrw SRC_XSTATUS, x1
+
+ LOAD x1, 1 * REGBYTES(sp)
+
+ 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)
+
+ addi sp, sp, 33 * REGBYTES
+.endm
+
+.macro RESTORE_ALL
+ /* resw ra to sepc */
+ LOAD x1, 0 * REGBYTES(sp)
+ csrw SRC_XEPC, x1
+
+ LOAD x1, 2 * REGBYTES(sp)
+ csrw SRC_XSTATUS, x1
+
+ LOAD x1, 1 * REGBYTES(sp)
+
+ 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)
+
+ //restore user sp
+ LOAD sp, 32 * REGBYTES(sp)
+.endm
+
+.macro RESTORE_SYS_GP
+ .option push
+ .option norelax
+ la gp, __global_pointer$
+ .option pop
+.endm
+
+#endif
diff --git a/libcpu/risc-v/virt64/startup_gcc.S b/libcpu/risc-v/virt64/startup_gcc.S
new file mode 100644
index 0000000000..ac980f6ed2
--- /dev/null
+++ b/libcpu/risc-v/virt64/startup_gcc.S
@@ -0,0 +1,57 @@
+/*
+ * 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 XSTATUS_FS (3 << 13) /* initial state of FPU, clear to disable */
+#define XSTATUS_PUM (1 << 18)
+#include <cpuport.h>
+
+ .global _start
+ .section ".start", "ax"
+_start:
+#ifndef RISCV_S_MODE
+ # 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
+
+ la t0, trap_entry
+ csrw SRC_XTVEC, t0 # set Trap Vector Base Address Register
+
+ /* 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
+
+.option push
+.option norelax
+ la gp, __global_pointer$
+.option pop
+
+ la sp, __stack_start__
+ li t0, __STACKSIZE__
+ add sp, sp, t0
+ csrw SRC_XSCRATCH, sp
+ j primary_cpu_entry
+
+park:
+ wfi
+ j park \ No newline at end of file
diff --git a/libcpu/risc-v/virt64/tick.c b/libcpu/risc-v/virt64/tick.c
new file mode 100644
index 0000000000..d6970ec417
--- /dev/null
+++ b/libcpu/risc-v/virt64/tick.c
@@ -0,0 +1,69 @@
+/*
+ * 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 "sbi.h"
+#include "tick.h"
+#include <riscv_io.h>
+#include <encoding.h>
+
+#define VIRT_CLINT_TIMEBASE_FREQ (10000000)
+
+static volatile uint64_t time_elapsed = 0;
+static volatile unsigned long tick_cycles = 0;
+
+static uint64_t get_ticks()
+{
+ __asm__ __volatile__(
+ "rdtime %0"
+ : "=r"(time_elapsed));
+ return time_elapsed;
+}
+
+int tick_isr(void)
+{
+ int tick_cycles = VIRT_CLINT_TIMEBASE_FREQ / RT_TICK_PER_SECOND;
+ rt_tick_increase();
+#ifdef RISCV_S_MODE
+ sbi_set_timer(get_ticks() + tick_cycles);
+#else
+ *(uint64_t*)CLINT_MTIMECMP(r_mhartid()) = *(uint64_t*)CLINT_MTIME + tick_cycles;
+#endif
+
+ return 0;
+}
+
+/* Sets and enable the timer interrupt */
+int rt_hw_tick_init(void)
+{
+ unsigned long interval = VIRT_CLINT_TIMEBASE_FREQ / RT_TICK_PER_SECOND;
+
+#ifdef RISCV_S_MODE
+ /* Clear the Supervisor-Timer bit in SIE */
+ clear_csr(sie, SIP_STIP);
+
+ /* calculate the tick cycles */
+ // tick_cycles = interval * sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000ULL - 1;
+ tick_cycles = 40000;
+ /* Set timer */
+ sbi_set_timer(get_ticks() + tick_cycles);
+
+ /* 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(r_mhartid()) = *(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
new file mode 100644
index 0000000000..c5a55cf16f
--- /dev/null
+++ b/libcpu/risc-v/virt64/tick.h
@@ -0,0 +1,22 @@
+/*
+ * 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__
+
+//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);
+
+#endif