From patchwork Fri Jul 8 16:35:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Long X-Patchwork-Id: 71686 Delivered-To: patches@linaro.org Received: by 10.140.28.4 with SMTP id 4csp540310qgy; Fri, 8 Jul 2016 09:36:08 -0700 (PDT) X-Received: by 10.129.106.215 with SMTP id f206mr5164155ywc.90.1467995764554; Fri, 08 Jul 2016 09:36:04 -0700 (PDT) Return-Path: Received: from mail-qt0-x235.google.com (mail-qt0-x235.google.com. [2607:f8b0:400d:c0d::235]) by mx.google.com with ESMTPS id n78si2480986qkl.217.2016.07.08.09.36.04 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 08 Jul 2016 09:36:04 -0700 (PDT) Received-SPF: pass (google.com: domain of dave.long@linaro.org designates 2607:f8b0:400d:c0d::235 as permitted sender) client-ip=2607:f8b0:400d:c0d::235; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: domain of dave.long@linaro.org designates 2607:f8b0:400d:c0d::235 as permitted sender) smtp.mailfrom=dave.long@linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by mail-qt0-x235.google.com with SMTP id f89so23692370qtd.2 for ; Fri, 08 Jul 2016 09:36:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bwpGrusQ3S+QovMdJFhe1xzevahW61DGFIrhqc5X3rA=; b=iptLcNkFxLYZDvRg7FryOSOEhvuOUvZwxcHEQTcoyhwIKD27ms/sJBuX+UPuw/HuYA iSAt4r4xsEsNhKXs3LVR7OhTS9KI6LiygUqcZL3gjKx1rcfhKTBPmxQxQRIVXMX+zjjF 6oyhEalNveocWUJ7Dw6ZZyQ0aphc6F/P897uY= 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=bwpGrusQ3S+QovMdJFhe1xzevahW61DGFIrhqc5X3rA=; b=jkJt9Y4BQbdlImMJX93OnkzzTBsFPCWzjiGz6mrzPZk25wAyYfm5N16ZsERSx6Ur/D FLub5B1obqxZk/iAv9pg58HP9YzI6vgZ5L7aQW+UtX8WR6ce1JvnFhr6PsYwS9LM9UNb lAji5PhWERNix9lpGaCGb6RnzeOez2s6fJqhqrSqHpQ0iSUNhRMd7t5YkiuwC+qzcvcs FXpvQpoJi8EkM7ljHdb+SPayCE+vaoTjyFRAhlHDgEzPJkK3bES/iCot783DnhWSG4N1 xsLZv7CStOTqz5ZgOcAJVfe+EHJQOamONBXEgCSxphANHwL+NZccsLNgwAmNHSjAs+Jk 9Klg== X-Gm-Message-State: ALyK8tKDbuU/1QIz8XQNCps8p2hSd9tguK2CCzcZHxLnbmTphU4LUIr1NOSDXXd1hYTw2TDIK8I= X-Received: by 10.237.36.108 with SMTP id s41mr9914779qtc.66.1467995764134; Fri, 08 Jul 2016 09:36:04 -0700 (PDT) Return-Path: Received: from localhost.localdomain (pool-72-71-243-181.cncdnh.fast00.myfairpoint.net. [72.71.243.181]) by smtp.googlemail.com with ESMTPSA id l27sm2254627qtc.34.2016.07.08.09.36.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 08 Jul 2016 09:36:03 -0700 (PDT) From: David Long To: Catalin Marinas , Huang Shijie , James Morse , Marc Zyngier , Pratyush Anand , Sandeepa Prabhu , Will Deacon , William Cohen , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Steve Capper , Masami Hiramatsu , Li Bin Cc: Adam Buchbinder , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Andrew Morton , Andrey Ryabinin , Ard Biesheuvel , Christoffer Dall , Daniel Thompson , Dave P Martin , Jens Wiklander , Jisheng Zhang , John Blackwood , Mark Rutland , Petr Mladek , Robin Murphy , Suzuki K Poulose , Vladimir Murzin , Yang Shi , Zi Shen Lim , yalin wang , Mark Brown Subject: [PATCH v15 03/10] arm64: add conditional instruction simulation support Date: Fri, 8 Jul 2016 12:35:47 -0400 Message-Id: <1467995754-32508-4-git-send-email-dave.long@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1467995754-32508-1-git-send-email-dave.long@linaro.org> References: <1467995754-32508-1-git-send-email-dave.long@linaro.org> From: "David A. Long" Cease using the arm32 arm_check_condition() function and replace it with a local version for use in deprecated instruction support on arm64. Also make the function table used by this available for future use by kprobes and/or uprobes. This function is derived from code written by Sandeepa Prabhu. Signed-off-by: Sandeepa Prabhu Signed-off-by: David A. Long Acked-by: Masami Hiramatsu --- arch/arm64/include/asm/insn.h | 3 ++ arch/arm64/kernel/Makefile | 3 +- arch/arm64/kernel/armv8_deprecated.c | 19 ++++++- arch/arm64/kernel/insn.c | 98 ++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 4 deletions(-) -- 2.5.0 diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 497f7a2..a44abbd 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -406,6 +406,9 @@ u32 aarch64_insn_extract_system_reg(u32 insn); u32 aarch32_insn_extract_reg_num(u32 insn, int offset); u32 aarch32_insn_mcr_extract_opc2(u32 insn); u32 aarch32_insn_mcr_extract_crm(u32 insn); + +typedef bool (pstate_check_t)(unsigned long); +extern pstate_check_t * const aarch32_opcode_cond_checks[16]; #endif /* __ASSEMBLY__ */ #endif /* __ASM_INSN_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 2173149..4653aca 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -26,8 +26,7 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE $(call if_changed,objcopy) arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ - sys_compat.o entry32.o \ - ../../arm/kernel/opcodes.o + sys_compat.o entry32.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index c37202c..2934894 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -366,6 +366,21 @@ static int emulate_swpX(unsigned int address, unsigned int *data, return res; } +#define ARM_OPCODE_CONDITION_UNCOND 0xf + +static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr) +{ + u32 cc_bits = opcode >> 28; + + if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) { + if ((*aarch32_opcode_cond_checks[cc_bits])(psr)) + return ARM_OPCODE_CONDTEST_PASS; + else + return ARM_OPCODE_CONDTEST_FAIL; + } + return ARM_OPCODE_CONDTEST_UNCOND; +} + /* * swp_handler logs the id of calling process, dissects the instruction, sanity * checks the memory location, calls emulate_swpX for the actual operation and @@ -380,7 +395,7 @@ static int swp_handler(struct pt_regs *regs, u32 instr) type = instr & TYPE_SWPB; - switch (arm_check_condition(instr, regs->pstate)) { + switch (aarch32_check_condition(instr, regs->pstate)) { case ARM_OPCODE_CONDTEST_PASS: break; case ARM_OPCODE_CONDTEST_FAIL: @@ -461,7 +476,7 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr) { perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); - switch (arm_check_condition(instr, regs->pstate)) { + switch (aarch32_check_condition(instr, regs->pstate)) { case ARM_OPCODE_CONDTEST_PASS: break; case ARM_OPCODE_CONDTEST_FAIL: diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 28c6110f..5cb2f3d 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -1234,3 +1234,101 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn) { return insn & CRM_MASK; } + +static bool __kprobes __check_eq(unsigned long pstate) +{ + return (pstate & PSR_Z_BIT) != 0; +} + +static bool __kprobes __check_ne(unsigned long pstate) +{ + return (pstate & PSR_Z_BIT) == 0; +} + +static bool __kprobes __check_cs(unsigned long pstate) +{ + return (pstate & PSR_C_BIT) != 0; +} + +static bool __kprobes __check_cc(unsigned long pstate) +{ + return (pstate & PSR_C_BIT) == 0; +} + +static bool __kprobes __check_mi(unsigned long pstate) +{ + return (pstate & PSR_N_BIT) != 0; +} + +static bool __kprobes __check_pl(unsigned long pstate) +{ + return (pstate & PSR_N_BIT) == 0; +} + +static bool __kprobes __check_vs(unsigned long pstate) +{ + return (pstate & PSR_V_BIT) != 0; +} + +static bool __kprobes __check_vc(unsigned long pstate) +{ + return (pstate & PSR_V_BIT) == 0; +} + +static bool __kprobes __check_hi(unsigned long pstate) +{ + pstate &= ~(pstate >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (pstate & PSR_C_BIT) != 0; +} + +static bool __kprobes __check_ls(unsigned long pstate) +{ + pstate &= ~(pstate >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (pstate & PSR_C_BIT) == 0; +} + +static bool __kprobes __check_ge(unsigned long pstate) +{ + pstate ^= (pstate << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (pstate & PSR_N_BIT) == 0; +} + +static bool __kprobes __check_lt(unsigned long pstate) +{ + pstate ^= (pstate << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (pstate & PSR_N_BIT) != 0; +} + +static bool __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) == 0; +} + +static bool __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) != 0; +} + +static bool __kprobes __check_al(unsigned long pstate) +{ + return true; +} + +/* + * Note that the ARMv8 ARM calls condition code 0b1111 "nv", but states that + * it behaves identically to 0b1110 ("al"). + */ +pstate_check_t * const aarch32_opcode_cond_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 +};