Browse Source

[qemu-virt64-riscv] fix MMU and virt mem;
refactor uart driver, remove rx thread;
add backtrace support;
add bsp network support;
fix stack overflow on virtio net;
fix POSIX signal;

wangxiaoyao 2 years ago
parent
commit
a32104c730

+ 16 - 1
bsp/qemu-virt64-aarch64/rtconfig.h

@@ -30,7 +30,6 @@
 #define RT_USING_EVENT
 #define RT_USING_MAILBOX
 #define RT_USING_MESSAGEQUEUE
-#define RT_USING_SIGNALS
 
 /* Memory Management */
 
@@ -249,6 +248,11 @@
 
 /* language packages */
 
+/* JSON: JavaScript Object Notation, a lightweight data-interchange format */
+
+
+/* XML: Extensible Markup Language */
+
 
 /* multimedia packages */
 
@@ -258,11 +262,17 @@
 /* u8g2: a monochrome graphic library */
 
 
+/* PainterEngine: A cross-platform graphics application framework written in C language */
+
+
 /* tools packages */
 
 
 /* system packages */
 
+/* enhanced kernel services */
+
+
 /* acceleration: Assembly language or algorithmic acceleration packages */
 
 
@@ -275,11 +285,16 @@
 /* peripheral libraries and drivers */
 
 
+/* Kendryte SDK */
+
+
 /* AI packages */
 
 
 /* miscellaneous packages */
 
+/* project laboratory */
+
 /* samples: kernel and components samples */
 
 

+ 90 - 9
bsp/qemu-virt64-riscv/.config

@@ -25,7 +25,7 @@ CONFIG_RT_USING_TIMER_SOFT=y
 CONFIG_RT_TIMER_THREAD_PRIO=4
 CONFIG_RT_TIMER_THREAD_STACK_SIZE=16384
 CONFIG_RT_DEBUG=y
-# CONFIG_RT_DEBUG_COLOR is not set
+CONFIG_RT_DEBUG_COLOR=y
 # CONFIG_RT_DEBUG_INIT_CONFIG is not set
 # CONFIG_RT_DEBUG_THREAD_CONFIG is not set
 # CONFIG_RT_DEBUG_SCHEDULER_CONFIG is not set
@@ -67,7 +67,7 @@ CONFIG_RT_USING_DEVICE_OPS=y
 # CONFIG_RT_USING_INTERRUPT_INFO is not set
 CONFIG_RT_USING_CONSOLE=y
 CONFIG_RT_CONSOLEBUF_SIZE=256
-CONFIG_RT_CONSOLE_DEVICE_NAME="uart"
+CONFIG_RT_CONSOLE_DEVICE_NAME="uart0"
 CONFIG_RT_VER_NUM=0x50000
 CONFIG_ARCH_CPU_64BIT=y
 CONFIG_RT_USING_CACHE=y
@@ -144,6 +144,7 @@ CONFIG_RT_USING_DFS_ROMFS=y
 # CONFIG_RT_USING_DFS_RAMFS 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
 
 #
 # Device Drivers
@@ -151,7 +152,9 @@ CONFIG_RT_USING_DFS_ROMFS=y
 CONFIG_RT_USING_DEVICE_IPC=y
 CONFIG_RT_UNAMED_PIPE_NUMBER=64
 CONFIG_RT_PIPE_BUFSZ=512
-# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
+CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
+CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=8192
+CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
 CONFIG_RT_USING_SERIAL=y
 CONFIG_RT_SERIAL_USING_DMA=y
 CONFIG_RT_SERIAL_RB_BUFSZ=64
@@ -191,7 +194,7 @@ CONFIG_RT_USING_VIRTIO=y
 CONFIG_RT_USING_VIRTIO10=y
 # CONFIG_RT_USING_VIRTIO_MMIO_ALIGN is not set
 CONFIG_RT_USING_VIRTIO_BLK=y
-# CONFIG_RT_USING_VIRTIO_NET is not set
+CONFIG_RT_USING_VIRTIO_NET=y
 # CONFIG_RT_USING_VIRTIO_CONSOLE is not set
 # CONFIG_RT_USING_VIRTIO_GPU is not set
 # CONFIG_RT_USING_VIRTIO_INPUT is not set
@@ -224,22 +227,98 @@ CONFIG_RT_USING_POSIX_CLOCKTIME=y
 #
 # Socket abstraction layer
 #
-# CONFIG_RT_USING_SAL is not set
+CONFIG_RT_USING_SAL=y
+
+#
+# protocol stack implement
+#
+CONFIG_SAL_USING_LWIP=y
+CONFIG_SAL_USING_POSIX=y
+# CONFIG_SAL_USING_AF_UNIX is not set
 
 #
 # Network interface device
 #
-# CONFIG_RT_USING_NETDEV is not set
+CONFIG_RT_USING_NETDEV=y
+CONFIG_NETDEV_USING_IFCONFIG=y
+CONFIG_NETDEV_USING_PING=y
+CONFIG_NETDEV_USING_NETSTAT=y
+CONFIG_NETDEV_USING_AUTO_DEFAULT=y
+# CONFIG_NETDEV_USING_IPV6 is not set
+CONFIG_NETDEV_IPV4=1
+CONFIG_NETDEV_IPV6=0
+# CONFIG_NETDEV_IPV6_SCOPES is not set
 
 #
 # light weight TCP/IP stack
 #
-# CONFIG_RT_USING_LWIP is not set
+CONFIG_RT_USING_LWIP=y
+# CONFIG_RT_USING_LWIP141 is not set
+CONFIG_RT_USING_LWIP202=y
+# CONFIG_RT_USING_LWIP212 is not set
+# CONFIG_RT_USING_LWIP_IPV6 is not set
+CONFIG_RT_LWIP_MEM_ALIGNMENT=4
+CONFIG_RT_LWIP_IGMP=y
+CONFIG_RT_LWIP_ICMP=y
+# CONFIG_RT_LWIP_SNMP is not set
+CONFIG_RT_LWIP_DNS=y
+CONFIG_RT_LWIP_DHCP=y
+CONFIG_IP_SOF_BROADCAST=1
+CONFIG_IP_SOF_BROADCAST_RECV=1
+
+#
+# Static IPv4 Address
+#
+CONFIG_RT_LWIP_IPADDR="192.168.1.30"
+CONFIG_RT_LWIP_GWADDR="192.168.1.1"
+CONFIG_RT_LWIP_MSKADDR="255.255.255.0"
+CONFIG_RT_LWIP_UDP=y
+CONFIG_RT_LWIP_TCP=y
+CONFIG_RT_LWIP_RAW=y
+# CONFIG_RT_LWIP_PPP is not set
+CONFIG_RT_MEMP_NUM_NETCONN=8
+CONFIG_RT_MEMP_NUM_TCPIP_MSG_API=16
+CONFIG_RT_MEMP_NUM_TCPIP_MSG_INPKT=16
+CONFIG_RT_LWIP_PBUF_NUM=16
+CONFIG_RT_LWIP_PBUF_STRUCT_NUM=16
+CONFIG_RT_LWIP_NETBUF_NUM=16
+CONFIG_RT_LWIP_RAW_PCB_NUM=4
+CONFIG_RT_LWIP_UDP_PCB_NUM=4
+CONFIG_RT_UDP_RECVMBOX_SIZE=16
+CONFIG_RT_RECV_BUFSIZE_DEFAULT=64
+CONFIG_RT_LWIP_TCP_PCB_NUM=4
+CONFIG_RT_LWIP_TCP_SEG_NUM=40
+CONFIG_RT_LWIP_TCP_SND_BUF=8196
+CONFIG_RT_LWIP_TCP_WND=8196
+CONFIG_RT_TCP_RECVMBOX_SIZE=16
+CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10
+CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8
+CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=8192
+# CONFIG_LWIP_NO_RX_THREAD is not set
+# CONFIG_LWIP_NO_TX_THREAD is not set
+CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12
+CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=8192
+CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8
+# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set
+CONFIG_LWIP_NETIF_STATUS_CALLBACK=1
+CONFIG_LWIP_NETIF_LINK_CALLBACK=1
+CONFIG_SO_REUSE=1
+CONFIG_LWIP_SO_RCVTIMEO=1
+CONFIG_LWIP_SO_SNDTIMEO=1
+CONFIG_LWIP_SO_RCVBUF=1
+CONFIG_LWIP_SO_LINGER=0
+# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set
+CONFIG_LWIP_NETIF_LOOPBACK=0
+# CONFIG_RT_LWIP_STATS is not set
+# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
+CONFIG_RT_LWIP_USING_PING=y
+# CONFIG_RT_LWIP_DEBUG is not set
 
 #
 # AT commands
 #
 # CONFIG_RT_USING_AT is not set
+# CONFIG_LWIP_USING_DHCPD is not set
 
 #
 # VBUS(Virtual Software BUS)
@@ -251,7 +330,9 @@ CONFIG_RT_USING_POSIX_CLOCKTIME=y
 #
 # CONFIG_RT_USING_RYM is not set
 # CONFIG_RT_USING_ULOG is not set
-# CONFIG_RT_USING_UTEST is not set
+CONFIG_RT_USING_UTEST=y
+CONFIG_UTEST_THR_STACK_SIZE=4096
+CONFIG_UTEST_THR_PRIORITY=20
 # CONFIG_RT_USING_RT_LINK is not set
 CONFIG_RT_USING_LWP=y
 CONFIG_RT_LWP_MAX_NR=30
@@ -726,7 +807,7 @@ CONFIG_ENABLE_FPU=y
 #
 CONFIG_RISCV_S_MODE=y
 CONFIG_BSP_USING_VIRTIO_BLK=y
-# CONFIG_BSP_USING_VIRTIO_NET is not set
+CONFIG_BSP_USING_VIRTIO_NET=y
 # CONFIG_BSP_USING_VIRTIO_CONSOLE is not set
 # CONFIG_BSP_USING_VIRTIO_GPU is not set
 # CONFIG_BSP_USING_VIRTIO_INPUT is not set

+ 0 - 2
bsp/qemu-virt64-riscv/applications/main.c

@@ -14,8 +14,6 @@
 
 int main(void)
 {
-    void rt_hw_uart_start_rx_thread();
-    rt_hw_uart_start_rx_thread();
     printf("Hello RISC-V\n");
 
     return 0;

+ 31 - 0
bsp/qemu-virt64-riscv/applications/mnt.c

@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021/08/19     bernard      the first version
+ */
+
+#include <rtthread.h>
+
+#ifdef RT_USING_DFS
+#include <dfs_fs.h>
+#include <rtdbg.h>
+
+int mnt_init(void)
+{
+    if (rt_device_find("virtio-blk0"))
+    {
+        /* mount virtio-blk as root directory */
+        if (dfs_mount("virtio-blk0", "/", "elm", 0, RT_NULL) != 0)
+        {
+            LOG_E("virtio-blk0 mount failed\n");
+        }
+    }
+
+    return 0;
+}
+INIT_ENV_EXPORT(mnt_init);
+#endif

+ 130 - 0
bsp/qemu-virt64-riscv/driver/backtrace.c

@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+#include <rtthread.h>
+#include <lwp_arch.h>
+
+#define TRANCE_LEVEL 20
+
+extern rt_ubase_t __text_start[];
+extern rt_ubase_t __text_end[];
+
+static char *_get_elf_name();
+
+void rt_hw_backtrace(rt_uint32_t *ffp, rt_ubase_t sepc)
+{
+    rt_ubase_t *ra;
+    rt_ubase_t *fp;
+    rt_ubase_t vas, vae;
+    int i, j;
+
+    rt_kprintf("riscv64-unknown-linux-musl-addr2line -e %s -a -f", _get_elf_name(sepc));
+
+    fp = (rt_ubase_t *)ffp;
+
+    if (!fp)
+    {
+        asm volatile("mv %0, s0"
+                     : "=r"(fp));
+    }
+
+    if (sepc)
+    {
+        rt_kprintf(" %p", sepc - 0x4);
+    }
+
+    if (fp > (rt_ubase_t *)USER_VADDR_START && fp < (rt_ubase_t *)USER_VADDR_TOP)
+    {
+        vas = USER_VADDR_START;
+        vae = USER_VADDR_TOP;
+    }
+    else
+    {
+        vas = (rt_ubase_t)&__text_start;
+        vae = (rt_ubase_t)&__text_end;
+    }
+
+    for (i = j = 0; i < TRANCE_LEVEL; i++)
+    {
+        // rt_kprintf("fp %d:%p\n", i, fp);
+        if (RT_ALIGN((rt_ubase_t)fp, sizeof(void *)) != (rt_ubase_t)fp)
+        {
+            break;
+        }
+
+        ra = fp - 1;
+        if (*ra < vas || *ra > vae)
+            break;
+
+        rt_kprintf(" %p", *ra - 0x04);
+
+        fp = fp - 2;
+        if (!fp)
+            break;
+        fp = (rt_ubase_t *)(*fp);
+    }
+
+    rt_kputs("\r\n");
+}
+
+static void _assert_backtrace_cb(const char *ex, const char *func, rt_size_t line)
+{
+    rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex, func, line);
+
+    rt_hw_backtrace(0, 0);
+}
+
+static int rt_hw_backtrace_init(void)
+{
+    rt_assert_set_hook(_assert_backtrace_cb);
+
+    return 0;
+}
+INIT_BOARD_EXPORT(rt_hw_backtrace_init);
+
+static void backtrace_test(int args, char *argv[])
+{
+    int *p = (void *)-1;
+    init_fn_t ft = 0;
+
+    if (args < 2)
+    {
+        rt_kprintf("backtrace_test usage:backtrace_test a(assert)/m(invalid memory)/i(illegal instruction)\r\n");
+        return;
+    }
+
+    if (!rt_strcmp(argv[1], "a"))
+    {
+        rt_kprintf("Assert test:\r\n", argv[1]);
+        RT_ASSERT(0);
+    }
+    else if (!rt_strcmp(argv[1], "m"))
+    {
+        rt_kprintf("Access invalid memory:\r\n", argv[1]);
+        *p = 0;
+    }
+    else if (!rt_strcmp(argv[1], "i"))
+    {
+        rt_kprintf("Illegal instruction:\r\n", argv[1]);
+        ft();
+    }
+    else
+    {
+        rt_kprintf("Unknown cmd :%s.\r\n", argv[1]);
+    }
+}
+MSH_CMD_EXPORT(backtrace_test, backtrace test case);
+
+extern struct rt_thread *rt_current_thread;
+
+#define IN_USERSPACE (sepc > USER_VADDR_START && sepc < USER_VADDR_TOP)
+
+static char *_get_elf_name(size_t sepc)
+{
+    return IN_USERSPACE ? rt_current_thread->name : "rtthread.elf";
+}

+ 10 - 164
bsp/qemu-virt64-riscv/driver/board.c

@@ -37,7 +37,7 @@ extern size_t MMUTable[];
 
 struct mem_desc platform_mem_desc[] = {
     {KERNEL_VADDR_START, KERNEL_VADDR_START + 0x10000000 - 1, KERNEL_VADDR_START + PV_OFFSET, NORMAL_MEM},
-    };
+};
 
 #define NUM_MEM_DESC (sizeof(platform_mem_desc) / sizeof(platform_mem_desc[0]))
 
@@ -84,27 +84,26 @@ void rt_hw_board_init(void)
     rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END);
 #endif
 
+    plic_init();
+
+    rt_hw_interrupt_init();
+
     rt_hw_uart_init();
 
 #ifdef RT_USING_CONSOLE
     /* set console device */
-    rt_console_set_device("uart");
-
-#ifdef RT_USING_HEAP
-    rt_kprintf("heap: [0x%08x - 0x%08x]\n", (rt_ubase_t)RT_HW_HEAP_BEGIN, (rt_ubase_t)RT_HW_HEAP_END);
-#endif
-
-    rt_hw_interrupt_init();
+    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+#endif /* RT_USING_CONSOLE */
 
     rt_hw_tick_init();
 
-#endif /* RT_USING_CONSOLE */
-
 #ifdef RT_USING_COMPONENTS_INIT
     rt_components_board_init();
 #endif
 
-    plic_init();
+#ifdef RT_USING_HEAP
+    rt_kprintf("heap: [0x%08x - 0x%08x]\n", (rt_ubase_t)RT_HW_HEAP_BEGIN, (rt_ubase_t)RT_HW_HEAP_END);
+#endif /* RT_USING_HEAP */
 }
 
 void rt_hw_cpu_reset(void)
@@ -116,156 +115,3 @@ void rt_hw_cpu_reset(void)
 }
 MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_reset, reboot, reset machine);
 
-void dump_regs(struct rt_hw_stack_frame *regs)
-{
-    rt_kprintf("--------------Dump Registers-----------------\n");
-
-    rt_kprintf("Function Registers:\n");
-    rt_kprintf("\tra(x1) = 0x%p\tuser_sp = 0x%p\n", regs->ra, regs->user_sp_exc_stack);
-    rt_kprintf("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n", regs->gp, regs->tp);
-    rt_kprintf("Temporary Registers:\n");
-    rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1);
-    rt_kprintf("\tt2(x7) = 0x%p\n", regs->t2);
-    rt_kprintf("\tt3(x28) = 0x%p\tt4(x29) = 0x%p\n", regs->t3, regs->t4);
-    rt_kprintf("\tt5(x30) = 0x%p\tt6(x31) = 0x%p\n", regs->t5, regs->t6);
-    rt_kprintf("Saved Registers:\n");
-    rt_kprintf("\ts0/fp(x8) = 0x%p\ts1(x9) = 0x%p\n", regs->s0_fp, regs->s1);
-    rt_kprintf("\ts2(x18) = 0x%p\ts3(x19) = 0x%p\n", regs->s2, regs->s3);
-    rt_kprintf("\ts4(x20) = 0x%p\ts5(x21) = 0x%p\n", regs->s4, regs->s5);
-    rt_kprintf("\ts6(x22) = 0x%p\ts7(x23) = 0x%p\n", regs->s6, regs->s7);
-    rt_kprintf("\ts8(x24) = 0x%p\ts9(x25) = 0x%p\n", regs->s8, regs->s9);
-    rt_kprintf("\ts10(x26) = 0x%p\ts11(x27) = 0x%p\n", regs->s10, regs->s11);
-    rt_kprintf("Function Arguments Registers:\n");
-    rt_kprintf("\ta0(x10) = 0x%p\ta1(x11) = 0x%p\n", regs->a0, regs->a1);
-    rt_kprintf("\ta2(x12) = 0x%p\ta3(x13) = 0x%p\n", regs->a2, regs->a3);
-    rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n", regs->a4, regs->a5);
-    rt_kprintf("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n", regs->a6, regs->a7);
-    rt_kprintf("sstatus = 0x%p\n", regs->sstatus);
-    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
-    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
-    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
-    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_PUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
-    rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
-    rt_size_t satp_v = read_csr(satp);
-    rt_kprintf("satp = 0x%p\n", satp_v);
-    rt_kprintf("\tCurrent Page Table(Physical) = 0x%p\n", __MASKVALUE(satp_v, __MASK(44)) << PAGE_OFFSET_BIT);
-    rt_kprintf("\tCurrent ASID = 0x%p\n", __MASKVALUE(satp_v >> 44, __MASK(16)) << PAGE_OFFSET_BIT);
-    const char *mode_str = "Unknown Address Translation/Protection Mode";
-
-    switch (__MASKVALUE(satp_v >> 60, __MASK(4)))
-    {
-    case 0:
-        mode_str = "No Address Translation/Protection Mode";
-        break;
-
-    case 8:
-        mode_str = "Page-based 39-bit Virtual Addressing Mode";
-        break;
-
-    case 9:
-        mode_str = "Page-based 48-bit Virtual Addressing Mode";
-        break;
-    }
-
-    rt_kprintf("\tMode = %s\n", mode_str);
-    rt_kprintf("-----------------Dump OK---------------------\n");
-}
-
-static const char *Exception_Name[] =
-    {
-        "Instruction Address Misaligned",
-        "Instruction Access Fault",
-        "Illegal Instruction",
-        "Breakpoint",
-        "Load Address Misaligned",
-        "Load Access Fault",
-        "Store/AMO Address Misaligned",
-        "Store/AMO Access Fault",
-        "Environment call from U-mode",
-        "Environment call from S-mode",
-        "Reserved-10",
-        "Reserved-11",
-        "Instruction Page Fault",
-        "Load Page Fault",
-        "Reserved-14",
-        "Store/AMO Page Fault"};
-
-static const char *Interrupt_Name[] =
-    {
-        "User Software Interrupt",
-        "Supervisor Software Interrupt",
-        "Reversed-2",
-        "Reversed-3",
-        "User Timer Interrupt",
-        "Supervisor Timer Interrupt",
-        "Reversed-6",
-        "Reversed-7",
-        "User External Interrupt",
-        "Supervisor External Interrupt",
-        "Reserved-10",
-        "Reserved-11",
-};
-
-extern struct rt_irq_desc irq_desc[];
-
-void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp)
-{
-    // rt_kprintf(".");
-    if (scause == (uint64_t)(0x8000000000000005))
-    {
-        rt_interrupt_enter();
-        tick_isr();
-        rt_interrupt_leave();
-    }
-    else if (scause == (uint64_t)(0x8000000000000009))
-    {
-        int plic_irq = plic_claim();
-        plic_complete(plic_irq);
-        irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
-    }
-    else
-    {
-        rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
-        const char *msg;
-
-        if (scause >> 63)
-        {
-            if (id < sizeof(Interrupt_Name) / sizeof(const char *))
-            {
-                msg = Interrupt_Name[id];
-            }
-            else
-            {
-                msg = "Unknown Interrupt";
-            }
-
-            rt_kprintf("Unhandled Interrupt %ld:%s\n", id, msg);
-        }
-        else
-        {
-#ifdef RT_USING_USERSPACE
-            if (id == 15)
-            {
-                arch_expand_user_stack((void *)stval);
-                return;
-            }
-#endif
-
-            if (id < sizeof(Exception_Name) / sizeof(const char *))
-            {
-                msg = Exception_Name[id];
-            }
-            else
-            {
-                msg = "Unknown Exception";
-            }
-
-            rt_kprintf("Unhandled Exception %ld:%s\n", id, msg);
-        }
-
-        rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
-        dump_regs(sp);
-        while (1)
-            ;
-    }
-}

+ 82 - 103
bsp/qemu-virt64-riscv/driver/drv_uart.c

@@ -1,12 +1,15 @@
 /*
- * Copyright (c) 2019-2020, Xim
+ * Copyright (c) 2006-2020, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
+ * Change Logs:
+ * Date           Author       Notes
  */
 
 #include <rthw.h>
 #include <rtdevice.h>
+#include <rtthread.h>
 
 #include "board.h"
 #include "drv_uart.h"
@@ -15,138 +18,114 @@
 #include <ioremap.h>
 #include "sbi.h"
 
-#define UART_DEFAULT_BAUDRATE               115200
-
 struct device_uart
 {
-    rt_ubase_t  hw_base;
+    rt_ubase_t hw_base;
     rt_uint32_t irqno;
 };
 
-static rt_err_t  rt_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
-static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg);
-static int       drv_uart_putc(struct rt_serial_device *serial, char c);
-static int       drv_uart_getc(struct rt_serial_device *serial);
-
-const struct rt_uart_ops _uart_ops =
-{
-    rt_uart_configure,
-    uart_control,
-    drv_uart_putc,
-    drv_uart_getc,
-    //TODO: add DMA support
-    RT_NULL
-};
+void *uart0_base = (void*)0x10000000;
+struct rt_serial_device serial0;
+struct device_uart uart0;
 
 void uart_init(void)
 {
-    return ;
-}
+    rt_uint32_t div = UART_REFERENCE_CLOCK / (UART_DEFAULT_BAUDRATE * 16);
 
-struct rt_serial_device  serial1;
-struct device_uart       uart1;
+    write8_uart0(UART_IER, 0x00);
+    write8_uart0(UART_LCR, UART_LCR_BAUD_LATCH);
 
-/*
- * UART interface
- */
-static rt_err_t rt_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
-{
-    struct device_uart *uart;
+    // LSB
+    write8_uart0(0, div & 0xff);
+    // MSB
+    write8_uart0(1, (div >> 8) & 0xff);
 
-    RT_ASSERT(serial != RT_NULL);
-    serial->config = *cfg;
+    // set word length to 8 bits, no parity
+    write8_uart0(UART_LCR, UART_LCR_EIGHT_BITS);
 
-    return (RT_EOK);
-}
-
-#define UART_LSR_DR     0x01            /* Data ready */
-#define UART_LSR_THRE   0x20            /* Xmit holding register empty */
-
-#define UART_RBR(hw)    HWREG32(hw + 0x00)
-#define UART_IER(hw)    HWREG32(hw + 0x04)
-#define UART_LSR(hw)    HWREG32(hw + 0x14)
+    write8_uart0(UART_FCR, UART_FCR_FIFO_ENABLE | UART_FCR_FIFO_CLEAR);
 
-static volatile uint64_t uart_hwbase = 0x10000000;
+    return;
+}
 
-void uart_putc(char c)
+static rt_err_t _uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
 {
-    while ((UART_LSR(uart_hwbase) & UART_LSR_THRE) == 0);
-
-    UART_RBR(uart_hwbase) = c;
+    uart_init();
+    return (RT_EOK);
 }
 
-static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
+static rt_err_t _uart_control(struct rt_serial_device *serial, int cmd, void *arg)
 {
-    struct device_uart *uart;
-
-    uart = serial->parent.user_data;
-    rt_uint32_t channel = 1;
-
-    RT_ASSERT(uart != RT_NULL);
-    RT_ASSERT(channel != 3);
+    struct device_uart *uart = (struct device_uart*)serial->parent.user_data;
 
     switch (cmd)
     {
     case RT_DEVICE_CTRL_CLR_INT:
-        /* Disable the UART Interrupt */
-        //rt_hw_interrupt_mask(uart->irqno);
-        //uart[channel]->IER &= ~0x1;
-        //UART_IER(uart_hwbase) &= ~0x1;
+        if ((size_t)arg == RT_DEVICE_FLAG_INT_RX)
+        {
+            rt_uint8_t value = read8_uart0(UART_IER);
+            write8_uart0(UART_IER, value & ~UART_IER_RX_ENABLE);
+        }
         break;
 
     case RT_DEVICE_CTRL_SET_INT:
-        /* install interrupt */
-        // rt_hw_interrupt_install(uart->irqno, uart_irq_handler,
-        //                        serial, serial->parent.parent.name);
-        // rt_hw_interrupt_umask(uart->irqno);
-        //uart[channel]->IER |= 0x1;
-        UART_IER(uart_hwbase) |= 0x1;
+        if ((size_t)arg == RT_DEVICE_FLAG_INT_RX)
+        {
+            rt_uint8_t value = read8_uart0(UART_IER);
+            write8_uart0(UART_IER, value | UART_IER_RX_ENABLE);
+        }
         break;
     }
 
     return (RT_EOK);
 }
 
-static int drv_uart_putc(struct rt_serial_device *serial, char c)
+static int _uart_putc(struct rt_serial_device *serial, char c)
 {
-    sbi_console_putchar(c);
+    struct device_uart *uart;
+    uart = (struct device_uart*)serial->parent.user_data;
+
+    // wait for Transmit Holding Empty to be set in LSR.
+    while((read8_uart0(UART_LSR) & UART_LSR_TX_IDLE) == 0)
+        ;
+    write8_uart0(UART_THR, c);
 
     return (1);
 }
 
-static int drv_uart_getc(struct rt_serial_device *serial)
+static int _uart_getc(struct rt_serial_device *serial)
 {
-    return sbi_console_getchar();
-}
+    struct device_uart *uart;
+    volatile rt_uint32_t lsr;
+    int ch = -1;
 
-#if 0
-void drv_uart_puts(char *str)
-{
-    sbi_console_putstr(str);
-}
+    uart = (struct device_uart*)serial->parent.user_data;
+    lsr = read8_uart0(UART_LSR);
 
-char rt_hw_console_getchar(void)
-{
-    return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
+    if (lsr & UART_LSR_RX_READY)
+    {
+        ch = read8_uart0(UART_RHR);
+    }
+    return ch;
 }
-#endif
 
-static void uart_rx(void *param)
+const struct rt_uart_ops _uart_ops = {
+    _uart_configure,
+    _uart_control,
+    _uart_putc,
+    _uart_getc,
+    // TODO: add DMA support
+    RT_NULL};
+
+static void rt_hw_uart_isr(int irqno, void *param)
 {
+    rt_ubase_t level = rt_hw_interrupt_disable();
+
     struct rt_serial_device *serial = (struct rt_serial_device *)param;
 
-    while(1)
-    {
-        rt_hw_serial_isr((struct rt_serial_device *)serial,RT_SERIAL_EVENT_RX_IND);
-        rt_thread_mdelay(10);
-    }
-}
+    rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
 
-void rt_hw_uart_start_rx_thread()
-{
-    rt_thread_t th;
-    RT_ASSERT((th = rt_thread_create("uartrx",uart_rx,(void *)&serial1,8192,8,20)) != RT_NULL);
-    RT_ASSERT(rt_thread_startup(th) == RT_EOK);
+    rt_hw_interrupt_enable(level);
 }
 
 /*
@@ -155,26 +134,26 @@ void rt_hw_uart_start_rx_thread()
 int rt_hw_uart_init(void)
 {
     struct rt_serial_device *serial;
-    struct device_uart      *uart;
+    struct device_uart *uart;
     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
 
-    {
-        serial  = &serial1;
-        uart    = &uart1;
+    uart0_base = rt_ioremap(uart0_base, 4096);
 
-        serial->ops              = &_uart_ops;
-        serial->config           = config;
-        serial->config.baud_rate = UART_DEFAULT_BAUDRATE;
+    // register device
+    serial = &serial0;
+    uart = &uart0;
 
-        uart->hw_base   = (rt_size_t)rt_ioremap((void*)0x10000000, 4096);
-        uart->irqno     = 0xa;
+    serial->ops = &_uart_ops;
+    serial->config = config;
+    serial->config.baud_rate = UART_DEFAULT_BAUDRATE;
+    uart->hw_base = (rt_ubase_t)uart0_base;
+    uart->irqno = 0x0a;
 
-        rt_hw_serial_register(serial,
-                              "uart",
-                              RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
-                              uart);
-    }
-    
+    rt_hw_serial_register(serial,
+                          RT_CONSOLE_DEVICE_NAME,
+                          RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
+                          uart);
+    rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, RT_CONSOLE_DEVICE_NAME);
     return 0;
 }
 

+ 48 - 1
bsp/qemu-virt64-riscv/driver/drv_uart.h

@@ -1,13 +1,60 @@
 /*
- * Copyright (c) 2019-2020, Xim
+ * Copyright (c) 2006-2020, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
+ * Change Logs:
+ * Date           Author       Notes
  */
 
 #ifndef __DRV_UART_H__
 #define __DRV_UART_H__
 
+#include "riscv_io.h"
+
+/**
+ * uart ns16550a
+ * http://byterunner.com/16550.html
+ */
+
+/* TRANSMIT AND RECEIVE HOLDING REGISTER */
+#define UART_RHR 0
+#define UART_THR 0
+
+/* INTERRUPT ENABLE REGISTER */
+#define UART_IER 1
+#define UART_IER_RX_ENABLE (1 << 0)
+#define UART_IER_TX_ENABLE (1 << 1)
+
+/* FIFO CONTROL REGISTER */
+#define UART_FCR 2
+#define UART_FCR_FIFO_ENABLE (1 << 0)
+#define UART_FCR_FIFO_CLEAR (3 << 1)
+
+/* INTERRUPT STATUS REGISTER */
+#define UART_ISR 2
+
+/* LINE CONTROL REGISTER */
+#define UART_LCR 3
+#define UART_LCR_EIGHT_BITS (3 << 0)
+// special mode to set baud rate
+#define UART_LCR_BAUD_LATCH (1 << 7)
+
+/* LINE STATUS REGISTER */
+#define UART_LSR 5
+// input is waiting to be read from RHR
+#define UART_LSR_RX_READY (1 << 0)
+// THR can accept another character to send
+#define UART_LSR_TX_IDLE (1 << 5)
+
+#define UART_REFERENCE_CLOCK  1843200
+#define UART_DEFAULT_BAUDRATE 115200
+
+extern void *uart0_base;
+
+#define write8_uart0(idx, value) __raw_writeb(((rt_uint8_t)value), (void*)((size_t)uart0_base + (idx)))
+#define read8_uart0(idx) __raw_readb((void*)((size_t)uart0_base + (idx)))
+
 void rt_hw_uart_start_rx_thread();
 int rt_hw_uart_init(void);
 void drv_uart_puts(char *str); // for syscall

+ 0 - 1
bsp/qemu-virt64-riscv/driver/drv_virtio.c

@@ -93,7 +93,6 @@ int rt_virtio_devices_init(void)
             init_handler((rt_ubase_t *)mmio_base, irq);
         }
     }
-    rt_kprintf("rt_virtio_devices_init done!\n");
 
     return 0;
 }

+ 3 - 1
bsp/qemu-virt64-riscv/link.lds

@@ -29,7 +29,7 @@ SECTIONS
     . = 0x80200000 ;
 
     /* __STACKSIZE__ = 4096; */
-
+    __text_start = .;
     .start :
     {
         *(.start);
@@ -81,6 +81,8 @@ SECTIONS
     .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } > SRAM
 
     . = ALIGN(8);
+    __text_end = .;
+    __text_size = __text_end - __text_start;
 
     .data : 
     {

+ 3 - 1
bsp/qemu-virt64-riscv/qemu-dbg.sh

@@ -1 +1,3 @@
-qemu-system-riscv64 -s -S -nographic -machine virt -m 256M -kernel rtthread.bin
+qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin -s -S \
+-drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 \
+-device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0

+ 8 - 1
bsp/qemu-virt64-riscv/qemu-nographic.bat

@@ -1 +1,8 @@
-qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin -bios default 
+@echo off
+if exist sd.bin goto run
+qemu-img create -f raw sd.bin 64M
+
+qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin ^
+-drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 ^
+-netdev user,id=tab0 -device virtio-net-device,netdev=tab0,bus=virtio-mmio-bus.1 ^
+-device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0

+ 1 - 0
bsp/qemu-virt64-riscv/qemu-nographic.sh

@@ -4,4 +4,5 @@ fi
 
 qemu-system-riscv64 -nographic -machine virt -m 256M -kernel rtthread.bin \
 -drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 \
+-netdev user,id=tab0 -device virtio-net-device,netdev=tab0,bus=virtio-mmio-bus.1 \
 -device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0

+ 71 - 1
bsp/qemu-virt64-riscv/rtconfig.h

@@ -20,6 +20,7 @@
 #define RT_TIMER_THREAD_PRIO 4
 #define RT_TIMER_THREAD_STACK_SIZE 16384
 #define RT_DEBUG
+#define RT_DEBUG_COLOR
 
 /* Inter-Thread communication */
 
@@ -42,7 +43,7 @@
 #define RT_USING_DEVICE_OPS
 #define RT_USING_CONSOLE
 #define RT_CONSOLEBUF_SIZE 256
-#define RT_CONSOLE_DEVICE_NAME "uart"
+#define RT_CONSOLE_DEVICE_NAME "uart0"
 #define RT_VER_NUM 0x50000
 #define ARCH_CPU_64BIT
 #define RT_USING_CACHE
@@ -105,6 +106,9 @@
 #define RT_USING_DEVICE_IPC
 #define RT_UNAMED_PIPE_NUMBER 64
 #define RT_PIPE_BUFSZ 512
+#define RT_USING_SYSTEM_WORKQUEUE
+#define RT_SYSTEM_WORKQUEUE_STACKSIZE 8192
+#define RT_SYSTEM_WORKQUEUE_PRIORITY 23
 #define RT_USING_SERIAL
 #define RT_SERIAL_USING_DMA
 #define RT_SERIAL_RB_BUFSZ 64
@@ -117,6 +121,7 @@
 #define RT_USING_VIRTIO
 #define RT_USING_VIRTIO10
 #define RT_USING_VIRTIO_BLK
+#define RT_USING_VIRTIO_NET
 
 /* Using USB */
 
@@ -132,12 +137,73 @@
 
 /* Socket abstraction layer */
 
+#define RT_USING_SAL
+
+/* protocol stack implement */
+
+#define SAL_USING_LWIP
+#define SAL_USING_POSIX
 
 /* Network interface device */
 
+#define RT_USING_NETDEV
+#define NETDEV_USING_IFCONFIG
+#define NETDEV_USING_PING
+#define NETDEV_USING_NETSTAT
+#define NETDEV_USING_AUTO_DEFAULT
+#define NETDEV_IPV4 1
+#define NETDEV_IPV6 0
 
 /* light weight TCP/IP stack */
 
+#define RT_USING_LWIP
+#define RT_USING_LWIP202
+#define RT_LWIP_MEM_ALIGNMENT 4
+#define RT_LWIP_IGMP
+#define RT_LWIP_ICMP
+#define RT_LWIP_DNS
+#define RT_LWIP_DHCP
+#define IP_SOF_BROADCAST 1
+#define IP_SOF_BROADCAST_RECV 1
+
+/* Static IPv4 Address */
+
+#define RT_LWIP_IPADDR "192.168.1.30"
+#define RT_LWIP_GWADDR "192.168.1.1"
+#define RT_LWIP_MSKADDR "255.255.255.0"
+#define RT_LWIP_UDP
+#define RT_LWIP_TCP
+#define RT_LWIP_RAW
+#define RT_MEMP_NUM_NETCONN 8
+#define RT_MEMP_NUM_TCPIP_MSG_API 16
+#define RT_MEMP_NUM_TCPIP_MSG_INPKT 16
+#define RT_LWIP_PBUF_NUM 16
+#define RT_LWIP_PBUF_STRUCT_NUM 16
+#define RT_LWIP_NETBUF_NUM 16
+#define RT_LWIP_RAW_PCB_NUM 4
+#define RT_LWIP_UDP_PCB_NUM 4
+#define RT_UDP_RECVMBOX_SIZE 16
+#define RT_RECV_BUFSIZE_DEFAULT 64
+#define RT_LWIP_TCP_PCB_NUM 4
+#define RT_LWIP_TCP_SEG_NUM 40
+#define RT_LWIP_TCP_SND_BUF 8196
+#define RT_LWIP_TCP_WND 8196
+#define RT_TCP_RECVMBOX_SIZE 16
+#define RT_LWIP_TCPTHREAD_PRIORITY 10
+#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8
+#define RT_LWIP_TCPTHREAD_STACKSIZE 8192
+#define RT_LWIP_ETHTHREAD_PRIORITY 12
+#define RT_LWIP_ETHTHREAD_STACKSIZE 8192
+#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
+#define LWIP_NETIF_STATUS_CALLBACK 1
+#define LWIP_NETIF_LINK_CALLBACK 1
+#define SO_REUSE 1
+#define LWIP_SO_RCVTIMEO 1
+#define LWIP_SO_SNDTIMEO 1
+#define LWIP_SO_RCVBUF 1
+#define LWIP_SO_LINGER 0
+#define LWIP_NETIF_LOOPBACK 0
+#define RT_LWIP_USING_PING
 
 /* AT commands */
 
@@ -147,6 +213,9 @@
 
 /* Utilities */
 
+#define RT_USING_UTEST
+#define UTEST_THR_STACK_SIZE 4096
+#define UTEST_THR_PRIORITY 20
 #define RT_USING_LWP
 #define RT_LWP_MAX_NR 30
 #define LWP_TASK_STACK_SIZE 16384
@@ -235,6 +304,7 @@
 
 #define RISCV_S_MODE
 #define BSP_USING_VIRTIO_BLK
+#define BSP_USING_VIRTIO_NET
 #define __STACKSIZE__ 16384
 
 #endif

+ 4 - 0
libcpu/risc-v/virt64/context_gcc.S

@@ -59,5 +59,9 @@ rt_hw_context_switch:
         jal lwp_mmu_switch
     #endif
 
+    LOAD t0, 2 * REGBYTES(sp)
+    andi t0, t0, 0x100
+    beqz t0, ret_to_user
+
     RESTORE_ALL
     sret

+ 22 - 2
libcpu/risc-v/virt64/encoding.h

@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
 // See LICENSE for license details.
 
 #ifndef RISCV_CSR_ENCODING_H
@@ -106,6 +114,18 @@
 #define SIP_STIP    MIP_STIP /* timer interrupt */
 #define SIP_SEIP    MIP_SEIP /* ext interrupt */
 
+#define SIE_SSIE            (1 << IRQ_S_SOFT)
+#define SIE_STIE            (1 << IRQ_S_TIMER)
+#define SIE_SEIE            (1 << IRQ_S_EXT)
+
+#define RISCV_XLEN    64
+
+#define SCAUSE_INTERRUPT    (1UL << (RISCV_XLEN - 1))
+
+#define SCAUSE_S_SOFTWARE_INTR  1
+#define SCAUSE_S_TIMER_INTR     5
+#define SCAUSE_S_EXTERNAL_INTR  9
+
 #define PRV_U 0
 #define PRV_S 1
 #define PRV_H 2
@@ -167,7 +187,7 @@
 #define RISCV_PGSHIFT 12
 #define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 #ifdef __GNUC__
 
@@ -208,7 +228,7 @@
 
 #endif /* end of __GNUC__ */
 
-#endif /* end of __ASSEMBLER__ */
+#endif /* end of __ASSEMBLY__ */
 
 #endif /* end of __riscv */
 

+ 7 - 1
libcpu/risc-v/virt64/interrupt_gcc.S

@@ -100,6 +100,10 @@ copy_context_loop_interrupt:
     #endif
 
 spurious_interrupt:
+    LOAD t0, 2 * REGBYTES(sp)
+    andi t0, t0, 0x100
+    beqz t0, ret_to_user
+
     RESTORE_ALL
     sret
 
@@ -153,7 +157,7 @@ copy_context_loop:
 .global syscall_exit
 syscall_exit:
 
-    #if defined(RT_USING_USERSPACE) && defined(RT_USING_SIGNALS)
+    #if defined(RT_USING_USERSPACE)
         LOAD s0, 2 * REGBYTES(sp)
         andi s0, s0, 0x100
         bnez s0, dont_ret_to_user
@@ -177,10 +181,12 @@ syscall_exit:
 
 .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

+ 80 - 72
libcpu/risc-v/virt64/mmu.c

@@ -15,8 +15,8 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define DBG_TAG     "mmu"
-#define DBG_LVL     DBG_INFO
+#define DBG_TAG "mmu"
+#define DBG_LVL DBG_INFO
 #include <rtdbg.h>
 
 #include <string.h>
@@ -138,7 +138,7 @@ void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info, rt_size_t vaddr_start, rt_
     rt_size_t va_e = GET_L1(vaddr_start + size - 1);
     rt_size_t i;
 
-    for(i = va_s;i <= va_e;i++)
+    for (i = va_s; i <= va_e; i++)
     {
         mmu_info->vtable[i] = COMBINEPTE(paddr_start, PAGE_ATTR_RWX | PTE_G | PTE_V);
         paddr_start += L1_PAGE_SIZE;
@@ -148,8 +148,6 @@ void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info, rt_size_t vaddr_start, rt_
 }
 
 // find a range of free virtual address specified by pages
-
-
 static size_t find_vaddr(rt_mmu_info *mmu_info, int pages)
 {
     size_t loop_pages;
@@ -237,13 +235,11 @@ static int check_vaddr(rt_mmu_info *mmu_info, void *va, rt_size_t pages)
     return 0;
 }
 
-// TODO pages ref_cnt problem
 static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t npages)
 {
     rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
     rt_size_t l1_off, l2_off, l3_off;
     rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
-    rt_size_t *ref_cnt;
 
     RT_ASSERT(mmu_info);
 
@@ -267,26 +263,29 @@ static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t npa
         *mmu_l3 = 0;
         rt_hw_cpu_dcache_clean(mmu_l3, sizeof(*mmu_l3));
 
-        // ref_cnt recalc, page in 8KB size
+        // decrease reference from leaf page to l3 page
         mmu_l3 -= l3_off;
-        ref_cnt = mmu_l3 + __SIZE(VPN0_BIT);
-        (*ref_cnt)--;
+        rt_pages_free(mmu_l3, 0);
+        int free = rt_page_ref_get(mmu_l3, 0);
 
-        if (!*ref_cnt)
+        if (free == 1)
         {
-            // release level 3 page
-            rt_pages_free(mmu_l3, 1); // entry page and ref_cnt page
+            // free l3 page
+            rt_pages_free(mmu_l3, 0);
+
             *mmu_l2 = 0;
             rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2));
-            mmu_l2 -= l2_off;
 
-            ref_cnt = mmu_l2 + __SIZE(VPN1_BIT);
-            (*ref_cnt)--;
+            // decrease reference from l3 page to l2 page
+            mmu_l2 -= l2_off;
+            rt_pages_free(mmu_l2, 0);
 
-            if (!*ref_cnt)
+            free = rt_page_ref_get(mmu_l2, 0);
+            if (free == 1)
             {
-                // release level 2 page
-                rt_pages_free(mmu_l2, 1); // entry page and ref_cnt page
+                // free l3 page
+                rt_pages_free(mmu_l2, 0);
+                // reset PTE in l1
                 *mmu_l1 = 0;
                 rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1));
             }
@@ -296,79 +295,88 @@ static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void *v_addr, rt_size_t npa
     }
 }
 
-static int __rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t npages, rt_size_t attr)
+static int _mmu_map_one_page(rt_mmu_info *mmu_info, size_t va, size_t pa, size_t attr)
 {
-    rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
-    rt_size_t loop_pa = __UMASKVALUE((rt_size_t)p_addr, PAGE_OFFSET_MASK);
     rt_size_t l1_off, l2_off, l3_off;
     rt_size_t *mmu_l1, *mmu_l2, *mmu_l3;
-    rt_size_t *ref_cnt;
 
-    if (!mmu_info)
+    l1_off = GET_L1(va);
+    l2_off = GET_L2(va);
+    l3_off = GET_L3(va);
+
+    mmu_l1 = ((rt_size_t *)mmu_info->vtable) + l1_off;
+
+    if (PTE_USED(*mmu_l1))
     {
-        return -1;
+        RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
+        mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), mmu_info->pv_off);
     }
-
-    while (npages--)
+    else
     {
-        l1_off = GET_L1(loop_va);
-        l2_off = GET_L2(loop_va);
-        l3_off = GET_L3(loop_va);
-        mmu_l1 = ((rt_size_t *)mmu_info->vtable) + l1_off;
+        mmu_l2 = (rt_size_t *)rt_pages_alloc(0);
 
-        if (PTE_USED(*mmu_l1))
+        if (mmu_l2)
         {
-            RT_ASSERT(!PAGE_IS_LEAF(*mmu_l1));
-            mmu_l2 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*mmu_l1), mmu_info->pv_off);
+            rt_memset(mmu_l2, 0, PAGE_SIZE);
+            rt_hw_cpu_dcache_clean(mmu_l2, PAGE_SIZE);
+            *mmu_l1 = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l2, mmu_info->pv_off), PAGE_DEFAULT_ATTR_NEXT);
+            rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1));
         }
         else
         {
-            mmu_l2 = (rt_size_t *)rt_pages_alloc(1);
-
-            if (mmu_l2)
-            {
-                rt_memset(mmu_l2, 0, PAGE_SIZE * 2);
-                rt_hw_cpu_dcache_clean(mmu_l2, PAGE_SIZE * 2);
-                *mmu_l1 = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l2, mmu_info->pv_off), PAGE_DEFAULT_ATTR_NEXT);
-                rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1));
-            }
-            else
-            {
-                __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
-                return -1;
-            }
+            return -1;
         }
+    }
 
-        if (PTE_USED(*(mmu_l2 + l2_off)))
+    if (PTE_USED(*(mmu_l2 + l2_off)))
+    {
+        RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off)));
+        mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)), mmu_info->pv_off);
+    }
+    else
+    {
+        mmu_l3 = (rt_size_t *)rt_pages_alloc(0);
+
+        if (mmu_l3)
         {
-            RT_ASSERT(!PAGE_IS_LEAF(*(mmu_l2 + l2_off)));
-            mmu_l3 = (rt_size_t *)PPN_TO_VPN(GET_PADDR(*(mmu_l2 + l2_off)), mmu_info->pv_off);
+            rt_memset(mmu_l3, 0, PAGE_SIZE);
+            rt_hw_cpu_dcache_clean(mmu_l3, PAGE_SIZE);
+            *(mmu_l2 + l2_off) = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l3, mmu_info->pv_off), PAGE_DEFAULT_ATTR_NEXT);
+            rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2));
+            // declares a reference to parent page table
+            rt_page_ref_inc((void *)mmu_l2, 0);
         }
         else
         {
-            mmu_l3 = (rt_size_t *)rt_pages_alloc(1);
-
-            if (mmu_l3)
-            {
-                rt_memset(mmu_l3, 0, PAGE_SIZE * 2);
-                rt_hw_cpu_dcache_clean(mmu_l3, PAGE_SIZE * 2);
-                *(mmu_l2 + l2_off) = COMBINEPTE((rt_size_t)VPN_TO_PPN(mmu_l3, mmu_info->pv_off), PAGE_DEFAULT_ATTR_NEXT);
-                rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2));
-                ref_cnt = mmu_l2 + __SIZE(VPN1_BIT);
-                (*ref_cnt)++;
-            }
-            else
-            {
-                __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
-                return -1;
-            }
+            return -1;
         }
+    }
+
+    RT_ASSERT(!PTE_USED(*(mmu_l3 + l3_off)));
+    // declares a reference to parent page table
+    rt_page_ref_inc((void *)mmu_l3, 0);
+    *(mmu_l3 + l3_off) = COMBINEPTE((rt_size_t)pa, attr);
+    rt_hw_cpu_dcache_clean(mmu_l3 + l3_off, sizeof(*(mmu_l3 + l3_off)));
+    return 0;
+}
+
+static int __rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void *p_addr, rt_size_t npages, rt_size_t attr)
+{
+    rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK);
+    rt_size_t loop_pa = __UMASKVALUE((rt_size_t)p_addr, PAGE_OFFSET_MASK);
+
+    if (!mmu_info)
+    {
+        return -1;
+    }
 
-        RT_ASSERT(!PTE_USED(*(mmu_l3 + l3_off)));
-        ref_cnt = mmu_l3 + __SIZE(VPN0_BIT);
-        (*ref_cnt)++;
-        *(mmu_l3 + l3_off) = COMBINEPTE((rt_size_t)loop_pa, attr);
-        rt_hw_cpu_dcache_clean(mmu_l3 + l3_off, sizeof(*(mmu_l3 + l3_off)));
+    while (npages--)
+    {
+        if (_mmu_map_one_page(mmu_info, loop_va, loop_pa, attr) != 0)
+        {
+            __rt_hw_mmu_unmap(mmu_info, v_addr, npages);
+            return -1;
+        }
 
         loop_va += PAGE_SIZE;
         loop_pa += PAGE_SIZE;

+ 1 - 0
libcpu/risc-v/virt64/riscv_mmu.h

@@ -81,6 +81,7 @@
 #define MMU_MAP_K_DEVICE        (PTE_G | PTE_W | PTE_R | PTE_V)
 #define MMU_MAP_K_RWCB          (PTE_G | PTE_X | PTE_W | PTE_R | PTE_V)
 #define MMU_MAP_U_RWCB          (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V)
+#define MMU_MAP_U_RWCB_XN       (PTE_U | PTE_W | PTE_R | PTE_V)
 #define MMU_MAP_U_RW            (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V)
 
 #define PTE_XWR_MASK            0xe

+ 239 - 0
libcpu/risc-v/virt64/trap.c

@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "encoding.h"
+#include "stack.h"
+#include "sbi.h"
+#include "riscv.h"
+#include "tick.h"
+#include "plic.h"
+#include "lwp_arch.h"
+
+void dump_regs(struct rt_hw_stack_frame *regs)
+{
+    rt_kprintf("--------------Dump Registers-----------------\n");
+
+    rt_kprintf("Function Registers:\n");
+    rt_kprintf("\tra(x1) = 0x%p\tuser_sp = 0x%p\n", regs->ra, regs->user_sp_exc_stack);
+    rt_kprintf("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n", regs->gp, regs->tp);
+    rt_kprintf("Temporary Registers:\n");
+    rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1);
+    rt_kprintf("\tt2(x7) = 0x%p\n", regs->t2);
+    rt_kprintf("\tt3(x28) = 0x%p\tt4(x29) = 0x%p\n", regs->t3, regs->t4);
+    rt_kprintf("\tt5(x30) = 0x%p\tt6(x31) = 0x%p\n", regs->t5, regs->t6);
+    rt_kprintf("Saved Registers:\n");
+    rt_kprintf("\ts0/fp(x8) = 0x%p\ts1(x9) = 0x%p\n", regs->s0_fp, regs->s1);
+    rt_kprintf("\ts2(x18) = 0x%p\ts3(x19) = 0x%p\n", regs->s2, regs->s3);
+    rt_kprintf("\ts4(x20) = 0x%p\ts5(x21) = 0x%p\n", regs->s4, regs->s5);
+    rt_kprintf("\ts6(x22) = 0x%p\ts7(x23) = 0x%p\n", regs->s6, regs->s7);
+    rt_kprintf("\ts8(x24) = 0x%p\ts9(x25) = 0x%p\n", regs->s8, regs->s9);
+    rt_kprintf("\ts10(x26) = 0x%p\ts11(x27) = 0x%p\n", regs->s10, regs->s11);
+    rt_kprintf("Function Arguments Registers:\n");
+    rt_kprintf("\ta0(x10) = 0x%p\ta1(x11) = 0x%p\n", regs->a0, regs->a1);
+    rt_kprintf("\ta2(x12) = 0x%p\ta3(x13) = 0x%p\n", regs->a2, regs->a3);
+    rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n", regs->a4, regs->a5);
+    rt_kprintf("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n", regs->a6, regs->a7);
+    rt_kprintf("sstatus = 0x%p\n", regs->sstatus);
+    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SIE) ? "Supervisor Interrupt Enabled" : "Supervisor Interrupt Disabled");
+    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled");
+    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode");
+    rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_PUM) ? "Permit to Access User Page" : "Not Permit to Access User Page");
+    rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page");
+    rt_size_t satp_v = read_csr(satp);
+    rt_kprintf("satp = 0x%p\n", satp_v);
+    rt_kprintf("\tCurrent Page Table(Physical) = 0x%p\n", __MASKVALUE(satp_v, __MASK(44)) << PAGE_OFFSET_BIT);
+    rt_kprintf("\tCurrent ASID = 0x%p\n", __MASKVALUE(satp_v >> 44, __MASK(16)) << PAGE_OFFSET_BIT);
+    const char *mode_str = "Unknown Address Translation/Protection Mode";
+
+    switch (__MASKVALUE(satp_v >> 60, __MASK(4)))
+    {
+    case 0:
+        mode_str = "No Address Translation/Protection Mode";
+        break;
+
+    case 8:
+        mode_str = "Page-based 39-bit Virtual Addressing Mode";
+        break;
+
+    case 9:
+        mode_str = "Page-based 48-bit Virtual Addressing Mode";
+        break;
+    }
+
+    rt_kprintf("\tMode = %s\n", mode_str);
+    rt_kprintf("-----------------Dump OK---------------------\n");
+}
+
+static const char *Exception_Name[] =
+    {
+        "Instruction Address Misaligned",
+        "Instruction Access Fault",
+        "Illegal Instruction",
+        "Breakpoint",
+        "Load Address Misaligned",
+        "Load Access Fault",
+        "Store/AMO Address Misaligned",
+        "Store/AMO Access Fault",
+        "Environment call from U-mode",
+        "Environment call from S-mode",
+        "Reserved-10",
+        "Reserved-11",
+        "Instruction Page Fault",
+        "Load Page Fault",
+        "Reserved-14",
+        "Store/AMO Page Fault"};
+
+static const char *Interrupt_Name[] =
+    {
+        "User Software Interrupt",
+        "Supervisor Software Interrupt",
+        "Reversed-2",
+        "Reversed-3",
+        "User Timer Interrupt",
+        "Supervisor Timer Interrupt",
+        "Reversed-6",
+        "Reversed-7",
+        "User External Interrupt",
+        "Supervisor External Interrupt",
+        "Reserved-10",
+        "Reserved-11",
+};
+
+enum
+{
+    EP_INSTRUCTION_ADDRESS_MISALIGNED = 0,
+    EP_INSTRUCTION_ACCESS_FAULT,
+    EP_ILLEGAL_INSTRUCTION,
+    EP_BREAKPOINT,
+    EP_LOAD_ADDRESS_MISALIGNED,
+    EP_LOAD_ACCESS_FAULT,
+    EP_STORE_ADDRESS_MISALIGNED,
+    EP_STORE_ACCESS_FAULT,
+    EP_ENVIRONMENT_CALL_U_MODE,
+    EP_ENVIRONMENT_CALL_S_MODE,
+    EP_RESERVED10,
+    EP_ENVIRONMENT_CALL_M_MODE,
+    EP_INSTRUCTION_PAGE_FAULT, /* page attr */
+    EP_LOAD_PAGE_FAULT,        /* read data */
+    EP_RESERVED14,
+    EP_STORE_PAGE_FAULT, /* write data */
+};
+
+
+extern struct rt_irq_desc irq_desc[];
+
+#include "rtdbg.h"
+#include "encoding.h"
+void sys_exit(int value);
+
+static const char *get_exception_msg(int id)
+{
+    const char *msg;
+    if (id < sizeof(Exception_Name) / sizeof(const char *))
+    {
+        msg = Exception_Name[id];
+    }
+    else
+    {
+        msg = "Unknown Exception";
+    }
+    return msg;
+}
+
+void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp)
+{
+    rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
+
+#ifdef RT_USING_USERSPACE
+    /* user page fault */
+    if (id == EP_LOAD_PAGE_FAULT ||
+        id == EP_STORE_PAGE_FAULT)
+    {
+        if (arch_expand_user_stack((void *)stval))
+        {
+            return;
+        }
+    }
+#endif
+    LOG_E("[FATAL ERROR] Exception %ld:%s\n", id, get_exception_msg(id));
+    LOG_E("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
+    dump_regs(sp);
+
+    rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc);
+
+    LOG_E("User Fault, killing thread: %s", rt_thread_self()->name);
+    sys_exit(-1);
+}
+
+/* Trap entry */
+void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp)
+{
+    rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
+    const char *msg;
+
+    /* supervisor external interrupt */
+    if (scause == (uint64_t)(0x8000000000000005))
+    {
+        rt_interrupt_enter();
+        tick_isr();
+        rt_interrupt_leave();
+    }
+    else if (scause == (uint64_t)(0x8000000000000009))
+    {
+        rt_interrupt_enter();
+        int plic_irq = plic_claim();
+        plic_complete(plic_irq);
+        irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
+        rt_interrupt_leave();
+    }
+    else
+    {
+        rt_size_t id = __MASKVALUE(scause, __MASK(63UL));
+        const char *msg;
+
+        if (scause >> 63)
+        {
+            if (id < sizeof(Interrupt_Name) / sizeof(const char *))
+            {
+                msg = Interrupt_Name[id];
+            }
+            else
+            {
+                msg = "Unknown Interrupt";
+            }
+
+            rt_kprintf("Unhandled Interrupt %ld:%s\n", id, msg);
+        }
+        else
+        {
+            if (!(sp->sstatus & 0x100))
+            {
+                handle_user(scause, stval, sepc, sp);
+                // after handle_user(), return to user space.
+                // otherwise it never returns
+                return ;
+            }
+
+            // handle kernel exception:
+            rt_kprintf("Unhandled Exception %ld:%s\n", id, get_exception_msg(id));
+        }
+
+        rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
+        dump_regs(sp);
+
+        extern struct rt_thread *rt_current_thread;
+
+        rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc);
+
+        while (1)
+            ;
+    }
+}