#include <linux/cfi.h>
#include <asm/insn.h>
static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
u32 *type)
{
unsigned long *regs_ptr = (unsigned long *)regs;
int rs1_num;
u32 insn;
*target = *type = 0;
if (get_kernel_nofault(insn, (void *)regs->epc - 4))
return false;
if (!riscv_insn_is_beq(insn))
return false;
*type = (u32)regs_ptr[RV_EXTRACT_RS1_REG(insn)];
if (get_kernel_nofault(insn, (void *)regs->epc) ||
get_kernel_nofault(insn, (void *)regs->epc + GET_INSN_LENGTH(insn)))
return false;
if (riscv_insn_is_jalr(insn))
rs1_num = RV_EXTRACT_RS1_REG(insn);
else if (riscv_insn_is_c_jalr(insn))
rs1_num = RVC_EXTRACT_C2_RS1_REG(insn);
else
return false;
*target = regs_ptr[rs1_num];
return true;
}
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
{
unsigned long target;
u32 type;
if (!is_cfi_trap(regs->epc))
return BUG_TRAP_TYPE_NONE;
if (!decode_cfi_insn(regs, &target, &type))
return report_cfi_failure_noaddr(regs, regs->epc);
return report_cfi_failure(regs, regs->epc, &target, type);
}