From patchwork Tue Oct 1 15:57:58 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sandeepa Prabhu X-Patchwork-Id: 20722 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f200.google.com (mail-ve0-f200.google.com [209.85.128.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 1B64B25E05 for ; Tue, 1 Oct 2013 15:59:46 +0000 (UTC) Received: by mail-ve0-f200.google.com with SMTP id oy12sf8294298veb.11 for ; Tue, 01 Oct 2013 08:59:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=mime-version:x-gm-message-state:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=i6RuIrvVIztorgzlDibyuUpEmHCpS/hZu8UZHJ7YZog=; b=CZ5xufaGwwvUOK2G39i1mZ4QEjxdGJiCGKyyj/DRBRAaArKmRlajW1Bh5FDhfothxI 1LBjlDkYf7b5dZNMvpxEpmT/o6N/6ClLWU9a1kZlAF6ITrfny4xKXT7J0/TIcAOaMmHg JFfHJkSarDNE20vmOthBgV/zDamq6SBBLUrg4qD0fOMUvRxItJVPaZ8Ct82dYgAspZ24 sobA/mgjQ53Suq7nzjQbMRG7VTACkQP/b6IlmR5DSM3rGXEuKbsC0cI+IW2CZSee7Pn3 gV4uOGsIAPz09M2hsdjCN4ezBfORvwMqNiH4XggjOUwoLsL8xn6LBkzKQWs2ns3y57pP chIg== X-Received: by 10.236.227.165 with SMTP id d35mr9205141yhq.51.1380643185916; Tue, 01 Oct 2013 08:59:45 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.4.231 with SMTP id n7ls130734qen.14.gmail; Tue, 01 Oct 2013 08:59:45 -0700 (PDT) X-Received: by 10.58.196.148 with SMTP id im20mr916098vec.28.1380643185808; Tue, 01 Oct 2013 08:59:45 -0700 (PDT) Received: from mail-ve0-f171.google.com (mail-ve0-f171.google.com [209.85.128.171]) by mx.google.com with ESMTPS id qu3si1472945vec.26.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 01 Oct 2013 08:59:45 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.171; Received: by mail-ve0-f171.google.com with SMTP id pa12so5272907veb.2 for ; Tue, 01 Oct 2013 08:59:45 -0700 (PDT) X-Gm-Message-State: ALoCoQns+vEIrBysC6ZIfgQHjF49XQvJmGL+wdGQdI0CpimdIWz/gyYn7bboL805GCwEQZ2l45aJ X-Received: by 10.58.100.144 with SMTP id ey16mr1170610veb.25.1380643185680; Tue, 01 Oct 2013 08:59:45 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp28279vcz; Tue, 1 Oct 2013 08:59:45 -0700 (PDT) X-Received: by 10.66.145.166 with SMTP id sv6mr34113245pab.31.1380643184672; Tue, 01 Oct 2013 08:59:44 -0700 (PDT) Received: from mail-pd0-f169.google.com (mail-pd0-f169.google.com [209.85.192.169]) by mx.google.com with ESMTPS id h4si5150879pbd.143.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 01 Oct 2013 08:59:44 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.192.169 is neither permitted nor denied by best guess record for domain of sandeepa.prabhu@linaro.org) client-ip=209.85.192.169; Received: by mail-pd0-f169.google.com with SMTP id r10so7474400pdi.14 for ; Tue, 01 Oct 2013 08:59:44 -0700 (PDT) X-Received: by 10.66.240.67 with SMTP id vy3mr9700507pac.141.1380643184127; Tue, 01 Oct 2013 08:59:44 -0700 (PDT) Received: from linaro-workstation.ban.broadcom.com ([202.122.18.226]) by mx.google.com with ESMTPSA id nj9sm7593660pbc.13.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 01 Oct 2013 08:59:43 -0700 (PDT) From: Sandeepa Prabhu To: linux-arm-kernel@lists.infradead.org Cc: deepak.saxena@linaro.org, catalin.marinas@arm.com, will.deacon@arm.com, tixy@linaro.org, linaro-kernel@lists.linaro.org, patches@linaro.org, Sandeepa Prabhu Subject: [PATCH RFC v1 3/5] AArch64: Instruction simulation and decode support Date: Tue, 1 Oct 2013 21:27:58 +0530 Message-Id: <1380643080-8984-4-git-send-email-sandeepa.prabhu@linaro.org> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1380643080-8984-1-git-send-email-sandeepa.prabhu@linaro.org> References: <1380643080-8984-1-git-send-email-sandeepa.prabhu@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: sandeepa.prabhu@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Support for v8 instruction decoding and simulation is implemented, which are common for use by kprobes as well as uprobes. Kprobes/uprobes on ARM64 is leveraged on single-stepping of instruction from a out-of-line memory slot. The instructions that use PC-relative access can not be stepped from out-of-line memory slot, so are simulated in C code using the saved copy of pt_regs. This patch implements helper macros and data structures for building instruction decode table, along with handlers for instruction prepare and simulation. Signed-off-by: Sandeepa Prabhu --- arch/arm64/include/asm/probes.h | 48 ++++++++ arch/arm64/kernel/probes-aarch64.c | 235 +++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/probes-aarch64.h | 127 ++++++++++++++++++++ arch/arm64/kernel/probes-common.c | 117 ++++++++++++++++++ 4 files changed, 527 insertions(+) create mode 100644 arch/arm64/include/asm/probes.h create mode 100644 arch/arm64/kernel/probes-aarch64.c create mode 100644 arch/arm64/kernel/probes-aarch64.h create mode 100644 arch/arm64/kernel/probes-common.c diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h new file mode 100644 index 0000000..8d4355e --- /dev/null +++ b/arch/arm64/include/asm/probes.h @@ -0,0 +1,48 @@ +/* + * arch/arm64/include/asm/probes.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#ifndef _ARM_PROBES_H +#define _ARM_PROBES_H + +struct kprobe; +struct arch_specific_insn; + +typedef u32 kprobe_opcode_t; +typedef unsigned long (kprobes_pstate_check_t)(unsigned long); +typedef unsigned long +(kprobes_condition_check_t)(struct kprobe *, struct pt_regs *); +typedef void +(kprobes_prepare_t)(struct kprobe *, struct arch_specific_insn *); +typedef void (kprobes_handler_t) (struct kprobe *, struct pt_regs *); + +typedef enum { + NO_RESTORE, + RESTORE_PC, +} pc_restore_t; + +struct kprobe_pc_restore { + pc_restore_t type; + unsigned long addr; +}; + +/* architecture specific copy of original instruction */ +struct arch_specific_insn { + kprobe_opcode_t *insn; + kprobes_pstate_check_t *pstate_cc; + kprobes_condition_check_t *check_condn; + kprobes_prepare_t *prepare; + kprobes_handler_t *handler; + /* restore address after step xol */ + struct kprobe_pc_restore restore; +}; + +#endif diff --git a/arch/arm64/kernel/probes-aarch64.c b/arch/arm64/kernel/probes-aarch64.c new file mode 100644 index 0000000..0163129 --- /dev/null +++ b/arch/arm64/kernel/probes-aarch64.c @@ -0,0 +1,235 @@ +/* + * arch/arm64/kernel/probes-aarch64.c + * + * Copyright (C) 2013 Linaro Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include + +#include "probes-aarch64.h" + +#define sign_extend(x, signbit) \ + ((x) | (0 - ((x) & (1 << (signbit))))) + +#define bbl_displacement(insn) \ + sign_extend(((insn) & 0x3ffffff) << 2, 27) + +#define bcond_displacement(insn) \ + sign_extend(((insn >> 5) & 0xfffff) << 2, 21) + +#define cbz_displacement(insn) \ + sign_extend(((insn >> 5) & 0xfffff) << 2, 21) + +#define tbz_displacement(insn) \ + sign_extend(((insn >> 5) & 0x3fff) << 2, 15) + +#define ldr_displacement(insn) \ + sign_extend(((insn >> 5) & 0xfffff) << 2, 21) + +/* conditional check functions */ +static unsigned long __kprobes +__check_pstate(struct kprobe *p, struct pt_regs *regs) +{ + struct arch_specific_insn *asi = &p->ainsn; + unsigned long pstate = regs->pstate & 0xffffffff; + + return asi->pstate_cc(pstate); +} + +static unsigned long __kprobes +__check_cbz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int xn = insn & 0x1f; + + return (insn & (1 << 31)) ? + !(regs->regs[xn]) : !(regs->regs[xn] & 0xffffffff); +} + +static unsigned long __kprobes +__check_cbnz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int xn = insn & 0x1f; + + return (insn & (1 << 31)) ? + (regs->regs[xn]) : (regs->regs[xn] & 0xffffffff); +} + +static unsigned long __kprobes +__check_tbz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int xn = insn & 0x1f; + int bit_pos = ((insn & (1 << 31)) >> 26) | ((insn >> 19) & 0x1f); + + return ~((regs->regs[xn] >> bit_pos) & 0x1); +} + +static unsigned long __kprobes +__check_tbnz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int xn = insn & 0x1f; + int bit_pos = ((insn & (1 << 31)) >> 26) | ((insn >> 19) & 0x1f); + + return (regs->regs[xn] >> bit_pos) & 0x1; +} + +/* prepare functions */ +void __kprobes prepare_none(struct kprobe *p, struct arch_specific_insn *asi) +{ +} + +void __kprobes prepare_bcond(struct kprobe *p, struct arch_specific_insn *asi) +{ + kprobe_opcode_t insn = p->opcode; + + asi->check_condn = __check_pstate; + asi->pstate_cc = kprobe_condition_checks[insn & 0xf]; +} + +void __kprobes +prepare_cbz_cbnz(struct kprobe *p, struct arch_specific_insn *asi) +{ + kprobe_opcode_t insn = p->opcode; + + asi->check_condn = (insn & (1 << 24)) ? __check_cbnz : __check_cbz; +} + +void __kprobes +prepare_tbz_tbnz(struct kprobe *p, struct arch_specific_insn *asi) +{ + kprobe_opcode_t insn = p->opcode; + + asi->check_condn = (insn & (1 << 24)) ? __check_tbnz : __check_tbz; +} + +/* simulate functions */ +void __kprobes simulate_none(struct kprobe *p, struct pt_regs *regs) +{ +} + +void __kprobes simulate_adr_adrp(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + long res, imm, xn; + + xn = insn & 0x1f; + imm = ((insn >> 3) & 0xffffc) | ((insn >> 29) & 0x3); + res = iaddr + 8 + sign_extend(imm, 20); + + regs->regs[xn] = insn & 0x80000000 ? res & 0xfffffffffffff000 : res; + instruction_pointer(regs) += 4; + + return; +} + +void __kprobes simulate_b_bl(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = bbl_displacement(insn); + + /* Link register */ + if (insn & (1 << 31)) + regs->regs[30] = iaddr + 4; + + instruction_pointer(regs) = iaddr + disp; + + return; +} + +void __kprobes simulate_b_cond(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = bcond_displacement(insn); + + instruction_pointer(regs) = iaddr + disp; + + return; +} + +void __kprobes simulate_br_blr_ret(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int xn = (insn >> 5) & 0x1f; + + /* BLR */ + if (((insn >> 21) & 0x3) == 1) + regs->regs[30] = iaddr + 4; + + instruction_pointer(regs) = regs->regs[xn]; + + return; +} + +void __kprobes simulate_cbz_cbnz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = cbz_displacement(insn); + + instruction_pointer(regs) = iaddr + disp; + + return; +} + +void __kprobes simulate_tbz_tbnz(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = tbz_displacement(insn); + + instruction_pointer(regs) = iaddr + disp; + + return; +} + +void __kprobes simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + u64 *load_addr; + long iaddr = (long)p->addr; + int xn = insn & 0x1f; + int disp = ldr_displacement(insn); + + load_addr = (u64 *) (iaddr + disp); + + if (insn & (1 << 30)) /* x0-x31 */ + regs->regs[xn] = *load_addr; + else /* w0-w31 */ + *(u32 *) (®s->regs[xn]) = (*(u32 *) (load_addr)); + + return; +} + +void __kprobes simulate_ldrsw_literal(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + u64 *load_addr; + long data, iaddr = (long)p->addr; + int xn = insn & 0x1f; + int disp = ldr_displacement(insn); + + load_addr = (u64 *) (iaddr + disp); + data = *load_addr; + + regs->regs[xn] = sign_extend(data, 63); + + return; +} diff --git a/arch/arm64/kernel/probes-aarch64.h b/arch/arm64/kernel/probes-aarch64.h new file mode 100644 index 0000000..fb7475c --- /dev/null +++ b/arch/arm64/kernel/probes-aarch64.h @@ -0,0 +1,127 @@ +/* + * arch/arm64/kernel/probes-aarch64.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _ARM_KERNEL_PROBES_AARCH64_H +#define _ARM_KERNEL_PROBES_AARCH64_H + +/* + * The following definitions and macros are used to build instruction + * decoding tables. + */ +enum decode_type { + DECODE_TYPE_END, + DECODE_TYPE_REJECT, + DECODE_TYPE_SINGLESTEP, + DECODE_TYPE_SIMULATE, + DECODE_TYPE_TABLE, + NUM_DECODE_TYPES, /* Must be last enum */ +}; + +struct aarch64_decode_item; + +struct aarch64_decode_header { + enum decode_type type; + u32 mask; + u32 val; +}; + +struct aarch64_decode_actions { + kprobes_prepare_t *prepare; + kprobes_handler_t *handler; +}; + +struct aarch64_decode_table { + const struct aarch64_decode_item *tbl; +}; + +union aarch64_decode_handler { + struct aarch64_decode_actions actions; + struct aarch64_decode_table table; +}; + +struct aarch64_decode_item { + struct aarch64_decode_header header; + union aarch64_decode_handler decode; +}; + +#define decode_get_type(_entry) ((_entry).header.type) + +#define decode_table_end(_entry) \ + ((_entry).header.type == DECODE_TYPE_END) + +#define decode_table_hit(_entry, insn) \ + ((insn & (_entry).header.mask) == (_entry).header.val) + +#define decode_prepare_fn(_entry) ((_entry).decode.actions.prepare) +#define decode_handler_fn(_entry) ((_entry).decode.actions.handler) +#define decode_sub_table(_entry) ((_entry).decode.table.tbl) + +#define DECODE_ADD_HEADER(_type, _val, _mask) \ + .header = { \ + .type = _type, \ + .mask = _mask, \ + .val = _val, \ + }, + +#define DECODE_ADD_ACTION(_prepare, _handler) \ + .decode = { \ + .actions = { \ + .prepare = _prepare, \ + .handler = _handler, \ + } \ + }, + +#define DECODE_ADD_TABLE(_table) \ + .decode = { \ + .table = {.tbl = _table} \ + }, + +#define DECODE_REJECT(_v, _m) \ + { DECODE_ADD_HEADER(DECODE_TYPE_REJECT, _v, _m) } + +#define DECODE_SINGLESTEP(_v, _m) \ + { DECODE_ADD_HEADER(DECODE_TYPE_SINGLESTEP, _v, _m) } + +#define DECODE_SIMULATE(_v, _m, _p, _h) \ + { DECODE_ADD_HEADER(DECODE_TYPE_SIMULATE, _v, _m) \ + DECODE_ADD_ACTION(_p, _h) } + +#define DECODE_TABLE(_v, _m, _table) \ + { DECODE_ADD_HEADER(DECODE_TYPE_TABLE, _v, _m) \ + DECODE_ADD_TABLE(_table) } + +#define DECODE_LITERAL(_v, _m, _p, _h) DECODE_SIMULATE(_v, _m, _p, _h) +#define DECODE_BRANCH(_v, _m, _p, _h) DECODE_SIMULATE(_v, _m, _p, _h) + +/* should be the last element in decode structure */ +#define DECODE_END { .header = {.type = DECODE_TYPE_END, } } + +extern kprobes_pstate_check_t *const kprobe_condition_checks[16]; + +void __kprobes prepare_none(struct kprobe *p, struct arch_specific_insn *asi); +void __kprobes prepare_bcond(struct kprobe *p, struct arch_specific_insn *asi); +void __kprobes prepare_cbz_cbnz(struct kprobe *p, + struct arch_specific_insn *asi); +void __kprobes prepare_tbz_tbnz(struct kprobe *p, + struct arch_specific_insn *asi); +void __kprobes simulate_none(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_adr_adrp(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_b_bl(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_b_cond(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_br_blr_ret(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_cbz_cbnz(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_tbz_tbnz(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_ldrsw_literal(struct kprobe *p, struct pt_regs *regs); + +#endif /* _ARM_KERNEL_PROBES_AARCH64_H */ diff --git a/arch/arm64/kernel/probes-common.c b/arch/arm64/kernel/probes-common.c new file mode 100644 index 0000000..4990940 --- /dev/null +++ b/arch/arm64/kernel/probes-common.c @@ -0,0 +1,117 @@ +/* + * arch/arm64/kernel/probes-common.c + * + * copied from arch/arm/kernel/kprobes-common.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Description: + * This file is the place for common routines for AArch64 and + * AArch32 conditional checks, needed by kprobes-AArch64 and + * uprobes-AArch32/AArch64 + * + * AArch64 and AArch32 instrcution decoding differ, and are implemented + * in respective probes-*** files, this file is for common code only. + */ +#include +#include +#include + +static unsigned long __kprobes __check_eq(unsigned long pstate) +{ + return pstate & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_ne(unsigned long pstate) +{ + return (~pstate) & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_cs(unsigned long pstate) +{ + return pstate & PSR_C_BIT; +} + +static unsigned long __kprobes __check_cc(unsigned long pstate) +{ + return (~pstate) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_mi(unsigned long pstate) +{ + return pstate & PSR_N_BIT; +} + +static unsigned long __kprobes __check_pl(unsigned long pstate) +{ + return (~pstate) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_vs(unsigned long pstate) +{ + return pstate & PSR_V_BIT; +} + +static unsigned long __kprobes __check_vc(unsigned long pstate) +{ + return (~pstate) & PSR_V_BIT; +} + +static unsigned long __kprobes __check_hi(unsigned long pstate) +{ + pstate &= ~(pstate >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return pstate & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ls(unsigned long pstate) +{ + pstate &= ~(pstate >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (~pstate) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ge(unsigned long pstate) +{ + pstate ^= (pstate << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (~pstate) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_lt(unsigned long pstate) +{ + pstate ^= (pstate << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return pstate & PSR_N_BIT; +} + +static unsigned long __kprobes __check_gt(unsigned long pstate) +{ + /*PSR_N_BIT ^= PSR_V_BIT */ + unsigned long temp = pstate ^ (pstate << 3); + temp |= (pstate << 1); /*PSR_N_BIT |= PSR_Z_BIT */ + return (~temp) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_le(unsigned long pstate) +{ + /*PSR_N_BIT ^= PSR_V_BIT */ + unsigned long temp = pstate ^ (pstate << 3); + temp |= (pstate << 1); /*PSR_N_BIT |= PSR_Z_BIT */ + return temp & PSR_N_BIT; +} + +static unsigned long __kprobes __check_al(unsigned long pstate) +{ + return true; +} + +kprobes_pstate_check_t *const kprobe_condition_checks[16] = { + &__check_eq, &__check_ne, &__check_cs, &__check_cc, + &__check_mi, &__check_pl, &__check_vs, &__check_vc, + &__check_hi, &__check_ls, &__check_ge, &__check_lt, + &__check_gt, &__check_le, &__check_al, &__check_al +};