:p
atchew
Login
The patch series is based on another one [Basic early_printk and smoke test implementation] which hasn't been commited yet. The patch series provides a basic implementation of exception handling. It can do only basic things such as decode a cause of an exception, save/restore registers and execute "wfi" instruction if an exception can not be handled. To verify that exception handling works well it was implemented macros from <asm/bug.h> such as BUG/WARN/run_in_exception/assert_failed. The implementation of macros is used "ebreak" instruction and set up bug frame tables for each type of macros. Also it was implemented register save/restore to return and continue work after WARN/run_in_exception. Not all functionality of the macros was implemented as some of them require hard-panic the system which is not available now. Instead of hard-panic 'wfi' instruction is used but it should be definitely changed in the neareset future. It wasn't implemented show_execution_state() and stack trace discovering as it's not necessary now. --- Changes in V2: - take the latest riscv_encoding.h from OpenSBI, update it with Xen related changes, and update the commit message with "Origin:" tag and the commit message itself. - add "Origin:" tag to the commit messag of the patch [xen/riscv: add <asm/csr.h> header]. - Remove the patch [xen/riscv: add early_printk_hnum() function] as the functionality provided by the patch isn't used now. - Refactor prcoess.h: move structure offset defines to asm-offsets.c, change register_t to unsigned long. - Refactor entry.S to use offsets defined in asm-offsets.C - Rename {__,}handle_exception to handle_trap() and do_trap() to be more consistent with RISC-V spec. - Merge the pathc which introduces do_unexpected_trap() with the patch [xen/riscv: introduce exception handlers implementation]. - Rename setup_trap_handler() to trap_init() and update correspondingly the patches in the patch series. - Refactor bug.h, remove bug_instr_t type from it. - Refactor decode_trap_cause() function to be more optimization-friendly. - Add two new empty headers: <cache.h> and <string.h> as they are needed to include <xen/lib.h> which provides ARRAY_SIZE and other macros. - Code style fixes. --- Oleksii Kurochko (14): xen/riscv: add _zicsr to CFLAGS xen/riscv: add <asm/asm.h> header xen/riscv: add <asm/riscv_encoding.h header xen/riscv: add <asm/csr.h> header xen/riscv: introduce empty <asm/string.h> xen/riscv: introduce empty <asm/cache.h> xen/riscv: introduce exception context xen/riscv: introduce exception handlers implementation xen/riscv: introduce decode_cause() stuff xen/riscv: mask all interrupts xen/riscv: introduce trap_init() xen/riscv: introduce an implementation of macros from <asm/bug.h> xen/riscv: test basic handling stuff automation: add smoke test to verify macros from bug.h automation/scripts/qemu-smoke-riscv64.sh | 2 +- xen/arch/riscv/Makefile | 2 + xen/arch/riscv/arch.mk | 2 +- xen/arch/riscv/entry.S | 94 ++ xen/arch/riscv/include/asm/asm.h | 54 ++ xen/arch/riscv/include/asm/bug.h | 118 +++ xen/arch/riscv/include/asm/cache.h | 6 + xen/arch/riscv/include/asm/csr.h | 84 ++ xen/arch/riscv/include/asm/processor.h | 82 ++ xen/arch/riscv/include/asm/riscv_encoding.h | 927 ++++++++++++++++++++ xen/arch/riscv/include/asm/string.h | 6 + xen/arch/riscv/include/asm/traps.h | 14 + xen/arch/riscv/riscv64/asm-offsets.c | 53 ++ xen/arch/riscv/riscv64/head.S | 5 + xen/arch/riscv/setup.c | 21 + xen/arch/riscv/traps.c | 231 +++++ xen/arch/riscv/xen.lds.S | 10 + 17 files changed, 1709 insertions(+), 2 deletions(-) create mode 100644 xen/arch/riscv/entry.S create mode 100644 xen/arch/riscv/include/asm/asm.h create mode 100644 xen/arch/riscv/include/asm/bug.h create mode 100644 xen/arch/riscv/include/asm/cache.h create mode 100644 xen/arch/riscv/include/asm/csr.h create mode 100644 xen/arch/riscv/include/asm/processor.h create mode 100644 xen/arch/riscv/include/asm/riscv_encoding.h create mode 100644 xen/arch/riscv/include/asm/string.h create mode 100644 xen/arch/riscv/include/asm/traps.h create mode 100644 xen/arch/riscv/traps.c -- 2.39.0
Work with some registers requires csr command which is part of Zicsr. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Nothing changed --- xen/arch/riscv/arch.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/riscv/arch.mk b/xen/arch/riscv/arch.mk index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/arch.mk +++ b/xen/arch/riscv/arch.mk @@ -XXX,XX +XXX,XX @@ riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c # into the upper half _or_ the lower half of the address space. # -mcmodel=medlow would force Xen into the lower half. -CFLAGS += -march=$(riscv-march-y) -mstrict-align -mcmodel=medany +CFLAGS += -march=$(riscv-march-y)_zicsr -mstrict-align -mcmodel=medany # TODO: Drop override when more of the build is working override ALL_OBJS-y = arch/$(TARGET_ARCH)/built_in.o -- 2.39.0
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Nothing changed --- xen/arch/riscv/include/asm/asm.h | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 xen/arch/riscv/include/asm/asm.h diff --git a/xen/arch/riscv/include/asm/asm.h b/xen/arch/riscv/include/asm/asm.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/asm.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: (GPL-2.0-only) */ +/* + * Copyright (C) 2015 Regents of the University of California + */ + +#ifndef _ASM_RISCV_ASM_H +#define _ASM_RISCV_ASM_H + +#ifdef __ASSEMBLY__ +#define __ASM_STR(x) x +#else +#define __ASM_STR(x) #x +#endif + +#if __riscv_xlen == 64 +#define __REG_SEL(a, b) __ASM_STR(a) +#elif __riscv_xlen == 32 +#define __REG_SEL(a, b) __ASM_STR(b) +#else +#error "Unexpected __riscv_xlen" +#endif + +#define REG_L __REG_SEL(ld, lw) +#define REG_S __REG_SEL(sd, sw) + +#if __SIZEOF_POINTER__ == 8 +#ifdef __ASSEMBLY__ +#define RISCV_PTR .dword +#else +#define RISCV_PTR ".dword" +#endif +#elif __SIZEOF_POINTER__ == 4 +#ifdef __ASSEMBLY__ +#define RISCV_PTR .word +#else +#define RISCV_PTR ".word" +#endif +#else +#error "Unexpected __SIZEOF_POINTER__" +#endif + +#if (__SIZEOF_INT__ == 4) +#define RISCV_INT __ASM_STR(.word) +#else +#error "Unexpected __SIZEOF_INT__" +#endif + +#if (__SIZEOF_SHORT__ == 2) +#define RISCV_SHORT __ASM_STR(.half) +#else +#error "Unexpected __SIZEOF_SHORT__" +#endif + +#endif /* _ASM_RISCV_ASM_H */ -- 2.39.0
The following changes were done in Xen code base in comparison with OpenSBI: * Remove "#include <sbi/sbi_const.h>" as most of the stuff inside it is present in Xen code base. * Add macros _UL and _ULL as they were in <sbi/sbi_const.h> before * Add SATP32_MODE_SHIFT/SATP64_MODE_SHIFT/SATP_MODE_SHIFT as they will be used in riscv/mm.c * Add CAUSE_IRQ_FLAG which is going to be used insised exception handler * Change ulong to unsigned long in macros REG_PTR(...) * Change s32 to int32_t Originally authored by Anup Patel <anup.patel@wdc.com> Origin: https://github.com/riscv-software-src/opensbi.git c45992cc2b12 Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Take the latest version of riscv_encoding.h from OpenSBI. - Update riscv_encoding.h with Xen related changes mentioned in the commit message. - Update commit message and add "Origin:" tag --- xen/arch/riscv/include/asm/riscv_encoding.h | 927 ++++++++++++++++++++ 1 file changed, 927 insertions(+) create mode 100644 xen/arch/riscv/include/asm/riscv_encoding.h diff --git a/xen/arch/riscv/include/asm/riscv_encoding.h b/xen/arch/riscv/include/asm/riscv_encoding.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/riscv_encoding.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel <anup.patel@wdc.com> + */ + +#ifndef __RISCV_ENCODING_H__ +#define __RISCV_ENCODING_H__ + +#define _UL(X) _AC(X, UL) +#define _ULL(X) _AC(X, ULL) + +/* clang-format off */ +#define MSTATUS_SIE _UL(0x00000002) +#define MSTATUS_MIE _UL(0x00000008) +#define MSTATUS_SPIE_SHIFT 5 +#define MSTATUS_SPIE (_UL(1) << MSTATUS_SPIE_SHIFT) +#define MSTATUS_UBE _UL(0x00000040) +#define MSTATUS_MPIE _UL(0x00000080) +#define MSTATUS_SPP_SHIFT 8 +#define MSTATUS_SPP (_UL(1) << MSTATUS_SPP_SHIFT) +#define MSTATUS_MPP_SHIFT 11 +#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT) +#define MSTATUS_FS _UL(0x00006000) +#define MSTATUS_XS _UL(0x00018000) +#define MSTATUS_VS _UL(0x00000600) +#define MSTATUS_MPRV _UL(0x00020000) +#define MSTATUS_SUM _UL(0x00040000) +#define MSTATUS_MXR _UL(0x00080000) +#define MSTATUS_TVM _UL(0x00100000) +#define MSTATUS_TW _UL(0x00200000) +#define MSTATUS_TSR _UL(0x00400000) +#define MSTATUS32_SD _UL(0x80000000) +#if __riscv_xlen == 64 +#define MSTATUS_UXL _ULL(0x0000000300000000) +#define MSTATUS_SXL _ULL(0x0000000C00000000) +#define MSTATUS_SBE _ULL(0x0000001000000000) +#define MSTATUS_MBE _ULL(0x0000002000000000) +#define MSTATUS_GVA _ULL(0x0000004000000000) +#define MSTATUS_GVA_SHIFT 38 +#define MSTATUS_MPV _ULL(0x0000008000000000) +#else +#define MSTATUSH_SBE _UL(0x00000010) +#define MSTATUSH_MBE _UL(0x00000020) +#define MSTATUSH_GVA _UL(0x00000040) +#define MSTATUSH_GVA_SHIFT 6 +#define MSTATUSH_MPV _UL(0x00000080) +#endif +#define MSTATUS32_SD _UL(0x80000000) +#define MSTATUS64_SD _ULL(0x8000000000000000) + +#define SSTATUS_SIE MSTATUS_SIE +#define SSTATUS_SPIE_SHIFT MSTATUS_SPIE_SHIFT +#define SSTATUS_SPIE MSTATUS_SPIE +#define SSTATUS_SPP_SHIFT MSTATUS_SPP_SHIFT +#define SSTATUS_SPP MSTATUS_SPP +#define SSTATUS_FS MSTATUS_FS +#define SSTATUS_XS MSTATUS_XS +#define SSTATUS_VS MSTATUS_VS +#define SSTATUS_SUM MSTATUS_SUM +#define SSTATUS_MXR MSTATUS_MXR +#define SSTATUS32_SD MSTATUS32_SD +#define SSTATUS64_UXL MSTATUS_UXL +#define SSTATUS64_SD MSTATUS64_SD + +#if __riscv_xlen == 64 +#define HSTATUS_VSXL _UL(0x300000000) +#define HSTATUS_VSXL_SHIFT 32 +#endif +#define HSTATUS_VTSR _UL(0x00400000) +#define HSTATUS_VTW _UL(0x00200000) +#define HSTATUS_VTVM _UL(0x00100000) +#define HSTATUS_VGEIN _UL(0x0003f000) +#define HSTATUS_VGEIN_SHIFT 12 +#define HSTATUS_HU _UL(0x00000200) +#define HSTATUS_SPVP _UL(0x00000100) +#define HSTATUS_SPV _UL(0x00000080) +#define HSTATUS_GVA _UL(0x00000040) +#define HSTATUS_VSBE _UL(0x00000020) + +#define IRQ_S_SOFT 1 +#define IRQ_VS_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_VS_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_VS_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_S_GEXT 12 +#define IRQ_PMU_OVF 13 + +#define MIP_SSIP (_UL(1) << IRQ_S_SOFT) +#define MIP_VSSIP (_UL(1) << IRQ_VS_SOFT) +#define MIP_MSIP (_UL(1) << IRQ_M_SOFT) +#define MIP_STIP (_UL(1) << IRQ_S_TIMER) +#define MIP_VSTIP (_UL(1) << IRQ_VS_TIMER) +#define MIP_MTIP (_UL(1) << IRQ_M_TIMER) +#define MIP_SEIP (_UL(1) << IRQ_S_EXT) +#define MIP_VSEIP (_UL(1) << IRQ_VS_EXT) +#define MIP_MEIP (_UL(1) << IRQ_M_EXT) +#define MIP_SGEIP (_UL(1) << IRQ_S_GEXT) +#define MIP_LCOFIP (_UL(1) << IRQ_PMU_OVF) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U _UL(0) +#define PRV_S _UL(1) +#define PRV_M _UL(3) + +#define SATP32_MODE _UL(0x80000000) +#define SATP32_MODE_SHIFT 31 +#define SATP32_ASID _UL(0x7FC00000) +#define SATP32_PPN _UL(0x003FFFFF) +#define SATP64_MODE _ULL(0xF000000000000000) +#define SATP64_MODE_SHIFT 60 +#define SATP64_ASID _ULL(0x0FFFF00000000000) +#define SATP64_PPN _ULL(0x00000FFFFFFFFFFF) + +#define SATP_MODE_OFF _UL(0) +#define SATP_MODE_SV32 _UL(1) +#define SATP_MODE_SV39 _UL(8) +#define SATP_MODE_SV48 _UL(9) +#define SATP_MODE_SV57 _UL(10) +#define SATP_MODE_SV64 _UL(11) + +#define HGATP_MODE_OFF _UL(0) +#define HGATP_MODE_SV32X4 _UL(1) +#define HGATP_MODE_SV39X4 _UL(8) +#define HGATP_MODE_SV48X4 _UL(9) + +#define HGATP32_MODE_SHIFT 31 +#define HGATP32_VMID_SHIFT 22 +#define HGATP32_VMID_MASK _UL(0x1FC00000) +#define HGATP32_PPN _UL(0x003FFFFF) + +#define HGATP64_MODE_SHIFT 60 +#define HGATP64_VMID_SHIFT 44 +#define HGATP64_VMID_MASK _ULL(0x03FFF00000000000) +#define HGATP64_PPN _ULL(0x00000FFFFFFFFFFF) + +#define PMP_R _UL(0x01) +#define PMP_W _UL(0x02) +#define PMP_X _UL(0x04) +#define PMP_A _UL(0x18) +#define PMP_A_TOR _UL(0x08) +#define PMP_A_NA4 _UL(0x10) +#define PMP_A_NAPOT _UL(0x18) +#define PMP_L _UL(0x80) + +#define PMP_SHIFT 2 +#define PMP_COUNT 64 +#if __riscv_xlen == 64 +#define PMP_ADDR_MASK ((_ULL(0x1) << 54) - 1) +#else +#define PMP_ADDR_MASK _UL(0xFFFFFFFF) +#endif + +#if __riscv_xlen == 64 +#define MSTATUS_SD MSTATUS64_SD +#define SSTATUS_SD SSTATUS64_SD +#define SATP_MODE SATP64_MODE +#define SATP_MODE_SHIFT SATP64_MODE_SHIFT + +#define HGATP_PPN HGATP64_PPN +#define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT +#define HGATP_VMID_MASK HGATP64_VMID_MASK +#define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT +#else +#define MSTATUS_SD MSTATUS32_SD +#define SSTATUS_SD SSTATUS32_SD +#define SATP_MODE SATP32_MODE +#define SATP_MODE_SHIFT SATP32_MODE_SHIFT + +#define HGATP_PPN HGATP32_PPN +#define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT +#define HGATP_VMID_MASK HGATP32_VMID_MASK +#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT +#endif + +#define TOPI_IID_SHIFT 16 +#define TOPI_IID_MASK 0xfff +#define TOPI_IPRIO_MASK 0xff + +#if __riscv_xlen == 64 +#define MHPMEVENT_OF (_UL(1) << 63) +#define MHPMEVENT_MINH (_UL(1) << 62) +#define MHPMEVENT_SINH (_UL(1) << 61) +#define MHPMEVENT_UINH (_UL(1) << 60) +#define MHPMEVENT_VSINH (_UL(1) << 59) +#define MHPMEVENT_VUINH (_UL(1) << 58) +#else +#define MHPMEVENTH_OF (_ULL(1) << 31) +#define MHPMEVENTH_MINH (_ULL(1) << 30) +#define MHPMEVENTH_SINH (_ULL(1) << 29) +#define MHPMEVENTH_UINH (_ULL(1) << 28) +#define MHPMEVENTH_VSINH (_ULL(1) << 27) +#define MHPMEVENTH_VUINH (_ULL(1) << 26) + +#define MHPMEVENT_OF (MHPMEVENTH_OF << 32) +#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32) +#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32) +#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32) +#define MHPMEVENT_VSINH (MHPMEVENTH_VSINH << 32) +#define MHPMEVENT_VUINH (MHPMEVENTH_VUINH << 32) + +#endif + +#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000) + +#if __riscv_xlen > 32 +#define ENVCFG_STCE (_ULL(1) << 63) +#define ENVCFG_PBMTE (_ULL(1) << 62) +#else +#define ENVCFGH_STCE (_UL(1) << 31) +#define ENVCFGH_PBMTE (_UL(1) << 30) +#endif +#define ENVCFG_CBZE (_UL(1) << 7) +#define ENVCFG_CBCFE (_UL(1) << 6) +#define ENVCFG_CBIE_SHIFT 4 +#define ENVCFG_CBIE (_UL(0x3) << ENVCFG_CBIE_SHIFT) +#define ENVCFG_CBIE_ILL _UL(0x0) +#define ENVCFG_CBIE_FLUSH _UL(0x1) +#define ENVCFG_CBIE_INV _UL(0x3) +#define ENVCFG_FIOM _UL(0x1) + +/* ===== User-level CSRs ===== */ + +/* User Trap Setup (N-extension) */ +#define CSR_USTATUS 0x000 +#define CSR_UIE 0x004 +#define CSR_UTVEC 0x005 + +/* User Trap Handling (N-extension) */ +#define CSR_USCRATCH 0x040 +#define CSR_UEPC 0x041 +#define CSR_UCAUSE 0x042 +#define CSR_UTVAL 0x043 +#define CSR_UIP 0x044 + +/* User Floating-point CSRs */ +#define CSR_FFLAGS 0x001 +#define CSR_FRM 0x002 +#define CSR_FCSR 0x003 + +/* User Counters/Timers */ +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f + +/* ===== Supervisor-level CSRs ===== */ + +/* Supervisor Trap Setup */ +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 + +/* Supervisor Configuration */ +#define CSR_SENVCFG 0x10a + +/* Supervisor Trap Handling */ +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 + +/* Sstc extension */ +#define CSR_STIMECMP 0x14D +#define CSR_STIMECMPH 0x15D + +/* Supervisor Protection and Translation */ +#define CSR_SATP 0x180 + +/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ +#define CSR_SISELECT 0x150 +#define CSR_SIREG 0x151 + +/* Supervisor-Level Interrupts (AIA) */ +#define CSR_STOPEI 0x15c +#define CSR_STOPI 0xdb0 + +/* Supervisor-Level High-Half CSRs (AIA) */ +#define CSR_SIEH 0x114 +#define CSR_SIPH 0x154 + +/* Supervisor stateen CSRs */ +#define CSR_SSTATEEN0 0x10C +#define CSR_SSTATEEN1 0x10D +#define CSR_SSTATEEN2 0x10E +#define CSR_SSTATEEN3 0x10F + +/* ===== Hypervisor-level CSRs ===== */ + +/* Hypervisor Trap Setup (H-extension) */ +#define CSR_HSTATUS 0x600 +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HIE 0x604 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HGEIE 0x607 + +/* Hypervisor Configuration */ +#define CSR_HENVCFG 0x60a +#define CSR_HENVCFGH 0x61a + +/* Hypervisor Trap Handling (H-extension) */ +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HVIP 0x645 +#define CSR_HTINST 0x64a +#define CSR_HGEIP 0xe12 + +/* Hypervisor Protection and Translation (H-extension) */ +#define CSR_HGATP 0x680 + +/* Hypervisor Counter/Timer Virtualization Registers (H-extension) */ +#define CSR_HTIMEDELTA 0x605 +#define CSR_HTIMEDELTAH 0x615 + +/* Virtual Supervisor Registers (H-extension) */ +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSATP 0x280 + +/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ +#define CSR_HVIEN 0x608 +#define CSR_HVICTL 0x609 +#define CSR_HVIPRIO1 0x646 +#define CSR_HVIPRIO2 0x647 + +/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */ +#define CSR_VSISELECT 0x250 +#define CSR_VSIREG 0x251 + +/* VS-Level Interrupts (H-extension with AIA) */ +#define CSR_VSTOPEI 0x25c +#define CSR_VSTOPI 0xeb0 + +/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ +#define CSR_HIDELEGH 0x613 +#define CSR_HVIENH 0x618 +#define CSR_HVIPH 0x655 +#define CSR_HVIPRIO1H 0x656 +#define CSR_HVIPRIO2H 0x657 +#define CSR_VSIEH 0x214 +#define CSR_VSIPH 0x254 + +/* Hypervisor stateen CSRs */ +#define CSR_HSTATEEN0 0x60C +#define CSR_HSTATEEN0H 0x61C +#define CSR_HSTATEEN1 0x60D +#define CSR_HSTATEEN1H 0x61D +#define CSR_HSTATEEN2 0x60E +#define CSR_HSTATEEN2H 0x61E +#define CSR_HSTATEEN3 0x60F +#define CSR_HSTATEEN3H 0x61F + +/* ===== Machine-level CSRs ===== */ + +/* Machine Information Registers */ +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 + +/* Machine Trap Setup */ +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MSTATUSH 0x310 + +/* Machine Configuration */ +#define CSR_MENVCFG 0x30a +#define CSR_MENVCFGH 0x31a + +/* Machine Trap Handling */ +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_MTINST 0x34a +#define CSR_MTVAL2 0x34b + +/* Machine Memory Protection */ +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPCFG4 0x3a4 +#define CSR_PMPCFG5 0x3a5 +#define CSR_PMPCFG6 0x3a6 +#define CSR_PMPCFG7 0x3a7 +#define CSR_PMPCFG8 0x3a8 +#define CSR_PMPCFG9 0x3a9 +#define CSR_PMPCFG10 0x3aa +#define CSR_PMPCFG11 0x3ab +#define CSR_PMPCFG12 0x3ac +#define CSR_PMPCFG13 0x3ad +#define CSR_PMPCFG14 0x3ae +#define CSR_PMPCFG15 0x3af +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_PMPADDR16 0x3c0 +#define CSR_PMPADDR17 0x3c1 +#define CSR_PMPADDR18 0x3c2 +#define CSR_PMPADDR19 0x3c3 +#define CSR_PMPADDR20 0x3c4 +#define CSR_PMPADDR21 0x3c5 +#define CSR_PMPADDR22 0x3c6 +#define CSR_PMPADDR23 0x3c7 +#define CSR_PMPADDR24 0x3c8 +#define CSR_PMPADDR25 0x3c9 +#define CSR_PMPADDR26 0x3ca +#define CSR_PMPADDR27 0x3cb +#define CSR_PMPADDR28 0x3cc +#define CSR_PMPADDR29 0x3cd +#define CSR_PMPADDR30 0x3ce +#define CSR_PMPADDR31 0x3cf +#define CSR_PMPADDR32 0x3d0 +#define CSR_PMPADDR33 0x3d1 +#define CSR_PMPADDR34 0x3d2 +#define CSR_PMPADDR35 0x3d3 +#define CSR_PMPADDR36 0x3d4 +#define CSR_PMPADDR37 0x3d5 +#define CSR_PMPADDR38 0x3d6 +#define CSR_PMPADDR39 0x3d7 +#define CSR_PMPADDR40 0x3d8 +#define CSR_PMPADDR41 0x3d9 +#define CSR_PMPADDR42 0x3da +#define CSR_PMPADDR43 0x3db +#define CSR_PMPADDR44 0x3dc +#define CSR_PMPADDR45 0x3dd +#define CSR_PMPADDR46 0x3de +#define CSR_PMPADDR47 0x3df +#define CSR_PMPADDR48 0x3e0 +#define CSR_PMPADDR49 0x3e1 +#define CSR_PMPADDR50 0x3e2 +#define CSR_PMPADDR51 0x3e3 +#define CSR_PMPADDR52 0x3e4 +#define CSR_PMPADDR53 0x3e5 +#define CSR_PMPADDR54 0x3e6 +#define CSR_PMPADDR55 0x3e7 +#define CSR_PMPADDR56 0x3e8 +#define CSR_PMPADDR57 0x3e9 +#define CSR_PMPADDR58 0x3ea +#define CSR_PMPADDR59 0x3eb +#define CSR_PMPADDR60 0x3ec +#define CSR_PMPADDR61 0x3ed +#define CSR_PMPADDR62 0x3ee +#define CSR_PMPADDR63 0x3ef + +/* Machine Counters/Timers */ +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f + +/* Machine Counter Setup */ +#define CSR_MCOUNTINHIBIT 0x320 +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f + +/* For RV32 */ +#define CSR_MHPMEVENT3H 0x723 +#define CSR_MHPMEVENT4H 0x724 +#define CSR_MHPMEVENT5H 0x725 +#define CSR_MHPMEVENT6H 0x726 +#define CSR_MHPMEVENT7H 0x727 +#define CSR_MHPMEVENT8H 0x728 +#define CSR_MHPMEVENT9H 0x729 +#define CSR_MHPMEVENT10H 0x72a +#define CSR_MHPMEVENT11H 0x72b +#define CSR_MHPMEVENT12H 0x72c +#define CSR_MHPMEVENT13H 0x72d +#define CSR_MHPMEVENT14H 0x72e +#define CSR_MHPMEVENT15H 0x72f +#define CSR_MHPMEVENT16H 0x730 +#define CSR_MHPMEVENT17H 0x731 +#define CSR_MHPMEVENT18H 0x732 +#define CSR_MHPMEVENT19H 0x733 +#define CSR_MHPMEVENT20H 0x734 +#define CSR_MHPMEVENT21H 0x735 +#define CSR_MHPMEVENT22H 0x736 +#define CSR_MHPMEVENT23H 0x737 +#define CSR_MHPMEVENT24H 0x738 +#define CSR_MHPMEVENT25H 0x739 +#define CSR_MHPMEVENT26H 0x73a +#define CSR_MHPMEVENT27H 0x73b +#define CSR_MHPMEVENT28H 0x73c +#define CSR_MHPMEVENT29H 0x73d +#define CSR_MHPMEVENT30H 0x73e +#define CSR_MHPMEVENT31H 0x73f + +/* Counter Overflow CSR */ +#define CSR_SCOUNTOVF 0xda0 + +/* Debug/Trace Registers */ +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 + +/* Debug Mode Registers */ +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH0 0x7b2 +#define CSR_DSCRATCH1 0x7b3 + +/* Machine-Level Window to Indirectly Accessed Registers (AIA) */ +#define CSR_MISELECT 0x350 +#define CSR_MIREG 0x351 + +/* Machine-Level Interrupts (AIA) */ +#define CSR_MTOPEI 0x35c +#define CSR_MTOPI 0xfb0 + +/* Virtual Interrupts for Supervisor Level (AIA) */ +#define CSR_MVIEN 0x308 +#define CSR_MVIP 0x309 + +/* Smstateen extension registers */ +/* Machine stateen CSRs */ +#define CSR_MSTATEEN0 0x30C +#define CSR_MSTATEEN0H 0x31C +#define CSR_MSTATEEN1 0x30D +#define CSR_MSTATEEN1H 0x31D +#define CSR_MSTATEEN2 0x30E +#define CSR_MSTATEEN2H 0x31E +#define CSR_MSTATEEN3 0x30F +#define CSR_MSTATEEN3H 0x31F + +/* Machine-Level High-Half CSRs (AIA) */ +#define CSR_MIDELEGH 0x313 +#define CSR_MIEH 0x314 +#define CSR_MVIENH 0x318 +#define CSR_MVIPH 0x319 +#define CSR_MIPH 0x354 + +/* ===== Trap/Exception Causes ===== */ + +/* Exception cause high bit - is an interrupt if set */ +#define CAUSE_IRQ_FLAG (_UL(1) << (__riscv_xlen - 1)) + +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FETCH_ACCESS 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_LOAD_ACCESS 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_STORE_ACCESS 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf +#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 +#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 +#define CAUSE_VIRTUAL_INST_FAULT 0x16 +#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 + +/* Common defines for all smstateen */ +#define SMSTATEEN_MAX_COUNT 4 +#define SMSTATEEN0_CS_SHIFT 0 +#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT) +#define SMSTATEEN0_FCSR_SHIFT 1 +#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT) +#define SMSTATEEN0_IMSIC_SHIFT 58 +#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT) +#define SMSTATEEN0_AIA_SHIFT 59 +#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT) +#define SMSTATEEN0_SVSLCT_SHIFT 60 +#define SMSTATEEN0_SVSLCT (_ULL(1) << SMSTATEEN0_SVSLCT_SHIFT) +#define SMSTATEEN0_HSENVCFG_SHIFT 62 +#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT) +#define SMSTATEEN_STATEN_SHIFT 63 +#define SMSTATEEN_STATEN (_ULL(1) << SMSTATEEN_STATEN_SHIFT) + +/* ===== Instruction Encodings ===== */ + +#define INSN_MATCH_LB 0x3 +#define INSN_MASK_LB 0x707f +#define INSN_MATCH_LH 0x1003 +#define INSN_MASK_LH 0x707f +#define INSN_MATCH_LW 0x2003 +#define INSN_MASK_LW 0x707f +#define INSN_MATCH_LD 0x3003 +#define INSN_MASK_LD 0x707f +#define INSN_MATCH_LBU 0x4003 +#define INSN_MASK_LBU 0x707f +#define INSN_MATCH_LHU 0x5003 +#define INSN_MASK_LHU 0x707f +#define INSN_MATCH_LWU 0x6003 +#define INSN_MASK_LWU 0x707f +#define INSN_MATCH_SB 0x23 +#define INSN_MASK_SB 0x707f +#define INSN_MATCH_SH 0x1023 +#define INSN_MASK_SH 0x707f +#define INSN_MATCH_SW 0x2023 +#define INSN_MASK_SW 0x707f +#define INSN_MATCH_SD 0x3023 +#define INSN_MASK_SD 0x707f + +#define INSN_MATCH_FLW 0x2007 +#define INSN_MASK_FLW 0x707f +#define INSN_MATCH_FLD 0x3007 +#define INSN_MASK_FLD 0x707f +#define INSN_MATCH_FLQ 0x4007 +#define INSN_MASK_FLQ 0x707f +#define INSN_MATCH_FSW 0x2027 +#define INSN_MASK_FSW 0x707f +#define INSN_MATCH_FSD 0x3027 +#define INSN_MASK_FSD 0x707f +#define INSN_MATCH_FSQ 0x4027 +#define INSN_MASK_FSQ 0x707f + +#define INSN_MATCH_C_LD 0x6000 +#define INSN_MASK_C_LD 0xe003 +#define INSN_MATCH_C_SD 0xe000 +#define INSN_MASK_C_SD 0xe003 +#define INSN_MATCH_C_LW 0x4000 +#define INSN_MASK_C_LW 0xe003 +#define INSN_MATCH_C_SW 0xc000 +#define INSN_MASK_C_SW 0xe003 +#define INSN_MATCH_C_LDSP 0x6002 +#define INSN_MASK_C_LDSP 0xe003 +#define INSN_MATCH_C_SDSP 0xe002 +#define INSN_MASK_C_SDSP 0xe003 +#define INSN_MATCH_C_LWSP 0x4002 +#define INSN_MASK_C_LWSP 0xe003 +#define INSN_MATCH_C_SWSP 0xc002 +#define INSN_MASK_C_SWSP 0xe003 + +#define INSN_MATCH_C_FLD 0x2000 +#define INSN_MASK_C_FLD 0xe003 +#define INSN_MATCH_C_FLW 0x6000 +#define INSN_MASK_C_FLW 0xe003 +#define INSN_MATCH_C_FSD 0xa000 +#define INSN_MASK_C_FSD 0xe003 +#define INSN_MATCH_C_FSW 0xe000 +#define INSN_MASK_C_FSW 0xe003 +#define INSN_MATCH_C_FLDSP 0x2002 +#define INSN_MASK_C_FLDSP 0xe003 +#define INSN_MATCH_C_FSDSP 0xa002 +#define INSN_MASK_C_FSDSP 0xe003 +#define INSN_MATCH_C_FLWSP 0x6002 +#define INSN_MASK_C_FLWSP 0xe003 +#define INSN_MATCH_C_FSWSP 0xe002 +#define INSN_MASK_C_FSWSP 0xe003 + +#define INSN_MASK_WFI 0xffffff00 +#define INSN_MATCH_WFI 0x10500000 + +#define INSN_MASK_FENCE_TSO 0xffffffff +#define INSN_MATCH_FENCE_TSO 0x8330000f + +#if __riscv_xlen == 64 + +/* 64-bit read for VS-stage address translation (RV64) */ +#define INSN_PSEUDO_VS_LOAD 0x00003000 + +/* 64-bit write for VS-stage address translation (RV64) */ +#define INSN_PSEUDO_VS_STORE 0x00003020 + +#elif __riscv_xlen == 32 + +/* 32-bit read for VS-stage address translation (RV32) */ +#define INSN_PSEUDO_VS_LOAD 0x00002000 + +/* 32-bit write for VS-stage address translation (RV32) */ +#define INSN_PSEUDO_VS_STORE 0x00002020 + +#else +#error "Unexpected __riscv_xlen" +#endif + +#define INSN_16BIT_MASK 0x3 +#define INSN_32BIT_MASK 0x1c + +#define INSN_IS_16BIT(insn) \ + (((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK) +#define INSN_IS_32BIT(insn) \ + (((insn) & INSN_16BIT_MASK) == INSN_16BIT_MASK && \ + ((insn) & INSN_32BIT_MASK) != INSN_32BIT_MASK) + +#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4) + +#if __riscv_xlen == 64 +#define LOG_REGBYTES 3 +#else +#define LOG_REGBYTES 2 +#endif +#define REGBYTES (1 << LOG_REGBYTES) + +#define SH_RD 7 +#define SH_RS1 15 +#define SH_RS2 20 +#define SH_RS2C 2 + +#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) +#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \ + (RV_X(x, 10, 3) << 3) | \ + (RV_X(x, 5, 1) << 6)) +#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | \ + (RV_X(x, 5, 2) << 6)) +#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | \ + (RV_X(x, 12, 1) << 5) | \ + (RV_X(x, 2, 2) << 6)) +#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | \ + (RV_X(x, 12, 1) << 5) | \ + (RV_X(x, 2, 3) << 6)) +#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | \ + (RV_X(x, 7, 2) << 6)) +#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | \ + (RV_X(x, 7, 3) << 6)) +#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3)) +#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3)) +#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5) + +#define SHIFT_RIGHT(x, y) \ + ((y) < 0 ? ((x) << -(y)) : ((x) >> (y))) + +#define REG_MASK \ + ((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES)) + +#define REG_OFFSET(insn, pos) \ + (SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK) + +#define REG_PTR(insn, pos, regs) \ + (unsigned long *)((unsigned long)(regs) + REG_OFFSET(insn, pos)) + +#define GET_RM(insn) (((insn) >> 12) & 7) + +#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs)) +#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs)) +#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs)) +#define GET_RS2S(insn, regs) (*REG_PTR(RVC_RS2S(insn), 0, regs)) +#define GET_RS2C(insn, regs) (*REG_PTR(insn, SH_RS2C, regs)) +#define GET_SP(regs) (*REG_PTR(2, 0, regs)) +#define SET_RD(insn, regs, val) (*REG_PTR(insn, SH_RD, regs) = (val)) +#define IMM_I(insn) ((int32_t)(insn) >> 20) +#define IMM_S(insn) (((int32_t)(insn) >> 25 << 5) | \ + (int32_t)(((insn) >> 7) & 0x1f)) +#define MASK_FUNCT3 0x7000 + +/* clang-format on */ + +#endif -- 2.39.0
The following changes were made in comparison with <asm/csr.h> from Linux: * remove all defines as they are defined in riscv_encoding.h * leave only csr_* macros Origin: https://github.com/torvalds/linux.git 2475bf0250de Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Minor refactoring mentioned in the commit message, switch tabs to spaces and refactor things around __asm__ __volatile__. - Update the commit message and add "Origin:" tag. --- xen/arch/riscv/include/asm/csr.h | 84 ++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 xen/arch/riscv/include/asm/csr.h diff --git a/xen/arch/riscv/include/asm/csr.h b/xen/arch/riscv/include/asm/csr.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/csr.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2015 Regents of the University of California + */ + +#ifndef _ASM_RISCV_CSR_H +#define _ASM_RISCV_CSR_H + +#include <asm/asm.h> +#include <xen/const.h> +#include <asm/riscv_encoding.h> + +#ifndef __ASSEMBLY__ + +#define csr_read(csr) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__ ( "csrr %0, " __ASM_STR(csr) \ + : "=r" (__v) \ + : : "memory" ); \ + __v; \ +}) + +#define csr_write(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ( "csrw " __ASM_STR(csr) ", %0" \ + : /* no outputs */ \ + : "rK" (__v) \ + : "memory" ); \ +}) + +#define csr_swap(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ( "csrrw %0, " __ASM_STR(csr) ", %1" \ + : "=r" (__v) \ + : "rK" (__v) \ + : "memory" ); \ + __v; \ +}) + +#define csr_read_set(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ( "csrrs %0, " __ASM_STR(csr) ", %1" \ + : "=r" (__v) \ + : "rK" (__v) \ + : "memory" ); \ + __v; \ +}) + +#define csr_set(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ( "csrs " __ASM_STR(csr) ", %0" \ + : /* no outputs */ \ + : "rK" (__v) \ + : "memory" ); \ +}) + +#define csr_read_clear(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ( "csrrc %0, " __ASM_STR(csr) ", %1" \ + : "=r" (__v) \ + : "rK" (__v) \ + : "memory" ); \ + __v; \ +}) + +#define csr_clear(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ( "csrc " __ASM_STR(csr) ", %0" \ + : /*no outputs */ \ + : "rK" (__v) \ + : "memory" ); \ +}) + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_CSR_H */ -- 2.39.0
To include <xen/lib.h> <asm/string.h> is required Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - <asm/string.h> is a new empty header which is required to include <xen/lib.h> --- xen/arch/riscv/include/asm/string.h | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 xen/arch/riscv/include/asm/string.h diff --git a/xen/arch/riscv/include/asm/string.h b/xen/arch/riscv/include/asm/string.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/string.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_STRING_H +#define _ASM_RISCV_STRING_H + +#endif /* _ASM_RISCV_STRING_H */ -- 2.39.0
To include <xen/lib.h> <asm/cache.h> is required Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - <asm/cache.h> is a new empty header which is required to include <xen/lib.h> --- xen/arch/riscv/include/asm/cache.h | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 xen/arch/riscv/include/asm/cache.h diff --git a/xen/arch/riscv/include/asm/cache.h b/xen/arch/riscv/include/asm/cache.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/cache.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_CACHE_H +#define _ASM_RISCV_CACHE_H + +#endif /* _ASM_RISCV_CACHE_H */ -- 2.39.0
The patch introduces a set of registers which should be saved to and restored from a stack after an exception occurs and a set of defines which will be used during exception context saving/restoring. Originally <asm/processor.h> header was introduced in the patch series from Bobby so partially it was re-used and the following changes were done: - Move all RISCV_CPU_USER_REGS_* to asm/asm-offsets.c - Remove RISCV_CPU_USER_REGS_OFFSET & RISCV_CPU_USER_REGS_SIZE as there is no sense in them after RISCV_CPU_USER_REGS_* were moved to asm/asm-offsets.c - Remove RISCV_PCPUINFO_* as they aren't needed for current status of the RISC-V port - register_t renamed to unsigned long - rename wait_for_interrupt to wfi Signed-off-by: Bobby Eshleman <bobby.eshleman@gmail.com> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - All the changes were added to the commit message. - temporarily was added function die() to stop exectution it will be removed after panic() will be available. --- xen/arch/riscv/include/asm/processor.h | 82 ++++++++++++++++++++++++++ xen/arch/riscv/riscv64/asm-offsets.c | 53 +++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 xen/arch/riscv/include/asm/processor.h diff --git a/xen/arch/riscv/include/asm/processor.h b/xen/arch/riscv/include/asm/processor.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: MIT */ +/****************************************************************************** + * + * Copyright 2019 (C) Alistair Francis <alistair.francis@wdc.com> + * Copyright 2021 (C) Bobby Eshleman <bobby.eshleman@gmail.com> + * Copyright 2023 (C) Vates + * + */ + +#ifndef _ASM_RISCV_PROCESSOR_H +#define _ASM_RISCV_PROCESSOR_H + +#ifndef __ASSEMBLY__ + +/* On stack VCPU state */ +struct cpu_user_regs +{ + unsigned long zero; + unsigned long ra; + unsigned long sp; + unsigned long gp; + unsigned long tp; + unsigned long t0; + unsigned long t1; + unsigned long t2; + unsigned long s0; + unsigned long s1; + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; + unsigned long s2; + unsigned long s3; + unsigned long s4; + unsigned long s5; + unsigned long s6; + unsigned long s7; + unsigned long s8; + unsigned long s9; + unsigned long s10; + unsigned long s11; + unsigned long t3; + unsigned long t4; + unsigned long t5; + unsigned long t6; + unsigned long sepc; + unsigned long sstatus; + /* pointer to previous stack_cpu_regs */ + unsigned long pregs; +}; + +static inline void wfi(void) +{ + __asm__ __volatile__ ("wfi"); +} + +/* + * panic() isn't available at the moment so an infinite loop will be + * used temporarily. + * TODO: change it to panic() + */ +static inline void die(void) +{ + for( ;; ) wfi(); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_PROCESSOR_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/riscv/riscv64/asm-offsets.c b/xen/arch/riscv/riscv64/asm-offsets.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/riscv64/asm-offsets.c +++ b/xen/arch/riscv/riscv64/asm-offsets.c @@ -XXX,XX +XXX,XX @@ +#define COMPILE_OFFSETS + +#include <asm/processor.h> +#include <xen/types.h> + +#define DEFINE(_sym, _val) \ + asm volatile ("\n.ascii\"==>#define " #_sym " %0 /* " #_val " */<==\"" \ + : : "i" (_val) ) +#define BLANK() \ + asm volatile ( "\n.ascii\"==><==\"" : : ) +#define OFFSET(_sym, _str, _mem) \ + DEFINE(_sym, offsetof(_str, _mem)); + +void asm_offsets(void) +{ + BLANK(); + DEFINE(CPU_USER_REGS_SIZE, sizeof(struct cpu_user_regs)); + OFFSET(CPU_USER_REGS_ZERO, struct cpu_user_regs, zero); + OFFSET(CPU_USER_REGS_RA, struct cpu_user_regs, ra); + OFFSET(CPU_USER_REGS_SP, struct cpu_user_regs, sp); + OFFSET(CPU_USER_REGS_GP, struct cpu_user_regs, gp); + OFFSET(CPU_USER_REGS_TP, struct cpu_user_regs, tp); + OFFSET(CPU_USER_REGS_T0, struct cpu_user_regs, t0); + OFFSET(CPU_USER_REGS_T1, struct cpu_user_regs, t1); + OFFSET(CPU_USER_REGS_T2, struct cpu_user_regs, t2); + OFFSET(CPU_USER_REGS_S0, struct cpu_user_regs, s0); + OFFSET(CPU_USER_REGS_S1, struct cpu_user_regs, s1); + OFFSET(CPU_USER_REGS_A0, struct cpu_user_regs, a0); + OFFSET(CPU_USER_REGS_A1, struct cpu_user_regs, a1); + OFFSET(CPU_USER_REGS_A2, struct cpu_user_regs, a2); + OFFSET(CPU_USER_REGS_A3, struct cpu_user_regs, a3); + OFFSET(CPU_USER_REGS_A4, struct cpu_user_regs, a4); + OFFSET(CPU_USER_REGS_A5, struct cpu_user_regs, a5); + OFFSET(CPU_USER_REGS_A6, struct cpu_user_regs, a6); + OFFSET(CPU_USER_REGS_A7, struct cpu_user_regs, a7); + OFFSET(CPU_USER_REGS_S2, struct cpu_user_regs, s2); + OFFSET(CPU_USER_REGS_S3, struct cpu_user_regs, s3); + OFFSET(CPU_USER_REGS_S4, struct cpu_user_regs, s4); + OFFSET(CPU_USER_REGS_S5, struct cpu_user_regs, s5); + OFFSET(CPU_USER_REGS_S6, struct cpu_user_regs, s6); + OFFSET(CPU_USER_REGS_S7, struct cpu_user_regs, s7); + OFFSET(CPU_USER_REGS_S8, struct cpu_user_regs, s8); + OFFSET(CPU_USER_REGS_S9, struct cpu_user_regs, s9); + OFFSET(CPU_USER_REGS_S10, struct cpu_user_regs, s10); + OFFSET(CPU_USER_REGS_S11, struct cpu_user_regs, s11); + OFFSET(CPU_USER_REGS_T3, struct cpu_user_regs, t3); + OFFSET(CPU_USER_REGS_T4, struct cpu_user_regs, t4); + OFFSET(CPU_USER_REGS_T5, struct cpu_user_regs, t5); + OFFSET(CPU_USER_REGS_T6, struct cpu_user_regs, t6); + OFFSET(CPU_USER_REGS_SEPC, struct cpu_user_regs, sepc); + OFFSET(CPU_USER_REGS_SSTATUS, struct cpu_user_regs, sstatus); + OFFSET(CPU_USER_REGS_PREGS, struct cpu_user_regs, pregs); +} -- 2.39.0
The patch introduces an implementation of basic exception handlers: - to save/restore context - to handle an exception itself. The handler calls wait_for_interrupt now, nothing more. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Refactor entry.S to start using of defines introduced in asm_offsets.C - Rename {__,}handle_exception to handle_trap() and do_trap() to be more consistent with RISC-V spec. - Wrap handle_trap() to ENTRY(). --- xen/arch/riscv/Makefile | 2 + xen/arch/riscv/entry.S | 94 ++++++++++++++++++++++++++++++ xen/arch/riscv/include/asm/traps.h | 13 +++++ xen/arch/riscv/traps.c | 13 +++++ 4 files changed, 122 insertions(+) create mode 100644 xen/arch/riscv/entry.S create mode 100644 xen/arch/riscv/include/asm/traps.h create mode 100644 xen/arch/riscv/traps.c diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/Makefile +++ b/xen/arch/riscv/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-y += entry.o obj-$(CONFIG_RISCV_64) += riscv64/ obj-y += sbi.o obj-y += setup.o +obj-y += traps.o $(TARGET): $(TARGET)-syms $(OBJCOPY) -O binary -S $< $@ diff --git a/xen/arch/riscv/entry.S b/xen/arch/riscv/entry.S new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/entry.S @@ -XXX,XX +XXX,XX @@ +#include <asm/asm.h> +#include <asm/asm-offsets.h> +#include <asm/processor.h> +#include <asm/riscv_encoding.h> +#include <asm/traps.h> + +/* WIP: only works while interrupting Xen context */ +ENTRY(handle_trap) + + /* Exceptions from xen */ +save_to_stack: + /* Save context to stack */ + REG_S sp, (CPU_USER_REGS_SP - CPU_USER_REGS_SIZE) (sp) + addi sp, sp, -CPU_USER_REGS_SIZE + REG_S t0, CPU_USER_REGS_T0(sp) + + /* Save registers */ + REG_S ra, CPU_USER_REGS_RA(sp) + REG_S gp, CPU_USER_REGS_GP(sp) + REG_S t1, CPU_USER_REGS_T1(sp) + REG_S t2, CPU_USER_REGS_T2(sp) + REG_S s0, CPU_USER_REGS_S0(sp) + REG_S s1, CPU_USER_REGS_S1(sp) + REG_S a0, CPU_USER_REGS_A0(sp) + REG_S a1, CPU_USER_REGS_A1(sp) + REG_S a2, CPU_USER_REGS_A2(sp) + REG_S a3, CPU_USER_REGS_A3(sp) + REG_S a4, CPU_USER_REGS_A4(sp) + REG_S a5, CPU_USER_REGS_A5(sp) + REG_S a6, CPU_USER_REGS_A6(sp) + REG_S a7, CPU_USER_REGS_A7(sp) + REG_S s2, CPU_USER_REGS_S2(sp) + REG_S s3, CPU_USER_REGS_S3(sp) + REG_S s4, CPU_USER_REGS_S4(sp) + REG_S s5, CPU_USER_REGS_S5(sp) + REG_S s6, CPU_USER_REGS_S6(sp) + REG_S s7, CPU_USER_REGS_S7(sp) + REG_S s8, CPU_USER_REGS_S8(sp) + REG_S s9, CPU_USER_REGS_S9(sp) + REG_S s10,CPU_USER_REGS_S10(sp) + REG_S s11,CPU_USER_REGS_S11(sp) + REG_S t3, CPU_USER_REGS_T3(sp) + REG_S t4, CPU_USER_REGS_T4(sp) + REG_S t5, CPU_USER_REGS_T5(sp) + REG_S t6, CPU_USER_REGS_T6(sp) + csrr t0, CSR_SEPC + REG_S t0, CPU_USER_REGS_SEPC(sp) + csrr t0, CSR_SSTATUS + REG_S t0, CPU_USER_REGS_SSTATUS(sp) + + mv a0, sp + jal do_trap + +restore_registers: + /* Restore stack_cpu_regs */ + REG_L t0, CPU_USER_REGS_SEPC(sp) + csrw CSR_SEPC, t0 + REG_L t0, CPU_USER_REGS_SSTATUS(sp) + csrw CSR_SSTATUS, t0 + + REG_L ra, CPU_USER_REGS_RA(sp) + REG_L gp, CPU_USER_REGS_GP(sp) + REG_L t0, CPU_USER_REGS_T0(sp) + REG_L t1, CPU_USER_REGS_T1(sp) + REG_L t2, CPU_USER_REGS_T2(sp) + REG_L s0, CPU_USER_REGS_S0(sp) + REG_L s1, CPU_USER_REGS_S1(sp) + REG_L a0, CPU_USER_REGS_A0(sp) + REG_L a1, CPU_USER_REGS_A1(sp) + REG_L a2, CPU_USER_REGS_A2(sp) + REG_L a3, CPU_USER_REGS_A3(sp) + REG_L a4, CPU_USER_REGS_A4(sp) + REG_L a5, CPU_USER_REGS_A5(sp) + REG_L a6, CPU_USER_REGS_A6(sp) + REG_L a7, CPU_USER_REGS_A7(sp) + REG_L s2, CPU_USER_REGS_S2(sp) + REG_L s3, CPU_USER_REGS_S3(sp) + REG_L s4, CPU_USER_REGS_S4(sp) + REG_L s5, CPU_USER_REGS_S5(sp) + REG_L s6, CPU_USER_REGS_S6(sp) + REG_L s7, CPU_USER_REGS_S7(sp) + REG_L s8, CPU_USER_REGS_S8(sp) + REG_L s9, CPU_USER_REGS_S9(sp) + REG_L s10, CPU_USER_REGS_S10(sp) + REG_L s11, CPU_USER_REGS_S11(sp) + REG_L t3, CPU_USER_REGS_T3(sp) + REG_L t4, CPU_USER_REGS_T4(sp) + REG_L t5, CPU_USER_REGS_T5(sp) + REG_L t6, CPU_USER_REGS_T6(sp) + + /* Restore sp */ + REG_L sp, CPU_USER_REGS_SP(sp) + + sret diff --git a/xen/arch/riscv/include/asm/traps.h b/xen/arch/riscv/include/asm/traps.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/traps.h @@ -XXX,XX +XXX,XX @@ +#ifndef __ASM_TRAPS_H__ +#define __ASM_TRAPS_H__ + +#include <asm/processor.h> + +#ifndef __ASSEMBLY__ + +void do_trap(struct cpu_user_regs *cpu_regs); +void handle_trap(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_TRAPS_H__ */ diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 Vates + * + * RISC-V Trap handlers + */ +#include <asm/processor.h> +#include <asm/traps.h> + +void do_trap(struct cpu_user_regs *cpu_regs) +{ + die(); +} -- 2.39.0
The patch introduces stuff needed to decode a reason of an exception. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Make decode_trap_cause() more optimization friendly. - Merge the pathc which introduces do_unexpected_trap() to the current one. --- xen/arch/riscv/traps.c | 85 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ * * RISC-V Trap handlers */ +#include <asm/csr.h> +#include <asm/early_printk.h> #include <asm/processor.h> #include <asm/traps.h> +#include <xen/errno.h> +#include <xen/lib.h> -void do_trap(struct cpu_user_regs *cpu_regs) +static const char *decode_trap_cause(unsigned long cause) +{ + static const char *const trap_causes[] = { + [CAUSE_MISALIGNED_FETCH] = "Instruction Address Misaligned", + [CAUSE_FETCH_ACCESS] = "Instruction Access Fault", + [CAUSE_ILLEGAL_INSTRUCTION] = "Illegal Instruction", + [CAUSE_BREAKPOINT] = "Breakpoint", + [CAUSE_MISALIGNED_LOAD] = "Load Address Misaligned", + [CAUSE_LOAD_ACCESS] = "Load Access Fault", + [CAUSE_MISALIGNED_STORE] = "Store/AMO Address Misaligned", + [CAUSE_STORE_ACCESS] = "Store/AMO Access Fault", + [CAUSE_USER_ECALL] = "Environment Call from U-Mode", + [CAUSE_SUPERVISOR_ECALL] = "Environment Call from S-Mode", + [CAUSE_MACHINE_ECALL] = "Environment Call from M-Mode", + [CAUSE_FETCH_PAGE_FAULT] = "Instruction Page Fault", + [CAUSE_LOAD_PAGE_FAULT] = "Load Page Fault", + [CAUSE_STORE_PAGE_FAULT] = "Store/AMO Page Fault", + [CAUSE_FETCH_GUEST_PAGE_FAULT] = "Instruction Guest Page Fault", + [CAUSE_LOAD_GUEST_PAGE_FAULT] = "Load Guest Page Fault", + [CAUSE_VIRTUAL_INST_FAULT] = "Virtualized Instruction Fault", + [CAUSE_STORE_GUEST_PAGE_FAULT] = "Guest Store/AMO Page Fault", + }; + + if ( cause < ARRAY_SIZE(trap_causes) && trap_causes[cause] ) + return trap_causes[cause]; + return "UNKNOWN"; +} + +const char *decode_reserved_interrupt_cause(unsigned long irq_cause) +{ + switch ( irq_cause ) + { + case IRQ_M_SOFT: + return "M-mode Software Interrupt"; + case IRQ_M_TIMER: + return "M-mode TIMER Interrupt"; + case IRQ_M_EXT: + return "M-mode TIMER Interrupt"; + default: + return "UNKNOWN IRQ type"; + } +} + +const char *decode_interrupt_cause(unsigned long cause) +{ + unsigned long irq_cause = cause & ~CAUSE_IRQ_FLAG; + + switch ( irq_cause ) + { + case IRQ_S_SOFT: + return "Supervisor Software Interrupt"; + case IRQ_S_TIMER: + return "Supervisor Timer Interrupt"; + case IRQ_S_EXT: + return "Supervisor External Interrupt"; + default: + return decode_reserved_interrupt_cause(irq_cause); + } +} + +const char *decode_cause(unsigned long cause) +{ + if ( cause & CAUSE_IRQ_FLAG ) + return decode_interrupt_cause(cause); + + return decode_trap_cause(cause); +} + +static void do_unexpected_trap(const struct cpu_user_regs *regs) { + unsigned long cause = csr_read(CSR_SCAUSE); + + early_printk("Unhandled exception: "); + early_printk(decode_cause(cause)); + early_printk("\n"); + die(); } + +void do_trap(struct cpu_user_regs *cpu_regs) +{ + do_unexpected_trap(cpu_regs); +} -- 2.39.0
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> --- Changes in V2: - Add Reviewed-by to the commit message --- xen/arch/riscv/riscv64/head.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xen/arch/riscv/riscv64/head.S b/xen/arch/riscv/riscv64/head.S index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/riscv64/head.S +++ b/xen/arch/riscv/riscv64/head.S @@ -XXX,XX +XXX,XX @@ +#include <asm/riscv_encoding.h> + .section .text.header, "ax", %progbits ENTRY(start) + /* Mask all interrupts */ + csrw CSR_SIE, zero + la sp, cpu0_boot_stack li t0, STACK_SIZE add sp, sp, t0 -- 2.39.0
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> --- Changes in V2: - Rename setup_trap_handler() to trap_init(). - Add Reviewed-by to the commit message. --- xen/arch/riscv/include/asm/traps.h | 1 + xen/arch/riscv/setup.c | 4 ++++ xen/arch/riscv/traps.c | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/xen/arch/riscv/include/asm/traps.h b/xen/arch/riscv/include/asm/traps.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/include/asm/traps.h +++ b/xen/arch/riscv/include/asm/traps.h @@ -XXX,XX +XXX,XX @@ void do_trap(struct cpu_user_regs *cpu_regs); void handle_trap(void); +void trap_init(void); #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/compile.h> #include <xen/init.h> +#include <asm/csr.h> #include <asm/early_printk.h> +#include <asm/traps.h> /* Xen stack for bringing up the first CPU. */ unsigned char __initdata cpu0_boot_stack[STACK_SIZE] @@ -XXX,XX +XXX,XX @@ void __init noreturn start_xen(void) { early_printk("Hello from C env\n"); + trap_init(); + for ( ;; ) asm volatile ("wfi"); diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ #include <xen/errno.h> #include <xen/lib.h> +void trap_init(void) +{ + unsigned long addr = (unsigned long)&handle_trap; + + csr_write(CSR_STVEC, addr); +} + static const char *decode_trap_cause(unsigned long cause) { static const char *const trap_causes[] = { -- 2.39.0
The patch introduces macros: BUG(), WARN(), run_in_exception(), assert_failed. The implementation uses "ebreak" instruction in combination with diffrent bug frame tables (for each type) which contains useful information. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes: - Remove __ in define namings - Update run_in_exception_handler() with register void *fn_ asm(__stringify(BUG_FN_REG)) = (fn); - Remove bug_instr_t type and change it's usage to uint32_t --- xen/arch/riscv/include/asm/bug.h | 118 ++++++++++++++++++++++++++++ xen/arch/riscv/traps.c | 128 +++++++++++++++++++++++++++++++ xen/arch/riscv/xen.lds.S | 10 +++ 3 files changed, 256 insertions(+) create mode 100644 xen/arch/riscv/include/asm/bug.h diff --git a/xen/arch/riscv/include/asm/bug.h b/xen/arch/riscv/include/asm/bug.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/bug.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2021-2023 Vates + * + */ + +#ifndef _ASM_RISCV_BUG_H +#define _ASM_RISCV_BUG_H + +#include <xen/stringify.h> +#include <xen/types.h> + +#ifndef __ASSEMBLY__ + +struct bug_frame { + signed int loc_disp; /* Relative address to the bug address */ + signed int file_disp; /* Relative address to the filename */ + signed int msg_disp; /* Relative address to the predicate (for ASSERT) */ + uint16_t line; /* Line number */ + uint32_t pad0:16; /* Padding for 8-bytes align */ +}; + +#define bug_loc(b) ((const void *)(b) + (b)->loc_disp) +#define bug_file(b) ((const void *)(b) + (b)->file_disp); +#define bug_line(b) ((b)->line) +#define bug_msg(b) ((const char *)(b) + (b)->msg_disp) + +#define BUGFRAME_run_fn 0 +#define BUGFRAME_warn 1 +#define BUGFRAME_bug 2 +#define BUGFRAME_assert 3 + +#define BUGFRAME_NR 4 + +#define INSN_LENGTH_MASK _UL(0x3) +#define INSN_LENGTH_32 _UL(0x3) + +#define BUG_INSN_32 _UL(0x00100073) /* ebreak */ +#define BUG_INSN_16 _UL(0x9002) /* c.ebreak */ +#define COMPRESSED_INSN_MASK _UL(0xffff) + +#define GET_INSN_LENGTH(insn) \ +({ \ + unsigned long len; \ + len = ((insn & INSN_LENGTH_MASK) == INSN_LENGTH_32) ? \ + 4UL : 2UL; \ + len; \ +}) + +/* These are defined by the architecture */ +int is_valid_bugaddr(uint32_t addr); + +#define BUG_FN_REG t0 + +/* Many versions of GCC doesn't support the asm %c parameter which would + * be preferable to this unpleasantness. We use mergeable string + * sections to avoid multiple copies of the string appearing in the + * Xen image. BUGFRAME_run_fn needs to be handled separately. + */ +#define BUG_FRAME(type, line, file, has_msg, msg) do { \ + asm ("1:ebreak\n" \ + ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \ + "2:\t.asciz " __stringify(file) "\n" \ + "3:\n" \ + ".if " #has_msg "\n" \ + "\t.asciz " #msg "\n" \ + ".endif\n" \ + ".popsection\n" \ + ".pushsection .bug_frames." __stringify(type) ", \"a\", %progbits\n"\ + "4:\n" \ + ".p2align 2\n" \ + ".long (1b - 4b)\n" \ + ".long (2b - 4b)\n" \ + ".long (3b - 4b)\n" \ + ".hword " __stringify(line) ", 0\n" \ + ".popsection"); \ +} while (0) + +/* + * GCC will not allow to use "i" when PIE is enabled (Xen doesn't set the + * flag but instead rely on the default value from the compiler). So the + * easiest way to implement run_in_exception_handler() is to pass the to + * be called function in a fixed register. + */ +#define run_in_exception_handler(fn) do { \ + register void *fn_ asm(__stringify(BUG_FN_REG)) = (fn); \ + asm ("1:ebreak\n" \ + ".pushsection .bug_frames." __stringify(BUGFRAME_run_fn) "," \ + " \"a\", %%progbits\n" \ + "2:\n" \ + ".p2align 2\n" \ + ".long (1b - 2b)\n" \ + ".long 0, 0, 0\n" \ + ".popsection" :: "r" (fn_) ); \ +} while (0) + +#define WARN() BUG_FRAME(BUGFRAME_warn, __LINE__, __FILE__, 0, "") + +#define BUG() do { \ + BUG_FRAME(BUGFRAME_bug, __LINE__, __FILE__, 0, ""); \ + unreachable(); \ +} while (0) + +#define assert_failed(msg) do { \ + BUG_FRAME(BUGFRAME_assert, __LINE__, __FILE__, 1, msg); \ + unreachable(); \ +} while (0) + +extern const struct bug_frame __start_bug_frames[], + __stop_bug_frames_0[], + __stop_bug_frames_1[], + __stop_bug_frames_2[], + __stop_bug_frames_3[]; + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_RISCV_BUG_H */ diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ * * RISC-V Trap handlers */ +#include <asm/bug.h> #include <asm/csr.h> #include <asm/early_printk.h> #include <asm/processor.h> @@ -XXX,XX +XXX,XX @@ static void do_unexpected_trap(const struct cpu_user_regs *regs) die(); } +void show_execution_state(const struct cpu_user_regs *regs) +{ + early_printk("implement show_execution_state(regs)\n"); +} + +int do_bug_frame(struct cpu_user_regs *regs, vaddr_t pc) +{ + struct bug_frame *start, *end; + struct bug_frame *bug = NULL; + unsigned int id = 0; + const char *filename, *predicate; + int lineno; + + unsigned long bug_frames[] = { + (unsigned long)&__start_bug_frames[0], + (unsigned long)&__stop_bug_frames_0[0], + (unsigned long)&__stop_bug_frames_1[0], + (unsigned long)&__stop_bug_frames_2[0], + (unsigned long)&__stop_bug_frames_3[0], + }; + + for ( id = 0; id < BUGFRAME_NR; id++ ) + { + start = (struct bug_frame *)bug_frames[id]; + end = (struct bug_frame *)bug_frames[id + 1]; + + while ( start != end ) + { + if ( (vaddr_t)bug_loc(start) == pc ) + { + bug = start; + goto found; + } + + start++; + } + } + + found: + if ( bug == NULL ) + return -ENOENT; + + if ( id == BUGFRAME_run_fn ) + { + void (*fn)(const struct cpu_user_regs *) = (void *)regs->BUG_FN_REG; + + fn(regs); + + goto end; + } + + /* WARN, BUG or ASSERT: decode the filename pointer and line number. */ + filename = bug_file(bug); + lineno = bug_line(bug); + + switch ( id ) + { + case BUGFRAME_warn: + /* + * TODO: change early_printk's function to early_printk with format + * when s(n)printf() will be added. + */ + early_printk("Xen WARN at "); + early_printk(filename); + early_printk(":"); + // early_printk_hnum(lineno); + + show_execution_state(regs); + + goto end; + + case BUGFRAME_bug: + /* + * TODO: change early_printk's function to early_printk with format + * when s(n)printf() will be added. + */ + early_printk("Xen BUG at "); + early_printk(filename); + early_printk(":"); + // early_printk_hnum(lineno); + + show_execution_state(regs); + early_printk("change wait_for_interrupt to panic() when common is available\n"); + die(); + + case BUGFRAME_assert: + /* ASSERT: decode the predicate string pointer. */ + predicate = bug_msg(bug); + + /* + * TODO: change early_printk's function to early_printk with format + * when s(n)printf() will be added. + */ + early_printk("Assertion \'"); + early_printk(predicate); + early_printk("\' failed at "); + early_printk(filename); + early_printk(":"); + // early_printk_hnum(lineno); + + show_execution_state(regs); + early_printk("change wait_for_interrupt to panic() when common is available\n"); + die(); + } + + return -EINVAL; + + end: + regs->sepc += GET_INSN_LENGTH(*(uint32_t *)pc); + + return 0; +} + +int is_valid_bugaddr(uint32_t insn) +{ + if ((insn & INSN_LENGTH_MASK) == INSN_LENGTH_32) + return (insn == BUG_INSN_32); + else + return ((insn & COMPRESSED_INSN_MASK) == BUG_INSN_16); +} + void do_trap(struct cpu_user_regs *cpu_regs) { + register_t pc = cpu_regs->sepc; + uint32_t instr = *(uint32_t *)pc; + + if (is_valid_bugaddr(instr)) + if (!do_bug_frame(cpu_regs, pc)) return; + do_unexpected_trap(cpu_regs); } diff --git a/xen/arch/riscv/xen.lds.S b/xen/arch/riscv/xen.lds.S index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/xen.lds.S +++ b/xen/arch/riscv/xen.lds.S @@ -XXX,XX +XXX,XX @@ SECTIONS . = ALIGN(PAGE_SIZE); .rodata : { _srodata = .; /* Read-only data */ + /* Bug frames table */ + __start_bug_frames = .; + *(.bug_frames.0) + __stop_bug_frames_0 = .; + *(.bug_frames.1) + __stop_bug_frames_1 = .; + *(.bug_frames.2) + __stop_bug_frames_2 = .; + *(.bug_frames.3) + __stop_bug_frames_3 = .; *(.rodata) *(.rodata.*) *(.data.rel.ro) -- 2.39.0
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Nothing changed --- xen/arch/riscv/setup.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/compile.h> #include <xen/init.h> +#include <asm/bug.h> #include <asm/csr.h> #include <asm/early_printk.h> #include <asm/traps.h> @@ -XXX,XX +XXX,XX @@ unsigned char __initdata cpu0_boot_stack[STACK_SIZE] __aligned(STACK_SIZE); +static void test_run_in_exception(struct cpu_user_regs *regs) +{ + early_printk("If you see this message, "); + early_printk("run_in_exception_handler is most likely working\n"); +} + +static void test_macros_from_bug_h(void) +{ + run_in_exception_handler(test_run_in_exception); + WARN(); + early_printk("If you see this message, "); + early_printk("WARN is most likely working\n"); +} + void __init noreturn start_xen(void) { early_printk("Hello from C env\n"); trap_init(); + test_macros_from_bug_h(); + for ( ;; ) asm volatile ("wfi"); -- 2.39.0
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V2: - Leave only the latest "grep ..." --- automation/scripts/qemu-smoke-riscv64.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/automation/scripts/qemu-smoke-riscv64.sh b/automation/scripts/qemu-smoke-riscv64.sh index XXXXXXX..XXXXXXX 100755 --- a/automation/scripts/qemu-smoke-riscv64.sh +++ b/automation/scripts/qemu-smoke-riscv64.sh @@ -XXX,XX +XXX,XX @@ qemu-system-riscv64 \ |& tee smoke.serial set -e -(grep -q "Hello from C env" smoke.serial) || exit 1 +(grep -q "WARN is most likely working" smoke.serial) || exit 1 exit 0 -- 2.39.0
The patch series is based on: * [introduce generic implementation of macros from bug.h][1] * [Do basic initialization things][2] * [Deal with GOT stuff for RISC-V][3] which haven't been commited yet. The patch series provides a basic implementation of exception handling. It can do only basic things such as decode a cause of an exception, save/restore registers and execute "wfi" instruction if an exception can not be handled. To verify that exception handling works well it was implemented macros from <asm/bug.h> such as BUG/WARN/run_in_exception/assert_failed. The implementation of macros is used "ebreak" instruction and set up bug frame tables for each type of macros. Also it was implemented register save/restore to return and continue work after WARN/run_in_exception. Not all functionality of the macros was implemented as some of them require hard-panic the system which is not available now. Instead of hard-panic 'wfi' instruction is used but it should be definitely changed in the neareset future. It wasn't implemented show_execution_state() and stack trace discovering as it's not necessary now. [1] https://lore.kernel.org/xen-devel/cover.1678900513.git.oleksii.kurochko@gmail.com/ [2] https://lore.kernel.org/xen-devel/cover.1677838213.git.oleksii.kurochko@gmail.com/ [3] https://lore.kernel.org/xen-devel/69e031eb-6172-1ab0-5ffa-4650f69e83a7@citrix.com/T/#t --- Changes in V5: - Rebase on top of [1] and [2] - Add new patch which introduces stub for <asm/bug.h> to keep Xen compilable as in the patch [xen/riscv: introduce decode_cause() stuff] is used header <xen/lib.h> which requires <asm/bug.h>. - Remove <xen/error.h> from riscv/traps/c as nothing would require inclusion. - decode_reserved_interrupt_cause(), decode_interrupt_cause(), decode_cause, do_unexpected_trap() were made as static they are expected to be used only in traps.c - Remove "#include <xen/types.h>" from <asm/bug.h> as there is no any need in it anymore - Update macros GET_INSN_LENGTH: remove UL and 'unsigned int len;' from it - Remove " include <xen/bug.h>" from risc/setup.c. it is not needed in the current version of the patch - change an argument type from vaddr_t to uint32_t for is_valid_bugaddr and introduce read_instr() to read instruction properly as the length of qinstruction can be either 32 or 16 bits. - Code style fixes - update the comments before do_bug_frame() in riscv/trap.c - [[PATCH v4 5/5] automation: modify RISC-V smoke test ] was dropped as it was provided more simple solution by Andrew. CI: Simplify RISCV smoke testing - Refactor is_valid_bugaddr() function. - 2 new patches ([PATCH v5 {1-2}/7]) were introduced, the goal of which is to recalculate addresses used in traps.c, which can be linker time relative. It is needed as we don't have enabled MMU yet. --- Changes in V4: - Rebase the patch series on top of new version of [introduce generic implementation of macros from bug.h] patch series. - Update the cover letter message as 'Early printk' was merged and the current one patch series is based only on [introduce generic implementation of macros from bug.h] which hasn't been commited yet. - The following patches of the patch series were merged to staging: [PATCH v3 01/14] xen/riscv: change ISA to r64G [PATCH v3 02/14] xen/riscv: add <asm/asm.h> header [PATCH v3 03/14] xen/riscv: add <asm/riscv_encoding.h header [PATCH v3 04/14] xen/riscv: add <asm/csr.h> header [PATCH v3 05/14] xen/riscv: introduce empty <asm/string.h> [PATCH v3 06/14] xen/riscv: introduce empty <asm/cache.h> [PATCH v3 07/14] xen/riscv: introduce exception context [PATCH v3 08/14] xen/riscv: introduce exception handlers implementation [PATCH v3 10/14] xen/riscv: mask all interrupts - Fix addressed comments in xen-devel mailing list. --- Changes in V3: - Change the name of config RISCV_ISA_RV64IMA to RISCV_ISA_RV64G as instructions from Zicsr and Zifencei extensions aren't part of I extension any more. - Rebase the patch "xen/riscv: introduce an implementation of macros from <asm/bug.h>" on top of patch series [introduce generic implementation of macros from bug.h] - Update commit messages --- Changes in V2: - take the latest riscv_encoding.h from OpenSBI, update it with Xen related changes, and update the commit message with "Origin:" tag and the commit message itself. - add "Origin:" tag to the commit messag of the patch [xen/riscv: add <asm/csr.h> header]. - Remove the patch [xen/riscv: add early_printk_hnum() function] as the functionality provided by the patch isn't used now. - Refactor prcoess.h: move structure offset defines to asm-offsets.c, change register_t to unsigned long. - Refactor entry.S to use offsets defined in asm-offsets.C - Rename {__,}handle_exception to handle_trap() and do_trap() to be more consistent with RISC-V spec. - Merge the pathc which introduces do_unexpected_trap() with the patch [xen/riscv: introduce exception handlers implementation]. - Rename setup_trap_handler() to trap_init() and update correspondingly the patches in the patch series. - Refactor bug.h, remove bug_instr_t type from it. - Refactor decode_trap_cause() function to be more optimization-friendly. - Add two new empty headers: <cache.h> and <string.h> as they are needed to include <xen/lib.h> which provides ARRAY_SIZE and other macros. - Code style fixes. --- Oleksii Kurochko (7): xen/riscv: introduce boot information structure xen/riscv: initialize boot_info structure xen/riscv: introduce dummy <asm/bug.h> xen/riscv: introduce decode_cause() stuff xen/riscv: introduce trap_init() xen/riscv: introduce an implementation of macros from <asm/bug.h> xen/riscv: test basic handling stuff xen/arch/riscv/include/asm/boot-info.h | 15 ++ xen/arch/riscv/include/asm/bug.h | 38 ++++ xen/arch/riscv/include/asm/processor.h | 2 + xen/arch/riscv/include/asm/traps.h | 1 + xen/arch/riscv/riscv64/asm-offsets.c | 3 + xen/arch/riscv/setup.c | 34 ++++ xen/arch/riscv/traps.c | 233 ++++++++++++++++++++++++- xen/arch/riscv/xen.lds.S | 10 ++ 8 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 xen/arch/riscv/include/asm/boot-info.h create mode 100644 xen/arch/riscv/include/asm/bug.h -- 2.39.2
The structure holds information about: 1. linker start/end address 2. load start/end address Also the patch introduces offsets for boot information structure members to access them in assembly code. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V5: * the patch was introduced in the current patch series (V5) --- xen/arch/riscv/include/asm/boot-info.h | 15 +++++++++++++++ xen/arch/riscv/riscv64/asm-offsets.c | 3 +++ 2 files changed, 18 insertions(+) create mode 100644 xen/arch/riscv/include/asm/boot-info.h diff --git a/xen/arch/riscv/include/asm/boot-info.h b/xen/arch/riscv/include/asm/boot-info.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/boot-info.h @@ -XXX,XX +XXX,XX @@ +#ifndef _ASM_BOOT_INFO_H +#define _ASM_BOOT_INFO_H + +extern struct boot_info { + unsigned long linker_start; + unsigned long linker_end; + unsigned long load_start; + unsigned long load_end; +} boot_info; + +/* LINK_TO_LOAD() and LOAD_TO_LINK() works only when MMU isn't enabled. */ +#define LINK_TO_LOAD(addr) ((addr) - boot_info.linker_start + boot_info.load_start) +#define LOAD_TO_LINK(addr) ((addr) - boot_info.load_start + boot_info.linker_start) + +#endif \ No newline at end of file diff --git a/xen/arch/riscv/riscv64/asm-offsets.c b/xen/arch/riscv/riscv64/asm-offsets.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/riscv64/asm-offsets.c +++ b/xen/arch/riscv/riscv64/asm-offsets.c @@ -XXX,XX +XXX,XX @@ #define COMPILE_OFFSETS +#include <asm/boot-info.h> #include <asm/processor.h> #include <xen/types.h> @@ -XXX,XX +XXX,XX @@ void asm_offsets(void) OFFSET(CPU_USER_REGS_SEPC, struct cpu_user_regs, sepc); OFFSET(CPU_USER_REGS_SSTATUS, struct cpu_user_regs, sstatus); OFFSET(CPU_USER_REGS_PREGS, struct cpu_user_regs, pregs); + OFFSET(BI_LINKER_START, struct boot_info, linker_start); + OFFSET(BI_LOAD_START, struct boot_info, load_start); } -- 2.39.2
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V5: * the patch was introduced in the current patch series (V5) --- xen/arch/riscv/setup.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/compile.h> #include <xen/init.h> +#include <xen/kernel.h> +#include <asm/boot-info.h> #include <asm/early_printk.h> /* Xen stack for bringing up the first CPU. */ unsigned char __initdata cpu0_boot_stack[STACK_SIZE] __aligned(STACK_SIZE); +struct boot_info boot_info = { (unsigned long)&_start, (unsigned long)&_end, 0UL, 0UL }; + /* * To be sure that .bss isn't zero. It will simplify code of * .bss initialization. @@ -XXX,XX +XXX,XX @@ unsigned char __initdata cpu0_boot_stack[STACK_SIZE] */ int dummy_bss __attribute__((unused)); +static void fill_boot_info(void) +{ + boot_info.load_start = (unsigned long)_start; + boot_info.load_end = (unsigned long)_end; +} + void __init noreturn start_xen(unsigned long bootcpu_id, unsigned long dtb_paddr) { early_printk("Hello from C env\n"); + fill_boot_info(); + early_printk("All set up\n"); for ( ;; ) asm volatile ("wfi"); -- 2.39.2
<xen/lib.h> will be used in the patch "xen/riscv: introduce decode_cause() stuff" and requires <asm/bug.h> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V5: * the patch was introduced in the current patch series (V5) --- xen/arch/riscv/include/asm/bug.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 xen/arch/riscv/include/asm/bug.h diff --git a/xen/arch/riscv/include/asm/bug.h b/xen/arch/riscv/include/asm/bug.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/riscv/include/asm/bug.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2021-2023 Vates + * + */ +#ifndef _ASM_RISCV_BUG_H +#define _ASM_RISCV_BUG_H + +#endif /* _ASM_RISCV_BUG_H */ -- 2.39.2
The patch introduces stuff needed to decode a reason of an exception. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V5: - Remove <xen/error.h> from riscv/traps/c as nothing would require inclusion. - decode_reserved_interrupt_cause(), decode_interrupt_cause(), decode_cause, do_unexpected_trap() were made as static they are expected to be used only in traps.c - use LINK_TO_LOAD() for addresses which can be linker time relative. --- Changes in V4: - fix string in decode_reserved_interrupt_cause() --- Changes in V3: - Nothing changed --- Changes in V2: - Make decode_trap_cause() more optimization friendly. - Merge the pathc which introduces do_unexpected_trap() to the current one. --- xen/arch/riscv/traps.c | 87 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ * * RISC-V Trap handlers */ + +#include <xen/lib.h> + +#include <asm/boot-info.h> +#include <asm/csr.h> +#include <asm/early_printk.h> #include <asm/processor.h> #include <asm/traps.h> -void do_trap(struct cpu_user_regs *cpu_regs) +static const char *decode_trap_cause(unsigned long cause) +{ + static const char *const trap_causes[] = { + [CAUSE_MISALIGNED_FETCH] = "Instruction Address Misaligned", + [CAUSE_FETCH_ACCESS] = "Instruction Access Fault", + [CAUSE_ILLEGAL_INSTRUCTION] = "Illegal Instruction", + [CAUSE_BREAKPOINT] = "Breakpoint", + [CAUSE_MISALIGNED_LOAD] = "Load Address Misaligned", + [CAUSE_LOAD_ACCESS] = "Load Access Fault", + [CAUSE_MISALIGNED_STORE] = "Store/AMO Address Misaligned", + [CAUSE_STORE_ACCESS] = "Store/AMO Access Fault", + [CAUSE_USER_ECALL] = "Environment Call from U-Mode", + [CAUSE_SUPERVISOR_ECALL] = "Environment Call from S-Mode", + [CAUSE_MACHINE_ECALL] = "Environment Call from M-Mode", + [CAUSE_FETCH_PAGE_FAULT] = "Instruction Page Fault", + [CAUSE_LOAD_PAGE_FAULT] = "Load Page Fault", + [CAUSE_STORE_PAGE_FAULT] = "Store/AMO Page Fault", + [CAUSE_FETCH_GUEST_PAGE_FAULT] = "Instruction Guest Page Fault", + [CAUSE_LOAD_GUEST_PAGE_FAULT] = "Load Guest Page Fault", + [CAUSE_VIRTUAL_INST_FAULT] = "Virtualized Instruction Fault", + [CAUSE_STORE_GUEST_PAGE_FAULT] = "Guest Store/AMO Page Fault", + }; + + if ( cause < ARRAY_SIZE(trap_causes) && trap_causes[cause] ) + return trap_causes[cause]; + return "UNKNOWN"; +} + +static const char *decode_reserved_interrupt_cause(unsigned long irq_cause) +{ + switch ( irq_cause ) + { + case IRQ_M_SOFT: + return "M-mode Software Interrupt"; + case IRQ_M_TIMER: + return "M-mode TIMER Interrupt"; + case IRQ_M_EXT: + return "M-mode External Interrupt"; + default: + return "UNKNOWN IRQ type"; + } +} + +static const char *decode_interrupt_cause(unsigned long cause) +{ + unsigned long irq_cause = cause & ~CAUSE_IRQ_FLAG; + + switch ( irq_cause ) + { + case IRQ_S_SOFT: + return "Supervisor Software Interrupt"; + case IRQ_S_TIMER: + return "Supervisor Timer Interrupt"; + case IRQ_S_EXT: + return "Supervisor External Interrupt"; + default: + return decode_reserved_interrupt_cause(irq_cause); + } +} + +static const char *decode_cause(unsigned long cause) +{ + if ( cause & CAUSE_IRQ_FLAG ) + return decode_interrupt_cause(cause); + + return decode_trap_cause(cause); +} + +static void do_unexpected_trap(const struct cpu_user_regs *regs) { + unsigned long cause = csr_read(CSR_SCAUSE); + + early_printk("Unhandled exception: "); + early_printk(LINK_TO_LOAD(decode_cause(cause))); + early_printk("\n"); + die(); } + +void do_trap(struct cpu_user_regs *cpu_regs) +{ + do_unexpected_trap(cpu_regs); +} -- 2.39.2
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> --- Changes in V5: - Nothing changed --- Changes in V4: - Nothing changed --- Changes in V3: - Nothing changed --- Changes in V2: - Rename setup_trap_handler() to trap_init(). - Add Reviewed-by to the commit message. --- xen/arch/riscv/include/asm/traps.h | 1 + xen/arch/riscv/setup.c | 5 +++++ xen/arch/riscv/traps.c | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/xen/arch/riscv/include/asm/traps.h b/xen/arch/riscv/include/asm/traps.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/include/asm/traps.h +++ b/xen/arch/riscv/include/asm/traps.h @@ -XXX,XX +XXX,XX @@ void do_trap(struct cpu_user_regs *cpu_regs); void handle_trap(void); +void trap_init(void); #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/kernel.h> #include <asm/boot-info.h> +#include <asm/csr.h> #include <asm/early_printk.h> +#include <asm/traps.h> /* Xen stack for bringing up the first CPU. */ unsigned char __initdata cpu0_boot_stack[STACK_SIZE] @@ -XXX,XX +XXX,XX @@ void __init noreturn start_xen(unsigned long bootcpu_id, fill_boot_info(); + trap_init(); + early_printk("All set up\n"); + for ( ;; ) asm volatile ("wfi"); diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ #include <asm/processor.h> #include <asm/traps.h> +void trap_init(void) +{ + unsigned long addr = (unsigned long)&handle_trap; + + csr_write(CSR_STVEC, addr); +} + static const char *decode_trap_cause(unsigned long cause) { static const char *const trap_causes[] = { -- 2.39.2
The patch introduces macros: BUG(), WARN(), run_in_exception(), assert_failed. To be precise, the macros from generic bug implementation (<xen/bug.h>) will be used. The implementation uses "ebreak" instruction in combination with diffrent bug frame tables (for each type) which contains useful information. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- Changes in V5: - Remove "#include <xen/types.h>" from <asm/bug.h> as there is no any need in it anymore - Update macros GET_INSN_LENGTH: remove UL and 'unsigned int len;' from it - Remove " include <xen/bug.h>" from risc/setup.c. it is not needed in the current version of the patch - change an argument type from vaddr_t to uint32_t for is_valid_bugaddr and introduce read_instr() to read instruction properly as the length of qinstruction can be either 32 or 16 bits. - Code style fixes - update the comments before do_bug_frame() in riscv/trap.c - Refactor is_valid_bugaddr() function. - introduce macros cast_to_bug_frame(addr) to hide casts. - use LINK_TO_LOAD() for addresses which are linker time relative. --- Changes in V4: - Updates in RISC-V's <asm/bug.h>: * Add explanatory comment about why there is only defined for 32-bits length instructions and 16/32-bits BUG_INSN_{16,32}. * Change 'unsigned long' to 'unsigned int' inside GET_INSN_LENGTH(). * Update declaration of is_valid_bugaddr(): switch return type from int to bool and the argument from 'unsigned int' to 'vaddr'. - Updates in RISC-V's traps.c: * replace /xen and /asm includes * update definition of is_valid_bugaddr():switch return type from int to bool and the argument from 'unsigned int' to 'vaddr'. Code style inside function was updated too. * do_bug_frame() refactoring: * local variables start and bug became 'const struct bug_frame' * bug_frames[] array became 'static const struct bug_frame[] = ...' * remove all casts * remove unneeded comments and add an explanatory comment that the do_bug_frame() will be switched to a generic one. * do_trap() refactoring: * read 16-bits value instead of 32-bits as compressed instruction can be used and it might happen than only 16-bits may be accessible. * code style updates * re-use instr variable instead of re-reading instruction. - Updates in setup.c: * add blank line between xen/ and asm/ includes. --- Changes in V3: - Rebase the patch "xen/riscv: introduce an implementation of macros from <asm/bug.h>" on top of patch series [introduce generic implementation of macros from bug.h] --- Changes in V2: - Remove __ in define namings - Update run_in_exception_handler() with register void *fn_ asm(__stringify(BUG_FN_REG)) = (fn); - Remove bug_instr_t type and change it's usage to uint32_t --- xen/arch/riscv/include/asm/bug.h | 28 +++++ xen/arch/riscv/include/asm/processor.h | 2 + xen/arch/riscv/traps.c | 139 +++++++++++++++++++++++++ xen/arch/riscv/xen.lds.S | 10 ++ 4 files changed, 179 insertions(+) diff --git a/xen/arch/riscv/include/asm/bug.h b/xen/arch/riscv/include/asm/bug.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/include/asm/bug.h +++ b/xen/arch/riscv/include/asm/bug.h @@ -XXX,XX +XXX,XX @@ #ifndef _ASM_RISCV_BUG_H #define _ASM_RISCV_BUG_H +#ifndef __ASSEMBLY__ + +#define BUG_INSTR "ebreak" + +/* + * The base instruction set has a fixed length of 32-bit naturally aligned + * instructions. + * + * There are extensions of variable length ( where each instruction can be + * any number of 16-bit parcels in length ) but they aren't used in Xen + * and Linux kernel ( where these definitions were taken from ). + * + * Compressed ISA is used now where the instruction length is 16 bit and + * 'ebreak' instruction, in this case, can be either 16 or 32 bit ( + * depending on if compressed ISA is used or not ) + */ +#define INSN_LENGTH_MASK _UL(0x3) +#define INSN_LENGTH_32 _UL(0x3) + +#define BUG_INSN_32 _UL(0x00100073) /* ebreak */ +#define BUG_INSN_16 _UL(0x9002) /* c.ebreak */ +#define COMPRESSED_INSN_MASK _UL(0xffff) + +#define GET_INSN_LENGTH(insn) \ + (((insn) & INSN_LENGTH_MASK) == INSN_LENGTH_32 ? 4 : 2) \ + +#endif /* !__ASSEMBLY__ */ + #endif /* _ASM_RISCV_BUG_H */ diff --git a/xen/arch/riscv/include/asm/processor.h b/xen/arch/riscv/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/include/asm/processor.h +++ b/xen/arch/riscv/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ static inline void die(void) wfi(); } +void show_execution_state(const struct cpu_user_regs *regs); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PROCESSOR_H */ diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -XXX,XX +XXX,XX @@ * RISC-V Trap handlers */ +#include <xen/bug.h> +#include <xen/errno.h> #include <xen/lib.h> #include <asm/boot-info.h> @@ -XXX,XX +XXX,XX @@ #include <asm/processor.h> #include <asm/traps.h> +#define cast_to_bug_frame(addr) \ + (const struct bug_frame *)(LINK_TO_LOAD((char *)addr)) + + void trap_init(void) { unsigned long addr = (unsigned long)&handle_trap; @@ -XXX,XX +XXX,XX @@ static void do_unexpected_trap(const struct cpu_user_regs *regs) die(); } +void show_execution_state(const struct cpu_user_regs *regs) +{ + early_printk("implement show_execution_state(regs)\n"); +} + +/* + * TODO: change early_printk's function to early_printk with format + * when s(n)printf() will be added. + * + * Probably the TODO won't be needed as generic do_bug_frame() + * has been introduced and current implementation will be replaced + * with generic one when panic(), printk() and find_text_region() + * (virtual memory?) will be ready/merged + */ +int do_bug_frame(const struct cpu_user_regs *regs, vaddr_t pc) +{ + const struct bug_frame *start, *end; + const struct bug_frame *bug = NULL; + unsigned int id = 0; + const char *filename, *predicate; + int lineno; + + static const struct bug_frame* bug_frames[] = { + &__start_bug_frames[0], + &__stop_bug_frames_0[0], + &__stop_bug_frames_1[0], + &__stop_bug_frames_2[0], + &__stop_bug_frames_3[0], + }; + + for ( id = 0; id < BUGFRAME_NR; id++ ) + { + start = cast_to_bug_frame(bug_frames[id]); + end = cast_to_bug_frame(bug_frames[id + 1]); + + while ( start != end ) + { + if ( (vaddr_t)bug_loc(start) == pc ) + { + bug = start; + goto found; + } + + start++; + } + } + + found: + if ( bug == NULL ) + return -ENOENT; + + if ( id == BUGFRAME_run_fn ) + { + void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug); + + fn(regs); + + goto end; + } + + /* WARN, BUG or ASSERT: decode the filename pointer and line number. */ + filename = bug_ptr(bug); + lineno = bug_line(bug); + + switch ( id ) + { + case BUGFRAME_warn: + early_printk("Xen WARN at "); + early_printk(filename); + early_printk("\n"); + + show_execution_state(regs); + + goto end; + + case BUGFRAME_bug: + early_printk("Xen BUG at "); + early_printk(filename); + early_printk("\n"); + + show_execution_state(regs); + early_printk("change wait_for_interrupt to panic() when common is available\n"); + die(); + + case BUGFRAME_assert: + /* ASSERT: decode the predicate string pointer. */ + predicate = bug_msg(bug); + + early_printk("Assertion \'"); + early_printk(predicate); + early_printk("\' failed at "); + early_printk(filename); + early_printk("\n"); + + show_execution_state(regs); + early_printk("change wait_for_interrupt to panic() when common is available\n"); + die(); + } + + return -EINVAL; + + end: + return 0; +} + +static bool is_valid_bugaddr(uint32_t insn) +{ + return insn == BUG_INSN_32 || + (insn & COMPRESSED_INSN_MASK) == BUG_INSN_16; +} + +static uint32_t read_instr(unsigned long pc) +{ + uint16_t instr16 = *(uint16_t *)pc; + + if ( GET_INSN_LENGTH(instr16) == 2 ) + return (uint32_t)instr16; + else + return *(uint32_t *)pc; +} + void do_trap(struct cpu_user_regs *cpu_regs) { + register_t pc = cpu_regs->sepc; + uint32_t instr = read_instr(pc); + + if ( is_valid_bugaddr(instr) ) + { + if ( !do_bug_frame(cpu_regs, pc) ) + { + cpu_regs->sepc += GET_INSN_LENGTH(instr); + return; + } + } + do_unexpected_trap(cpu_regs); } diff --git a/xen/arch/riscv/xen.lds.S b/xen/arch/riscv/xen.lds.S index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/xen.lds.S +++ b/xen/arch/riscv/xen.lds.S @@ -XXX,XX +XXX,XX @@ SECTIONS . = ALIGN(PAGE_SIZE); .rodata : { _srodata = .; /* Read-only data */ + /* Bug frames table */ + __start_bug_frames = .; + *(.bug_frames.0) + __stop_bug_frames_0 = .; + *(.bug_frames.1) + __stop_bug_frames_1 = .; + *(.bug_frames.2) + __stop_bug_frames_2 = .; + *(.bug_frames.3) + __stop_bug_frames_3 = .; *(.rodata) *(.rodata.*) *(.data.rel.ro) -- 2.39.2
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> --- Changes in V5: - Nothing changed --- Changes in V4: - Add Acked-by: Alistair Francis <alistair.francis@wdc.com> --- Changes in V3: - Nothing changed --- Changes in V2: - Nothing changed --- xen/arch/riscv/setup.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -XXX,XX +XXX,XX @@ +#include <xen/bug.h> #include <xen/compile.h> #include <xen/init.h> #include <xen/kernel.h> @@ -XXX,XX +XXX,XX @@ static void fill_boot_info(void) boot_info.load_end = (unsigned long)_end; } +static void test_run_in_exception(struct cpu_user_regs *regs) +{ + early_printk("If you see this message, "); + early_printk("run_in_exception_handler is most likely working\n"); +} + +static void test_macros_from_bug_h(void) +{ + run_in_exception_handler(test_run_in_exception); + WARN(); + early_printk("If you see this message, "); + early_printk("WARN is most likely working\n"); +} + void __init noreturn start_xen(unsigned long bootcpu_id, unsigned long dtb_paddr) { @@ -XXX,XX +XXX,XX @@ void __init noreturn start_xen(unsigned long bootcpu_id, trap_init(); + test_macros_from_bug_h(); + early_printk("All set up\n"); for ( ;; ) -- 2.39.2