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: 2970811 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9A75CBFF0B for ; Tue, 1 Oct 2013 16:01:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CF9B62013B for ; Tue, 1 Oct 2013 16:01:26 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B2E60201FD for ; Tue, 1 Oct 2013 16:01:20 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VR2NP-0004tm-EG; Tue, 01 Oct 2013 16:00:43 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VR2NH-0005mG-B0; Tue, 01 Oct 2013 16:00:35 +0000 Received: from mail-pb0-f50.google.com ([209.85.160.50]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VR2Mn-0005cv-JE for linux-arm-kernel@lists.infradead.org; Tue, 01 Oct 2013 16:00:07 +0000 Received: by mail-pb0-f50.google.com with SMTP id uo5so7272287pbc.23 for ; Tue, 01 Oct 2013 08:59:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=i6RuIrvVIztorgzlDibyuUpEmHCpS/hZu8UZHJ7YZog=; b=RDc6kkvHbOCSn3xu0eP5gsTxdYqF7Onk0Veu0cANtPIGZlzJSsRjqhzTOp0NgcXATR sMQVH1YX5MuHRhV4NRubKCbm+ZNSsA1gUpv5ORg0v1sqOBJ3vPu95Z3NAcaGksZIuJDT 1xH3s3jqZI4V9DQxkGu0pncFp3Qr3pet7/VvLYedg8oPYmxXt2+PQ06qOOmqCXC2JrGp NuODcxpf3AReUrevD4gzsjvQ26O6GGXpgOAc7XwRQzdfAq4v0K7xaG+SOr0GoFNhddUf xqz1/zuu9s/hsW665EO6fxVWbKzqZcQvrzhX78khk/pOF6EZDtlczsjKJ0EL096vox3e QttQ== X-Gm-Message-State: ALoCoQkCDsh9bTI5GDzkPfwg872DNPlA4TfAeJLKSMmHQdHNwLr9FUCsZTalCWnHPXBiVj2bkrOF 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 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-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131001_120005_853031_3F82837B X-CRM114-Status: GOOD ( 17.60 ) X-Spam-Score: -2.6 (--) Cc: tixy@linaro.org, deepak.saxena@linaro.org, linaro-kernel@lists.linaro.org, patches@linaro.org, Sandeepa Prabhu , catalin.marinas@arm.com, will.deacon@arm.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 +};