Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750907AbcCBFOk (ORCPT ); Wed, 2 Mar 2016 00:14:40 -0500 Received: from mail-qg0-f42.google.com ([209.85.192.42]:35374 "EHLO mail-qg0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750747AbcCBFOi (ORCPT ); Wed, 2 Mar 2016 00:14:38 -0500 Subject: Re: [PATCH v10 4/9] arm64: add conditional instruction simulation support To: Marc Zyngier , Catalin Marinas , Will Deacon , Sandeepa Prabhu , William Cohen , Pratyush Anand , Steve Capper , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org References: <1456801047-29014-1-git-send-email-dave.long@linaro.org> <1456801047-29014-5-git-send-email-dave.long@linaro.org> <56D5D4CC.8010808@arm.com> Cc: Dave P Martin , Mark Rutland , Robin Murphy , Ard Biesheuvel , Jens Wiklander , Christoffer Dall , =?UTF-8?Q?Alex_Benn=c3=a9e?= , Yang Shi , Greg Kroah-Hartman , Viresh Kumar , "Suzuki K. Poulose" , Kees Cook , Zi Shen Lim , John Blackwood , Feng Kan , Balamurugan Shanmugam , James Morse , Vladimir Murzin , Mark Salyzyn , Petr Mladek , Andrew Morton , Mark Brown From: David Long Message-ID: <56D676B3.1030302@linaro.org> Date: Wed, 2 Mar 2016 00:14:27 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 In-Reply-To: <56D5D4CC.8010808@arm.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7266 Lines: 221 On 03/01/2016 12:43 PM, Marc Zyngier wrote: > On 01/03/16 02:57, David Long wrote: >> 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 dervied from code written by Sandeepa Prabhu. >> >> Signed-off-by: Sandeepa Prabhu >> Signed-off-by: David A. Long >> --- >> arch/arm64/include/asm/insn.h | 3 ++ >> arch/arm64/kernel/Makefile | 3 +- >> arch/arm64/kernel/armv8_deprecated.c | 19 ++++++- >> arch/arm64/kernel/insn.c | 96 ++++++++++++++++++++++++++++++++++++ >> 4 files changed, 117 insertions(+), 4 deletions(-) >> >> diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h >> index 662b42a..72dda48 100644 >> --- a/arch/arm64/include/asm/insn.h >> +++ b/arch/arm64/include/asm/insn.h >> @@ -405,6 +405,9 @@ u32 aarch64_extract_system_register(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 opcode_condition_checks[16]; >> #endif /* __ASSEMBLY__ */ >> >> #endif /* __ASM_INSN_H */ >> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile >> index 83cd7e6..fd5f163 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_PERF_EVENTS) += perf_regs.o perf_callchain.o >> diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c >> index 3e01207..6d4d6fe 100644 >> --- a/arch/arm64/kernel/armv8_deprecated.c >> +++ b/arch/arm64/kernel/armv8_deprecated.c >> @@ -369,6 +369,21 @@ static int emulate_swpX(unsigned int address, unsigned int *data, >> return res; >> } >> >> +#define ARM_OPCODE_CONDITION_UNCOND 0xf >> + >> +static unsigned int __kprobes arm64_check_condition(u32 opcode, u32 psr) > > Nit: since this is exclusively targeted at emulating 32bit code, having > arm64_ as a prefix is mildly confusing. Either keep the arm_ prefix, or > turn it into arm32_. > The goal was to make sure it didn't conflict with the definition in arch/arm/include/asm/opcodes.h, but naming it arm32_check_condition() will do that too. >> +{ >> + u32 cc_bits = opcode >> 28; >> + >> + if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) { >> + if ((*opcode_condition_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 >> @@ -383,7 +398,7 @@ static int swp_handler(struct pt_regs *regs, u32 instr) >> >> type = instr & TYPE_SWPB; >> >> - switch (arm_check_condition(instr, regs->pstate)) { >> + switch (arm64_check_condition(instr, regs->pstate)) { >> case ARM_OPCODE_CONDTEST_PASS: >> break; >> case ARM_OPCODE_CONDTEST_FAIL: >> @@ -464,7 +479,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 (arm64_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 60c1c71..f7f2f95 100644 >> --- a/arch/arm64/kernel/insn.c >> +++ b/arch/arm64/kernel/insn.c >> @@ -1234,3 +1234,99 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn) >> { >> return insn & CRM_MASK; >> } >> + >> +#define ARM_OPCODE_CONDITION_UNCOND 0xf > > This is the second time you define this, which makes me think that this > should live in some include file. On the other hand, it doesn't seem to > be used in the following code, so maybe get rid of it altogether? > Yeah, this looks like a leftover after moving the related code to another file. Deleted. >> + >> +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; >> +} >> + >> +pstate_check_t * const opcode_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 >> +}; >> > > Thanks, > > M. >