From patchwork Thu May 28 05:51:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Li Bin X-Patchwork-Id: 6496211 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id A7DA6C0020 for ; Thu, 28 May 2015 05:59:40 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 55C42206A1 for ; Thu, 28 May 2015 05:59:39 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F0EA220671 for ; Thu, 28 May 2015 05:59:37 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Yxqoh-0008UY-MC; Thu, 28 May 2015 05:57:19 +0000 Received: from szxga02-in.huawei.com ([119.145.14.65]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1YxqnV-00082u-5Y for linux-arm-kernel@lists.infradead.org; Thu, 28 May 2015 05:56:09 +0000 Received: from 172.24.2.119 (EHLO szxeml433-hub.china.huawei.com) ([172.24.2.119]) by szxrg02-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id CMA38403; Thu, 28 May 2015 13:54:59 +0800 (CST) Received: from localhost.localdomain (10.175.100.166) by szxeml433-hub.china.huawei.com (10.82.67.210) with Microsoft SMTP Server id 14.3.158.1; Thu, 28 May 2015 13:54:50 +0800 From: Li Bin To: , , , , , , , , Subject: [RFC PATCH 5/5] livepatch: arm64: support relocation in a module Date: Thu, 28 May 2015 13:51:05 +0800 Message-ID: <1432792265-24076-6-git-send-email-huawei.libin@huawei.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1432792265-24076-1-git-send-email-huawei.libin@huawei.com> References: <1432792265-24076-1-git-send-email-huawei.libin@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.175.100.166] X-CFilter-Loop: Reflected X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150527_225605_913853_08E53E39 X-CRM114-Status: GOOD ( 17.17 ) X-Spam-Score: -2.3 (--) Cc: huawei.libin@huawei.com, xiexiuqi@huawei.com, linux-kernel@vger.kernel.org, lizefan@huawei.com, felix.yang@huawei.com, guohanjun@huawei.com, live-patching@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_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 From: Xie XiuQi This patch implement klp_write_module_reloc on arm64 platform. Signed-off-by: Xie XiuQi Signed-off-by: Li Bin --- arch/arm64/kernel/livepatch.c | 7 +- arch/arm64/kernel/module.c | 355 +++++++++++++++++++++-------------------- 2 files changed, 186 insertions(+), 176 deletions(-) diff --git a/arch/arm64/kernel/livepatch.c b/arch/arm64/kernel/livepatch.c index 2a55532..ad674f0 100644 --- a/arch/arm64/kernel/livepatch.c +++ b/arch/arm64/kernel/livepatch.c @@ -18,8 +18,11 @@ */ #include +#include #include +extern int static_relocate(struct module *mod, unsigned long type, + void * loc, unsigned long value); /** * klp_write_module_reloc() - write a relocation in a module * @mod: module in which the section to be modified is found @@ -33,6 +36,6 @@ int klp_write_module_reloc(struct module *mod, unsigned long type, unsigned long loc, unsigned long value) { - pr_err("lpc_write_module_reloc has not supported now\n"); - return -ENOSYS; + /* Perform the static relocation. */ + return static_relocate(mod, type, (void *)loc, value); } diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 67bf410..7781241 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -193,6 +193,182 @@ static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, return 0; } +int static_relocate(struct module *me, unsigned long type, void *loc, + unsigned long val) +{ + int ovf = 0; + bool overflow_check = true; + /* Perform the static relocation. */ + switch (type) { + /* Null relocations. */ + case R_ARM_NONE: + case R_AARCH64_NONE: + ovf = 0; + break; + + /* Data relocations. */ + case R_AARCH64_ABS64: + overflow_check = false; + ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); + break; + case R_AARCH64_ABS32: + ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); + break; + case R_AARCH64_ABS16: + ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); + break; + case R_AARCH64_PREL64: + overflow_check = false; + ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); + break; + case R_AARCH64_PREL32: + ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); + break; + case R_AARCH64_PREL16: + ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); + break; + + /* MOVW instruction relocations. */ + case R_AARCH64_MOVW_UABS_G0_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G0: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, + AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G1_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G1: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, + AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G2_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G2: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, + AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G3: + /* We're using the top bits so we can't overflow. */ + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, + AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_SABS_G0: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, + AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_SABS_G1: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, + AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_SABS_G2: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, + AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G0_NC: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, + AARCH64_INSN_IMM_MOVK); + break; + case R_AARCH64_MOVW_PREL_G0: + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, + AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G1_NC: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, + AARCH64_INSN_IMM_MOVK); + break; + case R_AARCH64_MOVW_PREL_G1: + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, + AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G2_NC: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, + AARCH64_INSN_IMM_MOVK); + break; + case R_AARCH64_MOVW_PREL_G2: + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, + AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G3: + /* We're using the top bits so we can't overflow. */ + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, + AARCH64_INSN_IMM_MOVNZ); + break; + + /* Immediate instruction relocations. */ + case R_AARCH64_LD_PREL_LO19: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, + AARCH64_INSN_IMM_19); + break; + case R_AARCH64_ADR_PREL_LO21: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, + AARCH64_INSN_IMM_ADR); + break; + case R_AARCH64_ADR_PREL_PG_HI21_NC: + overflow_check = false; + case R_AARCH64_ADR_PREL_PG_HI21: + ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, + AARCH64_INSN_IMM_ADR); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, + AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST16_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, + AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST32_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, + AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, + AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST128_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, + AARCH64_INSN_IMM_12); + break; + case R_AARCH64_TSTBR14: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, + AARCH64_INSN_IMM_14); + break; + case R_AARCH64_CONDBR19: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, + AARCH64_INSN_IMM_19); + break; + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, + AARCH64_INSN_IMM_26); + break; + + default: + pr_err("module %s: unsupported RELA relocation: %lu\n", + me->name, type); + return -ENOEXEC; + } + + if (overflow_check && ovf == -ERANGE) { + pr_err("module %s: overflow in relocation type %lu val %lx\n", + me->name, type, val); + return -ENOEXEC; + } + + return 0; +} + int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -200,12 +376,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, struct module *me) { unsigned int i; - int ovf; - bool overflow_check; Elf64_Sym *sym; void *loc; u64 val; Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; + int type, ret; for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* loc corresponds to P in the AArch64 ELF document. */ @@ -219,182 +394,14 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, /* val corresponds to (S + A) in the AArch64 ELF document. */ val = sym->st_value + rel[i].r_addend; + type = ELF64_R_TYPE(rel[i].r_info); /* Check for overflow by default. */ - overflow_check = true; - - /* Perform the static relocation. */ - switch (ELF64_R_TYPE(rel[i].r_info)) { - /* Null relocations. */ - case R_ARM_NONE: - case R_AARCH64_NONE: - ovf = 0; - break; - - /* Data relocations. */ - case R_AARCH64_ABS64: - overflow_check = false; - ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); - break; - case R_AARCH64_ABS32: - ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); - break; - case R_AARCH64_ABS16: - ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); - break; - case R_AARCH64_PREL64: - overflow_check = false; - ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); - break; - case R_AARCH64_PREL32: - ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); - break; - case R_AARCH64_PREL16: - ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); - break; - - /* MOVW instruction relocations. */ - case R_AARCH64_MOVW_UABS_G0_NC: - overflow_check = false; - case R_AARCH64_MOVW_UABS_G0: - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, - AARCH64_INSN_IMM_16); - break; - case R_AARCH64_MOVW_UABS_G1_NC: - overflow_check = false; - case R_AARCH64_MOVW_UABS_G1: - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, - AARCH64_INSN_IMM_16); - break; - case R_AARCH64_MOVW_UABS_G2_NC: - overflow_check = false; - case R_AARCH64_MOVW_UABS_G2: - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, - AARCH64_INSN_IMM_16); - break; - case R_AARCH64_MOVW_UABS_G3: - /* We're using the top bits so we can't overflow. */ - overflow_check = false; - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, - AARCH64_INSN_IMM_16); - break; - case R_AARCH64_MOVW_SABS_G0: - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, - AARCH64_INSN_IMM_MOVNZ); - break; - case R_AARCH64_MOVW_SABS_G1: - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, - AARCH64_INSN_IMM_MOVNZ); - break; - case R_AARCH64_MOVW_SABS_G2: - ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, - AARCH64_INSN_IMM_MOVNZ); - break; - case R_AARCH64_MOVW_PREL_G0_NC: - overflow_check = false; - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, - AARCH64_INSN_IMM_MOVK); - break; - case R_AARCH64_MOVW_PREL_G0: - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, - AARCH64_INSN_IMM_MOVNZ); - break; - case R_AARCH64_MOVW_PREL_G1_NC: - overflow_check = false; - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, - AARCH64_INSN_IMM_MOVK); - break; - case R_AARCH64_MOVW_PREL_G1: - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, - AARCH64_INSN_IMM_MOVNZ); - break; - case R_AARCH64_MOVW_PREL_G2_NC: - overflow_check = false; - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, - AARCH64_INSN_IMM_MOVK); - break; - case R_AARCH64_MOVW_PREL_G2: - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, - AARCH64_INSN_IMM_MOVNZ); - break; - case R_AARCH64_MOVW_PREL_G3: - /* We're using the top bits so we can't overflow. */ - overflow_check = false; - ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, - AARCH64_INSN_IMM_MOVNZ); - break; - - /* Immediate instruction relocations. */ - case R_AARCH64_LD_PREL_LO19: - ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, - AARCH64_INSN_IMM_19); - break; - case R_AARCH64_ADR_PREL_LO21: - ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, - AARCH64_INSN_IMM_ADR); - break; - case R_AARCH64_ADR_PREL_PG_HI21_NC: - overflow_check = false; - case R_AARCH64_ADR_PREL_PG_HI21: - ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, - AARCH64_INSN_IMM_ADR); - break; - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_LDST8_ABS_LO12_NC: - overflow_check = false; - ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, - AARCH64_INSN_IMM_12); - break; - case R_AARCH64_LDST16_ABS_LO12_NC: - overflow_check = false; - ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, - AARCH64_INSN_IMM_12); - break; - case R_AARCH64_LDST32_ABS_LO12_NC: - overflow_check = false; - ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, - AARCH64_INSN_IMM_12); - break; - case R_AARCH64_LDST64_ABS_LO12_NC: - overflow_check = false; - ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, - AARCH64_INSN_IMM_12); - break; - case R_AARCH64_LDST128_ABS_LO12_NC: - overflow_check = false; - ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, - AARCH64_INSN_IMM_12); - break; - case R_AARCH64_TSTBR14: - ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, - AARCH64_INSN_IMM_14); - break; - case R_AARCH64_CONDBR19: - ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, - AARCH64_INSN_IMM_19); - break; - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: - ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, - AARCH64_INSN_IMM_26); - break; - - default: - pr_err("module %s: unsupported RELA relocation: %llu\n", - me->name, ELF64_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - - if (overflow_check && ovf == -ERANGE) - goto overflow; - + ret = static_relocate(me, type, loc, val); + if (ret) + return ret; } return 0; - -overflow: - pr_err("module %s: overflow in relocation type %d val %Lx\n", - me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); - return -ENOEXEC; } int module_finalize(const Elf_Ehdr *hdr,