Path: blob/master/arch/csky/kernel/probes/simulate-insn.c
26489 views
// SPDX-License-Identifier: GPL-2.0+12#include <linux/bitops.h>3#include <linux/kernel.h>4#include <linux/kprobes.h>56#include "decode-insn.h"7#include "simulate-insn.h"89static inline bool csky_insn_reg_get_val(struct pt_regs *regs,10unsigned long index,11unsigned long *ptr)12{13if (index < 14)14*ptr = *(®s->a0 + index);1516if (index > 15 && index < 31)17*ptr = *(®s->exregs[0] + index - 16);1819switch (index) {20case 14:21*ptr = regs->usp;22break;23case 15:24*ptr = regs->lr;25break;26case 31:27*ptr = regs->tls;28break;29default:30goto fail;31}3233return true;34fail:35return false;36}3738static inline bool csky_insn_reg_set_val(struct pt_regs *regs,39unsigned long index,40unsigned long val)41{42if (index < 14)43*(®s->a0 + index) = val;4445if (index > 15 && index < 31)46*(®s->exregs[0] + index - 16) = val;4748switch (index) {49case 14:50regs->usp = val;51break;52case 15:53regs->lr = val;54break;55case 31:56regs->tls = val;57break;58default:59goto fail;60}6162return true;63fail:64return false;65}6667void __kprobes68simulate_br16(u32 opcode, long addr, struct pt_regs *regs)69{70instruction_pointer_set(regs,71addr + sign_extend32((opcode & 0x3ff) << 1, 9));72}7374void __kprobes75simulate_br32(u32 opcode, long addr, struct pt_regs *regs)76{77instruction_pointer_set(regs,78addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));79}8081void __kprobes82simulate_bt16(u32 opcode, long addr, struct pt_regs *regs)83{84if (regs->sr & 1)85instruction_pointer_set(regs,86addr + sign_extend32((opcode & 0x3ff) << 1, 9));87else88instruction_pointer_set(regs, addr + 2);89}9091void __kprobes92simulate_bt32(u32 opcode, long addr, struct pt_regs *regs)93{94if (regs->sr & 1)95instruction_pointer_set(regs,96addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));97else98instruction_pointer_set(regs, addr + 4);99}100101void __kprobes102simulate_bf16(u32 opcode, long addr, struct pt_regs *regs)103{104if (!(regs->sr & 1))105instruction_pointer_set(regs,106addr + sign_extend32((opcode & 0x3ff) << 1, 9));107else108instruction_pointer_set(regs, addr + 2);109}110111void __kprobes112simulate_bf32(u32 opcode, long addr, struct pt_regs *regs)113{114if (!(regs->sr & 1))115instruction_pointer_set(regs,116addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));117else118instruction_pointer_set(regs, addr + 4);119}120121void __kprobes122simulate_jmp16(u32 opcode, long addr, struct pt_regs *regs)123{124unsigned long tmp = (opcode >> 2) & 0xf;125126csky_insn_reg_get_val(regs, tmp, &tmp);127128instruction_pointer_set(regs, tmp & 0xfffffffe);129}130131void __kprobes132simulate_jmp32(u32 opcode, long addr, struct pt_regs *regs)133{134unsigned long tmp = opcode & 0x1f;135136csky_insn_reg_get_val(regs, tmp, &tmp);137138instruction_pointer_set(regs, tmp & 0xfffffffe);139}140141void __kprobes142simulate_jsr16(u32 opcode, long addr, struct pt_regs *regs)143{144unsigned long tmp = (opcode >> 2) & 0xf;145146csky_insn_reg_get_val(regs, tmp, &tmp);147148regs->lr = addr + 2;149150instruction_pointer_set(regs, tmp & 0xfffffffe);151}152153void __kprobes154simulate_jsr32(u32 opcode, long addr, struct pt_regs *regs)155{156unsigned long tmp = opcode & 0x1f;157158csky_insn_reg_get_val(regs, tmp, &tmp);159160regs->lr = addr + 4;161162instruction_pointer_set(regs, tmp & 0xfffffffe);163}164165void __kprobes166simulate_lrw16(u32 opcode, long addr, struct pt_regs *regs)167{168unsigned long val;169unsigned long tmp = (opcode & 0x300) >> 3;170unsigned long offset = ((opcode & 0x1f) | tmp) << 2;171172tmp = (opcode & 0xe0) >> 5;173174val = *(unsigned int *)(instruction_pointer(regs) + offset);175176csky_insn_reg_set_val(regs, tmp, val);177}178179void __kprobes180simulate_lrw32(u32 opcode, long addr, struct pt_regs *regs)181{182unsigned long val;183unsigned long offset = (opcode & 0xffff0000) >> 14;184unsigned long tmp = opcode & 0x0000001f;185186val = *(unsigned int *)187((instruction_pointer(regs) + offset) & 0xfffffffc);188189csky_insn_reg_set_val(regs, tmp, val);190}191192void __kprobes193simulate_pop16(u32 opcode, long addr, struct pt_regs *regs)194{195unsigned long *tmp = (unsigned long *)regs->usp;196int i;197198for (i = 0; i < (opcode & 0xf); i++) {199csky_insn_reg_set_val(regs, i + 4, *tmp);200tmp += 1;201}202203if (opcode & 0x10) {204csky_insn_reg_set_val(regs, 15, *tmp);205tmp += 1;206}207208regs->usp = (unsigned long)tmp;209210instruction_pointer_set(regs, regs->lr);211}212213void __kprobes214simulate_pop32(u32 opcode, long addr, struct pt_regs *regs)215{216unsigned long *tmp = (unsigned long *)regs->usp;217int i;218219for (i = 0; i < ((opcode & 0xf0000) >> 16); i++) {220csky_insn_reg_set_val(regs, i + 4, *tmp);221tmp += 1;222}223224if (opcode & 0x100000) {225csky_insn_reg_set_val(regs, 15, *tmp);226tmp += 1;227}228229for (i = 0; i < ((opcode & 0xe00000) >> 21); i++) {230csky_insn_reg_set_val(regs, i + 16, *tmp);231tmp += 1;232}233234if (opcode & 0x1000000) {235csky_insn_reg_set_val(regs, 29, *tmp);236tmp += 1;237}238239regs->usp = (unsigned long)tmp;240241instruction_pointer_set(regs, regs->lr);242}243244void __kprobes245simulate_bez32(u32 opcode, long addr, struct pt_regs *regs)246{247unsigned long tmp = opcode & 0x1f;248249csky_insn_reg_get_val(regs, tmp, &tmp);250251if (tmp == 0) {252instruction_pointer_set(regs,253addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));254} else255instruction_pointer_set(regs, addr + 4);256}257258void __kprobes259simulate_bnez32(u32 opcode, long addr, struct pt_regs *regs)260{261unsigned long tmp = opcode & 0x1f;262263csky_insn_reg_get_val(regs, tmp, &tmp);264265if (tmp != 0) {266instruction_pointer_set(regs,267addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));268} else269instruction_pointer_set(regs, addr + 4);270}271272void __kprobes273simulate_bnezad32(u32 opcode, long addr, struct pt_regs *regs)274{275unsigned long tmp = opcode & 0x1f;276long val;277278csky_insn_reg_get_val(regs, tmp, (unsigned long *)&val);279280val -= 1;281282if (val > 0) {283instruction_pointer_set(regs,284addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));285} else286instruction_pointer_set(regs, addr + 4);287288csky_insn_reg_set_val(regs, tmp, (unsigned long)val);289}290291void __kprobes292simulate_bhsz32(u32 opcode, long addr, struct pt_regs *regs)293{294unsigned long tmp = opcode & 0x1f;295unsigned long val;296297csky_insn_reg_get_val(regs, tmp, &val);298299if ((long) val >= 0) {300instruction_pointer_set(regs,301addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));302} else303instruction_pointer_set(regs, addr + 4);304}305306void __kprobes307simulate_bhz32(u32 opcode, long addr, struct pt_regs *regs)308{309unsigned long tmp = opcode & 0x1f;310unsigned long val;311312csky_insn_reg_get_val(regs, tmp, &val);313314if ((long) val > 0) {315instruction_pointer_set(regs,316addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));317} else318instruction_pointer_set(regs, addr + 4);319}320321void __kprobes322simulate_blsz32(u32 opcode, long addr, struct pt_regs *regs)323{324unsigned long tmp = opcode & 0x1f;325unsigned long val;326327csky_insn_reg_get_val(regs, tmp, &val);328329if ((long) val <= 0) {330instruction_pointer_set(regs,331addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));332} else333instruction_pointer_set(regs, addr + 4);334}335336void __kprobes337simulate_blz32(u32 opcode, long addr, struct pt_regs *regs)338{339unsigned long tmp = opcode & 0x1f;340unsigned long val;341342csky_insn_reg_get_val(regs, tmp, &val);343344if ((long) val < 0) {345instruction_pointer_set(regs,346addr + sign_extend32((opcode & 0xffff0000) >> 15, 15));347} else348instruction_pointer_set(regs, addr + 4);349}350351void __kprobes352simulate_bsr32(u32 opcode, long addr, struct pt_regs *regs)353{354unsigned long tmp;355356tmp = (opcode & 0xffff) << 16;357tmp |= (opcode & 0xffff0000) >> 16;358359instruction_pointer_set(regs,360addr + sign_extend32((tmp & 0x3ffffff) << 1, 15));361362regs->lr = addr + 4;363}364365void __kprobes366simulate_jmpi32(u32 opcode, long addr, struct pt_regs *regs)367{368unsigned long val;369unsigned long offset = ((opcode & 0xffff0000) >> 14);370371val = *(unsigned int *)372((instruction_pointer(regs) + offset) & 0xfffffffc);373374instruction_pointer_set(regs, val);375}376377void __kprobes378simulate_jsri32(u32 opcode, long addr, struct pt_regs *regs)379{380unsigned long val;381unsigned long offset = ((opcode & 0xffff0000) >> 14);382383val = *(unsigned int *)384((instruction_pointer(regs) + offset) & 0xfffffffc);385386regs->lr = addr + 4;387388instruction_pointer_set(regs, val);389}390391392