forked from Mirrors/opensbi

Rather than hand-rolling scaled pointer arithmetic with casts and shifts, let the compiler do so by indexing an array of GPRs, taking advantage of the language's type system to scale based on whatever type the register happens to be. This makes it easier to support CHERI where the registers are capabilities, not plain integers, and so this pointer arithmetic would need to change (and currently REGBYTES is both the size of a register and the size of an integer word upstream). Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20250709232932.37622-1-jrtc27@jrtc27.com Signed-off-by: Anup Patel <anup@brainfault.org>
295 lines
8.5 KiB
C
295 lines
8.5 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
|
*
|
|
* Authors:
|
|
* Anup Patel <anup.patel@wdc.com>
|
|
*/
|
|
|
|
#ifndef __SBI_TRAP_H__
|
|
#define __SBI_TRAP_H__
|
|
|
|
#include <sbi/riscv_encoding.h>
|
|
|
|
/* clang-format off */
|
|
|
|
/** Index of zero member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_zero 0
|
|
/** Index of ra member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_ra 1
|
|
/** Index of sp member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_sp 2
|
|
/** Index of gp member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_gp 3
|
|
/** Index of tp member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_tp 4
|
|
/** Index of t0 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t0 5
|
|
/** Index of t1 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t1 6
|
|
/** Index of t2 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t2 7
|
|
/** Index of s0 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s0 8
|
|
/** Index of s1 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s1 9
|
|
/** Index of a0 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a0 10
|
|
/** Index of a1 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a1 11
|
|
/** Index of a2 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a2 12
|
|
/** Index of a3 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a3 13
|
|
/** Index of a4 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a4 14
|
|
/** Index of a5 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a5 15
|
|
/** Index of a6 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a6 16
|
|
/** Index of a7 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_a7 17
|
|
/** Index of s2 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s2 18
|
|
/** Index of s3 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s3 19
|
|
/** Index of s4 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s4 20
|
|
/** Index of s5 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s5 21
|
|
/** Index of s6 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s6 22
|
|
/** Index of s7 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s7 23
|
|
/** Index of s8 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s8 24
|
|
/** Index of s9 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s9 25
|
|
/** Index of s10 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s10 26
|
|
/** Index of s11 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_s11 27
|
|
/** Index of t3 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t3 28
|
|
/** Index of t4 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t4 29
|
|
/** Index of t5 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t5 30
|
|
/** Index of t6 member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_t6 31
|
|
/** Index of mepc member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_mepc 32
|
|
/** Index of mstatus member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_mstatus 33
|
|
/** Index of mstatusH member in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_mstatusH 34
|
|
/** Last member index in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_last 35
|
|
|
|
/** Index of cause member in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_cause 0
|
|
/** Index of tval member in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_tval 1
|
|
/** Index of tval2 member in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_tval2 2
|
|
/** Index of tinst member in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_tinst 3
|
|
/** Index of gva member in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_gva 4
|
|
/** Last member index in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_last 5
|
|
|
|
/* clang-format on */
|
|
|
|
/** Get offset of member with name 'x' in sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_OFFSET(x) ((SBI_TRAP_REGS_##x) * __SIZEOF_POINTER__)
|
|
/** Size (in bytes) of sbi_trap_regs */
|
|
#define SBI_TRAP_REGS_SIZE SBI_TRAP_REGS_OFFSET(last)
|
|
|
|
/** Get offset of member with name 'x' in sbi_trap_info */
|
|
#define SBI_TRAP_INFO_OFFSET(x) ((SBI_TRAP_INFO_##x) * __SIZEOF_POINTER__)
|
|
/** Size (in bytes) of sbi_trap_info */
|
|
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
|
|
|
|
#define STACK_BOUNDARY 16
|
|
#define ALIGN_TO_BOUNDARY(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
|
|
|
/** Size (in bytes) of sbi_trap_context */
|
|
#define SBI_TRAP_CONTEXT_SIZE ALIGN_TO_BOUNDARY((SBI_TRAP_REGS_SIZE + \
|
|
SBI_TRAP_INFO_SIZE + \
|
|
__SIZEOF_POINTER__), STACK_BOUNDARY)
|
|
|
|
#ifndef __ASSEMBLER__
|
|
|
|
#include <sbi/sbi_types.h>
|
|
#include <sbi/sbi_scratch.h>
|
|
|
|
/** Representation of register state at time of trap/interrupt */
|
|
struct sbi_trap_regs {
|
|
union {
|
|
unsigned long gprs[32];
|
|
struct {
|
|
/** zero register state */
|
|
unsigned long zero;
|
|
/** ra register state */
|
|
unsigned long ra;
|
|
/** sp register state */
|
|
unsigned long sp;
|
|
/** gp register state */
|
|
unsigned long gp;
|
|
/** tp register state */
|
|
unsigned long tp;
|
|
/** t0 register state */
|
|
unsigned long t0;
|
|
/** t1 register state */
|
|
unsigned long t1;
|
|
/** t2 register state */
|
|
unsigned long t2;
|
|
/** s0 register state */
|
|
unsigned long s0;
|
|
/** s1 register state */
|
|
unsigned long s1;
|
|
/** a0 register state */
|
|
unsigned long a0;
|
|
/** a1 register state */
|
|
unsigned long a1;
|
|
/** a2 register state */
|
|
unsigned long a2;
|
|
/** a3 register state */
|
|
unsigned long a3;
|
|
/** a4 register state */
|
|
unsigned long a4;
|
|
/** a5 register state */
|
|
unsigned long a5;
|
|
/** a6 register state */
|
|
unsigned long a6;
|
|
/** a7 register state */
|
|
unsigned long a7;
|
|
/** s2 register state */
|
|
unsigned long s2;
|
|
/** s3 register state */
|
|
unsigned long s3;
|
|
/** s4 register state */
|
|
unsigned long s4;
|
|
/** s5 register state */
|
|
unsigned long s5;
|
|
/** s6 register state */
|
|
unsigned long s6;
|
|
/** s7 register state */
|
|
unsigned long s7;
|
|
/** s8 register state */
|
|
unsigned long s8;
|
|
/** s9 register state */
|
|
unsigned long s9;
|
|
/** s10 register state */
|
|
unsigned long s10;
|
|
/** s11 register state */
|
|
unsigned long s11;
|
|
/** t3 register state */
|
|
unsigned long t3;
|
|
/** t4 register state */
|
|
unsigned long t4;
|
|
/** t5 register state */
|
|
unsigned long t5;
|
|
/** t6 register state */
|
|
unsigned long t6;
|
|
};
|
|
};
|
|
/** mepc register state */
|
|
unsigned long mepc;
|
|
/** mstatus register state */
|
|
unsigned long mstatus;
|
|
/** mstatusH register state (only for 32-bit) */
|
|
unsigned long mstatusH;
|
|
};
|
|
|
|
_Static_assert(
|
|
sizeof(((struct sbi_trap_regs *)0)->gprs) ==
|
|
offsetof(struct sbi_trap_regs, t6) +
|
|
sizeof(((struct sbi_trap_regs *)0)->t6),
|
|
"struct sbi_trap_regs's layout differs between gprs and named members");
|
|
|
|
#define REG_VAL(idx, regs) ((regs)->gprs[(idx)])
|
|
|
|
#define GET_RS1(insn, regs) REG_VAL(GET_RS1_NUM(insn), regs)
|
|
#define GET_RS2(insn, regs) REG_VAL(GET_RS2_NUM(insn), regs)
|
|
#define GET_RS1S(insn, regs) REG_VAL(GET_RS1S_NUM(insn), regs)
|
|
#define GET_RS2S(insn, regs) REG_VAL(GET_RS2S_NUM(insn), regs)
|
|
#define GET_RS2C(insn, regs) REG_VAL(GET_RS2C_NUM(insn), regs)
|
|
#define SET_RD(insn, regs, val) (REG_VAL(GET_RD_NUM(insn), regs) = (val))
|
|
|
|
/** Representation of trap details */
|
|
struct sbi_trap_info {
|
|
/** cause Trap exception cause */
|
|
unsigned long cause;
|
|
/** tval Trap value */
|
|
unsigned long tval;
|
|
/** tval2 Trap value 2 */
|
|
unsigned long tval2;
|
|
/** tinst Trap instruction */
|
|
unsigned long tinst;
|
|
/** gva Guest virtual address in tval flag */
|
|
unsigned long gva;
|
|
};
|
|
|
|
/** Representation of trap context saved on stack */
|
|
struct sbi_trap_context {
|
|
/** Register state */
|
|
struct sbi_trap_regs regs;
|
|
/** Trap details */
|
|
struct sbi_trap_info trap;
|
|
/** Pointer to previous trap context */
|
|
struct sbi_trap_context *prev_context;
|
|
};
|
|
|
|
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
|
|
{
|
|
/*
|
|
* If the hypervisor extension is not implemented, mstatus[h].GVA is a
|
|
* WPRI field, which is guaranteed to read as zero. In addition, in this
|
|
* case we don't read mstatush and instead pretend it is zero, which
|
|
* handles privileged spec version < 1.12.
|
|
*/
|
|
|
|
#if __riscv_xlen == 32
|
|
return (regs->mstatusH & MSTATUSH_GVA) ? 1 : 0;
|
|
#else
|
|
return (regs->mstatus & MSTATUS_GVA) ? 1 : 0;
|
|
#endif
|
|
}
|
|
|
|
static inline bool sbi_regs_from_virt(const struct sbi_trap_regs *regs)
|
|
{
|
|
#if __riscv_xlen == 32
|
|
return (regs->mstatusH & MSTATUSH_MPV) ? true : false;
|
|
#else
|
|
return (regs->mstatus & MSTATUS_MPV) ? true : false;
|
|
#endif
|
|
}
|
|
|
|
static inline int sbi_mstatus_prev_mode(unsigned long mstatus)
|
|
{
|
|
return (mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
|
}
|
|
|
|
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
|
const struct sbi_trap_info *trap);
|
|
|
|
static inline struct sbi_trap_context *sbi_trap_get_context(struct sbi_scratch *scratch)
|
|
{
|
|
return (scratch) ? (void *)scratch->trap_context : NULL;
|
|
}
|
|
|
|
static inline void sbi_trap_set_context(struct sbi_scratch *scratch,
|
|
struct sbi_trap_context *tcntx)
|
|
{
|
|
scratch->trap_context = (unsigned long)tcntx;
|
|
}
|
|
|
|
struct sbi_trap_context *sbi_trap_handler(struct sbi_trap_context *tcntx);
|
|
|
|
#endif
|
|
|
|
#endif
|