summaryrefslogtreecommitdiff
path: root/include/sbi
diff options
context:
space:
mode:
Diffstat (limited to 'include/sbi')
-rw-r--r--include/sbi/riscv_asm.h244
-rw-r--r--include/sbi/riscv_atomic.h38
-rw-r--r--include/sbi/riscv_barrier.h53
-rw-r--r--include/sbi/riscv_encoding.h423
-rw-r--r--include/sbi/riscv_io.h109
-rw-r--r--include/sbi/riscv_locks.h33
-rw-r--r--include/sbi/sbi_bits.h44
-rw-r--r--include/sbi/sbi_console.h37
-rw-r--r--include/sbi/sbi_const.h43
-rw-r--r--include/sbi/sbi_ecall.h26
-rw-r--r--include/sbi/sbi_emulate_csr.h27
-rw-r--r--include/sbi/sbi_error.h25
-rw-r--r--include/sbi/sbi_hart.h41
-rw-r--r--include/sbi/sbi_illegal_insn.h22
-rw-r--r--include/sbi/sbi_init.h19
-rw-r--r--include/sbi/sbi_ipi.h33
-rw-r--r--include/sbi/sbi_platform.h258
-rw-r--r--include/sbi/sbi_scratch.h35
-rw-r--r--include/sbi/sbi_system.h31
-rw-r--r--include/sbi/sbi_timer.h30
-rw-r--r--include/sbi/sbi_trap.h57
-rw-r--r--include/sbi/sbi_types.h57
-rw-r--r--include/sbi/sbi_unpriv.h111
23 files changed, 1796 insertions, 0 deletions
diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
new file mode 100644
index 0000000..516bf6f
--- /dev/null
+++ b/include/sbi/riscv_asm.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ASM_H__
+#define __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)
+#define SZREG __REG_SEL(8, 4)
+#define LGREG __REG_SEL(3, 2)
+
+#if __SIZEOF_POINTER__ == 8
+#ifdef __ASSEMBLY__
+#define RISCV_PTR .dword
+#define RISCV_SZPTR 8
+#define RISCV_LGPTR 3
+#else
+#define RISCV_PTR ".dword"
+#define RISCV_SZPTR "8"
+#define RISCV_LGPTR "3"
+#endif
+#elif __SIZEOF_POINTER__ == 4
+#ifdef __ASSEMBLY__
+#define RISCV_PTR .word
+#define RISCV_SZPTR 4
+#define RISCV_LGPTR 2
+#else
+#define RISCV_PTR ".word"
+#define RISCV_SZPTR "4"
+#define RISCV_LGPTR "2"
+#endif
+#else
+#error "Unexpected __SIZEOF_POINTER__"
+#endif
+
+#if (__SIZEOF_INT__ == 4)
+#define RISCV_INT __ASM_STR(.word)
+#define RISCV_SZINT __ASM_STR(4)
+#define RISCV_LGINT __ASM_STR(2)
+#else
+#error "Unexpected __SIZEOF_INT__"
+#endif
+
+#if (__SIZEOF_SHORT__ == 2)
+#define RISCV_SHORT __ASM_STR(.half)
+#define RISCV_SZSHORT __ASM_STR(2)
+#define RISCV_LGSHORT __ASM_STR(1)
+#else
+#error "Unexpected __SIZEOF_SHORT__"
+#endif
+
+#define RISCV_SCRATCH_TMP0_OFFSET (0 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_FW_START_OFFSET (1 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_FW_SIZE_OFFSET (2 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_IPI_TYPE_OFFSET (9 * __SIZEOF_POINTER__)
+#define RISCV_SCRATCH_SIZE 256
+
+#define RISCV_TRAP_REGS_zero 0
+#define RISCV_TRAP_REGS_ra 1
+#define RISCV_TRAP_REGS_sp 2
+#define RISCV_TRAP_REGS_gp 3
+#define RISCV_TRAP_REGS_tp 4
+#define RISCV_TRAP_REGS_t0 5
+#define RISCV_TRAP_REGS_t1 6
+#define RISCV_TRAP_REGS_t2 7
+#define RISCV_TRAP_REGS_s0 8
+#define RISCV_TRAP_REGS_s1 9
+#define RISCV_TRAP_REGS_a0 10
+#define RISCV_TRAP_REGS_a1 11
+#define RISCV_TRAP_REGS_a2 12
+#define RISCV_TRAP_REGS_a3 13
+#define RISCV_TRAP_REGS_a4 14
+#define RISCV_TRAP_REGS_a5 15
+#define RISCV_TRAP_REGS_a6 16
+#define RISCV_TRAP_REGS_a7 17
+#define RISCV_TRAP_REGS_s2 18
+#define RISCV_TRAP_REGS_s3 19
+#define RISCV_TRAP_REGS_s4 20
+#define RISCV_TRAP_REGS_s5 21
+#define RISCV_TRAP_REGS_s6 22
+#define RISCV_TRAP_REGS_s7 23
+#define RISCV_TRAP_REGS_s8 24
+#define RISCV_TRAP_REGS_s9 25
+#define RISCV_TRAP_REGS_s10 26
+#define RISCV_TRAP_REGS_s11 27
+#define RISCV_TRAP_REGS_t3 28
+#define RISCV_TRAP_REGS_t4 29
+#define RISCV_TRAP_REGS_t5 30
+#define RISCV_TRAP_REGS_t6 31
+#define RISCV_TRAP_REGS_mepc 32
+#define RISCV_TRAP_REGS_mstatus 33
+#define RISCV_TRAP_REGS_last 34
+
+#define RISCV_TRAP_REGS_OFFSET(x) \
+ ((RISCV_TRAP_REGS_##x) * __SIZEOF_POINTER__)
+#define RISCV_TRAP_REGS_SIZE RISCV_TRAP_REGS_OFFSET(last)
+
+#ifndef __ASSEMBLY__
+
+#define csr_swap(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrrw %0, " #csr ", %1" \
+ : "=r" (__v) : "rK" (__v) \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_read(csr) \
+({ \
+ register unsigned long __v; \
+ __asm__ __volatile__ ("csrr %0, " #csr \
+ : "=r" (__v) : \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_read_n(csr_num) \
+({ \
+ register unsigned long __v; \
+ __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr_num) \
+ : "=r" (__v) : \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_write(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrw " #csr ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+#define csr_write_n(csr_num, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrw " __ASM_STR(csr_num) ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+#define csr_read_set(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrrs %0, " #csr ", %1" \
+ : "=r" (__v) : "rK" (__v) \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_set(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrs " #csr ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+#define csr_read_clear(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrrc %0, " #csr ", %1" \
+ : "=r" (__v) : "rK" (__v) \
+ : "memory"); \
+ __v; \
+})
+
+#define csr_clear(csr, val) \
+({ \
+ unsigned long __v = (unsigned long)(val); \
+ __asm__ __volatile__ ("csrc " #csr ", %0" \
+ : : "rK" (__v) \
+ : "memory"); \
+})
+
+unsigned long csr_read_num(int csr_num);
+
+void csr_write_num(int csr_num, unsigned long val);
+
+#define wfi() \
+do { \
+ __asm__ __volatile__ ("wfi" ::: "memory"); \
+} while (0)
+
+static inline int misa_extension(char ext)
+{
+ return csr_read(misa) & (1 << (ext - 'A'));
+}
+
+static inline int misa_xlen(void)
+{
+ return ((long)csr_read(misa) < 0) ? 64 : 32;
+}
+
+static inline void misa_string(char *out, unsigned int out_sz)
+{
+ unsigned long i, val = csr_read(misa);
+
+ for (i = 0; i < 26; i++) {
+ if (val & (1 << i)) {
+ *out = 'A' + i;
+ out++;
+ }
+ }
+ *out = '\0';
+ out++;
+}
+
+int pmp_set(unsigned int n, unsigned long prot,
+ unsigned long addr, unsigned long log2len);
+
+int pmp_get(unsigned int n, unsigned long *prot_out,
+ unsigned long *addr_out, unsigned long *log2len_out);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/include/sbi/riscv_atomic.h b/include/sbi/riscv_atomic.h
new file mode 100644
index 0000000..775cd6f
--- /dev/null
+++ b/include/sbi/riscv_atomic.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ATOMIC_H__
+#define __RISCV_ATOMIC_H__
+
+typedef struct {
+ volatile long counter;
+} atomic_t;
+
+#define ATOMIC_INIT(_lptr, val) \
+ (_lptr)->counter = (val)
+
+#define ATOMIC_INITIALIZER(val) \
+ { .counter = (val), }
+
+long atomic_read(atomic_t *atom);
+
+void atomic_write(atomic_t *atom, long value);
+
+long atomic_add_return(atomic_t *atom, long value);
+
+long atomic_sub_return(atomic_t *atom, long value);
+
+long arch_atomic_cmpxchg(atomic_t *atom, long oldval, long newval);
+
+long arch_atomic_xchg(atomic_t *atom, long newval);
+
+unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
+ unsigned int newval);
+
+#endif
diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h
new file mode 100644
index 0000000..993cbda
--- /dev/null
+++ b/include/sbi/riscv_barrier.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_BARRIER_H__
+#define __RISCV_BARRIER_H__
+
+#define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n"
+#define RISCV_RELEASE_BARRIER "\tfence rw, w\n"
+
+#define RISCV_FENCE(p, s) \
+ __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
+
+/* Read & Write Memory barrier */
+#define mb() RISCV_FENCE(iorw,iorw)
+
+/* Read Memory barrier */
+#define rmb() RISCV_FENCE(ir,ir)
+
+/* Write Memory barrier */
+#define wmb() RISCV_FENCE(ow,ow)
+
+/* SMP Read & Write Memory barrier */
+#define smp_mb() RISCV_FENCE(rw,rw)
+
+/* SMP Read Memory barrier */
+#define smp_rmb() RISCV_FENCE(r,r)
+
+/* SMP Write Memory barrier */
+#define smp_wmb() RISCV_FENCE(w,w)
+
+/* CPU relax for busy loop */
+#define cpu_relax() asm volatile ("" : : : "memory")
+
+#define __smp_store_release(p, v) \
+do { \
+ RISCV_FENCE(rw,w); \
+ *(p) = (v); \
+} while (0)
+
+#define __smp_load_acquire(p) \
+({ \
+ typeof(*p) ___p1 = *(p); \
+ RISCV_FENCE(r,rw); \
+ ___p1; \
+})
+
+#endif
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
new file mode 100644
index 0000000..a4407d2
--- /dev/null
+++ b/include/sbi/riscv_encoding.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_ENCODING_H__
+#define __RISCV_ENCODING_H__
+
+#include <sbi/sbi_const.h>
+
+/* TODO: Make constants usable in assembly with _AC() macro */
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_SUM 0x00040000
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_TVM 0x00100000
+#define MSTATUS_TW 0x00200000
+#define MSTATUS_TSR 0x00400000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS_UXL 0x0000000300000000
+#define MSTATUS_SXL 0x0000000C00000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_SUM 0x00040000
+#define SSTATUS_MXR 0x00080000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS_UXL 0x0000000300000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define DCSR_XDEBUGVER (3U<<30)
+#define DCSR_NDRESET (1<<29)
+#define DCSR_FULLRESET (1<<28)
+#define DCSR_EBREAKM (1<<15)
+#define DCSR_EBREAKH (1<<14)
+#define DCSR_EBREAKS (1<<13)
+#define DCSR_EBREAKU (1<<12)
+#define DCSR_STOPCYCLE (1<<10)
+#define DCSR_STOPTIME (1<<9)
+#define DCSR_CAUSE (7<<6)
+#define DCSR_DEBUGINT (1<<5)
+#define DCSR_HALT (1<<3)
+#define DCSR_STEP (1<<2)
+#define DCSR_PRV (3<<0)
+
+#define DCSR_CAUSE_NONE 0
+#define DCSR_CAUSE_SWBP 1
+#define DCSR_CAUSE_HWBP 2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_HALT 5
+
+#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT (1<<19)
+#define MCONTROL_TIMING (1<<18)
+#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_CHAIN (1<<11)
+#define MCONTROL_MATCH (0xf<<7)
+#define MCONTROL_M (1<<6)
+#define MCONTROL_H (1<<5)
+#define MCONTROL_S (1<<4)
+#define MCONTROL_U (1<<3)
+#define MCONTROL_EXECUTE (1<<2)
+#define MCONTROL_STORE (1<<1)
+#define MCONTROL_LOAD (1<<0)
+
+#define MCONTROL_TYPE_NONE 0
+#define MCONTROL_TYPE_MATCH 2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
+#define MCONTROL_ACTION_DEBUG_MODE 1
+#define MCONTROL_ACTION_TRACE_START 2
+#define MCONTROL_ACTION_TRACE_STOP 3
+#define MCONTROL_ACTION_TRACE_EMIT 4
+
+#define MCONTROL_MATCH_EQUAL 0
+#define MCONTROL_MATCH_NAPOT 1
+#define MCONTROL_MATCH_GE 2
+#define MCONTROL_MATCH_LT 3
+#define MCONTROL_MATCH_MASK_LOW 4
+#define MCONTROL_MATCH_MASK_HIGH 5
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_HSIP (1 << IRQ_H_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_HTIP (1 << IRQ_H_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_HEIP (1 << IRQ_H_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define SATP32_MODE 0x80000000
+#define SATP32_ASID 0x7FC00000
+#define SATP32_PPN 0x003FFFFF
+#define SATP64_MODE 0xF000000000000000
+#define SATP64_ASID 0x0FFFF00000000000
+#define SATP64_PPN 0x00000FFFFFFFFFFF
+
+#define SATP_MODE_OFF 0
+#define SATP_MODE_SV32 1
+#define SATP_MODE_SV39 8
+#define SATP_MODE_SV48 9
+#define SATP_MODE_SV57 10
+#define SATP_MODE_SV64 11
+
+#define PMP_R 0x01
+#define PMP_W 0x02
+#define PMP_X 0x04
+#define PMP_A 0x18
+#define PMP_A_TOR 0x08
+#define PMP_A_NA4 0x10
+#define PMP_A_NAPOT 0x18
+#define PMP_L 0x80
+
+#define PMP_SHIFT 2
+#define PMP_COUNT 16
+
+/* page table entry (PTE) fields */
+#define PTE_V 0x001 /* Valid */
+#define PTE_R 0x002 /* Read */
+#define PTE_W 0x004 /* Write */
+#define PTE_X 0x008 /* Execute */
+#define PTE_U 0x010 /* User */
+#define PTE_G 0x020 /* Global */
+#define PTE_A 0x040 /* Accessed */
+#define PTE_D 0x080 /* Dirty */
+#define PTE_SOFT 0x300 /* Reserved for Software */
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) \
+ (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#if __riscv_xlen == 64
+#define MSTATUS_SD MSTATUS64_SD
+#define SSTATUS_SD SSTATUS64_SD
+#define RISCV_PGLEVEL_BITS 9
+#define SATP_MODE SATP64_MODE
+#else
+#define MSTATUS_SD MSTATUS32_SD
+#define SSTATUS_SD SSTATUS32_SD
+#define RISCV_PGLEVEL_BITS 10
+#define SATP_MODE SATP32_MODE
+#endif
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
+
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#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_SSTATUS 0x100
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SCOUNTEREN 0x106
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_STVAL 0x143
+#define CSR_SIP 0x144
+#define CSR_SATP 0x180
+#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_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MTVAL 0x343
+#define CSR_MIP 0x344
+#define CSR_PMPCFG0 0x3a0
+#define CSR_PMPCFG1 0x3a1
+#define CSR_PMPCFG2 0x3a2
+#define CSR_PMPCFG3 0x3a3
+#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_TSELECT 0x7a0
+#define CSR_TDATA1 0x7a1
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA3 0x7a3
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+#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_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
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+#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
+#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
+
+#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_HYPERVISOR_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
+
+#endif
diff --git a/include/sbi/riscv_io.h b/include/sbi/riscv_io.h
new file mode 100644
index 0000000..08f1a2f
--- /dev/null
+++ b/include/sbi/riscv_io.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_IO_H__
+#define __RISCV_IO_H__
+
+#include <sbi/riscv_barrier.h>
+#include <sbi/sbi_types.h>
+
+static inline void __raw_writeb(u8 val, volatile void *addr)
+{
+ asm volatile("sb %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writew(u16 val, volatile void *addr)
+{
+ asm volatile("sh %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+
+static inline void __raw_writel(u32 val, volatile void *addr)
+{
+ asm volatile("sw %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+
+#if __riscv_xlen != 32
+static inline void __raw_writeq(u64 val, volatile void *addr)
+{
+ asm volatile("sd %0, 0(%1)" : : "r" (val), "r" (addr));
+}
+#endif
+
+static inline u8 __raw_readb(const volatile void *addr)
+{
+ u8 val;
+
+ asm volatile("lb %0, 0(%1)" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+static inline u16 __raw_readw(const volatile void *addr)
+{
+ u16 val;
+
+ asm volatile("lh %0, 0(%1)" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+static inline u32 __raw_readl(const volatile void *addr)
+{
+ u32 val;
+
+ asm volatile("lw %0, 0(%1)" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+#if __riscv_xlen != 32
+static inline u64 __raw_readq(const volatile void *addr)
+{
+ u64 val;
+
+ asm volatile("ld %0, 0(%1)" : "=r" (val) : "r" (addr));
+ return val;
+}
+#endif
+
+/* FIXME: These are now the same as asm-generic */
+#define __io_rbr() do {} while (0)
+#define __io_rar() do {} while (0)
+#define __io_rbw() do {} while (0)
+#define __io_raw() do {} while (0)
+
+#define readb_relaxed(c) ({ u8 __v; __io_rbr(); __v = __raw_readb(c); __io_rar(); __v; })
+#define readw_relaxed(c) ({ u16 __v; __io_rbr(); __v = __raw_readw(c); __io_rar(); __v; })
+#define readl_relaxed(c) ({ u32 __v; __io_rbr(); __v = __raw_readl(c); __io_rar(); __v; })
+
+#define writeb_relaxed(v,c) ({ __io_rbw(); __raw_writeb((v),(c)); __io_raw(); })
+#define writew_relaxed(v,c) ({ __io_rbw(); __raw_writew((v),(c)); __io_raw(); })
+#define writel_relaxed(v,c) ({ __io_rbw(); __raw_writel((v),(c)); __io_raw(); })
+
+#if __riscv_xlen != 32
+#define readq_relaxed(c) ({ u64 __v; __io_rbr(); __v = __raw_readq(c); __io_rar(); __v; })
+#define writeq_relaxed(v,c) ({ __io_rbw(); __raw_writeq((v),(c)); __io_raw(); })
+#endif
+
+#define __io_br() do {} while (0)
+#define __io_ar() __asm__ __volatile__ ("fence i,r" : : : "memory");
+#define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory");
+#define __io_aw() do {} while (0)
+
+#define readb(c) ({ u8 __v; __io_br(); __v = __raw_readb(c); __io_ar(); __v; })
+#define readw(c) ({ u16 __v; __io_br(); __v = __raw_readw(c); __io_ar(); __v; })
+#define readl(c) ({ u32 __v; __io_br(); __v = __raw_readl(c); __io_ar(); __v; })
+
+#define writeb(v,c) ({ __io_bw(); __raw_writeb((v),(c)); __io_aw(); })
+#define writew(v,c) ({ __io_bw(); __raw_writew((v),(c)); __io_aw(); })
+#define writel(v,c) ({ __io_bw(); __raw_writel((v),(c)); __io_aw(); })
+
+#if __riscv_xlen != 32
+#define readq(c) ({ u64 __v; __io_br(); __v = __raw_readq(c); __io_ar(); __v; })
+#define writeq(v,c) ({ __io_bw(); __raw_writeq((v),(c)); __io_aw(); })
+#endif
+
+#endif
diff --git a/include/sbi/riscv_locks.h b/include/sbi/riscv_locks.h
new file mode 100644
index 0000000..4a683d9
--- /dev/null
+++ b/include/sbi/riscv_locks.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __RISCV_LOCKS_H__
+#define __RISCV_LOCKS_H__
+
+typedef struct {
+ volatile long lock;
+} spinlock_t;
+
+#define __RISCV_SPIN_UNLOCKED 0
+
+#define SPIN_LOCK_INIT(_lptr) \
+ (_lptr)->lock = __RISCV_SPIN_UNLOCKED
+
+#define SPIN_LOCK_INITIALIZER \
+ { .lock = __RISCV_SPIN_UNLOCKED, }
+
+int spin_lock_check(spinlock_t *lock);
+
+int spin_trylock(spinlock_t *lock);
+
+void spin_lock(spinlock_t *lock);
+
+void spin_unlock(spinlock_t *lock);
+
+#endif
diff --git a/include/sbi/sbi_bits.h b/include/sbi/sbi_bits.h
new file mode 100644
index 0000000..118fab2
--- /dev/null
+++ b/include/sbi/sbi_bits.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_BITS_H__
+#define __SBI_BITS_H__
+
+#define likely(x) __builtin_expect((x), 1)
+#define unlikely(x) __builtin_expect((x), 0)
+
+#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
+#define ROUNDDOWN(a, b) ((a)/(b)*(b))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
+
+#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
+#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
+
+#define STR(x) XSTR(x)
+#define XSTR(x) #x
+
+#if __riscv_xlen == 64
+#define SLL32 sllw
+#define STORE sd
+#define LOAD ld
+#define LWU lwu
+#define LOG_REGBYTES 3
+#else
+#define SLL32 sll
+#define STORE sw
+#define LOAD lw
+#define LWU lw
+#define LOG_REGBYTES 2
+#endif
+#define REGBYTES (1 << LOG_REGBYTES)
+
+#endif
diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h
new file mode 100644
index 0000000..df258ba
--- /dev/null
+++ b/include/sbi/sbi_console.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_CONSOLE_H__
+#define __SBI_CONSOLE_H__
+
+#include <sbi/sbi_types.h>
+
+#define __printf(a, b) __attribute__((format(printf, a, b)))
+
+bool sbi_isprintable(char ch);
+
+char sbi_getc(void);
+
+void sbi_putc(char ch);
+
+void sbi_puts(const char *str);
+
+void sbi_gets(char *s, int maxwidth, char endchar);
+
+int __printf(2, 3) sbi_sprintf(char *out, const char *format, ...);
+
+int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz,
+ const char *format, ...);
+
+int __printf(1, 2) sbi_printf(const char *format, ...);
+
+struct sbi_scratch;
+int sbi_console_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_const.h b/include/sbi/sbi_const.h
new file mode 100644
index 0000000..3071094
--- /dev/null
+++ b/include/sbi/sbi_const.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_CONST_H__
+#define __SBI_CONST_H__
+
+/* Some constant macros are used in both assembler and
+ * C code. Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally. We
+ * use the following macros to deal with this.
+ *
+ * Similarly, _AT() will cast an expression with a type in C, but
+ * leave it unchanged in asm.
+ */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y) X
+#define _AT(T,X) X
+#else
+#define __AC(X,Y) (X##Y)
+#define _AC(X,Y) __AC(X,Y)
+#define _AT(T,X) ((T)(X))
+#endif
+
+#define _UL(x) (_AC(x, UL))
+#define _ULL(x) (_AC(x, ULL))
+
+#define _BITUL(x) (_UL(1) << (x))
+#define _BITULL(x) (_ULL(1) << (x))
+
+#define UL(x) (_UL(x))
+#define ULL(x) (_ULL(x))
+
+#define __STR(s) #s
+#define STRINGIFY(s) __STR(s)
+
+#endif
diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h
new file mode 100644
index 0000000..4f39329
--- /dev/null
+++ b/include/sbi/sbi_ecall.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ECALL_H__
+#define __SBI_ECALL_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+struct sbi_scratch;
+
+u16 sbi_ecall_version_major(void);
+
+u16 sbi_ecall_version_minor(void);
+
+int sbi_ecall_handler(u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_emulate_csr.h b/include/sbi/sbi_emulate_csr.h
new file mode 100644
index 0000000..c6fe419
--- /dev/null
+++ b/include/sbi/sbi_emulate_csr.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_EMULATE_CSR_H__
+#define __SBI_EMULATE_CSR_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_emulate_csr_read(int csr_num,
+ u32 hartid, ulong mstatus,
+ struct sbi_scratch *scratch,
+ ulong *csr_val);
+
+int sbi_emulate_csr_write(int csr_num,
+ u32 hartid, ulong mstatus,
+ struct sbi_scratch *scratch,
+ ulong csr_val);
+
+#endif
diff --git a/include/sbi/sbi_error.h b/include/sbi/sbi_error.h
new file mode 100644
index 0000000..955674e
--- /dev/null
+++ b/include/sbi/sbi_error.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ERROR_H__
+#define __SBI_ERROR_H__
+
+#define SBI_OK 0
+#define SBI_EUNKNOWN -1
+#define SBI_EFAIL -2
+#define SBI_EINVAL -3
+#define SBI_ENOENT -4
+#define SBI_ENOTSUPP -5
+#define SBI_ENODEV -6
+#define SBI_ENOSYS -7
+#define SBI_ETIMEDOUT -8
+#define SBI_EIO -9
+#define SBI_EILL -10
+
+#endif
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
new file mode 100644
index 0000000..38032ed
--- /dev/null
+++ b/include/sbi/sbi_hart.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_HART_H__
+#define __SBI_HART_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_hart_pmp_dump(void);
+
+void __attribute__((noreturn)) sbi_hart_hang(void);
+
+void __attribute__((noreturn)) sbi_hart_boot_next(unsigned long arg0,
+ unsigned long arg1,
+ unsigned long next_addr,
+ unsigned long next_mode);
+
+void sbi_hart_mark_available(u32 hartid);
+
+ulong sbi_hart_available_mask(void);
+
+void sbi_hart_unmark_available(u32 hartid);
+
+struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
+ u32 hartid);
+
+void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_illegal_insn.h b/include/sbi/sbi_illegal_insn.h
new file mode 100644
index 0000000..1b8837f
--- /dev/null
+++ b/include/sbi/sbi_illegal_insn.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_ILLEGAl_INSN_H__
+#define __SBI_ILLEGAl_INSN_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_regs;
+struct sbi_scratch;
+
+int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
+ struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_init.h b/include/sbi/sbi_init.h
new file mode 100644
index 0000000..b3aafdc
--- /dev/null
+++ b/include/sbi/sbi_init.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_INIT_H__
+#define __SBI_INIT_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+void __attribute__((noreturn)) sbi_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h
new file mode 100644
index 0000000..4058194
--- /dev/null
+++ b/include/sbi/sbi_ipi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_IPI_H__
+#define __SBI_IPI_H__
+
+#include <sbi/sbi_types.h>
+
+#define SBI_IPI_EVENT_SOFT 0x1
+#define SBI_IPI_EVENT_FENCE_I 0x2
+#define SBI_IPI_EVENT_SFENCE_VMA 0x4
+#define SBI_IPI_EVENT_HALT 0x8
+
+struct sbi_scratch;
+
+int sbi_ipi_send_many(struct sbi_scratch *scratch,
+ u32 hartid, ulong *pmask, u32 event);
+
+void sbi_ipi_clear_smode(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_ipi_process(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_ipi_warm_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_ipi_cold_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
new file mode 100644
index 0000000..57b8e6b
--- /dev/null
+++ b/include/sbi/sbi_platform.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_PLATFORM_H__
+#define __SBI_PLATFORM_H__
+
+#include <sbi/sbi_scratch.h>
+
+enum sbi_platform_features {
+ SBI_PLATFORM_HAS_MMIO_TIMER_VALUE = (1 << 0),
+ SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
+};
+
+struct sbi_platform {
+ char name[64];
+ u64 features;
+ u32 hart_count;
+ u32 hart_stack_size;
+ int (*cold_early_init)(void);
+ int (*cold_final_init)(void);
+ int (*warm_early_init)(u32 target_hart);
+ int (*warm_final_init)(u32 target_hart);
+ u32 (*pmp_region_count)(u32 target_hart);
+ int (*pmp_region_info)(u32 target_hart, u32 index,
+ ulong *prot, ulong *addr, ulong *log2size);
+ void (*console_putc)(char ch);
+ char (*console_getc)(void);
+ int (*console_init)(void);
+ int (*cold_irqchip_init)(void);
+ int (*warm_irqchip_init)(u32 target_hart);
+ void (*ipi_inject)(u32 target_hart, u32 source_hart);
+ void (*ipi_sync)(u32 target_hart, u32 source_hart);
+ void (*ipi_clear)(u32 target_hart);
+ int (*cold_ipi_init)(void);
+ int (*warm_ipi_init)(u32 target_hart);
+ u64 (*timer_value)(void);
+ void (*timer_event_stop)(u32 target_hart);
+ void (*timer_event_start)(u32 target_hart, u64 next_event);
+ int (*cold_timer_init)(void);
+ int (*warm_timer_init)(u32 target_hart);
+ int (*system_reboot)(u32 type);
+ int (*system_shutdown)(u32 type);
+} __attribute__((packed));
+
+#define sbi_platform_ptr(__s) \
+((struct sbi_platform *)((__s)->platform_addr))
+
+#define sbi_platform_thishart_ptr() \
+((struct sbi_platform *)(sbi_scratch_thishart_ptr()->platform_addr))
+
+#define sbi_platform_has_mmio_timer_value(__p) \
+((__p)->features & SBI_PLATFORM_HAS_MMIO_TIMER_VALUE)
+
+#define sbi_platform_has_hart_hotplug(__p) \
+((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
+
+static inline const char *sbi_platform_name(struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->name;
+ return NULL;
+}
+
+static inline u32 sbi_platform_hart_count(struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->hart_count;
+ return 0;
+}
+
+static inline u32 sbi_platform_hart_stack_size(struct sbi_platform *plat)
+{
+ if (plat)
+ return plat->hart_stack_size;
+ return 0;
+}
+
+static inline int sbi_platform_cold_early_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_early_init)
+ return plat->cold_early_init();
+ return 0;
+}
+
+static inline int sbi_platform_cold_final_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_final_init)
+ return plat->cold_final_init();
+ return 0;
+}
+
+static inline int sbi_platform_warm_early_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_early_init)
+ return plat->warm_early_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_warm_final_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_final_init)
+ return plat->warm_final_init(target_hart);
+ return 0;
+}
+
+static inline u32 sbi_platform_pmp_region_count(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->pmp_region_count)
+ return plat->pmp_region_count(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_pmp_region_info(struct sbi_platform *plat,
+ u32 target_hart, u32 index,
+ ulong *prot, ulong *addr,
+ ulong *log2size)
+{
+ if (plat && plat->pmp_region_info)
+ return plat->pmp_region_info(target_hart, index,
+ prot, addr, log2size);
+ return 0;
+}
+
+static inline void sbi_platform_console_putc(struct sbi_platform *plat,
+ char ch)
+{
+ if (plat && plat->console_putc)
+ plat->console_putc(ch);
+}
+
+static inline char sbi_platform_console_getc(struct sbi_platform *plat)
+{
+ if (plat && plat->console_getc)
+ return plat->console_getc();
+ return 0;
+}
+
+static inline int sbi_platform_console_init(struct sbi_platform *plat)
+{
+ if (plat && plat->console_init)
+ return plat->console_init();
+ return 0;
+}
+
+static inline int sbi_platform_warm_irqchip_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_irqchip_init)
+ return plat->warm_irqchip_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_cold_irqchip_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_irqchip_init)
+ return plat->cold_irqchip_init();
+ return 0;
+}
+
+static inline void sbi_platform_ipi_inject(struct sbi_platform *plat,
+ u32 target_hart, u32 source_hart)
+{
+ if (plat && plat->ipi_inject)
+ plat->ipi_inject(target_hart, source_hart);
+}
+
+static inline void sbi_platform_ipi_sync(struct sbi_platform *plat,
+ u32 target_hart, u32 source_hart)
+{
+ if (plat && plat->ipi_sync)
+ plat->ipi_sync(target_hart, source_hart);
+}
+
+static inline void sbi_platform_ipi_clear(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->ipi_clear)
+ plat->ipi_clear(target_hart);
+}
+
+static inline int sbi_platform_warm_ipi_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_ipi_init)
+ return plat->warm_ipi_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_cold_ipi_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_ipi_init)
+ return plat->cold_ipi_init();
+ return 0;
+}
+
+static inline u64 sbi_platform_timer_value(struct sbi_platform *plat)
+{
+ if (plat && plat->timer_value)
+ return plat->timer_value();
+ return 0;
+}
+
+static inline void sbi_platform_timer_event_stop(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->timer_event_stop)
+ plat->timer_event_stop(target_hart);
+}
+
+static inline void sbi_platform_timer_event_start(struct sbi_platform *plat,
+ u32 target_hart,
+ u64 next_event)
+{
+ if (plat && plat->timer_event_start)
+ plat->timer_event_start(target_hart, next_event);
+}
+
+static inline int sbi_platform_warm_timer_init(struct sbi_platform *plat,
+ u32 target_hart)
+{
+ if (plat && plat->warm_timer_init)
+ return plat->warm_timer_init(target_hart);
+ return 0;
+}
+
+static inline int sbi_platform_cold_timer_init(struct sbi_platform *plat)
+{
+ if (plat && plat->cold_timer_init)
+ return plat->cold_timer_init();
+ return 0;
+}
+
+static inline int sbi_platform_system_reboot(struct sbi_platform *plat,
+ u32 type)
+{
+ if (plat && plat->system_reboot)
+ return plat->system_reboot(type);
+ return 0;
+}
+
+static inline int sbi_platform_system_shutdown(struct sbi_platform *plat,
+ u32 type)
+{
+ if (plat && plat->system_shutdown)
+ return plat->system_shutdown(type);
+ return 0;
+}
+
+#endif
diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h
new file mode 100644
index 0000000..d5c6f35
--- /dev/null
+++ b/include/sbi/sbi_scratch.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_SCRATCH_H__
+#define __SBI_SCRATCH_H__
+
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch {
+ unsigned long tmp0;
+ unsigned long fw_start;
+ unsigned long fw_size;
+ unsigned long next_arg1;
+ unsigned long next_addr;
+ unsigned long next_mode;
+ unsigned long warmboot_addr;
+ unsigned long platform_addr;
+ unsigned long hartid_to_scratch;
+ unsigned long ipi_type;
+} __attribute__((packed));
+
+#define sbi_scratch_thishart_ptr() \
+((struct sbi_scratch *)csr_read(mscratch))
+
+#define sbi_scratch_thishart_arg1_ptr() \
+((void *)(sbi_scratch_thishart_ptr()->next_arg1))
+
+#endif
diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h
new file mode 100644
index 0000000..ac1fb36
--- /dev/null
+++ b/include/sbi/sbi_system.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_SYSTEM_H__
+#define __SBI_SYSTEM_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+int sbi_system_warm_early_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_system_warm_final_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_system_cold_early_init(struct sbi_scratch *scratch);
+
+int sbi_system_cold_final_init(struct sbi_scratch *scratch);
+
+void __attribute__((noreturn)) sbi_system_reboot(struct sbi_scratch *scratch,
+ u32 type);
+
+void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch,
+ u32 type);
+
+#endif
diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
new file mode 100644
index 0000000..914e9c0
--- /dev/null
+++ b/include/sbi/sbi_timer.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TIMER_H__
+#define __SBI_TIMER_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_scratch;
+
+u64 sbi_timer_value(struct sbi_scratch *scratch);
+
+void sbi_timer_event_stop(struct sbi_scratch *scratch, u32 hartid);
+
+void sbi_timer_event_start(struct sbi_scratch *scratch, u32 hartid,
+ u64 next_event);
+
+void sbi_timer_process(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_timer_warm_init(struct sbi_scratch *scratch, u32 hartid);
+
+int sbi_timer_cold_init(struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_trap.h b/include/sbi/sbi_trap.h
new file mode 100644
index 0000000..a6b22e4
--- /dev/null
+++ b/include/sbi/sbi_trap.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TRAP_H__
+#define __SBI_TRAP_H__
+
+#include <sbi/sbi_types.h>
+
+struct sbi_trap_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 mepc;
+ unsigned long mstatus;
+} __attribute__((packed));
+
+struct sbi_scratch;
+
+void sbi_trap_handler(struct sbi_trap_regs *regs,
+ struct sbi_scratch *scratch);
+
+#endif
diff --git a/include/sbi/sbi_types.h b/include/sbi/sbi_types.h
new file mode 100644
index 0000000..ddcdea2
--- /dev/null
+++ b/include/sbi/sbi_types.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_TYPES_H__
+#define __SBI_TYPES_H__
+
+typedef char s8;
+typedef unsigned char u8;
+typedef char int8_t;
+typedef unsigned char uint8_t;
+
+typedef short s16;
+typedef unsigned short u16;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+
+typedef int s32;
+typedef unsigned int u32;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+
+#if __riscv_xlen == 64
+typedef long s64;
+typedef unsigned long u64;
+typedef long int64_t;
+typedef unsigned long uint64_t;
+#elif __riscv_xlen == 32
+typedef long long s64;
+typedef unsigned long long u64;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#else
+#error "Unexpected __riscv_xlen"
+#endif
+
+typedef int bool;
+typedef unsigned long ulong;
+typedef unsigned long uintptr_t;
+typedef unsigned long size_t;
+typedef long ssize_t;
+typedef unsigned long virtual_addr_t;
+typedef unsigned long virtual_size_t;
+typedef unsigned long physical_addr_t;
+typedef unsigned long physical_size_t;
+
+#define TRUE 1
+#define FALSE 0
+
+#define NULL ((void *)0)
+
+#endif
diff --git a/include/sbi/sbi_unpriv.h b/include/sbi/sbi_unpriv.h
new file mode 100644
index 0000000..2b925c5
--- /dev/null
+++ b/include/sbi/sbi_unpriv.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_UNPRIV_H__
+#define __SBI_UNPRIV_H__
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_bits.h>
+#include <sbi/sbi_types.h>
+
+#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
+static inline type load_##type(const type *addr, ulong mepc) \
+{ \
+ register ulong __mepc asm ("a2") = mepc; \
+ register ulong __mstatus asm ("a3"); \
+ type val; \
+ asm ("csrrs %0, mstatus, %3\n" \
+ #insn " %1, %2\n" \
+ "csrw mstatus, %0" \
+ : "+&r" (__mstatus), "=&r" (val) \
+ : "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
+ return val; \
+}
+
+#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
+static inline void store_##type(type *addr, type val, ulong mepc) \
+{ \
+ register ulong __mepc asm ("a2") = mepc; \
+ register ulong __mstatus asm ("a3"); \
+ asm volatile ("csrrs %0, mstatus, %3\n" \
+ #insn " %1, %2\n" \
+ "csrw mstatus, %0" \
+ : "+&r" (__mstatus) \
+ : "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
+}
+
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw)
+#if __riscv_xlen == 64
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
+#else
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
+
+static inline u64 load_u64(const u64 *addr, ulong mepc)
+{
+ return load_u32((u32 *)addr, mepc)
+ + ((u64)load_u32((u32 *)addr + 1, mepc) << 32);
+}
+
+static inline void store_u64(u64 *addr, u64 val, ulong mepc)
+{
+ store_u32((u32 *)addr, val, mepc);
+ store_u32((u32 *)addr + 1, val >> 32, mepc);
+}
+#endif
+
+static inline ulong get_insn(ulong mepc, ulong *mstatus)
+{
+ register ulong __mepc asm ("a2") = mepc;
+ register ulong __mstatus asm ("a3");
+ ulong val;
+#ifndef __riscv_compressed
+ asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+ STR(LWU) " %[insn], (%[addr])\n"
+ "csrw mstatus, %[mstatus]"
+ : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
+ : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
+#else
+ ulong rvc_mask = 3, tmp;
+ asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+ "and %[tmp], %[addr], 2\n"
+ "bnez %[tmp], 1f\n"
+ STR(LWU) " %[insn], (%[addr])\n"
+ "and %[tmp], %[insn], %[rvc_mask]\n"
+ "beq %[tmp], %[rvc_mask], 2f\n"
+ "sll %[insn], %[insn], %[xlen_minus_16]\n"
+ "srl %[insn], %[insn], %[xlen_minus_16]\n"
+ "j 2f\n"
+ "1:\n"
+ "lhu %[insn], (%[addr])\n"
+ "and %[tmp], %[insn], %[rvc_mask]\n"
+ "bne %[tmp], %[rvc_mask], 2f\n"
+ "lhu %[tmp], 2(%[addr])\n"
+ "sll %[tmp], %[tmp], 16\n"
+ "add %[insn], %[insn], %[tmp]\n"
+ "2: csrw mstatus, %[mstatus]"
+ : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
+ : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
+ [rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
+#endif
+ *mstatus = __mstatus;
+ return val;
+}
+
+#endif