133e53ae1SGuo Ren // SPDX-License-Identifier: GPL-2.0+ 233e53ae1SGuo Ren 333e53ae1SGuo Ren #include <linux/bitops.h> 433e53ae1SGuo Ren #include <linux/kernel.h> 533e53ae1SGuo Ren #include <linux/kprobes.h> 633e53ae1SGuo Ren 733e53ae1SGuo Ren #include "decode-insn.h" 833e53ae1SGuo Ren #include "simulate-insn.h" 933e53ae1SGuo Ren 1033e53ae1SGuo Ren static inline bool csky_insn_reg_get_val(struct pt_regs *regs, 1133e53ae1SGuo Ren unsigned long index, 1233e53ae1SGuo Ren unsigned long *ptr) 1333e53ae1SGuo Ren { 1433e53ae1SGuo Ren if (index < 14) 1533e53ae1SGuo Ren *ptr = *(®s->a0 + index); 1633e53ae1SGuo Ren 1733e53ae1SGuo Ren if (index > 15 && index < 31) 1833e53ae1SGuo Ren *ptr = *(®s->exregs[0] + index - 16); 1933e53ae1SGuo Ren 2033e53ae1SGuo Ren switch (index) { 2133e53ae1SGuo Ren case 14: 2233e53ae1SGuo Ren *ptr = regs->usp; 2333e53ae1SGuo Ren break; 2433e53ae1SGuo Ren case 15: 2533e53ae1SGuo Ren *ptr = regs->lr; 2633e53ae1SGuo Ren break; 2733e53ae1SGuo Ren case 31: 2833e53ae1SGuo Ren *ptr = regs->tls; 2933e53ae1SGuo Ren break; 3033e53ae1SGuo Ren default: 3133e53ae1SGuo Ren goto fail; 3233e53ae1SGuo Ren } 3333e53ae1SGuo Ren 3433e53ae1SGuo Ren return true; 3533e53ae1SGuo Ren fail: 3633e53ae1SGuo Ren return false; 3733e53ae1SGuo Ren } 3833e53ae1SGuo Ren 3933e53ae1SGuo Ren static inline bool csky_insn_reg_set_val(struct pt_regs *regs, 4033e53ae1SGuo Ren unsigned long index, 4133e53ae1SGuo Ren unsigned long val) 4233e53ae1SGuo Ren { 4333e53ae1SGuo Ren if (index < 14) 4433e53ae1SGuo Ren *(®s->a0 + index) = val; 4533e53ae1SGuo Ren 4633e53ae1SGuo Ren if (index > 15 && index < 31) 4733e53ae1SGuo Ren *(®s->exregs[0] + index - 16) = val; 4833e53ae1SGuo Ren 4933e53ae1SGuo Ren switch (index) { 5033e53ae1SGuo Ren case 14: 5133e53ae1SGuo Ren regs->usp = val; 5233e53ae1SGuo Ren break; 5333e53ae1SGuo Ren case 15: 5433e53ae1SGuo Ren regs->lr = val; 5533e53ae1SGuo Ren break; 5633e53ae1SGuo Ren case 31: 5733e53ae1SGuo Ren regs->tls = val; 5833e53ae1SGuo Ren break; 5933e53ae1SGuo Ren default: 6033e53ae1SGuo Ren goto fail; 6133e53ae1SGuo Ren } 6233e53ae1SGuo Ren 6333e53ae1SGuo Ren return true; 6433e53ae1SGuo Ren fail: 6533e53ae1SGuo Ren return false; 6633e53ae1SGuo Ren } 6733e53ae1SGuo Ren 6833e53ae1SGuo Ren void __kprobes 6933e53ae1SGuo Ren simulate_br16(u32 opcode, long addr, struct pt_regs *regs) 7033e53ae1SGuo Ren { 7133e53ae1SGuo Ren instruction_pointer_set(regs, 7233e53ae1SGuo Ren addr + sign_extend32((opcode & 0x3ff) << 1, 9)); 7333e53ae1SGuo Ren } 7433e53ae1SGuo Ren 7533e53ae1SGuo Ren void __kprobes 7633e53ae1SGuo Ren simulate_br32(u32 opcode, long addr, struct pt_regs *regs) 7733e53ae1SGuo Ren { 7833e53ae1SGuo Ren instruction_pointer_set(regs, 7933e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 8033e53ae1SGuo Ren } 8133e53ae1SGuo Ren 8233e53ae1SGuo Ren void __kprobes 8333e53ae1SGuo Ren simulate_bt16(u32 opcode, long addr, struct pt_regs *regs) 8433e53ae1SGuo Ren { 8533e53ae1SGuo Ren if (regs->sr & 1) 8633e53ae1SGuo Ren instruction_pointer_set(regs, 8733e53ae1SGuo Ren addr + sign_extend32((opcode & 0x3ff) << 1, 9)); 8833e53ae1SGuo Ren else 8933e53ae1SGuo Ren instruction_pointer_set(regs, addr + 2); 9033e53ae1SGuo Ren } 9133e53ae1SGuo Ren 9233e53ae1SGuo Ren void __kprobes 9333e53ae1SGuo Ren simulate_bt32(u32 opcode, long addr, struct pt_regs *regs) 9433e53ae1SGuo Ren { 9533e53ae1SGuo Ren if (regs->sr & 1) 9633e53ae1SGuo Ren instruction_pointer_set(regs, 9733e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 9833e53ae1SGuo Ren else 9933e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 10033e53ae1SGuo Ren } 10133e53ae1SGuo Ren 10233e53ae1SGuo Ren void __kprobes 10333e53ae1SGuo Ren simulate_bf16(u32 opcode, long addr, struct pt_regs *regs) 10433e53ae1SGuo Ren { 10533e53ae1SGuo Ren if (!(regs->sr & 1)) 10633e53ae1SGuo Ren instruction_pointer_set(regs, 10733e53ae1SGuo Ren addr + sign_extend32((opcode & 0x3ff) << 1, 9)); 10833e53ae1SGuo Ren else 10933e53ae1SGuo Ren instruction_pointer_set(regs, addr + 2); 11033e53ae1SGuo Ren } 11133e53ae1SGuo Ren 11233e53ae1SGuo Ren void __kprobes 11333e53ae1SGuo Ren simulate_bf32(u32 opcode, long addr, struct pt_regs *regs) 11433e53ae1SGuo Ren { 11533e53ae1SGuo Ren if (!(regs->sr & 1)) 11633e53ae1SGuo Ren instruction_pointer_set(regs, 11733e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 11833e53ae1SGuo Ren else 11933e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 12033e53ae1SGuo Ren } 12133e53ae1SGuo Ren 12233e53ae1SGuo Ren void __kprobes 12333e53ae1SGuo Ren simulate_jmp16(u32 opcode, long addr, struct pt_regs *regs) 12433e53ae1SGuo Ren { 12533e53ae1SGuo Ren unsigned long tmp = (opcode >> 2) & 0xf; 12633e53ae1SGuo Ren 12733e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &tmp); 12833e53ae1SGuo Ren 12933e53ae1SGuo Ren instruction_pointer_set(regs, tmp & 0xfffffffe); 13033e53ae1SGuo Ren } 13133e53ae1SGuo Ren 13233e53ae1SGuo Ren void __kprobes 13333e53ae1SGuo Ren simulate_jmp32(u32 opcode, long addr, struct pt_regs *regs) 13433e53ae1SGuo Ren { 13533e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 13633e53ae1SGuo Ren 13733e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &tmp); 13833e53ae1SGuo Ren 13933e53ae1SGuo Ren instruction_pointer_set(regs, tmp & 0xfffffffe); 14033e53ae1SGuo Ren } 14133e53ae1SGuo Ren 14233e53ae1SGuo Ren void __kprobes 14333e53ae1SGuo Ren simulate_jsr16(u32 opcode, long addr, struct pt_regs *regs) 14433e53ae1SGuo Ren { 14533e53ae1SGuo Ren unsigned long tmp = (opcode >> 2) & 0xf; 14633e53ae1SGuo Ren 14733e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &tmp); 14833e53ae1SGuo Ren 14933e53ae1SGuo Ren regs->lr = addr + 2; 15033e53ae1SGuo Ren 15133e53ae1SGuo Ren instruction_pointer_set(regs, tmp & 0xfffffffe); 15233e53ae1SGuo Ren } 15333e53ae1SGuo Ren 15433e53ae1SGuo Ren void __kprobes 15533e53ae1SGuo Ren simulate_jsr32(u32 opcode, long addr, struct pt_regs *regs) 15633e53ae1SGuo Ren { 15733e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 15833e53ae1SGuo Ren 15933e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &tmp); 16033e53ae1SGuo Ren 16133e53ae1SGuo Ren regs->lr = addr + 4; 16233e53ae1SGuo Ren 16333e53ae1SGuo Ren instruction_pointer_set(regs, tmp & 0xfffffffe); 16433e53ae1SGuo Ren } 16533e53ae1SGuo Ren 16633e53ae1SGuo Ren void __kprobes 16733e53ae1SGuo Ren simulate_lrw16(u32 opcode, long addr, struct pt_regs *regs) 16833e53ae1SGuo Ren { 16933e53ae1SGuo Ren unsigned long val; 17033e53ae1SGuo Ren unsigned long tmp = (opcode & 0x300) >> 3; 17133e53ae1SGuo Ren unsigned long offset = ((opcode & 0x1f) | tmp) << 2; 17233e53ae1SGuo Ren 17333e53ae1SGuo Ren tmp = (opcode & 0xe0) >> 5; 17433e53ae1SGuo Ren 17533e53ae1SGuo Ren val = *(unsigned int *)(instruction_pointer(regs) + offset); 17633e53ae1SGuo Ren 17733e53ae1SGuo Ren csky_insn_reg_set_val(regs, tmp, val); 17833e53ae1SGuo Ren } 17933e53ae1SGuo Ren 18033e53ae1SGuo Ren void __kprobes 18133e53ae1SGuo Ren simulate_lrw32(u32 opcode, long addr, struct pt_regs *regs) 18233e53ae1SGuo Ren { 18333e53ae1SGuo Ren unsigned long val; 18433e53ae1SGuo Ren unsigned long offset = (opcode & 0xffff0000) >> 14; 18533e53ae1SGuo Ren unsigned long tmp = opcode & 0x0000001f; 18633e53ae1SGuo Ren 18733e53ae1SGuo Ren val = *(unsigned int *) 18833e53ae1SGuo Ren ((instruction_pointer(regs) + offset) & 0xfffffffc); 18933e53ae1SGuo Ren 19033e53ae1SGuo Ren csky_insn_reg_set_val(regs, tmp, val); 19133e53ae1SGuo Ren } 19233e53ae1SGuo Ren 19333e53ae1SGuo Ren void __kprobes 19433e53ae1SGuo Ren simulate_pop16(u32 opcode, long addr, struct pt_regs *regs) 19533e53ae1SGuo Ren { 19633e53ae1SGuo Ren unsigned long *tmp = (unsigned long *)regs->usp; 19733e53ae1SGuo Ren int i; 19833e53ae1SGuo Ren 19933e53ae1SGuo Ren for (i = 0; i < (opcode & 0xf); i++) { 20033e53ae1SGuo Ren csky_insn_reg_set_val(regs, i + 4, *tmp); 20133e53ae1SGuo Ren tmp += 1; 20233e53ae1SGuo Ren } 20333e53ae1SGuo Ren 20433e53ae1SGuo Ren if (opcode & 0x10) { 20533e53ae1SGuo Ren csky_insn_reg_set_val(regs, 15, *tmp); 20633e53ae1SGuo Ren tmp += 1; 20733e53ae1SGuo Ren } 20833e53ae1SGuo Ren 20933e53ae1SGuo Ren regs->usp = (unsigned long)tmp; 21033e53ae1SGuo Ren 21133e53ae1SGuo Ren instruction_pointer_set(regs, regs->lr); 21233e53ae1SGuo Ren } 21333e53ae1SGuo Ren 21433e53ae1SGuo Ren void __kprobes 21533e53ae1SGuo Ren simulate_pop32(u32 opcode, long addr, struct pt_regs *regs) 21633e53ae1SGuo Ren { 21733e53ae1SGuo Ren unsigned long *tmp = (unsigned long *)regs->usp; 21833e53ae1SGuo Ren int i; 21933e53ae1SGuo Ren 22033e53ae1SGuo Ren for (i = 0; i < ((opcode & 0xf0000) >> 16); i++) { 22133e53ae1SGuo Ren csky_insn_reg_set_val(regs, i + 4, *tmp); 22233e53ae1SGuo Ren tmp += 1; 22333e53ae1SGuo Ren } 22433e53ae1SGuo Ren 22533e53ae1SGuo Ren if (opcode & 0x100000) { 22633e53ae1SGuo Ren csky_insn_reg_set_val(regs, 15, *tmp); 22733e53ae1SGuo Ren tmp += 1; 22833e53ae1SGuo Ren } 22933e53ae1SGuo Ren 23033e53ae1SGuo Ren for (i = 0; i < ((opcode & 0xe00000) >> 21); i++) { 23133e53ae1SGuo Ren csky_insn_reg_set_val(regs, i + 16, *tmp); 23233e53ae1SGuo Ren tmp += 1; 23333e53ae1SGuo Ren } 23433e53ae1SGuo Ren 23533e53ae1SGuo Ren if (opcode & 0x1000000) { 23633e53ae1SGuo Ren csky_insn_reg_set_val(regs, 29, *tmp); 23733e53ae1SGuo Ren tmp += 1; 23833e53ae1SGuo Ren } 23933e53ae1SGuo Ren 24033e53ae1SGuo Ren regs->usp = (unsigned long)tmp; 24133e53ae1SGuo Ren 24233e53ae1SGuo Ren instruction_pointer_set(regs, regs->lr); 24333e53ae1SGuo Ren } 24433e53ae1SGuo Ren 24533e53ae1SGuo Ren void __kprobes 24633e53ae1SGuo Ren simulate_bez32(u32 opcode, long addr, struct pt_regs *regs) 24733e53ae1SGuo Ren { 24833e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 24933e53ae1SGuo Ren 25033e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &tmp); 25133e53ae1SGuo Ren 25233e53ae1SGuo Ren if (tmp == 0) { 25333e53ae1SGuo Ren instruction_pointer_set(regs, 25433e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 25533e53ae1SGuo Ren } else 25633e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 25733e53ae1SGuo Ren } 25833e53ae1SGuo Ren 25933e53ae1SGuo Ren void __kprobes 26033e53ae1SGuo Ren simulate_bnez32(u32 opcode, long addr, struct pt_regs *regs) 26133e53ae1SGuo Ren { 26233e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 26333e53ae1SGuo Ren 26433e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &tmp); 26533e53ae1SGuo Ren 26633e53ae1SGuo Ren if (tmp != 0) { 26733e53ae1SGuo Ren instruction_pointer_set(regs, 26833e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 26933e53ae1SGuo Ren } else 27033e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 27133e53ae1SGuo Ren } 27233e53ae1SGuo Ren 27333e53ae1SGuo Ren void __kprobes 27433e53ae1SGuo Ren simulate_bnezad32(u32 opcode, long addr, struct pt_regs *regs) 27533e53ae1SGuo Ren { 27633e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 277*8dcbc611SGuo Ren long val; 27833e53ae1SGuo Ren 279*8dcbc611SGuo Ren csky_insn_reg_get_val(regs, tmp, (unsigned long *)&val); 28033e53ae1SGuo Ren 28133e53ae1SGuo Ren val -= 1; 28233e53ae1SGuo Ren 28333e53ae1SGuo Ren if (val > 0) { 28433e53ae1SGuo Ren instruction_pointer_set(regs, 28533e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 28633e53ae1SGuo Ren } else 28733e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 28833e53ae1SGuo Ren 289*8dcbc611SGuo Ren csky_insn_reg_set_val(regs, tmp, (unsigned long)val); 29033e53ae1SGuo Ren } 29133e53ae1SGuo Ren 29233e53ae1SGuo Ren void __kprobes 29333e53ae1SGuo Ren simulate_bhsz32(u32 opcode, long addr, struct pt_regs *regs) 29433e53ae1SGuo Ren { 29533e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 29633e53ae1SGuo Ren unsigned long val; 29733e53ae1SGuo Ren 29833e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &val); 29933e53ae1SGuo Ren 300*8dcbc611SGuo Ren if ((long) val >= 0) { 30133e53ae1SGuo Ren instruction_pointer_set(regs, 30233e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 30333e53ae1SGuo Ren } else 30433e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 30533e53ae1SGuo Ren } 30633e53ae1SGuo Ren 30733e53ae1SGuo Ren void __kprobes 30833e53ae1SGuo Ren simulate_bhz32(u32 opcode, long addr, struct pt_regs *regs) 30933e53ae1SGuo Ren { 31033e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 31133e53ae1SGuo Ren unsigned long val; 31233e53ae1SGuo Ren 31333e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &val); 31433e53ae1SGuo Ren 315*8dcbc611SGuo Ren if ((long) val > 0) { 31633e53ae1SGuo Ren instruction_pointer_set(regs, 31733e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 31833e53ae1SGuo Ren } else 31933e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 32033e53ae1SGuo Ren } 32133e53ae1SGuo Ren 32233e53ae1SGuo Ren void __kprobes 32333e53ae1SGuo Ren simulate_blsz32(u32 opcode, long addr, struct pt_regs *regs) 32433e53ae1SGuo Ren { 32533e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 32633e53ae1SGuo Ren unsigned long val; 32733e53ae1SGuo Ren 32833e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &val); 32933e53ae1SGuo Ren 330*8dcbc611SGuo Ren if ((long) val <= 0) { 33133e53ae1SGuo Ren instruction_pointer_set(regs, 33233e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 33333e53ae1SGuo Ren } else 33433e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 33533e53ae1SGuo Ren } 33633e53ae1SGuo Ren 33733e53ae1SGuo Ren void __kprobes 33833e53ae1SGuo Ren simulate_blz32(u32 opcode, long addr, struct pt_regs *regs) 33933e53ae1SGuo Ren { 34033e53ae1SGuo Ren unsigned long tmp = opcode & 0x1f; 34133e53ae1SGuo Ren unsigned long val; 34233e53ae1SGuo Ren 34333e53ae1SGuo Ren csky_insn_reg_get_val(regs, tmp, &val); 34433e53ae1SGuo Ren 345*8dcbc611SGuo Ren if ((long) val < 0) { 34633e53ae1SGuo Ren instruction_pointer_set(regs, 34733e53ae1SGuo Ren addr + sign_extend32((opcode & 0xffff0000) >> 15, 15)); 34833e53ae1SGuo Ren } else 34933e53ae1SGuo Ren instruction_pointer_set(regs, addr + 4); 35033e53ae1SGuo Ren } 35133e53ae1SGuo Ren 35233e53ae1SGuo Ren void __kprobes 35333e53ae1SGuo Ren simulate_bsr32(u32 opcode, long addr, struct pt_regs *regs) 35433e53ae1SGuo Ren { 35533e53ae1SGuo Ren unsigned long tmp; 35633e53ae1SGuo Ren 35733e53ae1SGuo Ren tmp = (opcode & 0xffff) << 16; 35833e53ae1SGuo Ren tmp |= (opcode & 0xffff0000) >> 16; 35933e53ae1SGuo Ren 36033e53ae1SGuo Ren instruction_pointer_set(regs, 36133e53ae1SGuo Ren addr + sign_extend32((tmp & 0x3ffffff) << 1, 15)); 36233e53ae1SGuo Ren 36333e53ae1SGuo Ren regs->lr = addr + 4; 36433e53ae1SGuo Ren } 36533e53ae1SGuo Ren 36633e53ae1SGuo Ren void __kprobes 36733e53ae1SGuo Ren simulate_jmpi32(u32 opcode, long addr, struct pt_regs *regs) 36833e53ae1SGuo Ren { 36933e53ae1SGuo Ren unsigned long val; 37033e53ae1SGuo Ren unsigned long offset = ((opcode & 0xffff0000) >> 14); 37133e53ae1SGuo Ren 37233e53ae1SGuo Ren val = *(unsigned int *) 37333e53ae1SGuo Ren ((instruction_pointer(regs) + offset) & 0xfffffffc); 37433e53ae1SGuo Ren 37533e53ae1SGuo Ren instruction_pointer_set(regs, val); 37633e53ae1SGuo Ren } 37733e53ae1SGuo Ren 37833e53ae1SGuo Ren void __kprobes 37933e53ae1SGuo Ren simulate_jsri32(u32 opcode, long addr, struct pt_regs *regs) 38033e53ae1SGuo Ren { 38133e53ae1SGuo Ren unsigned long val; 38233e53ae1SGuo Ren unsigned long offset = ((opcode & 0xffff0000) >> 14); 38333e53ae1SGuo Ren 38433e53ae1SGuo Ren val = *(unsigned int *) 38533e53ae1SGuo Ren ((instruction_pointer(regs) + offset) & 0xfffffffc); 38633e53ae1SGuo Ren 38733e53ae1SGuo Ren regs->lr = addr + 4; 38833e53ae1SGuo Ren 38933e53ae1SGuo Ren instruction_pointer_set(regs, val); 39033e53ae1SGuo Ren } 391