From patchwork Thu May 5 16:34:18 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 67223 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp844797qge; Thu, 5 May 2016 09:36:04 -0700 (PDT) X-Received: by 10.176.3.43 with SMTP id 40mr9961570uat.82.1462466156429; Thu, 05 May 2016 09:35:56 -0700 (PDT) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id 7si5161323uab.20.2016.05.05.09.35.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 May 2016 09:35:56 -0700 (PDT) Received-SPF: neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) client-ip=192.237.175.120; Authentication-Results: mx.google.com; spf=neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) smtp.mailfrom=xen-devel-bounces@lists.xen.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ayMEh-0001sr-RY; Thu, 05 May 2016 16:34:47 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ayMEg-0001q3-9Y for xen-devel@lists.xen.org; Thu, 05 May 2016 16:34:46 +0000 Received: from [85.158.137.68] by server-4.bemta-3.messagelabs.com id 98/BA-03606-5267B275; Thu, 05 May 2016 16:34:45 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrALMWRWlGSWpSXmKPExsVysyfVTVelTDv cYOs8K4slHxezODB6HN39mymAMYo1My8pvyKBNWNqi2bBfJ+K7Y9DGhinOXQxcnEICWxilNj7 4D4LhHOaUeLqydesXYycHGwCmhJ3Pn9iArFFBKQlrn2+zAhSxCzQzCgxfdFrti5GDg5hgUiJm we9QGpYBFQltr2dC1bPK+Aq8WXiYXYQW0JATuLksclgMzmB4kvPr2QBsYUEXCRO7pjENoGRew EjwypG9eLUorLUIl0zvaSizPSMktzEzBxdQwNjvdzU4uLE9NScxKRiveT83E2MQN/WMzAw7mC 80uZ8iFGSg0lJlHe7kna4EF9SfkplRmJxRnxRaU5q8SFGGQ4OJQleuVKgnGBRanpqRVpmDjDI YNISHDxKIrwSIGne4oLE3OLMdIjUKUZdjmNzb6xlEmLJy89LlRLnVQApEgApyijNgxsBC/hLj LJSwryMDAwMQjwFqUW5mSWo8q8YxTkYlYR5mUCm8GTmlcBtegV0BBPQEe/naoIcUZKIkJJqYK w93llZ/Z8/N1pmWtm+J3bTuIwVNX55Hvuhw1pe+WLlptaQKvk93Q2qes/rDDkeciikSl7ecjF vArNp42reOz2Jcic+m69kWvfm6Az/L8G/Tsn8Yj3E/X7BnN49lt/fSJmzWESpeEWf7bjwdfeM h6F17N8CBY0er5uy4N2EyuTT9W5W2mG1X5VYijMSDbWYi4oTAUcvjn9zAgAA X-Env-Sender: julien.grall@arm.com X-Msg-Ref: server-13.tower-31.messagelabs.com!1462466084!38086042!1 X-Originating-IP: [217.140.101.70] X-SpamReason: No, hits=0.3 required=7.0 tests=MAILTO_TO_SPAM_ADDR X-StarScan-Received: X-StarScan-Version: 8.34; banners=-,-,- X-VirusChecked: Checked Received: (qmail 43724 invoked from network); 5 May 2016 16:34:44 -0000 Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by server-13.tower-31.messagelabs.com with SMTP; 5 May 2016 16:34:44 -0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 64CF53DB; Thu, 5 May 2016 09:34:51 -0700 (PDT) Received: from e108454-lin.cambridge.arm.com (e108454-lin.cambridge.arm.com [10.1.215.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D4A5C3F252; Thu, 5 May 2016 09:34:42 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xen.org Date: Thu, 5 May 2016 17:34:18 +0100 Message-Id: <1462466065-30212-10-git-send-email-julien.grall@arm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1462466065-30212-1-git-send-email-julien.grall@arm.com> References: <1462466065-30212-1-git-send-email-julien.grall@arm.com> Cc: andre.przywara@arm.com, Julien Grall , sstabellini@kernel.org, wei.chen@arm.com, steve.capper@arm.com Subject: [Xen-devel] [RFC 09/16] xen/arm: arm64: Add helpers to decode and encode branch instructions X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" We may need to update branch instruction when patching Xen. The code has been imported from the files arch/arm64/kernel/insn.c and arch/arm64/include/asm/insn.h in Linux v4.6-rc3. Note that only the necessary helpers have been imported. Signed-off-by: Julien Grall --- xen/arch/arm/arm64/Makefile | 1 + xen/arch/arm/arm64/insn.c | 213 +++++++++++++++++++++++++++++++++++++++ xen/include/asm-arm/arm64/insn.h | 72 +++++++++++++ xen/include/asm-arm/insn.h | 22 ++++ 4 files changed, 308 insertions(+) create mode 100644 xen/arch/arm/arm64/insn.c create mode 100644 xen/include/asm-arm/arm64/insn.h create mode 100644 xen/include/asm-arm/insn.h diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile index 39c6ac6..c1fa43f 100644 --- a/xen/arch/arm/arm64/Makefile +++ b/xen/arch/arm/arm64/Makefile @@ -5,6 +5,7 @@ obj-$(EARLY_PRINTK) += debug.o obj-y += domctl.o obj-y += domain.o obj-y += entry.o +obj-y += insn.o obj-y += smpboot.o obj-y += traps.o obj-y += vfp.o diff --git a/xen/arch/arm/arm64/insn.c b/xen/arch/arm/arm64/insn.c new file mode 100644 index 0000000..54a6b62 --- /dev/null +++ b/xen/arch/arm/arm64/insn.c @@ -0,0 +1,213 @@ +/* + * Based on Linux arch/arm64/kernel/insn.c + * + * Copyright (C) 2013 Huawei Ltd. + * Author: Jiang Liu + * + * Copyright (C) 2014-2016 Zi Shen Lim + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include + +bool aarch64_insn_is_branch_imm(u32 insn) +{ + return (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn) || + aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn) || + aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) || + aarch64_insn_is_bcond(insn)); +} + +static int aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type, + u32 *maskp, int *shiftp) +{ + u32 mask; + int shift; + + switch (type) { + case AARCH64_INSN_IMM_26: + mask = BIT(26) - 1; + shift = 0; + break; + case AARCH64_INSN_IMM_19: + mask = BIT(19) - 1; + shift = 5; + break; + case AARCH64_INSN_IMM_16: + mask = BIT(16) - 1; + shift = 5; + break; + case AARCH64_INSN_IMM_14: + mask = BIT(14) - 1; + shift = 5; + break; + case AARCH64_INSN_IMM_12: + mask = BIT(12) - 1; + shift = 10; + break; + case AARCH64_INSN_IMM_9: + mask = BIT(9) - 1; + shift = 12; + break; + case AARCH64_INSN_IMM_7: + mask = BIT(7) - 1; + shift = 15; + break; + case AARCH64_INSN_IMM_6: + case AARCH64_INSN_IMM_S: + mask = BIT(6) - 1; + shift = 10; + break; + case AARCH64_INSN_IMM_R: + mask = BIT(6) - 1; + shift = 16; + break; + default: + return -EINVAL; + } + + *maskp = mask; + *shiftp = shift; + + return 0; +} + +#define ADR_IMM_HILOSPLIT 2 +#define ADR_IMM_SIZE SZ_2M +#define ADR_IMM_LOMASK ((1 << ADR_IMM_HILOSPLIT) - 1) +#define ADR_IMM_HIMASK ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1) +#define ADR_IMM_LOSHIFT 29 +#define ADR_IMM_HISHIFT 5 + +u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn) +{ + u32 immlo, immhi, mask; + int shift; + + switch (type) { + case AARCH64_INSN_IMM_ADR: + shift = 0; + immlo = (insn >> ADR_IMM_LOSHIFT) & ADR_IMM_LOMASK; + immhi = (insn >> ADR_IMM_HISHIFT) & ADR_IMM_HIMASK; + insn = (immhi << ADR_IMM_HILOSPLIT) | immlo; + mask = ADR_IMM_SIZE - 1; + break; + default: + if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) { + printk(XENLOG_ERR "aarch64_insn_decode_immediate: unknown immediate encoding %d\n", + type); + return 0; + } + } + + return (insn >> shift) & mask; +} + +u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, + u32 insn, u64 imm) +{ + u32 immlo, immhi, mask; + int shift; + + switch (type) { + case AARCH64_INSN_IMM_ADR: + shift = 0; + immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT; + imm >>= ADR_IMM_HILOSPLIT; + immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT; + imm = immlo | immhi; + mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) | + (ADR_IMM_HIMASK << ADR_IMM_HISHIFT)); + break; + default: + if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) { + printk(XENLOG_ERR "aarch64_insn_encode_immediate: unknown immediate encoding %d\n", + type); + return AARCH64_BREAK_FAULT; + } + } + + /* Update the immediate field. */ + insn &= ~(mask << shift); + insn |= (imm & mask) << shift; + + return insn; +} + +/* + * Decode the imm field of a branch, and return the byte offset as a + * signed value (so it can be used when computing a new branch + * target). + */ +s32 aarch64_get_branch_offset(u32 insn) +{ + s32 imm; + + if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) { + imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn); + return (imm << 6) >> 4; + } + + if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) || + aarch64_insn_is_bcond(insn)) { + imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_19, insn); + return (imm << 13) >> 11; + } + + if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn)) { + imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_14, insn); + return (imm << 18) >> 16; + } + + /* Unhandled instruction */ + BUG(); +} + +/* + * Encode the displacement of a branch in the imm field and return the + * updated instruction. + */ +u32 aarch64_set_branch_offset(u32 insn, s32 offset) +{ + if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn, + offset >> 2); + + if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) || + aarch64_insn_is_bcond(insn)) + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn, + offset >> 2); + + if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn)) + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_14, insn, + offset >> 2); + + /* Unhandled instruction */ + BUG(); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */ diff --git a/xen/include/asm-arm/arm64/insn.h b/xen/include/asm-arm/arm64/insn.h new file mode 100644 index 0000000..cfcdbe9 --- /dev/null +++ b/xen/include/asm-arm/arm64/insn.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 Huawei Ltd. + * Author: Jiang Liu + * + * Copyright (C) 2014 Zi Shen Lim + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ARCH_ARM_ARM64_INSN +#define __ARCH_ARM_ARM64_INSN + +#include +#include +#include + +enum aarch64_insn_imm_type { + AARCH64_INSN_IMM_ADR, + AARCH64_INSN_IMM_26, + AARCH64_INSN_IMM_19, + AARCH64_INSN_IMM_16, + AARCH64_INSN_IMM_14, + AARCH64_INSN_IMM_12, + AARCH64_INSN_IMM_9, + AARCH64_INSN_IMM_7, + AARCH64_INSN_IMM_6, + AARCH64_INSN_IMM_S, + AARCH64_INSN_IMM_R, + AARCH64_INSN_IMM_MAX +}; + +#define __AARCH64_INSN_FUNCS(abbr, mask, val) \ +static always_inline bool_t aarch64_insn_is_##abbr(u32 code) \ +{ return (code & (mask)) == (val); } \ +static always_inline u32 aarch64_insn_get_##abbr##_value(void) \ +{ return (val); } + +__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000) +__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000) +__AARCH64_INSN_FUNCS(cbz, 0x7F000000, 0x34000000) +__AARCH64_INSN_FUNCS(cbnz, 0x7F000000, 0x35000000) +__AARCH64_INSN_FUNCS(tbz, 0x7F000000, 0x36000000) +__AARCH64_INSN_FUNCS(tbnz, 0x7F000000, 0x37000000) +__AARCH64_INSN_FUNCS(bcond, 0xFF000010, 0x54000000) + +bool aarch64_insn_is_branch_imm(u32 insn); + +u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn); +u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, + u32 insn, u64 imm); + +s32 aarch64_get_branch_offset(u32 insn); +u32 aarch64_set_branch_offset(u32 insn, s32 offset); + +#endif /* !__ARCH_ARM_ARM64_INSN */ +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */ diff --git a/xen/include/asm-arm/insn.h b/xen/include/asm-arm/insn.h new file mode 100644 index 0000000..fe9419c --- /dev/null +++ b/xen/include/asm-arm/insn.h @@ -0,0 +1,22 @@ +#ifndef __ARCH_ARM_INSN +#define __ARCH_ARM_INSN + +#include + +#if defined(CONFIG_ARM_32) +# include +#elif defined(CONFIG_ARM_64) +# include +#else +# error "unknown ARM variant" +#endif + +#endif /* !__ARCH_ARM_INSN */ +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */