From patchwork Thu Aug 24 08:18:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110876 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315399qge; Thu, 24 Aug 2017 01:19:07 -0700 (PDT) X-Received: by 10.99.174.6 with SMTP id q6mr5347872pgf.331.1503562747692; Thu, 24 Aug 2017 01:19:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562747; cv=none; d=google.com; s=arc-20160816; b=Vw3JFm+fzaJK3T66Cur58bX8J6pQs91jD8PZDsEI2KBefTlctv5eEbviQUjYl2LPCr 9fLJO6Mf6Kq4YAFD7a6cDCkBGVA2PGFzUj+QHLAkPdCVr8iD6LznndzBzDFGN3bSyGFY s6X61P8EmFfkco+7I5F3XGRuT8HvtHBH/pgFi+oDL2Iniuc4DiZQoRuD90w4U8CMEB6s qfzfL03Qg8eOeza/icm56prKi78NlVbCHuniaqnPl26oKxzFEe/vAqfjyFb1swQLXLuU rRI7riACV/CjC982k00MVGUJgbAuSVzi7BkzUVhzBMzhuNKjdNeOLXJcPbJ4hbjEs2hm 7v0A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=eQYwYlkVT/OpBbZqyLVQ8xMt5FVlB2XLU5cwIMjTWyo=; b=rEri5I/+vJy5P1cFkTJQJZiq+PgLAXX7iKSGIRffjhPPKug4QRB80LYO43dgtOAUyH WBELm/WyBjqpwhpoh/DKTNxR/d1udimu2TKVEitjffpehKj/bzvA68VMBDy0GJaSt7AS h6mB/JahOmHdY3UKwC7s+ShTSiwA+S+WLjdmKobEu2WNSox6LgReK1vjf7X2s/BTiHE7 JIce8qzRETMPiAxM4NYEkdf7JokppdsA1+fLmbCpZ6t7H2WoMsjN0l1pniAt/8Xoh+qF SgvqJHKa9UpfoA6nrh6pMrjrSddXI6LcTOz9HlrMPdNLdMZSyTkUhLmQka6O7AQ7A9t0 2u5Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LqDt5R6l; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c124si2434964pfa.353.2017.08.24.01.19.07; Thu, 24 Aug 2017 01:19:07 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LqDt5R6l; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751757AbdHXITG (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:06 -0400 Received: from mail-pg0-f46.google.com ([74.125.83.46]:37983 "EHLO mail-pg0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751475AbdHXISp (ORCPT ); Thu, 24 Aug 2017 04:18:45 -0400 Received: by mail-pg0-f46.google.com with SMTP id m133so13378538pga.5 for ; Thu, 24 Aug 2017 01:18:45 -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=eQYwYlkVT/OpBbZqyLVQ8xMt5FVlB2XLU5cwIMjTWyo=; b=LqDt5R6lyH/cgHG9exjQdpXi3YisIupJK85bOJe36xdlx7P8DnyiX9IVsRnykDkx0v T43GK/iK2X46F2o8cyTo1GQ5GlRwXjxG9hEv6CEHpb7WRp2OIATPefVq3teh6FrYdPuh DGXE1ei//CjvpuBuXWlUuC6u+wlAfsYL04qe4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=eQYwYlkVT/OpBbZqyLVQ8xMt5FVlB2XLU5cwIMjTWyo=; b=GWv8m/8zeBMJULQr0mAzuv8h77tGZJkGxOV1jrj4YjKCFZGunaAbqXbEu7wR8Uw3QL 0ZBkA+5dyu15TFWDid+D+eWE5A8duatPJFQdBYgHfzuDZLkR+GlKBHIgY/nqmLsoAOdn eUUHVMsGYx1Tq4j37xY7IeGMN+QbkUn3q04Vo/KfFEbvn0uNcu4NsOrq+n1p9m02Pz1f DfDpkOZd5by6h/lFsg+fb+hQ31Pui+Orlv1RmIaeD9Sq0GPKCh9jb0duNzU5MOzphYYR VfYlKG86cMDf4zMsjZnLXreWlpTefFr+EMR3DqKPg2aPBCZfF5a7RvyK25uXoJfzSXlD mtUA== X-Gm-Message-State: AHYfb5imryDCVpI/KIG2XdEKRlqfGcoWyHOkCoFQQyht8wTj8EZmJEer xgfpUaKHip3xGvgZ X-Received: by 10.101.85.7 with SMTP id f7mr5653123pgr.131.1503562724729; Thu, 24 Aug 2017 01:18:44 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id j6sm3023725pgn.43.2017.08.24.01.18.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:44 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 08/14] arm64: kexec_file: create purgatory Date: Thu, 24 Aug 2017 17:18:05 +0900 Message-Id: <20170824081811.19299-9-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This is a basic purgtory, or a kind of glue code between the two kernel, for arm64. We will later add a feature of verifying a digest check against loaded memory segments. arch_kexec_apply_relocations_add() is responsible for re-linking any relative symbols in purgatory. Please note that the purgatory is not an executable, but a non-linked archive of binaries so relative symbols contained here must be resolved at kexec load time. Despite that arm64_kernel_start and arm64_dtb_addr are only such global variables now, arch_kexec_apply_relocations_add() can manage more various types of relocations. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/Makefile | 1 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/machine_kexec_file.c | 199 +++++++++++++++++++++++++++++++++ arch/arm64/purgatory/Makefile | 24 ++++ arch/arm64/purgatory/entry.S | 28 +++++ 5 files changed, 253 insertions(+) create mode 100644 arch/arm64/kernel/machine_kexec_file.c create mode 100644 arch/arm64/purgatory/Makefile create mode 100644 arch/arm64/purgatory/entry.S -- 2.14.1 diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 9b41f1e3b1a0..429f60728c0a 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -105,6 +105,7 @@ core-$(CONFIG_XEN) += arch/arm64/xen/ core-$(CONFIG_CRYPTO) += arch/arm64/crypto/ libs-y := arch/arm64/lib/ $(libs-y) core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a +core-$(CONFIG_KEXEC_FILE) += arch/arm64/purgatory/ # Default target when executing plain make boot := arch/arm64/boot diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index f2b4e816b6de..16e9f56b536a 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -50,6 +50,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ cpu-reset.o +arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c new file mode 100644 index 000000000000..183f7776d6dd --- /dev/null +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -0,0 +1,199 @@ +/* + * kexec_file for arm64 + * + * Copyright (C) 2017 Linaro Limited + * Author: AKASHI Takahiro + * + * Most code is derived from arm64 port of kexec-tools + * + * 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. + */ + +#define pr_fmt(fmt) "kexec_file: " fmt + +#include +#include +#include +#include +#include + +/* + * Apply purgatory relocations. + * + * ehdr: Pointer to elf headers + * sechdrs: Pointer to section headers. + * relsec: section index of SHT_RELA section. + * + * Note: + * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26 + * are the only types to be generated from purgatory code. + * If we add more functionalities, other types may also be used. + */ +int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, + Elf64_Shdr *sechdrs, unsigned int relsec) +{ + Elf64_Rela *rel; + Elf64_Shdr *section, *symtabsec; + Elf64_Sym *sym; + const char *strtab, *name, *shstrtab; + unsigned long address, sec_base, value; + void *location; + u64 *loc64; + u32 *loc32, imm; + unsigned int i; + + /* + * ->sh_offset has been modified to keep the pointer to section + * contents in memory + */ + rel = (void *)sechdrs[relsec].sh_offset; + + /* Section to which relocations apply */ + section = &sechdrs[sechdrs[relsec].sh_info]; + + pr_debug("reloc: Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + /* Associated symbol table */ + symtabsec = &sechdrs[sechdrs[relsec].sh_link]; + + /* String table */ + if (symtabsec->sh_link >= ehdr->e_shnum) { + /* Invalid strtab section number */ + pr_err("reloc: Invalid string table section index %d\n", + symtabsec->sh_link); + return -ENOEXEC; + } + + strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset; + + /* section header string table */ + shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset; + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + + /* + * rel[i].r_offset contains byte offset from beginning + * of section to the storage unit affected. + * + * This is location to update (->sh_offset). This is temporary + * buffer where section is currently loaded. This will finally + * be loaded to a different address later, pointed to by + * ->sh_addr. kexec takes care of moving it + * (kexec_load_segment()). + */ + location = (void *)(section->sh_offset + rel[i].r_offset); + + /* Final address of the location */ + address = section->sh_addr + rel[i].r_offset; + + /* + * rel[i].r_info contains information about symbol table index + * w.r.t which relocation must be made and type of relocation + * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get + * these respectively. + */ + sym = (Elf64_Sym *)symtabsec->sh_offset + + ELF64_R_SYM(rel[i].r_info); + + if (sym->st_name) + name = strtab + sym->st_name; + else + name = shstrtab + sechdrs[sym->st_shndx].sh_name; + + pr_debug("Symbol: %-16s info: %02x shndx: %02x value=%llx size: %llx reloc type:%d\n", + name, sym->st_info, sym->st_shndx, sym->st_value, + sym->st_size, (int)ELF64_R_TYPE(rel[i].r_info)); + + if (sym->st_shndx == SHN_UNDEF) { + pr_err("reloc: Undefined symbol: %s\n", name); + return -ENOEXEC; + } + + if (sym->st_shndx == SHN_COMMON) { + pr_err("reloc: symbol '%s' in common section\n", name); + return -ENOEXEC; + } + + if (sym->st_shndx == SHN_ABS) { + sec_base = 0; + } else if (sym->st_shndx < ehdr->e_shnum) { + sec_base = sechdrs[sym->st_shndx].sh_addr; + } else { + pr_err("reloc: Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return -ENOEXEC; + } + + value = sym->st_value; + value += sec_base; + value += rel[i].r_addend; + + switch (ELF64_R_TYPE(rel[i].r_info)) { + case R_AARCH64_ABS64: + loc64 = location; + *loc64 = cpu_to_elf64(ehdr, + elf64_to_cpu(ehdr, *loc64) + value); + break; + case R_AARCH64_PREL32: + loc32 = location; + *loc32 = cpu_to_elf32(ehdr, + elf32_to_cpu(ehdr, *loc32) + value + - address); + break; + case R_AARCH64_LD_PREL_LO19: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) << 3) & 0xffffe0)); + break; + case R_AARCH64_ADR_PREL_LO21: + if (value & 3) { + pr_err("reloc: Unaligned value: %lx\n", value); + return -ENOEXEC; + } + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) << 3) & 0xffffe0)); + break; + case R_AARCH64_ADR_PREL_PG_HI21: + imm = ((value & ~0xfff) - (address & ~0xfff)) >> 12; + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + ((imm & 3) << 29) + + ((imm & 0x1ffffc) << (5 - 2))); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + ((value & 0xfff) << 10)); + break; + case R_AARCH64_JUMP26: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) >> 2) & 0x3ffffff)); + break; + case R_AARCH64_CALL26: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) >> 2) & 0x3ffffff)); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + if (value & 7) { + pr_err("reloc: Unaligned value: %lx\n", value); + return -ENOEXEC; + } + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + ((value & 0xff8) << (10 - 3))); + break; + default: + pr_err("reloc: Unknown relocation type: %llu\n", + ELF64_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + + return 0; +} diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile new file mode 100644 index 000000000000..c2127a2cbd51 --- /dev/null +++ b/arch/arm64/purgatory/Makefile @@ -0,0 +1,24 @@ +OBJECT_FILES_NON_STANDARD := y + +purgatory-y := entry.o + +targets += $(purgatory-y) +PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) + +LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \ + -nostdlib -z nodefaultlib +targets += purgatory.ro + +$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE + $(call if_changed,ld) + +targets += kexec_purgatory.c + +CMD_BIN2C = $(objtree)/scripts/basic/bin2c +quiet_cmd_bin2c = BIN2C $@ + cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@ + +$(obj)/kexec_purgatory.c: $(obj)/purgatory.ro FORCE + $(call if_changed,bin2c) + +obj-${CONFIG_KEXEC_FILE} += kexec_purgatory.o diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S new file mode 100644 index 000000000000..bc4e6b3bf8a1 --- /dev/null +++ b/arch/arm64/purgatory/entry.S @@ -0,0 +1,28 @@ +/* + * kexec core purgatory + */ +#include + +.text + +ENTRY(purgatory_start) + /* Start new image. */ + ldr x17, arm64_kernel_entry + ldr x0, arm64_dtb_addr + mov x1, xzr + mov x2, xzr + mov x3, xzr + br x17 +END(purgatory_start) + +.data + +.align 3 + +ENTRY(arm64_kernel_entry) + .quad 0 +END(arm64_kernel_entry) + +ENTRY(arm64_dtb_addr) + .quad 0 +END(arm64_dtb_addr)