feat: libcpu/risc-v: unify interrupt & IO on rv64

This patch aims to unify the two currently separated RISC-V 64-bit
architecture ports, 'virt64' and 'c906', into a single generic
'common64' port. The changes include renaming files and updating
includes to use a unified 'interrupt.h' header, as well as making
adjustments to IO and trap handling to be more consistent between the
two architectures.

Changes:
- Renamed 'rt_interrupt.h' to 'interrupt.h' and updated includes accordingly.
- Unified IO register access functions in 'riscv_io.h'.
- Added 'opcode.h' for portable assembly support.
- Updated 'plic.c' and 'plic.h' to handle interrupts in a unified manner.
- Modified 'trap.c' to handle exceptions and interrupts consistently for 'rv64'.

Signed-off-by: Shell <smokewood@qq.com>
This commit is contained in:
Shell 2024-09-02 18:02:15 +08:00 committed by Meco Man
parent a00aaab2ba
commit e244c196c4
13 changed files with 442 additions and 347 deletions

View File

@ -11,7 +11,7 @@
#include <rthw.h> #include <rthw.h>
#include <rtthread.h> #include <rtthread.h>
#include "rt_interrupt.h" #include "interrupt.h"
#include "riscv.h" #include "riscv.h"
#include "plic.h" #include "plic.h"

View File

@ -15,7 +15,7 @@
#include <rtdbg.h> #include <rtdbg.h>
#include "plic.h" #include "plic.h"
#include "rt_interrupt.h" #include "interrupt.h"
#include "io.h" #include "io.h"
#include "encoding.h" #include "encoding.h"
#include "ioremap.h" #include "ioremap.h"

View File

@ -12,7 +12,7 @@
#ifndef __RISCV64_PLIC_H__ #ifndef __RISCV64_PLIC_H__
#define __RISCV64_PLIC_H__ #define __RISCV64_PLIC_H__
#include <rt_interrupt.h> #include <interrupt.h>
#ifndef C906_PLIC_PHY_ADDR #ifndef C906_PLIC_PHY_ADDR
#define C906_PLIC_PHY_ADDR (0x10000000) #define C906_PLIC_PHY_ADDR (0x10000000)

View File

@ -1,11 +1,12 @@
/* /*
* Copyright (c) 2006-2021, RT-Thread Development Team * Copyright (c) 2006-2024, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2021-01-30 lizhirui first version * 2021-01-30 lizhirui first version
* 2024-08-28 RT-Thread Fit into rv64ilp32 ABI
*/ */
#ifndef __RISCV_H__ #ifndef __RISCV_H__
@ -13,13 +14,15 @@
#include <encoding.h> #include <encoding.h>
#define __SIZE(bit) (1UL << (bit)) /* using unsigned long long for the case of rv64ilp32 */
#define __MASK(bit) (__SIZE(bit) - 1UL) #define __SIZE(bit) (1ULL << (bit))
#define __MASK(bit) (__SIZE(bit) - 1ULL)
#define __UMASK(bit) (~(__MASK(bit))) #define __UMASK(bit) (~(__MASK(bit)))
#define __MASKVALUE(value,maskvalue) ((value) & (maskvalue)) #define __MASKVALUE(value,maskvalue) ((value) & (maskvalue))
#define __UMASKVALUE(value,maskvalue) ((value) & (~(maskvalue))) #define __UMASKVALUE(value,maskvalue) ((value) & (~(maskvalue)))
#define __CHECKUPBOUND(value,bit_count) (!(((rt_size_t)value) & (~__MASK(bit_count)))) #define __CHECKUPBOUND(value,bit_count) (!(((rt_ubase_t)value) & (~__MASK(bit_count))))
#define __CHECKALIGN(value,start_bit) (!(((rt_size_t)value) & (__MASK(start_bit)))) #define __CHECKALIGN(value,start_bit) (!(((rt_ubase_t)value) & (__MASK(start_bit))))
#define __PARTBIT(value,start_bit,length) (((value) >> (start_bit)) & __MASK(length)) #define __PARTBIT(value,start_bit,length) (((value) >> (start_bit)) & __MASK(length))

View File

@ -10,6 +10,12 @@
#ifndef __RISCV_IO_H__ #ifndef __RISCV_IO_H__
#define __RISCV_IO_H__ #define __RISCV_IO_H__
static inline uint32_t __raw_hartid(void)
{
extern int boot_hartid;
return boot_hartid;
}
static inline void __raw_writeb(rt_uint8_t val, volatile void *addr) static inline void __raw_writeb(rt_uint8_t val, volatile void *addr)
{ {
asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr)); asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr));

View File

@ -1,36 +1,29 @@
/* /*
* Copyright (c) 2006-2021, RT-Thread Development Team * Copyright (c) 2006-2024, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2021/1/30 lizirui first version * 2022-12-08 RT-Thread first version
* 2021/10/20 JasonHu move to trap.c
*/ */
#include <rthw.h> #include <rthw.h>
#include <rtthread.h> #include <rtthread.h>
#include <stdint.h> #include <stdint.h>
#include "board.h"
#include "tick.h"
#include <mm_fault.h> #include <mm_fault.h>
#include "mmu.h" #include <mmu.h>
#include "encoding.h" #include <encoding.h>
#include "stack.h" #include <stack.h>
#include "sbi.h" #include <sbi.h>
#include "riscv.h" #include <riscv.h>
#include "rt_interrupt.h" #include <interrupt.h>
#include "plic.h" #include <plic.h>
#include <tick.h>
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
#include <lwp_arch.h> #include <lwp_arch.h>
void rt_hw_backtrace(rt_uint32_t *ffp, rt_ubase_t sepc);
#else
#define rt_hw_backtrace(...) (0)
#endif #endif
#define DBG_TAG "libcpu.trap" #define DBG_TAG "libcpu.trap"
@ -42,7 +35,8 @@ void dump_regs(struct rt_hw_stack_frame *regs)
rt_kprintf("--------------Dump Registers-----------------\n"); rt_kprintf("--------------Dump Registers-----------------\n");
rt_kprintf("Function 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("\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("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n", regs->gp, regs->tp);
rt_kprintf("Temporary Registers:\n"); rt_kprintf("Temporary Registers:\n");
rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1); rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1);
@ -62,15 +56,27 @@ void dump_regs(struct rt_hw_stack_frame *regs)
rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n", regs->a4, regs->a5); 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("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n", regs->a6, regs->a7);
rt_kprintf("sstatus = 0x%p\n", regs->sstatus); 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_SIE)
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled"); ? "Supervisor Interrupt Enabled"
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode"); : "Supervisor Interrupt Disabled");
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 & SSTATUS_SPIE)
rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page"); ? "Last Time Supervisor Interrupt Enabled"
rt_size_t satp_v = read_csr(satp); : "Last Time Supervisor Interrupt Disabled");
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP)
? "Last Privilege is Supervisor Mode"
: "Last Privilege is User Mode");
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SUM)
? "Permit to Access User Page"
: "Not Permit to Access User Page");
rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19))
? "Permit to Read Executable-only Page"
: "Not Permit to Read Executable-only Page");
rt_ubase_t satp_v = read_csr(satp);
rt_kprintf("satp = 0x%p\n", satp_v); 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 Page Table(Physical) = 0x%p\n",
rt_kprintf("\tCurrent ASID = 0x%p\n", __MASKVALUE(satp_v >> 44, __MASK(16)) << PAGE_OFFSET_BIT); __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"; const char *mode_str = "Unknown Address Translation/Protection Mode";
switch (__MASKVALUE(satp_v >> 60, __MASK(4))) switch (__MASKVALUE(satp_v >> 60, __MASK(4)))
@ -92,9 +98,7 @@ void dump_regs(struct rt_hw_stack_frame *regs)
rt_kprintf("-----------------Dump OK---------------------\n"); rt_kprintf("-----------------Dump OK---------------------\n");
} }
static const char *Exception_Name[] = static const char *Exception_Name[] = {"Instruction Address Misaligned",
{
"Instruction Address Misaligned",
"Instruction Access Fault", "Instruction Access Fault",
"Illegal Instruction", "Illegal Instruction",
"Breakpoint", "Breakpoint",
@ -111,8 +115,7 @@ static const char *Exception_Name[] =
"Reserved-14", "Reserved-14",
"Store/AMO Page Fault"}; "Store/AMO Page Fault"};
static const char *Interrupt_Name[] = static const char *Interrupt_Name[] = {
{
"User Software Interrupt", "User Software Interrupt",
"Supervisor Software Interrupt", "Supervisor Software Interrupt",
"Reversed-2", "Reversed-2",
@ -129,13 +132,10 @@ static const char *Interrupt_Name[] =
#ifndef RT_USING_SMP #ifndef RT_USING_SMP
static volatile int nested = 0; static volatile int nested = 0;
#define ENTER_TRAP \ #define ENTER_TRAP nested += 1
nested += 1 #define EXIT_TRAP nested -= 1
#define EXIT_TRAP \
nested -= 1
#define CHECK_NESTED_PANIC(cause, tval, epc, eframe) \ #define CHECK_NESTED_PANIC(cause, tval, epc, eframe) \
if (nested != 1) \ if (nested != 1) handle_nested_trap_panic(cause, tval, epc, eframe)
handle_nested_trap_panic(cause, tval, epc, eframe)
#endif /* RT_USING_SMP */ #endif /* RT_USING_SMP */
static const char *get_exception_msg(int id) static const char *get_exception_msg(int id)
@ -153,9 +153,11 @@ static const char *get_exception_msg(int id)
} }
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp) #include "lwp.h"
void handle_user(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc,
struct rt_hw_stack_frame *sp)
{ {
rt_size_t id = __MASKVALUE(scause, __MASK(63UL)); rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
struct rt_lwp *lwp; struct rt_lwp *lwp;
/* user page fault */ /* user page fault */
@ -165,11 +167,11 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
{ {
case EP_LOAD_PAGE_FAULT: case EP_LOAD_PAGE_FAULT:
fault_op = MM_FAULT_OP_READ; fault_op = MM_FAULT_OP_READ;
fault_type = MM_FAULT_TYPE_PAGE_FAULT; fault_type = MM_FAULT_TYPE_GENERIC_MMU;
break; break;
case EP_LOAD_ACCESS_FAULT: case EP_LOAD_ACCESS_FAULT:
fault_op = MM_FAULT_OP_READ; fault_op = MM_FAULT_OP_READ;
fault_type = MM_FAULT_TYPE_GENERIC; fault_type = MM_FAULT_TYPE_BUS_ERROR;
break; break;
case EP_LOAD_ADDRESS_MISALIGNED: case EP_LOAD_ADDRESS_MISALIGNED:
fault_op = MM_FAULT_OP_READ; fault_op = MM_FAULT_OP_READ;
@ -177,11 +179,11 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
break; break;
case EP_STORE_PAGE_FAULT: case EP_STORE_PAGE_FAULT:
fault_op = MM_FAULT_OP_WRITE; fault_op = MM_FAULT_OP_WRITE;
fault_type = MM_FAULT_TYPE_PAGE_FAULT; fault_type = MM_FAULT_TYPE_GENERIC_MMU;
break; break;
case EP_STORE_ACCESS_FAULT: case EP_STORE_ACCESS_FAULT:
fault_op = MM_FAULT_OP_WRITE; fault_op = MM_FAULT_OP_WRITE;
fault_type = MM_FAULT_TYPE_GENERIC; fault_type = MM_FAULT_TYPE_BUS_ERROR;
break; break;
case EP_STORE_ADDRESS_MISALIGNED: case EP_STORE_ADDRESS_MISALIGNED:
fault_op = MM_FAULT_OP_WRITE; fault_op = MM_FAULT_OP_WRITE;
@ -189,11 +191,11 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
break; break;
case EP_INSTRUCTION_PAGE_FAULT: case EP_INSTRUCTION_PAGE_FAULT:
fault_op = MM_FAULT_OP_EXECUTE; fault_op = MM_FAULT_OP_EXECUTE;
fault_type = MM_FAULT_TYPE_PAGE_FAULT; fault_type = MM_FAULT_TYPE_GENERIC_MMU;
break; break;
case EP_INSTRUCTION_ACCESS_FAULT: case EP_INSTRUCTION_ACCESS_FAULT:
fault_op = MM_FAULT_OP_EXECUTE; fault_op = MM_FAULT_OP_EXECUTE;
fault_type = MM_FAULT_TYPE_GENERIC; fault_type = MM_FAULT_TYPE_BUS_ERROR;
break; break;
case EP_INSTRUCTION_ADDRESS_MISALIGNED: case EP_INSTRUCTION_ADDRESS_MISALIGNED:
fault_op = MM_FAULT_OP_EXECUTE; fault_op = MM_FAULT_OP_EXECUTE;
@ -225,16 +227,19 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
LOG_E("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc); LOG_E("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
dump_regs(sp); dump_regs(sp);
rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc); rt_thread_t cur_thr = rt_thread_self();
struct rt_hw_backtrace_frame frame = {.fp = sp->s0_fp, .pc = sepc};
rt_kprintf("fp = %p\n", frame.fp);
lwp_backtrace_frame(cur_thr, &frame);
LOG_E("User Fault, killing thread: %s", rt_thread_self()->parent.name); LOG_E("User Fault, killing thread: %s", cur_thr->parent.name);
EXIT_TRAP; EXIT_TRAP;
sys_exit_group(-1); sys_exit_group(-1);
} }
#endif #endif
#ifdef ENABLE_VECTOR #ifdef ARCH_RISCV_VECTOR
static void vector_enable(struct rt_hw_stack_frame *sp) static void vector_enable(struct rt_hw_stack_frame *sp)
{ {
sp->sstatus |= SSTATUS_VS_INITIAL; sp->sstatus |= SSTATUS_VS_INITIAL;
@ -243,7 +248,8 @@ static void vector_enable(struct rt_hw_stack_frame *sp)
/** /**
* detect V/D support, and do not distinguish V/D instruction * 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) static int illegal_inst_recoverable(rt_ubase_t stval,
struct rt_hw_stack_frame *sp)
{ {
// first 7 bits is opcode // first 7 bits is opcode
int opcode = stval & 0x7f; int opcode = stval & 0x7f;
@ -271,10 +277,8 @@ static int illegal_inst_recoverable(rt_ubase_t stval, struct rt_hw_stack_frame *
} }
#endif #endif
static void handle_nested_trap_panic( static void handle_nested_trap_panic(rt_ubase_t cause, rt_ubase_t tval,
rt_size_t cause, rt_ubase_t epc,
rt_size_t tval,
rt_size_t epc,
struct rt_hw_stack_frame *eframe) struct rt_hw_stack_frame *eframe)
{ {
LOG_E("\n-------- [SEVER ERROR] --------"); LOG_E("\n-------- [SEVER ERROR] --------");
@ -288,18 +292,20 @@ static void handle_nested_trap_panic(
#define PAGE_FAULT (id == EP_LOAD_PAGE_FAULT || id == EP_STORE_PAGE_FAULT) #define PAGE_FAULT (id == EP_LOAD_PAGE_FAULT || id == EP_STORE_PAGE_FAULT)
/* Trap entry */ /* Trap entry */
void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp) void handle_trap(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc,
struct rt_hw_stack_frame *sp)
{ {
rt_size_t id = __MASKVALUE(scause,__MASK(63UL)); ENTER_TRAP;
rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
const char *msg; const char *msg;
/* supervisor external interrupt */ /* supervisor external interrupt */
if ((SCAUSE_INTERRUPT & scause) && SCAUSE_S_EXTERNAL_INTR == (scause & 0xff)) if ((SCAUSE_INTERRUPT & scause) &&
SCAUSE_S_EXTERNAL_INTR == (scause & 0xff))
{ {
rt_interrupt_enter(); rt_interrupt_enter();
plic_handle_irq(); plic_handle_irq();
rt_interrupt_leave(); rt_interrupt_leave();
return;
} }
else if ((SCAUSE_INTERRUPT | SCAUSE_S_TIMER_INTR) == scause) else if ((SCAUSE_INTERRUPT | SCAUSE_S_TIMER_INTR) == scause)
{ {
@ -307,9 +313,10 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
rt_interrupt_enter(); rt_interrupt_enter();
tick_isr(); tick_isr();
rt_interrupt_leave(); rt_interrupt_leave();
return;
} }
else if (SCAUSE_INTERRUPT & scause) else
{
if (SCAUSE_INTERRUPT & scause)
{ {
if (id < sizeof(Interrupt_Name) / sizeof(const char *)) if (id < sizeof(Interrupt_Name) / sizeof(const char *))
{ {
@ -319,32 +326,61 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
{ {
msg = "Unknown Interrupt"; msg = "Unknown Interrupt";
} }
LOG_E("Unhandled Interrupt %ld:%s\n", id, msg); LOG_E("Unhandled Interrupt %ld:%s\n", id, msg);
} }
else else
{ {
#ifdef ARCH_RISCV_VECTOR
if (scause == 0x2)
{
if (!(sp->sstatus & SSTATUS_VS) &&
illegal_inst_recoverable(stval, sp))
goto _exit;
}
#endif /* ARCH_RISCV_VECTOR */
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
if (!(sp->sstatus & 0x100) || (PAGE_FAULT && IN_USER_SPACE)) if (!(sp->sstatus & 0x100) || (PAGE_FAULT && IN_USER_SPACE))
{ {
handle_user(scause, stval, sepc, sp); handle_user(scause, stval, sepc, sp);
// if handle_user() return here, jump to u mode then // if handle_user() return here, jump to u mode then
return ; goto _exit;
} }
#endif #endif
// handle kernel exception: // handle kernel exception:
rt_kprintf("Unhandled Exception %ld:%s\n", id, get_exception_msg(id)); rt_kprintf("Unhandled Exception %ld:%s\n", id,
get_exception_msg(id));
} }
// trap cannot nested when handling another trap / interrupt
CHECK_NESTED_PANIC(scause, stval, sepc, sp);
rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc); rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
dump_regs(sp); dump_regs(sp);
rt_kprintf("--------------Thread list--------------\n");
rt_kprintf("current thread: %s\n", rt_thread_self()->parent.name);
extern struct rt_thread *rt_current_thread; rt_thread_t cur_thr = rt_thread_self();
rt_kprintf("--------------Thread list--------------\n");
rt_kprintf("current thread: %s\n", cur_thr->parent.name);
rt_kprintf("--------------Backtrace--------------\n"); rt_kprintf("--------------Backtrace--------------\n");
rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc); struct rt_hw_backtrace_frame frame = {.fp = sp->s0_fp, .pc = sepc};
#ifdef RT_USING_SMART
if (!(sp->sstatus & 0x100))
{
lwp_backtrace_frame(cur_thr, &frame);
}
else
#endif
{
rt_backtrace_frame(cur_thr, &frame);
}
while (1) while (1)
; ;
} }
_exit:
EXIT_TRAP;
return;
}

View File

@ -40,13 +40,13 @@ static inline uint32_t readl(const volatile void *addr)
static inline void write_reg( static inline void write_reg(
uint32_t val, volatile void *addr, unsigned offset) uint32_t val, volatile void *addr, unsigned offset)
{ {
writel(val, addr + offset); writel(val, (void *)((rt_size_t)addr + offset));
} }
static inline uint32_t read_reg( static inline uint32_t read_reg(
const volatile void *addr, unsigned offset) const volatile void *addr, unsigned offset)
{ {
return readl(addr + offset); return readl((void *)((rt_size_t)addr + offset));
} }
#endif // ARCH_IO_H #endif // ARCH_IO_H

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-09 Shell Add portable asm support
*/
#ifndef __OPCODE_H__
#define __OPCODE_H__
/**
* @brief binary opcode pseudo operations
* Used to bypass toolchain restriction on extension ISA
*
*/
/**
* @brief RISC-V instruction formats
*/
/**
* R type: .insn r opcode6, func3, func7, rd, rs1, rs2
*
* +-------+-----+-----+-------+----+---------+
* | func7 | rs2 | rs1 | func3 | rd | opcode6 |
* +-------+-----+-----+-------+----+---------+
* 31 25 20 15 12 7 0
*/
#define __OPC_INSN_FORMAT_R(opcode, func3, func7, rd, rs1, rs2) \
".insn r "RT_STRINGIFY(opcode)","RT_STRINGIFY(func3)","RT_STRINGIFY(func7)","RT_STRINGIFY(rd)","RT_STRINGIFY(rs1)","RT_STRINGIFY(rs2)
#ifdef _TOOLCHAIN_SUPP_ZIFENCEI_ISA_
#define OPC_FENCE_I "fence.i"
#else /* !_TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
#define OPC_FENCE_I ".long 0x0000100F"
#endif /* _TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
#endif /* __OPCODE_H__ */

View File

@ -14,6 +14,7 @@
#include "plic.h" #include "plic.h"
#include <riscv_io.h> #include <riscv_io.h>
#include "encoding.h" #include "encoding.h"
#include <interrupt.h>
#include <riscv.h> #include <riscv.h>
#include <string.h> #include <string.h>
@ -139,3 +140,17 @@ void plic_init()
// in a single core system, only current context was set // in a single core system, only current context was set
_set_sie(__raw_hartid()); _set_sie(__raw_hartid());
} }
extern struct rt_irq_desc irq_desc[MAX_HANDLERS];
/*
* Handling an interrupt is a two-step process: first you claim the interrupt
* by reading the claim register, then you complete the interrupt by writing
* that source ID back to the same claim register. This automatically enables
* and disables the interrupt, so there's nothing else to do.
*/
void plic_handle_irq(void)
{
int plic_irq = plic_claim();
plic_complete(plic_irq);
irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
}

View File

@ -72,5 +72,6 @@ void plic_complete(int irq);
void plic_set_thresh(rt_uint32_t val); void plic_set_thresh(rt_uint32_t val);
void plic_set_ie(rt_uint32_t word_index,rt_uint32_t val); void plic_set_ie(rt_uint32_t word_index,rt_uint32_t val);
void plic_init(); void plic_init();
void plic_handle_irq(void);
#endif #endif

View File

@ -18,31 +18,23 @@ static inline uint32_t __raw_hartid(void)
static inline void __raw_writeb(rt_uint8_t val, volatile void *addr) static inline void __raw_writeb(rt_uint8_t val, volatile void *addr)
{ {
asm volatile("sb %0, 0(%1)" asm volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr));
:
: "r"(val), "r"(addr));
} }
static inline void __raw_writew(rt_uint16_t val, volatile void *addr) static inline void __raw_writew(rt_uint16_t val, volatile void *addr)
{ {
asm volatile("sh %0, 0(%1)" asm volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr));
:
: "r"(val), "r"(addr));
} }
static inline void __raw_writel(rt_uint32_t val, volatile void *addr) static inline void __raw_writel(rt_uint32_t val, volatile void *addr)
{ {
asm volatile("sw %0, 0(%1)" asm volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr));
:
: "r"(val), "r"(addr));
} }
#if __riscv_xlen != 32 #if __riscv_xlen != 32
static inline void __raw_writeq(rt_uint64_t val, volatile void *addr) static inline void __raw_writeq(rt_uint64_t val, volatile void *addr)
{ {
asm volatile("sd %0, 0(%1)" asm volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr));
:
: "r"(val), "r"(addr));
} }
#endif #endif
@ -50,9 +42,7 @@ static inline rt_uint8_t __raw_readb(const volatile void *addr)
{ {
rt_uint8_t val; rt_uint8_t val;
asm volatile("lb %0, 0(%1)" asm volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr));
: "=r"(val)
: "r"(addr));
return val; return val;
} }
@ -60,9 +50,7 @@ static inline rt_uint16_t __raw_readw(const volatile void *addr)
{ {
rt_uint16_t val; rt_uint16_t val;
asm volatile("lh %0, 0(%1)" asm volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr));
: "=r"(val)
: "r"(addr));
return val; return val;
} }
@ -70,9 +58,7 @@ static inline rt_uint32_t __raw_readl(const volatile void *addr)
{ {
rt_uint32_t val; rt_uint32_t val;
asm volatile("lw %0, 0(%1)" asm volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr));
: "=r"(val)
: "r"(addr));
return val; return val;
} }
@ -81,9 +67,7 @@ static inline rt_uint64_t __raw_readq(const volatile void *addr)
{ {
rt_uint64_t val; rt_uint64_t val;
asm volatile("ld %0, 0(%1)" asm volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr));
: "=r"(val)
: "r"(addr));
return val; return val;
} }
#endif #endif

View File

@ -7,24 +7,23 @@
* Date Author Notes * Date Author Notes
* 2022-12-08 RT-Thread first version * 2022-12-08 RT-Thread first version
*/ */
#include <rthw.h> #include <rthw.h>
#include <rtthread.h> #include <rtthread.h>
#include <stdint.h> #include <stdint.h>
#include <mm_fault.h> #include <mm_fault.h>
#include "mmu.h" #include <mmu.h>
#include "encoding.h" #include <encoding.h>
#include "stack.h" #include <stack.h>
#include "sbi.h" #include <sbi.h>
#include "riscv.h" #include <riscv.h>
#include "interrupt.h" #include <interrupt.h>
#include "plic.h" #include <plic.h>
#include "tick.h" #include <tick.h>
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
#include <lwp_arch.h> #include <lwp_arch.h>
#else
#define rt_hw_backtrace(...) (0)
#endif #endif
#define DBG_TAG "libcpu.trap" #define DBG_TAG "libcpu.trap"
@ -36,7 +35,8 @@ void dump_regs(struct rt_hw_stack_frame *regs)
rt_kprintf("--------------Dump Registers-----------------\n"); rt_kprintf("--------------Dump Registers-----------------\n");
rt_kprintf("Function 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("\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("\tgp(x3) = 0x%p\ttp(x4) = 0x%p\n", regs->gp, regs->tp);
rt_kprintf("Temporary Registers:\n"); rt_kprintf("Temporary Registers:\n");
rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1); rt_kprintf("\tt0(x5) = 0x%p\tt1(x6) = 0x%p\n", regs->t0, regs->t1);
@ -56,15 +56,27 @@ void dump_regs(struct rt_hw_stack_frame *regs)
rt_kprintf("\ta4(x14) = 0x%p\ta5(x15) = 0x%p\n", regs->a4, regs->a5); 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("\ta6(x16) = 0x%p\ta7(x17) = 0x%p\n", regs->a6, regs->a7);
rt_kprintf("sstatus = 0x%p\n", regs->sstatus); 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_SIE)
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPIE) ? "Last Time Supervisor Interrupt Enabled" : "Last Time Supervisor Interrupt Disabled"); ? "Supervisor Interrupt Enabled"
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP) ? "Last Privilege is Supervisor Mode" : "Last Privilege is User Mode"); : "Supervisor Interrupt Disabled");
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 & SSTATUS_SPIE)
rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19)) ? "Permit to Read Executable-only Page" : "Not Permit to Read Executable-only Page"); ? "Last Time Supervisor Interrupt Enabled"
: "Last Time Supervisor Interrupt Disabled");
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SPP)
? "Last Privilege is Supervisor Mode"
: "Last Privilege is User Mode");
rt_kprintf("\t%s\n", (regs->sstatus & SSTATUS_SUM)
? "Permit to Access User Page"
: "Not Permit to Access User Page");
rt_kprintf("\t%s\n", (regs->sstatus & (1 << 19))
? "Permit to Read Executable-only Page"
: "Not Permit to Read Executable-only Page");
rt_ubase_t satp_v = read_csr(satp); rt_ubase_t satp_v = read_csr(satp);
rt_kprintf("satp = 0x%p\n", satp_v); 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 Page Table(Physical) = 0x%p\n",
rt_kprintf("\tCurrent ASID = 0x%p\n", __MASKVALUE(satp_v >> 44, __MASK(16)) << PAGE_OFFSET_BIT); __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"; const char *mode_str = "Unknown Address Translation/Protection Mode";
switch (__MASKVALUE(satp_v >> 60, __MASK(4))) switch (__MASKVALUE(satp_v >> 60, __MASK(4)))
@ -86,9 +98,7 @@ void dump_regs(struct rt_hw_stack_frame *regs)
rt_kprintf("-----------------Dump OK---------------------\n"); rt_kprintf("-----------------Dump OK---------------------\n");
} }
static const char *Exception_Name[] = static const char *Exception_Name[] = {"Instruction Address Misaligned",
{
"Instruction Address Misaligned",
"Instruction Access Fault", "Instruction Access Fault",
"Illegal Instruction", "Illegal Instruction",
"Breakpoint", "Breakpoint",
@ -105,8 +115,7 @@ static const char *Exception_Name[] =
"Reserved-14", "Reserved-14",
"Store/AMO Page Fault"}; "Store/AMO Page Fault"};
static const char *Interrupt_Name[] = static const char *Interrupt_Name[] = {
{
"User Software Interrupt", "User Software Interrupt",
"Supervisor Software Interrupt", "Supervisor Software Interrupt",
"Reversed-2", "Reversed-2",
@ -121,17 +130,12 @@ static const char *Interrupt_Name[] =
"Reserved-11", "Reserved-11",
}; };
extern struct rt_irq_desc irq_desc[];
#ifndef RT_USING_SMP #ifndef RT_USING_SMP
static volatile int nested = 0; static volatile int nested = 0;
#define ENTER_TRAP \ #define ENTER_TRAP nested += 1
nested += 1 #define EXIT_TRAP nested -= 1
#define EXIT_TRAP \
nested -= 1
#define CHECK_NESTED_PANIC(cause, tval, epc, eframe) \ #define CHECK_NESTED_PANIC(cause, tval, epc, eframe) \
if (nested != 1) \ if (nested != 1) handle_nested_trap_panic(cause, tval, epc, eframe)
handle_nested_trap_panic(cause, tval, epc, eframe)
#endif /* RT_USING_SMP */ #endif /* RT_USING_SMP */
static const char *get_exception_msg(int id) static const char *get_exception_msg(int id)
@ -150,7 +154,8 @@ static const char *get_exception_msg(int id)
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
#include "lwp.h" #include "lwp.h"
void handle_user(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc, struct rt_hw_stack_frame *sp) void handle_user(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc,
struct rt_hw_stack_frame *sp)
{ {
rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL)); rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
struct rt_lwp *lwp; struct rt_lwp *lwp;
@ -223,10 +228,7 @@ void handle_user(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc, struct rt
dump_regs(sp); dump_regs(sp);
rt_thread_t cur_thr = rt_thread_self(); rt_thread_t cur_thr = rt_thread_self();
struct rt_hw_backtrace_frame frame = { struct rt_hw_backtrace_frame frame = {.fp = sp->s0_fp, .pc = sepc};
.fp = sp->s0_fp,
.pc = sepc
};
rt_kprintf("fp = %p\n", frame.fp); rt_kprintf("fp = %p\n", frame.fp);
lwp_backtrace_frame(cur_thr, &frame); lwp_backtrace_frame(cur_thr, &frame);
@ -237,7 +239,7 @@ void handle_user(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc, struct rt
} }
#endif #endif
#ifdef ENABLE_VECTOR #ifdef ARCH_RISCV_VECTOR
static void vector_enable(struct rt_hw_stack_frame *sp) static void vector_enable(struct rt_hw_stack_frame *sp)
{ {
sp->sstatus |= SSTATUS_VS_INITIAL; sp->sstatus |= SSTATUS_VS_INITIAL;
@ -246,7 +248,8 @@ static void vector_enable(struct rt_hw_stack_frame *sp)
/** /**
* detect V/D support, and do not distinguish V/D instruction * 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) static int illegal_inst_recoverable(rt_ubase_t stval,
struct rt_hw_stack_frame *sp)
{ {
// first 7 bits is opcode // first 7 bits is opcode
int opcode = stval & 0x7f; int opcode = stval & 0x7f;
@ -274,9 +277,7 @@ static int illegal_inst_recoverable(rt_ubase_t stval, struct rt_hw_stack_frame *
} }
#endif #endif
static void handle_nested_trap_panic( static void handle_nested_trap_panic(rt_ubase_t cause, rt_ubase_t tval,
rt_ubase_t cause,
rt_ubase_t tval,
rt_ubase_t epc, rt_ubase_t epc,
struct rt_hw_stack_frame *eframe) struct rt_hw_stack_frame *eframe)
{ {
@ -291,35 +292,31 @@ static void handle_nested_trap_panic(
#define PAGE_FAULT (id == EP_LOAD_PAGE_FAULT || id == EP_STORE_PAGE_FAULT) #define PAGE_FAULT (id == EP_LOAD_PAGE_FAULT || id == EP_STORE_PAGE_FAULT)
/* Trap entry */ /* Trap entry */
void handle_trap(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc, struct rt_hw_stack_frame *sp) void handle_trap(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc,
struct rt_hw_stack_frame *sp)
{ {
ENTER_TRAP; ENTER_TRAP;
rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL)); rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
const char *msg; const char *msg;
/* supervisor external interrupt */ /* supervisor external interrupt */
if (scause == (uint64_t)(0x8000000000000005)) if ((SCAUSE_INTERRUPT & scause) &&
SCAUSE_S_EXTERNAL_INTR == (scause & 0xff))
{ {
rt_interrupt_enter();
plic_handle_irq();
rt_interrupt_leave();
}
else if ((SCAUSE_INTERRUPT | SCAUSE_S_TIMER_INTR) == scause)
{
/* supervisor timer */
rt_interrupt_enter(); rt_interrupt_enter();
tick_isr(); tick_isr();
rt_interrupt_leave(); 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 else
{ {
// trap cannot nested when handling another trap / interrupt if (SCAUSE_INTERRUPT & scause)
CHECK_NESTED_PANIC(scause, stval, sepc, sp);
rt_ubase_t id = __MASKVALUE(scause, __MASK(63UL));
const char *msg;
if (scause >> 63)
{ {
if (id < sizeof(Interrupt_Name) / sizeof(const char *)) if (id < sizeof(Interrupt_Name) / sizeof(const char *))
{ {
@ -330,17 +327,18 @@ void handle_trap(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc, struct rt
msg = "Unknown Interrupt"; msg = "Unknown Interrupt";
} }
rt_kprintf("Unhandled Interrupt %ld:%s\n", id, msg); LOG_E("Unhandled Interrupt %ld:%s\n", id, msg);
} }
else else
{ {
#ifdef ENABLE_VECTOR #ifdef ARCH_RISCV_VECTOR
if (scause == 0x2) if (scause == 0x2)
{ {
if (!(sp->sstatus & SSTATUS_VS) && illegal_inst_recoverable(stval, sp)) if (!(sp->sstatus & SSTATUS_VS) &&
illegal_inst_recoverable(stval, sp))
goto _exit; goto _exit;
} }
#endif /* ENABLE_VECTOR */ #endif /* ARCH_RISCV_VECTOR */
#ifdef RT_USING_SMART #ifdef RT_USING_SMART
if (!(sp->sstatus & 0x100) || (PAGE_FAULT && IN_USER_SPACE)) if (!(sp->sstatus & 0x100) || (PAGE_FAULT && IN_USER_SPACE))
{ {
@ -351,24 +349,36 @@ void handle_trap(rt_ubase_t scause, rt_ubase_t stval, rt_ubase_t sepc, struct rt
#endif #endif
// handle kernel exception: // handle kernel exception:
rt_kprintf("Unhandled Exception %ld:%s\n", id, get_exception_msg(id)); rt_kprintf("Unhandled Exception %ld:%s\n", id,
get_exception_msg(id));
} }
// trap cannot nested when handling another trap / interrupt
CHECK_NESTED_PANIC(scause, stval, sepc, sp);
rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc); rt_kprintf("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc);
dump_regs(sp); dump_regs(sp);
rt_thread_t cur_thr = rt_thread_self();
rt_kprintf("--------------Thread list--------------\n"); rt_kprintf("--------------Thread list--------------\n");
rt_kprintf("current thread: %s\n", rt_thread_self()->parent.name); rt_kprintf("current thread: %s\n", cur_thr->parent.name);
extern struct rt_thread *rt_current_thread;
rt_kprintf("--------------Backtrace--------------\n"); rt_kprintf("--------------Backtrace--------------\n");
struct rt_hw_backtrace_frame frame = { struct rt_hw_backtrace_frame frame = {.fp = sp->s0_fp, .pc = sepc};
.fp = sp->s0_fp,
.pc = sepc
};
rt_kprintf("fp = %p", frame.fp);
rt_backtrace_frame(rt_thread_self(), &frame);
RT_ASSERT(0); #ifdef RT_USING_SMART
if (!(sp->sstatus & 0x100))
{
lwp_backtrace_frame(cur_thr, &frame);
}
else
#endif
{
rt_backtrace_frame(cur_thr, &frame);
}
while (1)
;
} }
_exit: _exit:
EXIT_TRAP; EXIT_TRAP;