Просмотр исходного кода

!586 Add QEMU rv64 vector support & interrupt handling/process switch improvement
Merge pull request !586 from PolarLush/riscv-vector

bernard 3 лет назад
Родитель
Сommit
80000298eb

+ 182 - 8
bsp/qemu-virt64-riscv/.config

@@ -16,7 +16,7 @@ CONFIG_RT_THREAD_PRIORITY_32=y
 # CONFIG_RT_THREAD_PRIORITY_256 is not set
 CONFIG_RT_THREAD_PRIORITY_MAX=32
 CONFIG_RT_TICK_PER_SECOND=100
-# CONFIG_RT_USING_OVERFLOW_CHECK is not set
+CONFIG_RT_USING_OVERFLOW_CHECK=y
 CONFIG_RT_USING_HOOK=y
 CONFIG_RT_USING_IDLE_HOOK=y
 CONFIG_RT_IDLE_HOOK_LIST_SIZE=4
@@ -102,12 +102,12 @@ CONFIG_RT_USING_MSH=y
 CONFIG_FINSH_USING_MSH=y
 CONFIG_FINSH_THREAD_NAME="tshell"
 CONFIG_FINSH_USING_HISTORY=y
-CONFIG_FINSH_HISTORY_LINES=5
+CONFIG_FINSH_HISTORY_LINES=10
 CONFIG_FINSH_USING_SYMTAB=y
 CONFIG_FINSH_USING_DESCRIPTION=y
 # CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set
 CONFIG_FINSH_THREAD_PRIORITY=20
-CONFIG_FINSH_THREAD_STACK_SIZE=4096
+CONFIG_FINSH_THREAD_STACK_SIZE=16384
 CONFIG_FINSH_CMD_SIZE=80
 # CONFIG_FINSH_USING_AUTH is not set
 CONFIG_FINSH_ARG_MAX=10
@@ -142,6 +142,7 @@ CONFIG_RT_USING_DFS_DEVFS=y
 CONFIG_RT_USING_DFS_ROMFS=y
 # CONFIG_RT_USING_DFS_CROMFS is not set
 # CONFIG_RT_USING_DFS_RAMFS is not set
+# CONFIG_RT_USING_DFS_TMPFS is not set
 # CONFIG_RT_USING_DFS_UFFS is not set
 # CONFIG_RT_USING_DFS_JFFS2 is not set
 # CONFIG_RT_USING_DFS_NFS is not set
@@ -562,6 +563,7 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_HASH_MATCH is not set
 # CONFIG_PKG_USING_FIRE_PID_CURVE is not set
 # CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set
+# CONFIG_PKG_USING_VOFA_PLUS is not set
 
 #
 # system packages
@@ -597,7 +599,6 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_UC_CLK is not set
 # CONFIG_PKG_USING_UC_COMMON is not set
 # CONFIG_PKG_USING_UC_MODBUS is not set
-# CONFIG_PKG_USING_RTDUINO is not set
 # CONFIG_PKG_USING_FREERTOS_WRAPPER is not set
 # CONFIG_PKG_USING_CAIRO is not set
 # CONFIG_PKG_USING_PIXMAN is not set
@@ -632,6 +633,7 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_KMULTI_RTIMER is not set
 # CONFIG_PKG_USING_TFDB is not set
 # CONFIG_PKG_USING_QPC is not set
+# CONFIG_PKG_USING_AGILE_UPGRADE is not set
 
 #
 # peripheral libraries and drivers
@@ -643,7 +645,7 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_ADT74XX is not set
 # CONFIG_PKG_USING_AS7341 is not set
 # CONFIG_PKG_USING_STM32_SDIO is not set
-# CONFIG_PKG_USING_RTT_ESP_IDF is not set
+# CONFIG_PKG_USING_ESP_IDF is not set
 # CONFIG_PKG_USING_ICM20608 is not set
 # CONFIG_PKG_USING_BUTTON is not set
 # CONFIG_PKG_USING_PCF8574 is not set
@@ -798,9 +800,176 @@ CONFIG_RT_LWP_SHM_MAX_NR=64
 # CONFIG_PKG_USING_MFBD is not set
 # CONFIG_PKG_USING_SLCAN2RTT is not set
 # CONFIG_PKG_USING_SOEM is not set
-CONFIG_BOARD_virt=y
-CONFIG_ENABLE_FPU=y
-# CONFIG_RT_USING_USERSPACE_32BIT_LIMIT is not set
+# CONFIG_PKG_USING_QPARAM is not set
+
+#
+# Arduino libraries
+#
+# CONFIG_PKG_USING_RTDUINO is not set
+
+#
+# Projects
+#
+# CONFIG_PKG_USING_ARDUINO_ULTRASOUND_RADAR is not set
+# CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set
+# CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set
+
+#
+# Sensors
+#
+# CONFIG_PKG_USING_ARDUINO_SEEED_BMP280 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL375 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VL53L0X is not set
+# CONFIG_PKG_USING_ARDUINO_SEEED_LIS3DHTR is not set
+# CONFIG_PKG_USING_ARDUINO_SEEED_DHT is not set
+# CONFIG_PKG_USING_ARDUINO_CAPACITIVESENSOR is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SENSOR is not set
+# CONFIG_PKG_USING_ADAFRUIT_MAX31855 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31865 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX31856 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90614 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS1 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AHTX0 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM9DS0 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP280 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADT7410 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME680 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9808 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4728 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA219 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR390 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL345 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DHT is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP9600 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM6DS is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO055 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MAX1704X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMC56X3 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90393 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90395 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ICM20X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DPS310 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTS221 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT4X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHT31 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADXL343 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BME280 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS726X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AMG88XX is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2320 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AM2315 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LTR329_LTR303 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP085_UNIFIED is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP183_UNIFIED is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BMP3XX is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MS8607 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3MDL is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MLX90640 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MMA8451 is not set
+# CONFIG_PKG_USING_ADAFRUIT_MSA301 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL115A2 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BNO08X_RVC is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS2MDL is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303DLH_MAG is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LC709203F is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CAP1188 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_CCS811 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_NAU7802 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS331 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS2X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LPS35HW is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LSM303_ACCEL is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_LIS3DH is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8591 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPL3115A2 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPR121 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPRLS is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MPU6050 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCT2075 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PM25AQI is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_EMC2101 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXAS21002C is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SCD30 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_FXOS8700 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HMC5883_UNIFIED is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP30 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP006 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TLA202X is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCS34725 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI7021 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI1145 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SGP40 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SHTC3 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HDC1000 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU21DF is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AS7341 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_HTU31D is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_INA260 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP007_LIBRARY is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_L3GD20 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TMP117 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSC2007 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2561 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TSL2591_LIBRARY is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VCNL4040 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6070 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML6075 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_VEML7700 is not set
+
+#
+# Display
+#
+# CONFIG_PKG_USING_ARDUINO_U8G2 is not set
+
+#
+# Timing
+#
+# CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set
+
+#
+# Data Processing
+#
+# CONFIG_PKG_USING_ARDUINO_KALMANFILTER is not set
+# CONFIG_PKG_USING_ARDUINO_ARDUINOJSON is not set
+
+#
+# Data Storage
+#
+
+#
+# Communication
+#
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PN532 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI4713 is not set
+
+#
+# Device Control
+#
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCF8574 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PCA9685 is not set
+
+#
+# Other
+#
+
+#
+# Signal IO
+#
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BUSIO is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_TCA8418 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP23017 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ADS1X15 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_AW9523 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP3008 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4725 is not set
+# CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BD3491FS is not set
+
+#
+# Uncategorized
+#
 
 #
 # RISC-V QEMU virt64 configs
@@ -812,4 +981,9 @@ CONFIG_BSP_USING_VIRTIO_NET=y
 # CONFIG_BSP_USING_VIRTIO_GPU is not set
 # CONFIG_BSP_USING_VIRTIO_INPUT is not set
 # CONFIG_BSP_USING_UART1 is not set
+CONFIG_BOARD_QEMU_VIRT_RV64=y
+CONFIG_ENABLE_FPU=y
+# CONFIG_ENABLE_VECTOR is not set
+# CONFIG_RT_USING_USERSPACE_32BIT_LIMIT is not set
+CONFIG_ARCH_USING_NEW_CTX_SWITCH=y
 CONFIG___STACKSIZE__=16384

+ 23 - 2
bsp/qemu-virt64-riscv/Kconfig

@@ -17,10 +17,12 @@ config PKGS_DIR
 
 source "$RTT_DIR/Kconfig"
 source "$PKGS_DIR/Kconfig"
+source "driver/Kconfig"
 
-config BOARD_virt
+config BOARD_QEMU_VIRT_RV64
     bool
     select ARCH_RISCV64
+    select ARCH_CONTEXT_EXTEND
     select RT_USING_COMPONENTS_INIT
     select RT_USING_USER_MAIN
     select RT_USING_CACHE
@@ -35,6 +37,23 @@ config ENABLE_FPU
     bool "Enable FPU"
     default y
 
+config ENABLE_VECTOR
+    bool "Using RISC-V Vector Extension"
+    default n
+
+if ENABLE_VECTOR
+    choice
+    prompt "Vector Registers Length in Bits"
+    default ARCH_VECTOR_VLEN_128
+    
+    config ARCH_VECTOR_VLEN_128
+        bool "128"
+
+    config ARCH_VECTOR_VLEN_256
+        bool "256"
+    endchoice
+endif
+
 config RT_USING_USERSPACE_32BIT_LIMIT
     bool "Enable userspace 32bit limit"
     default n
@@ -43,7 +62,9 @@ config RT_USING_VIRTIO_MMIO_ALIGN
     bool "Open packed attribution, this may caused an error on virtio"
     default n
 
-source "driver/Kconfig"
+config ARCH_USING_NEW_CTX_SWITCH
+    bool
+    default y
 
 config __STACKSIZE__
     int "stack size for interrupt"

+ 9 - 0
bsp/qemu-virt64-riscv/applications/test/test_vector/SConscript

@@ -0,0 +1,9 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src	= Glob('*.c') + Glob('*.cpp')
+CPPPATH = [cwd]
+
+group = DefineGroup('Vector', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 178 - 0
bsp/qemu-virt64-riscv/applications/test/test_vector/test_vector.c

@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+#include <rtthread.h>
+#include <rthw.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(RT_USING_UTEST) && defined(ENABLE_VECTOR)
+#include <utest.h>
+#include <ext_context.h>
+
+void rt_hw_vector_ctx_restore(void *buf);
+void rt_hw_vector_ctx_save(void *buf);
+
+/**
+ * ==============================================================
+ * TEST FEATURE
+ * Use libc `memcpy` which employing V extension codes
+ * to test V extension features
+ * ==============================================================
+ */
+static char *constant = "hello,it's a nice day and i'm happy to see you\n";
+#define ARR_SIZE 4096
+static char array[ARR_SIZE];
+
+static void test_feature(void)
+{
+    memcpy(array, constant, sizeof array);
+    char *src = constant;
+    char *dst = array;
+    int error = 0;
+
+    for (size_t i = 0; i < ARR_SIZE; i++)
+    {
+        if (src[i] != dst[i])
+        {
+            error = 1;
+            break;
+        }
+    }
+
+    uassert_false(error);
+}
+
+/**
+ * ==============================================================
+ * TEST CONTEXT SAVING
+ * Create 2 threads employing V extension, verify V states are
+ * not modified by each other
+ * ==============================================================
+ */
+#define TEST_THREAD 2
+#define VECTOR_CTX_BYTES (CTX_VECTOR_REG_NR * REGBYTES)
+void *ctx_vector[TEST_THREAD * 2];
+
+static rt_sem_t sem;
+
+void dump_frame(void *frame)
+{
+    uint64_t *content = frame;
+    for (size_t i = 0; i < VECTOR_CTX_BYTES / 8; i++)
+    {
+        rt_kprintf("%x ", content[i]);
+    }
+    rt_kprintf("\n");
+}
+
+static void vector_child(void *param)
+{
+    void **ctx = param;
+    uint64_t *reg = ctx[0];
+    uint64_t vtype;
+    uint64_t vl;
+
+    rt_sem_release(sem);
+
+    rt_hw_vector_ctx_restore(ctx[0]);
+
+    /* STAGE 2, save t2 context */
+    test_feature();
+
+    /**
+     * @brief vtype & vl will be modified after context saving,
+     * it's ok because it will be recover after context restoring
+     * We restore these states manually here.
+     */
+    asm volatile("csrr %0, vtype":"=r"(vtype));
+    asm volatile("csrr %0, vl":"=r"(vl));
+    rt_hw_vector_ctx_save(ctx[0]);
+
+    rt_memcpy(ctx[1], ctx[0], VECTOR_CTX_BYTES);
+
+    rt_thread_yield();
+
+    asm volatile("vsetvl x0, %0, %1"::"r"(vl), "r"(vtype));
+    rt_hw_vector_ctx_save(ctx[0]);
+
+    uassert_false(rt_memcmp(ctx[1], ctx[0], VECTOR_CTX_BYTES));
+}
+
+/**
+ * @brief Test if context save/restore codes work properly
+ */
+static void test_context()
+{
+    rt_thread_t child;
+    uint64_t vtype;
+    uint64_t vl;
+
+    for (size_t i = 0; i < TEST_THREAD; i++)
+    {
+        ctx_vector[i * 2] = calloc(VECTOR_CTX_BYTES, 1);
+        ctx_vector[i * 2 + 1] = calloc(VECTOR_CTX_BYTES, 1);
+    }
+    rt_hw_vector_ctx_restore(ctx_vector[0]);
+
+    child = rt_thread_create("test_vector_child", vector_child, &ctx_vector[2], 4096, 10, 20);
+
+    /* STAGE 1, save t1 context */
+    /* assuming that rt libc memcpy do not use vector instruction */
+    asm volatile("csrr %0, vtype":"=r"(vtype));
+    asm volatile("csrr %0, vl":"=r"(vl));
+    rt_hw_vector_ctx_save(ctx_vector[0]);
+
+    rt_memcpy(ctx_vector[1], ctx_vector[0], VECTOR_CTX_BYTES);
+
+    rt_thread_startup(child);
+    rt_sem_take(sem, 0);
+
+    /* STAGE 3, verify t1 context */
+    asm volatile("vsetvl x0, %0, %1"::"r"(vl), "r"(vtype));
+    rt_hw_vector_ctx_save(ctx_vector[0]);
+    uassert_false(rt_memcmp(ctx_vector[1], ctx_vector[0], VECTOR_CTX_BYTES));
+
+    rt_thread_yield();
+}
+
+/**
+ * ==============================================================
+ * TEST NO VECTOR raise error and recover
+ * ==============================================================
+ */
+
+static void test_no_vector()
+{
+    asm volatile ("li t0, 0x600\n"
+                "csrc sstatus, t0");
+    test_feature();
+    uassert_true(1);
+}
+
+static rt_err_t utest_tc_init(void)
+{
+    sem = rt_sem_create("test_ctx", 0, RT_IPC_FLAG_FIFO);
+    return RT_EOK;
+}
+
+static rt_err_t utest_tc_cleanup(void)
+{
+    rt_sem_delete(sem);
+    return RT_EOK;
+}
+
+static void testcase(void)
+{
+    UTEST_UNIT_RUN(test_feature);
+    UTEST_UNIT_RUN(test_context);
+    UTEST_UNIT_RUN(test_no_vector);
+}
+
+UTEST_TC_EXPORT(testcase, "testcases.libcpu.vector", utest_tc_init, utest_tc_cleanup, 10);
+#endif /* RT_USING_UTEST && ENABLE_VECTOR */

+ 39 - 4
bsp/qemu-virt64-riscv/rtconfig.h

@@ -12,6 +12,7 @@
 #define RT_THREAD_PRIORITY_32
 #define RT_THREAD_PRIORITY_MAX 32
 #define RT_TICK_PER_SECOND 100
+#define RT_USING_OVERFLOW_CHECK
 #define RT_USING_HOOK
 #define RT_USING_IDLE_HOOK
 #define RT_IDLE_HOOK_LIST_SIZE 4
@@ -71,11 +72,11 @@
 #define FINSH_USING_MSH
 #define FINSH_THREAD_NAME "tshell"
 #define FINSH_USING_HISTORY
-#define FINSH_HISTORY_LINES 5
+#define FINSH_HISTORY_LINES 10
 #define FINSH_USING_SYMTAB
 #define FINSH_USING_DESCRIPTION
 #define FINSH_THREAD_PRIORITY 20
-#define FINSH_THREAD_STACK_SIZE 4096
+#define FINSH_THREAD_STACK_SIZE 16384
 #define FINSH_CMD_SIZE 80
 #define FINSH_ARG_MAX 10
 
@@ -297,14 +298,48 @@
 
 /* entertainment: terminal games and other interesting software packages */
 
-#define BOARD_virt
-#define ENABLE_FPU
+
+/* Arduino libraries */
+
+
+/* Projects */
+
+
+/* Sensors */
+
+
+/* Display */
+
+
+/* Timing */
+
+
+/* Data Processing */
+
+
+/* Data Storage */
+
+/* Communication */
+
+
+/* Device Control */
+
+
+/* Other */
+
+/* Signal IO */
+
+
+/* Uncategorized */
 
 /* RISC-V QEMU virt64 configs */
 
 #define RISCV_S_MODE
 #define BSP_USING_VIRTIO_BLK
 #define BSP_USING_VIRTIO_NET
+#define BOARD_QEMU_VIRT_RV64
+#define ENABLE_FPU
+#define ARCH_USING_NEW_CTX_SWITCH
 #define __STACKSIZE__ 16384
 
 #endif

+ 4 - 4
bsp/qemu-virt64-riscv/rtconfig.py

@@ -37,15 +37,15 @@ if PLATFORM == 'gcc':
     OBJDUMP = PREFIX + 'objdump'
     OBJCPY  = PREFIX + 'objcopy'
 
-    DEVICE  = ' -mcmodel=medany -march=rv64imafdc -mabi=lp64'
-    CFLAGS  = DEVICE + ' -fvar-tracking -ffreestanding -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields'
-    AFLAGS  = ' -c' + DEVICE + ' -x assembler-with-cpp'
+    DEVICE  = ' -mcmodel=medany -march=rv64imafdc -mabi=lp64 '
+    CFLAGS  = DEVICE + '-ffreestanding -fno-common -ffunction-sections -fdata-sections -fstrict-volatile-bitfields'
+    AFLAGS  = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__ '
     LFLAGS  = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,_start -T link.lds' + ' -lsupc++ -lgcc -static'
     CPATH   = ''
     LPATH   = ''
 
     if BUILD == 'debug':
-        CFLAGS += ' -O0 -ggdb'
+        CFLAGS += ' -O0 -ggdb -fvar-tracking '
         AFLAGS += ' -ggdb'
     else:
         CFLAGS += ' -O2 -Os'

+ 61 - 24
components/lwp/arch/risc-v/rv64/lwp_gcc.S

@@ -25,6 +25,8 @@
 .global arch_start_umode
 .type arch_start_umode, % function
 arch_start_umode:
+    // load kstack for user process
+    csrw sscratch, a3
     li t0, SSTATUS_SPP | SSTATUS_SIE    // set as user mode, close interrupt
     csrc sstatus, t0 
     li t0, SSTATUS_SPIE // enable interrupt when return to user mode
@@ -57,18 +59,20 @@ arch_crt_start_umode:
     mv sp, a0//user_sp
     mv ra, a0//return address
     mv a0, s0//args
+
+    csrw sscratch, s3
     sret//enter user mode
 
 .global arch_ret_to_user
 arch_ret_to_user:
     call lwp_signal_check
     beqz a0, ret_to_user_exit
-    RESTORE_ALL
-    //now sp is user sp
+    // now sp is user sp
     J user_do_signal
 
 ret_to_user_exit:
     RESTORE_ALL
+    // `RESTORE_ALL` also reset sp to user sp
     sret
 
 /*#ifdef RT_USING_LWP
@@ -127,23 +131,27 @@ lwp_check_debug_quit:
 //#endif
 */
 
-.global arch_signal_quit
 arch_signal_quit:
     call lwp_signal_restore
     //a0 is user_ctx
     mv sp, a0
     RESTORE_ALL
+    csrw sscratch, zero
     sret
 
 user_do_signal:
-    //now sp is user sp
-    //save context to user sp
+    csrw sscratch, sp
+    RESTORE_ALL
+    // now sp is user sp
+    // and in interrupt close
     SAVE_ALL
-    //ensure original user sp correct
+
+    // save user sp in SAVE_ALL frame
     mv t0, sp
     addi t0, t0, CTX_REG_NR * REGBYTES
-    STORE t0, CTX_REG_NR * REGBYTES(sp)
-    OPEN_INTERRUPT
+    STORE t0, 32 * REGBYTES(sp)
+
+    // save lwp_sigreturn in user memory
     mv s0, sp
     la t0, lwp_sigreturn//t0 = src
     la t1, lwp_sigreturn_end
@@ -159,25 +167,53 @@ lwp_sigreturn_copy_loop:
     mv t1, t2
     bnez t1, lwp_sigreturn_copy_loop
 
-    mv a0, sp//sp
-    li a1, 0//pc
-    li a2, 0//flag
+    // restore kernel stack
+    csrrw sp, sscratch, s0
+
+    /**
+     * a0: user sp
+     * a1: user_pc (not used)
+     * a2: user_flag (not used)
+     */ 
+    csrr a0, sscratch
+    mv a1, zero
+    mv a2, zero
     call lwp_signal_backup
-    //a0 = signal id
-    mv sp, s0//update new sp
-    mv s2, a0//signal id backup
-    call lwp_sighandler_get//need a0 returned by lwp_signal_backup
-    mv ra, s0//lwp_sigreturn func addr
-    mv s1, s0//if func = 0,s1 = lwp_sigreturn func
+    // a0 <- signal id
+
+    // restore kernel sp to initial, and load `sp` to user stack
+
+    // s2 <- signal id(a0)
+    mv s2, a0
+    call lwp_sighandler_get
+    // a0 <- signal_handler
+
+    // ra <- lwp_sigreturn
+    mv ra, s0
+
+    mv s1, s0
     beqz a0, skip_user_signal_handler
+    // a0 <- signal_handler
     mv s1, a0
 
 skip_user_signal_handler:
-    li t0, 0x100
-    csrc sstatus, t0
+    // enter user mode and enable interrupt when return to user mode
+    li t0, SSTATUS_SPP
+    csrc sstatus, t0 
+    li t0, SSTATUS_SPIE
+    csrs sstatus, t0
+
+    /**
+     * sp <- user sp
+     * sscratch <- kernel sp
+     */
+    csrrw sp, sscratch, sp
+
+    // sepc <- signal_handler
     csrw sepc, s1
-    mv a0, s2//signal id as arg 0
-    sret//enter lwp signal handler
+    // a0 <- signal id
+    mv a0, s2
+    sret
 
 .align 3
 lwp_debugreturn:
@@ -235,6 +271,7 @@ arch_clone_exit:
 
 .global syscall_entry
 syscall_entry:
+#ifndef ARCH_USING_NEW_CTX_SWITCH
     //swap to thread kernel stack
     csrr t0, sstatus
     andi t0, t0, 0x100
@@ -265,7 +302,7 @@ copy_context_loop:
     addi t1, t1, 8
     addi t2, t2, 8
     bnez s0, copy_context_loop
-
+#endif /* ARCH_USING_NEW_CTX_SWITCH */
     LOAD s0, 7 * REGBYTES(sp)
     addi s0, s0, -0xfe
     beqz s0, arch_signal_quit
@@ -289,10 +326,9 @@ arch_syscall_exit:
         LOAD s0, 2 * REGBYTES(sp)
         andi s0, s0, 0x100
         bnez s0, dont_ret_to_user
-        li s0, 0
         j arch_ret_to_user
-        dont_ret_to_user:
     #endif
+dont_ret_to_user:
 
 #ifdef RT_USING_USERSPACE
     /* restore setting when syscall exit */
@@ -305,5 +341,6 @@ arch_syscall_exit:
 
     //restore context
     RESTORE_ALL
+    csrw sscratch, zero
     sret
 

+ 6 - 2
libcpu/risc-v/virt64/backtrace.c

@@ -18,6 +18,7 @@ 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;
@@ -57,15 +58,17 @@ void rt_hw_backtrace(rt_uint32_t *ffp, rt_ubase_t sepc)
         }
 
         ra = fp - 1;
-        if (*ra < vas || *ra > vae)
+        if (!rt_hw_mmu_v2p(&mmu_info, ra) || *ra < vas || *ra > vae)
             break;
 
         rt_kprintf(" %p", *ra - 0x04);
 
         fp = fp - 2;
-        if (!fp)
+        if (!rt_hw_mmu_v2p(&mmu_info, fp))
             break;
         fp = (rt_ubase_t *)(*fp);
+        if (!fp)
+            break;
     }
 
     rt_kputs("\r\n");
@@ -76,6 +79,7 @@ static void _assert_backtrace_cb(const char *ex, const char *func, rt_size_t lin
     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)

+ 99 - 21
libcpu/risc-v/virt64/context_gcc.S

@@ -8,13 +8,70 @@
  * 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
  */
 
-#define __ASSEMBLY__
 #include "cpuport.h"
 #include "stackframe.h"
 
-    .globl rt_hw_context_switch_to
+.macro PUSH_8 reg
+    addi    sp, sp, -8
+    STORE   \reg, (sp)
+.endm
+
+.macro POP_8 reg
+    LOAD    \reg, (sp)
+    addi    sp, sp, 8
+.endm
+
+.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
+
+/*
+ * void rt_hw_context_switch_to(rt_ubase_t to);
+ *
+ * a0 --> to SP pointer
+ */
+.globl rt_hw_context_switch_to
 rt_hw_context_switch_to:
     LOAD sp, (a0)
 
@@ -26,31 +83,26 @@ rt_hw_context_switch_to:
         jal lwp_mmu_switch
     #endif
 
-    RESTORE_ALL
+    RESTORE_CONTEXT
     sret
 
 /*
  * void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
  *
- * a0 --> from
- * a1 --> to
+ * 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:
-    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
-
+    RESERVE_CONTEXT
     STORE sp, (a0)
 
-    //restore to thread context
+    // restore to thread SP
     LOAD sp, (a1)
 
+    // restore Address Space
     la s0, rt_current_thread
     LOAD s1, (s0)
 
@@ -59,9 +111,35 @@ rt_hw_context_switch:
         jal lwp_mmu_switch
     #endif
 
-    LOAD t0, 2 * REGBYTES(sp)
-    andi t0, t0, 0x100
-    beqz t0, arch_ret_to_user
-
-    RESTORE_ALL
+    RESTORE_CONTEXT
     sret
+
+#ifdef ENABLE_VECTOR
+/**
+ * @param a0 pointer to frame bottom
+ */
+.global rt_hw_vector_ctx_save
+rt_hw_vector_ctx_save:
+    SAVE_VECTOR a0
+    ret
+
+/**
+ * @param a0 pointer to frame bottom
+ */
+.global rt_hw_vector_ctx_restore
+rt_hw_vector_ctx_restore:
+    RESTORE_VECTOR a0
+    ret
+
+.global rt_hw_disable_vector
+rt_hw_disable_vector:
+    li t0, SSTATUS_VS
+    csrc sstatus, t0
+    ret
+
+.global rt_hw_enable_vector
+rt_hw_enable_vector:
+    li t0, SSTATUS_VS
+    csrs sstatus, t0
+    ret
+#endif /* ENABLE_VECTOR */

+ 45 - 44
libcpu/risc-v/virt64/cpuport.c

@@ -14,30 +14,34 @@
 
 #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;
 
-
 /**
- * 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
@@ -45,41 +49,38 @@ 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);
-
-    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;
+    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);
+
+    (*--sp) = (rt_ubase_t)tentry;
+    (*--sp) = (rt_ubase_t)parameter;
+    (*--sp) = (rt_ubase_t)texit;
+
+    /* compatible to RESTORE_CONTEXT */
+    extern void _rt_thread_entry(void);
+    (*--sp) = 0;                                /* tp */
+    (*--sp) = (rt_ubase_t)_rt_thread_entry;     /* 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) = K_SSTATUS_DEFAULT;                /* sstatus */
+
+    return (rt_uint8_t *)sp;
 }
 
 /*
@@ -98,7 +99,7 @@ void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t
     rt_interrupt_to_thread = to;
     rt_thread_switch_interrupt_flag = 1;
 
-    return ;
+    return;
 }
 #endif /* end of RT_USING_SMP */
 
@@ -109,14 +110,14 @@ void rt_hw_cpu_shutdown()
     rt_kprintf("shutdown...\n");
 
     level = rt_hw_interrupt_disable();
-    while (level)
-    {
-        RT_ASSERT(0);
-    }
+
+    sbi_shutdown();
+
+    while (1)
+        ;
 }
 
 void rt_hw_set_process_id(int pid)
 {
-    //TODO
+    // TODO
 }
-

+ 15 - 1
libcpu/risc-v/virt64/cpuport.h

@@ -20,6 +20,7 @@
 #define REGBYTES                8
 #else
 // error here, not portable
+#error "Not supported XLEN"
 #endif
 
 /* 33 general register */
@@ -32,8 +33,21 @@
 #define CTX_FPU_REG_NR  0
 #endif
 
+#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
+#define CTX_VECTOR_REG_NR  0
+#endif
+
 /* all context registers */
-#define CTX_REG_NR  (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR)
+#define CTX_REG_NR  (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR + CTX_VECTOR_REG_NR)
 
 #ifndef __ASSEMBLY__
 rt_inline void rt_hw_dsb()

+ 22 - 0
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

+ 6 - 1
libcpu/risc-v/virt64/encoding.h

@@ -23,6 +23,7 @@
 #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
@@ -40,8 +41,12 @@
 #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_PUM         0x00040000
+#define SSTATUS_SUM         0x00040000
 #define SSTATUS32_SD        0x80000000
 #define SSTATUS64_SD        0x8000000000000000
 

+ 155 - 0
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__ */

+ 57 - 87
libcpu/risc-v/virt64/interrupt_gcc.S

@@ -9,112 +9,82 @@
  * 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
  */
 
-#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
+    .align 2
+    .global trap_entry
+    .global debug_check_sp
 trap_entry:
-    //backup sp
-    csrrw sp, sscratch, sp
-    //load interrupt stack
-    la sp, __stack_cpu0
-    //backup context
+    // distingush exception from kernel or user
+    csrrw   sp, sscratch, sp
+    bnez    sp, _save_context
+
+    // 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
+
+_save_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
+    // clear sscratch to say 'now in kernel mode'
+    csrw    sscratch, zero
 
-__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:
-    LOAD t0, 2 * REGBYTES(sp)
-    andi t0, t0, 0x100
-    beqz t0, arch_ret_to_user
+    RESTORE_SYS_GP
 
+    // 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
+
+_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
+
+_interrupt_exit:
+    la      s0, rt_thread_switch_interrupt_flag
+    lw      s2, 0(s0)
+    beqz    s2, _resume_execution
+    sw      zero, 0(s0)
+
+_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
+
+_resume_execution:
+    LOAD    t0, FRAME_OFF_SSTATUS(sp)
+    andi    t0, t0, SSTATUS_SPP
+    beqz    t0, arch_ret_to_user
+
+_resume_kernel:
     RESTORE_ALL
+    csrw    sscratch, zero
     sret
 
 .global rt_hw_interrupt_enable
 rt_hw_interrupt_enable:
-    fence.i
     csrs sstatus, a0    /* restore to old csr */
     jr ra
 
 .global rt_hw_interrupt_disable
 rt_hw_interrupt_disable:
     csrrci a0, sstatus, 2   /* clear SIE */
-    fence.i
     jr ra

+ 2 - 2
libcpu/risc-v/virt64/riscv_mmu.c

@@ -30,10 +30,10 @@ void mmu_set_pagetable(rt_ubase_t addr)
 
 void mmu_enable_user_page_access()
 {
-    set_csr(sstatus, SSTATUS_PUM);
+    set_csr(sstatus, SSTATUS_SUM);
 }
 
 void mmu_disable_user_page_access()
 {
-    clear_csr(sstatus, SSTATUS_PUM);
+    clear_csr(sstatus, SSTATUS_SUM);
 }

+ 3 - 0
libcpu/risc-v/virt64/stack.h

@@ -50,6 +50,9 @@ struct rt_hw_stack_frame
 #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

+ 47 - 47
libcpu/risc-v/virt64/stackframe.h

@@ -8,6 +8,7 @@
  * 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__
@@ -15,49 +16,12 @@
 
 #include "cpuport.h"
 #include "encoding.h"
+#include "ext_context.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 */
+#define BYTES(idx) ((idx) * REGBYTES)
+#define FRAME_OFF_SSTATUS BYTES(2)
 
-/**
- * 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.
- */
+#ifdef __ASSEMBLY__
 
 .macro SAVE_ALL
 
@@ -65,16 +29,20 @@
     /* 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, sstatus
-    STORE x1,   2 * REGBYTES(sp)
+    STORE x1, FRAME_OFF_SSTATUS(sp)
 
     csrr  x1, sepc
-    STORE x1, 0 * REGBYTES(sp)
+    STORE x1,   0 * REGBYTES(sp)
 
     STORE x3,   3 * REGBYTES(sp)
     STORE x4,   4 * REGBYTES(sp) /* save tp */
@@ -157,14 +125,42 @@
 
 #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
 
+#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  */
-    mv t2, sp
-    addi t2, t2, CTX_GENERAL_REG_NR * REGBYTES   /* skip all normal reg */
+    addi t2, sp, CTX_GENERAL_REG_NR * REGBYTES
 
     li  t0, SSTATUS_FS
     csrs sstatus, t0
@@ -211,9 +207,11 @@
 #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)
+    LOAD x1, 0 * REGBYTES(sp)
     csrw sepc, x1
 
     LOAD x1,   2 * REGBYTES(sp)
@@ -270,4 +268,6 @@
     csrci sstatus, 2
 .endm
 
-#endif
+#endif /* __ASSEMBLY__ */
+
+#endif /* __STACKFRAME_H__ */

+ 5 - 2
libcpu/risc-v/virt64/startup_gcc.S

@@ -11,7 +11,6 @@
  */
 
 #define SSTATUS_FS      0x00006000U /* initial state of FPU, clear to disable */
-#define __ASSEMBLY__
 #include <cpuport.h>
 
 boot_hartid: .int
@@ -87,5 +86,9 @@ _start:
   la   sp, __stack_start__
   li   t0, __STACKSIZE__
   add  sp, sp, t0
-  csrw sscratch, sp
+
+  /**
+   * sscratch is always zero on kernel mode
+   */
+  csrw sscratch, zero
   j primary_cpu_entry

+ 74 - 3
libcpu/risc-v/virt64/trap.c

@@ -45,7 +45,7 @@ void dump_regs(struct rt_hw_stack_frame *regs)
     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 & 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);
@@ -172,9 +172,69 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
     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;
 
@@ -195,6 +255,8 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
     }
     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;
 
@@ -213,11 +275,18 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
         }
         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
-                return;
+                goto _exit;
             }
 
             // handle kernel exception:
@@ -228,7 +297,6 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
         dump_regs(sp);
         rt_kprintf("--------------Thread list--------------\n");
         rt_kprintf("current thread: %s\n", rt_thread_self()->name);
-        list_process();
 
         extern struct rt_thread *rt_current_thread;
         rt_kprintf("--------------Backtrace--------------\n");
@@ -237,4 +305,7 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
         while (1)
             ;
     }
+_exit:
+    EXIT_TRAP;
+    return ;
 }

+ 44 - 0
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__ */