12a0a5b22SJan Willeke /* 22a0a5b22SJan Willeke * User-space Probes (UProbes) for s390 32a0a5b22SJan Willeke * 42a0a5b22SJan Willeke * Copyright IBM Corp. 2014 52a0a5b22SJan Willeke * Author(s): Jan Willeke, 62a0a5b22SJan Willeke */ 72a0a5b22SJan Willeke 82a0a5b22SJan Willeke #include <linux/uaccess.h> 92a0a5b22SJan Willeke #include <linux/uprobes.h> 102a0a5b22SJan Willeke #include <linux/compat.h> 112a0a5b22SJan Willeke #include <linux/kdebug.h> 122a0a5b22SJan Willeke #include <asm/switch_to.h> 132a0a5b22SJan Willeke #include <asm/facility.h> 14d6fe5be3SJan Willeke #include <asm/kprobes.h> 152a0a5b22SJan Willeke #include <asm/dis.h> 162a0a5b22SJan Willeke #include "entry.h" 172a0a5b22SJan Willeke 182a0a5b22SJan Willeke #define UPROBE_TRAP_NR UINT_MAX 192a0a5b22SJan Willeke 202a0a5b22SJan Willeke int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, 212a0a5b22SJan Willeke unsigned long addr) 222a0a5b22SJan Willeke { 232a0a5b22SJan Willeke return probe_is_prohibited_opcode(auprobe->insn); 242a0a5b22SJan Willeke } 252a0a5b22SJan Willeke 262a0a5b22SJan Willeke int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 272a0a5b22SJan Willeke { 282a0a5b22SJan Willeke if (psw_bits(regs->psw).eaba == PSW_AMODE_24BIT) 292a0a5b22SJan Willeke return -EINVAL; 302a0a5b22SJan Willeke if (!is_compat_task() && psw_bits(regs->psw).eaba == PSW_AMODE_31BIT) 312a0a5b22SJan Willeke return -EINVAL; 322a0a5b22SJan Willeke clear_pt_regs_flag(regs, PIF_PER_TRAP); 332a0a5b22SJan Willeke auprobe->saved_per = psw_bits(regs->psw).r; 342a0a5b22SJan Willeke auprobe->saved_int_code = regs->int_code; 352a0a5b22SJan Willeke regs->int_code = UPROBE_TRAP_NR; 362a0a5b22SJan Willeke regs->psw.addr = current->utask->xol_vaddr; 372a0a5b22SJan Willeke set_tsk_thread_flag(current, TIF_UPROBE_SINGLESTEP); 382a0a5b22SJan Willeke update_cr_regs(current); 392a0a5b22SJan Willeke return 0; 402a0a5b22SJan Willeke } 412a0a5b22SJan Willeke 422a0a5b22SJan Willeke bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) 432a0a5b22SJan Willeke { 442a0a5b22SJan Willeke struct pt_regs *regs = task_pt_regs(tsk); 452a0a5b22SJan Willeke 462a0a5b22SJan Willeke if (regs->int_code != UPROBE_TRAP_NR) 472a0a5b22SJan Willeke return true; 482a0a5b22SJan Willeke return false; 492a0a5b22SJan Willeke } 502a0a5b22SJan Willeke 512a0a5b22SJan Willeke int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 522a0a5b22SJan Willeke { 532a0a5b22SJan Willeke int fixup = probe_get_fixup_type(auprobe->insn); 542a0a5b22SJan Willeke struct uprobe_task *utask = current->utask; 552a0a5b22SJan Willeke 562a0a5b22SJan Willeke clear_tsk_thread_flag(current, TIF_UPROBE_SINGLESTEP); 572a0a5b22SJan Willeke update_cr_regs(current); 582a0a5b22SJan Willeke psw_bits(regs->psw).r = auprobe->saved_per; 592a0a5b22SJan Willeke regs->int_code = auprobe->saved_int_code; 602a0a5b22SJan Willeke 612a0a5b22SJan Willeke if (fixup & FIXUP_PSW_NORMAL) 622a0a5b22SJan Willeke regs->psw.addr += utask->vaddr - utask->xol_vaddr; 632a0a5b22SJan Willeke if (fixup & FIXUP_RETURN_REGISTER) { 642a0a5b22SJan Willeke int reg = (auprobe->insn[0] & 0xf0) >> 4; 652a0a5b22SJan Willeke 662a0a5b22SJan Willeke regs->gprs[reg] += utask->vaddr - utask->xol_vaddr; 672a0a5b22SJan Willeke } 682a0a5b22SJan Willeke if (fixup & FIXUP_BRANCH_NOT_TAKEN) { 692a0a5b22SJan Willeke int ilen = insn_length(auprobe->insn[0] >> 8); 702a0a5b22SJan Willeke 712a0a5b22SJan Willeke if (regs->psw.addr - utask->xol_vaddr == ilen) 722a0a5b22SJan Willeke regs->psw.addr = utask->vaddr + ilen; 732a0a5b22SJan Willeke } 742a0a5b22SJan Willeke /* If per tracing was active generate trap */ 752a0a5b22SJan Willeke if (regs->psw.mask & PSW_MASK_PER) 762a0a5b22SJan Willeke do_per_trap(regs); 772a0a5b22SJan Willeke return 0; 782a0a5b22SJan Willeke } 792a0a5b22SJan Willeke 802a0a5b22SJan Willeke int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, 812a0a5b22SJan Willeke void *data) 822a0a5b22SJan Willeke { 832a0a5b22SJan Willeke struct die_args *args = data; 842a0a5b22SJan Willeke struct pt_regs *regs = args->regs; 852a0a5b22SJan Willeke 862a0a5b22SJan Willeke if (!user_mode(regs)) 872a0a5b22SJan Willeke return NOTIFY_DONE; 882a0a5b22SJan Willeke if (regs->int_code & 0x200) /* Trap during transaction */ 892a0a5b22SJan Willeke return NOTIFY_DONE; 902a0a5b22SJan Willeke switch (val) { 912a0a5b22SJan Willeke case DIE_BPT: 922a0a5b22SJan Willeke if (uprobe_pre_sstep_notifier(regs)) 932a0a5b22SJan Willeke return NOTIFY_STOP; 942a0a5b22SJan Willeke break; 952a0a5b22SJan Willeke case DIE_SSTEP: 962a0a5b22SJan Willeke if (uprobe_post_sstep_notifier(regs)) 972a0a5b22SJan Willeke return NOTIFY_STOP; 982a0a5b22SJan Willeke default: 992a0a5b22SJan Willeke break; 1002a0a5b22SJan Willeke } 1012a0a5b22SJan Willeke return NOTIFY_DONE; 1022a0a5b22SJan Willeke } 1032a0a5b22SJan Willeke 1042a0a5b22SJan Willeke void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 1052a0a5b22SJan Willeke { 1062a0a5b22SJan Willeke clear_thread_flag(TIF_UPROBE_SINGLESTEP); 1072a0a5b22SJan Willeke regs->int_code = auprobe->saved_int_code; 1082a0a5b22SJan Willeke regs->psw.addr = current->utask->vaddr; 1092a0a5b22SJan Willeke } 1102a0a5b22SJan Willeke 1112a0a5b22SJan Willeke unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline, 1122a0a5b22SJan Willeke struct pt_regs *regs) 1132a0a5b22SJan Willeke { 1142a0a5b22SJan Willeke unsigned long orig; 1152a0a5b22SJan Willeke 1162a0a5b22SJan Willeke orig = regs->gprs[14]; 1172a0a5b22SJan Willeke regs->gprs[14] = trampoline; 1182a0a5b22SJan Willeke return orig; 1192a0a5b22SJan Willeke } 1202a0a5b22SJan Willeke 1212a0a5b22SJan Willeke /* Instruction Emulation */ 1222a0a5b22SJan Willeke 1232a0a5b22SJan Willeke static void adjust_psw_addr(psw_t *psw, unsigned long len) 1242a0a5b22SJan Willeke { 1252a0a5b22SJan Willeke psw->addr = __rewind_psw(*psw, -len); 1262a0a5b22SJan Willeke } 1272a0a5b22SJan Willeke 1282a0a5b22SJan Willeke #define EMU_ILLEGAL_OP 1 1292a0a5b22SJan Willeke #define EMU_SPECIFICATION 2 1302a0a5b22SJan Willeke #define EMU_ADDRESSING 3 1312a0a5b22SJan Willeke 1322a0a5b22SJan Willeke #define emu_load_ril(ptr, output) \ 1332a0a5b22SJan Willeke ({ \ 1342a0a5b22SJan Willeke unsigned int mask = sizeof(*(ptr)) - 1; \ 1352a0a5b22SJan Willeke __typeof__(*(ptr)) input; \ 1362a0a5b22SJan Willeke int __rc = 0; \ 1372a0a5b22SJan Willeke \ 1382a0a5b22SJan Willeke if (!test_facility(34)) \ 1392a0a5b22SJan Willeke __rc = EMU_ILLEGAL_OP; \ 1402a0a5b22SJan Willeke else if ((u64 __force)ptr & mask) \ 1412a0a5b22SJan Willeke __rc = EMU_SPECIFICATION; \ 1422a0a5b22SJan Willeke else if (get_user(input, ptr)) \ 1432a0a5b22SJan Willeke __rc = EMU_ADDRESSING; \ 1442a0a5b22SJan Willeke else \ 1452a0a5b22SJan Willeke *(output) = input; \ 1462a0a5b22SJan Willeke __rc; \ 1472a0a5b22SJan Willeke }) 1482a0a5b22SJan Willeke 1492a0a5b22SJan Willeke #define emu_store_ril(ptr, input) \ 1502a0a5b22SJan Willeke ({ \ 1512a0a5b22SJan Willeke unsigned int mask = sizeof(*(ptr)) - 1; \ 1522a0a5b22SJan Willeke int __rc = 0; \ 1532a0a5b22SJan Willeke \ 1542a0a5b22SJan Willeke if (!test_facility(34)) \ 1552a0a5b22SJan Willeke __rc = EMU_ILLEGAL_OP; \ 1562a0a5b22SJan Willeke else if ((u64 __force)ptr & mask) \ 1572a0a5b22SJan Willeke __rc = EMU_SPECIFICATION; \ 1582a0a5b22SJan Willeke else if (put_user(*(input), ptr)) \ 1592a0a5b22SJan Willeke __rc = EMU_ADDRESSING; \ 1602a0a5b22SJan Willeke __rc; \ 1612a0a5b22SJan Willeke }) 1622a0a5b22SJan Willeke 1632a0a5b22SJan Willeke #define emu_cmp_ril(regs, ptr, cmp) \ 1642a0a5b22SJan Willeke ({ \ 1652a0a5b22SJan Willeke unsigned int mask = sizeof(*(ptr)) - 1; \ 1662a0a5b22SJan Willeke __typeof__(*(ptr)) input; \ 1672a0a5b22SJan Willeke int __rc = 0; \ 1682a0a5b22SJan Willeke \ 1692a0a5b22SJan Willeke if (!test_facility(34)) \ 1702a0a5b22SJan Willeke __rc = EMU_ILLEGAL_OP; \ 1712a0a5b22SJan Willeke else if ((u64 __force)ptr & mask) \ 1722a0a5b22SJan Willeke __rc = EMU_SPECIFICATION; \ 1732a0a5b22SJan Willeke else if (get_user(input, ptr)) \ 1742a0a5b22SJan Willeke __rc = EMU_ADDRESSING; \ 1752a0a5b22SJan Willeke else if (input > *(cmp)) \ 1762a0a5b22SJan Willeke psw_bits((regs)->psw).cc = 1; \ 1772a0a5b22SJan Willeke else if (input < *(cmp)) \ 1782a0a5b22SJan Willeke psw_bits((regs)->psw).cc = 2; \ 1792a0a5b22SJan Willeke else \ 1802a0a5b22SJan Willeke psw_bits((regs)->psw).cc = 0; \ 1812a0a5b22SJan Willeke __rc; \ 1822a0a5b22SJan Willeke }) 1832a0a5b22SJan Willeke 1842a0a5b22SJan Willeke struct insn_ril { 1852a0a5b22SJan Willeke u8 opc0; 1862a0a5b22SJan Willeke u8 reg : 4; 1872a0a5b22SJan Willeke u8 opc1 : 4; 1882a0a5b22SJan Willeke s32 disp; 1892a0a5b22SJan Willeke } __packed; 1902a0a5b22SJan Willeke 1912a0a5b22SJan Willeke union split_register { 1922a0a5b22SJan Willeke u64 u64; 1932a0a5b22SJan Willeke u32 u32[2]; 1942a0a5b22SJan Willeke u16 u16[4]; 1952a0a5b22SJan Willeke s64 s64; 1962a0a5b22SJan Willeke s32 s32[2]; 1972a0a5b22SJan Willeke s16 s16[4]; 1982a0a5b22SJan Willeke }; 1992a0a5b22SJan Willeke 2002a0a5b22SJan Willeke /* 2012a0a5b22SJan Willeke * pc relative instructions are emulated, since parameters may not be 2022a0a5b22SJan Willeke * accessible from the xol area due to range limitations. 2032a0a5b22SJan Willeke */ 2042a0a5b22SJan Willeke static void handle_insn_ril(struct arch_uprobe *auprobe, struct pt_regs *regs) 2052a0a5b22SJan Willeke { 2062a0a5b22SJan Willeke union split_register *rx; 2072a0a5b22SJan Willeke struct insn_ril *insn; 2082a0a5b22SJan Willeke unsigned int ilen; 2092a0a5b22SJan Willeke void *uptr; 2102a0a5b22SJan Willeke int rc = 0; 2112a0a5b22SJan Willeke 2122a0a5b22SJan Willeke insn = (struct insn_ril *) &auprobe->insn; 2132a0a5b22SJan Willeke rx = (union split_register *) ®s->gprs[insn->reg]; 2142a0a5b22SJan Willeke uptr = (void *)(regs->psw.addr + (insn->disp * 2)); 2152a0a5b22SJan Willeke ilen = insn_length(insn->opc0); 2162a0a5b22SJan Willeke 2172a0a5b22SJan Willeke switch (insn->opc0) { 2182a0a5b22SJan Willeke case 0xc0: 2192a0a5b22SJan Willeke switch (insn->opc1) { 2202a0a5b22SJan Willeke case 0x00: /* larl */ 2212a0a5b22SJan Willeke rx->u64 = (unsigned long)uptr; 2222a0a5b22SJan Willeke break; 2232a0a5b22SJan Willeke } 2242a0a5b22SJan Willeke break; 2252a0a5b22SJan Willeke case 0xc4: 2262a0a5b22SJan Willeke switch (insn->opc1) { 2272a0a5b22SJan Willeke case 0x02: /* llhrl */ 2282a0a5b22SJan Willeke rc = emu_load_ril((u16 __user *)uptr, &rx->u32[1]); 2292a0a5b22SJan Willeke break; 2302a0a5b22SJan Willeke case 0x04: /* lghrl */ 2312a0a5b22SJan Willeke rc = emu_load_ril((s16 __user *)uptr, &rx->u64); 2322a0a5b22SJan Willeke break; 2332a0a5b22SJan Willeke case 0x05: /* lhrl */ 2342a0a5b22SJan Willeke rc = emu_load_ril((s16 __user *)uptr, &rx->u32[1]); 2352a0a5b22SJan Willeke break; 2362a0a5b22SJan Willeke case 0x06: /* llghrl */ 2372a0a5b22SJan Willeke rc = emu_load_ril((u16 __user *)uptr, &rx->u64); 2382a0a5b22SJan Willeke break; 2392a0a5b22SJan Willeke case 0x08: /* lgrl */ 2402a0a5b22SJan Willeke rc = emu_load_ril((u64 __user *)uptr, &rx->u64); 2412a0a5b22SJan Willeke break; 2422a0a5b22SJan Willeke case 0x0c: /* lgfrl */ 2432a0a5b22SJan Willeke rc = emu_load_ril((s32 __user *)uptr, &rx->u64); 2442a0a5b22SJan Willeke break; 2452a0a5b22SJan Willeke case 0x0d: /* lrl */ 2462a0a5b22SJan Willeke rc = emu_load_ril((u32 __user *)uptr, &rx->u32[1]); 2472a0a5b22SJan Willeke break; 2482a0a5b22SJan Willeke case 0x0e: /* llgfrl */ 2492a0a5b22SJan Willeke rc = emu_load_ril((u32 __user *)uptr, &rx->u64); 2502a0a5b22SJan Willeke break; 2512a0a5b22SJan Willeke case 0x07: /* sthrl */ 2522a0a5b22SJan Willeke rc = emu_store_ril((u16 __user *)uptr, &rx->u16[3]); 2532a0a5b22SJan Willeke break; 2542a0a5b22SJan Willeke case 0x0b: /* stgrl */ 2552a0a5b22SJan Willeke rc = emu_store_ril((u64 __user *)uptr, &rx->u64); 2562a0a5b22SJan Willeke break; 2572a0a5b22SJan Willeke case 0x0f: /* strl */ 2582a0a5b22SJan Willeke rc = emu_store_ril((u32 __user *)uptr, &rx->u32[1]); 2592a0a5b22SJan Willeke break; 2602a0a5b22SJan Willeke } 2612a0a5b22SJan Willeke break; 2622a0a5b22SJan Willeke case 0xc6: 2632a0a5b22SJan Willeke switch (insn->opc1) { 2642a0a5b22SJan Willeke case 0x02: /* pfdrl */ 2652a0a5b22SJan Willeke if (!test_facility(34)) 2662a0a5b22SJan Willeke rc = EMU_ILLEGAL_OP; 2672a0a5b22SJan Willeke break; 2682a0a5b22SJan Willeke case 0x04: /* cghrl */ 2692a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (s16 __user *)uptr, &rx->s64); 2702a0a5b22SJan Willeke break; 2712a0a5b22SJan Willeke case 0x05: /* chrl */ 2722a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (s16 __user *)uptr, &rx->s32[1]); 2732a0a5b22SJan Willeke break; 2742a0a5b22SJan Willeke case 0x06: /* clghrl */ 2752a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (u16 __user *)uptr, &rx->u64); 2762a0a5b22SJan Willeke break; 2772a0a5b22SJan Willeke case 0x07: /* clhrl */ 2782a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (u16 __user *)uptr, &rx->u32[1]); 2792a0a5b22SJan Willeke break; 2802a0a5b22SJan Willeke case 0x08: /* cgrl */ 2812a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (s64 __user *)uptr, &rx->s64); 2822a0a5b22SJan Willeke break; 2832a0a5b22SJan Willeke case 0x0a: /* clgrl */ 2842a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (u64 __user *)uptr, &rx->u64); 2852a0a5b22SJan Willeke break; 2862a0a5b22SJan Willeke case 0x0c: /* cgfrl */ 2872a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (s32 __user *)uptr, &rx->s64); 2882a0a5b22SJan Willeke break; 2892a0a5b22SJan Willeke case 0x0d: /* crl */ 2902a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (s32 __user *)uptr, &rx->s32[1]); 2912a0a5b22SJan Willeke break; 2922a0a5b22SJan Willeke case 0x0e: /* clgfrl */ 2932a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (u32 __user *)uptr, &rx->u64); 2942a0a5b22SJan Willeke break; 2952a0a5b22SJan Willeke case 0x0f: /* clrl */ 2962a0a5b22SJan Willeke rc = emu_cmp_ril(regs, (u32 __user *)uptr, &rx->u32[1]); 2972a0a5b22SJan Willeke break; 2982a0a5b22SJan Willeke } 2992a0a5b22SJan Willeke break; 3002a0a5b22SJan Willeke } 3012a0a5b22SJan Willeke adjust_psw_addr(®s->psw, ilen); 3022a0a5b22SJan Willeke switch (rc) { 3032a0a5b22SJan Willeke case EMU_ILLEGAL_OP: 3042a0a5b22SJan Willeke regs->int_code = ilen << 16 | 0x0001; 3052a0a5b22SJan Willeke do_report_trap(regs, SIGILL, ILL_ILLOPC, NULL); 3062a0a5b22SJan Willeke break; 3072a0a5b22SJan Willeke case EMU_SPECIFICATION: 3082a0a5b22SJan Willeke regs->int_code = ilen << 16 | 0x0006; 3092a0a5b22SJan Willeke do_report_trap(regs, SIGILL, ILL_ILLOPC , NULL); 3102a0a5b22SJan Willeke break; 3112a0a5b22SJan Willeke case EMU_ADDRESSING: 3122a0a5b22SJan Willeke regs->int_code = ilen << 16 | 0x0005; 3132a0a5b22SJan Willeke do_report_trap(regs, SIGSEGV, SEGV_MAPERR, NULL); 3142a0a5b22SJan Willeke break; 3152a0a5b22SJan Willeke } 3162a0a5b22SJan Willeke } 3172a0a5b22SJan Willeke 3182a0a5b22SJan Willeke bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) 3192a0a5b22SJan Willeke { 3202a0a5b22SJan Willeke if ((psw_bits(regs->psw).eaba == PSW_AMODE_24BIT) || 3212a0a5b22SJan Willeke ((psw_bits(regs->psw).eaba == PSW_AMODE_31BIT) && 3222a0a5b22SJan Willeke !is_compat_task())) { 3232a0a5b22SJan Willeke regs->psw.addr = __rewind_psw(regs->psw, UPROBE_SWBP_INSN_SIZE); 3242a0a5b22SJan Willeke do_report_trap(regs, SIGILL, ILL_ILLADR, NULL); 3252a0a5b22SJan Willeke return true; 3262a0a5b22SJan Willeke } 3272a0a5b22SJan Willeke if (probe_is_insn_relative_long(auprobe->insn)) { 3282a0a5b22SJan Willeke handle_insn_ril(auprobe, regs); 3292a0a5b22SJan Willeke return true; 3302a0a5b22SJan Willeke } 3312a0a5b22SJan Willeke return false; 3322a0a5b22SJan Willeke } 333