[PATCH v3 5/8] arm64: kdump: set up kernel image segment
On arm64, we can use the same kernel image as 1st kernel, but we have to modify the entry point as well as segments' addresses in the kernel's elf header in order to load them into correct places. Signed-off-by: AKASHI Takahiro--- kexec/arch/arm64/crashdump-arm64.c | 23 +++ kexec/arch/arm64/crashdump-arm64.h | 1 + kexec/arch/arm64/kexec-arm64.c | 25 - kexec/arch/arm64/kexec-elf-arm64.c | 10 +- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c index 8346131..9517329 100644 --- a/kexec/arch/arm64/crashdump-arm64.c +++ b/kexec/arch/arm64/crashdump-arm64.c @@ -213,3 +213,26 @@ int load_crashdump_segments(struct kexec_info *info) return 0; } + +/* + * e_entry and p_paddr are actually in virtual address space. + * Those values will be translated to physcal addresses by + * using virt_to_phys(). + * So let's get ready for later use so the memory base (phys_offset) + * will be correctly replaced with crash_reserved_mem.start. + */ +void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr) +{ + struct mem_phdr *phdr; + int i; + + ehdr->e_entry += - arm64_mem.phys_offset + crash_reserved_mem.start; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = >e_phdr[i]; + if (phdr->p_type != PT_LOAD) + continue; + phdr->p_paddr += + (-arm64_mem.phys_offset + crash_reserved_mem.start); + } +} diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h index da75a2d..382f571 100644 --- a/kexec/arch/arm64/crashdump-arm64.h +++ b/kexec/arch/arm64/crashdump-arm64.h @@ -21,5 +21,6 @@ extern struct memory_range crash_reserved_mem; extern struct memory_range elfcorehdr_mem; extern int load_crashdump_segments(struct kexec_info *info); +extern void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr); #endif /* CRASHDUMP_ARM64_H */ diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c index bc96c76..498b218 100644 --- a/kexec/arch/arm64/kexec-arm64.c +++ b/kexec/arch/arm64/kexec-arm64.c @@ -305,12 +305,27 @@ unsigned long arm64_locate_kernel_segment(struct kexec_info *info) { unsigned long hole; - hole = locate_hole(info, - arm64_mem.text_offset + arm64_mem.image_size, - MiB(2), 0, ULONG_MAX, 1); + if (info->kexec_flags & KEXEC_ON_CRASH) { + unsigned long hole_end; + + hole = (crash_reserved_mem.start < mem_min ? + mem_min : crash_reserved_mem.start); + hole = _ALIGN_UP(hole, MiB(2)); + hole_end = hole + arm64_mem.text_offset + arm64_mem.image_size; + + if ((hole_end > mem_max) || + (hole_end > crash_reserved_mem.end)) { + dbgprintf("%s: Crash kernel out of range\n", __func__); + hole = ULONG_MAX; + } + } else { + hole = locate_hole(info, + arm64_mem.text_offset + arm64_mem.image_size, + MiB(2), 0, ULONG_MAX, 1); - if (hole == ULONG_MAX) - dbgprintf("%s: locate_hole failed\n", __func__); + if (hole == ULONG_MAX) + dbgprintf("%s: locate_hole failed\n", __func__); + } return hole; } diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c index c70a37a..842ce21 100644 --- a/kexec/arch/arm64/kexec-elf-arm64.c +++ b/kexec/arch/arm64/kexec-elf-arm64.c @@ -9,6 +9,7 @@ #include #include +#include "crashdump-arm64.h" #include "kexec-arm64.h" #include "kexec-elf.h" #include "kexec-syscall.h" @@ -105,7 +106,8 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, } arm64_mem.vp_offset = _ALIGN_DOWN(ehdr.e_entry, MiB(2)); - arm64_mem.vp_offset -= kernel_segment - get_phys_offset(); + if (!(info->kexec_flags & KEXEC_ON_CRASH)) + arm64_mem.vp_offset -= kernel_segment - get_phys_offset(); dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment); dbgprintf("%s: text_offset:%016lx\n", __func__, @@ -127,6 +129,12 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf, __func__); goto exit; } + + /* +* offset addresses in order to fit vmlinux +* (elf_exec) into crash kernel's memory +*/ + modify_ehdr_for_crashdump(); } /* load the kernel */ -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
Re: [PATCH v26 0/7] arm64: add kdump support
On Wed, Sep 07, 2016 at 01:29:02PM +0900, AKASHI Takahiro wrote: > v26-specific note: After a comment from Rob[0], an idea of adding > "linux,usable-memory-range" was dropped. Instead, an existing > "reserved-memory" node will be used to limit usable memory ranges > on crash dump kernel. > This works not only on UEFI/ACPI systems but also on DT-only systems, > but if he really insists on using DT-specific "usable-memory" property, > I will post additional patches for kexec-tools. Those would be > redundant, though. > Even in that case, the kernel will not have to be changed. > > This patch series adds kdump support on arm64. > There are some prerequisite patches [1],[2]. > > To load a crash-dump kernel to the systems, a series of patches to > kexec-tools, which have not yet been merged upstream, are needed. > Please always use my latest kdump patches, v3 [3]. > > To examine vmcore (/proc/vmcore) on a crash-dump kernel, you can use > - crash utility (coming v7.1.6 or later) [4] > (Necessary patches have already been queued in the master.) > > > [0] > http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/452582.html > [1] "arm64: mark reserved memblock regions explicitly in iomem" > > http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/450433.html > [2] "efi: arm64: treat regions with WT/WC set but WB cleared as memory" > > http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/451491.html > [3] T.B.D. For kexec-tools, see: http://lists.infradead.org/pipermail/kexec/2016-September/017158.html -Takahiro AKASHI > [4] https://github.com/crash-utility/crash.git > > > Changes for v26 (Sep 7, 2016): > o Use /reserved-memory instead of "linux,usable-memory-range" property > (dropping v25's patch#2 and #3, updating ex-patch#9.) > > Changes for v25 (Aug 29, 2016): > o Rebase to Linux-4.8-rc4 > o Use memremap() instead of ioremap_cache() [patch#5] > > Changes for v24 (Aug 9, 2016): > o Rebase to Linux-4.8-rc1 > o Update descriptions about newly added DT proerties > > Changes for v23 (July 26, 2016): > > o Move memblock_reserve() to a single place in reserve_crashkernel() > o Use cpu_park_loop() in ipi_cpu_crash_stop() > o Always enforce ARCH_LOW_ADDRESS_LIMIT to the memory range of crash kernel > o Re-implement fdt_enforce_memory_region() to remove non-reserve regions > (for ACPI) from usable memory at crash kernel > > Changes for v22 (July 12, 2016): > > o Export "crashkernel-base" and "crashkernel-size" via device-tree, > and add some descriptions about them in chosen.txt > o Rename "usable-memory" to "usable-memory-range" to avoid inconsistency > with powerpc's "usable-memory" > o Make cosmetic changes regarding "ifdef" usage > o Correct some wordings in kdump.txt > > Changes for v21 (July 6, 2016): > > o Remove kexec patches. > o Rebase to arm64's for-next/core (Linux-4.7-rc4 based). > o Clarify the description about kvm in kdump.txt. > > See the following link [3] for older changes: > [3] > http://lists.infradead.org/pipermail/linux-arm-kernel/2016-June/438780.html > > AKASHI Takahiro (8): > arm64: kdump: reserve memory for crash dump kernel > memblock: add memblock_cap_memory_range() > arm64: limit memory regions based on DT property, usable-memory-range > arm64: kdump: implement machine_crash_shutdown() > arm64: kdump: add kdump support > arm64: kdump: add VMCOREINFO's for user-space coredump tools > arm64: kdump: enable kdump in the arm64 defconfig > arm64: kdump: update a kernel doc > > James Morse (1): > Documentation: dt: chosen properties for arm64 kdump > > Documentation/devicetree/bindings/chosen.txt | 45 ++ > Documentation/kdump/kdump.txt| 16 ++- > arch/arm64/Kconfig | 11 ++ > arch/arm64/configs/defconfig | 1 + > arch/arm64/include/asm/hardirq.h | 2 +- > arch/arm64/include/asm/kexec.h | 41 +- > arch/arm64/include/asm/smp.h | 2 + > arch/arm64/kernel/Makefile | 1 + > arch/arm64/kernel/crash_dump.c | 71 ++ > arch/arm64/kernel/machine_kexec.c| 67 - > arch/arm64/kernel/setup.c| 7 +- > arch/arm64/kernel/smp.c | 63 + > arch/arm64/mm/init.c | 202 > +++ > include/linux/memblock.h | 1 + > mm/memblock.c| 28 > 15 files changed, 551 insertions(+), 7 deletions(-) > create mode 100644 arch/arm64/kernel/crash_dump.c > > -- > 2.9.0 > > > AKASHI Takahiro (6): > arm64: kdump: reserve memory for crash dump kernel > arm64: kdump: implement machine_crash_shutdown() > arm64: kdump: add kdump support > arm64: kdump: add VMCOREINFO's for user-space coredump tools > arm64: kdump:
[PATCH v3 4/8] arm64: kdump: add elf core header segment
Elf core header contains the information necessary for the coredump of the 1st kernel, including its physcal memory layout as well as cpu register states at the panic. The segment is allocated inside the reserved memory of crash dump kernel. Signed-off-by: AKASHI Takahiro--- kexec/arch/arm64/crashdump-arm64.c | 96 ++ kexec/arch/arm64/crashdump-arm64.h | 3 ++ kexec/arch/arm64/iomem.h | 2 + kexec/arch/arm64/kexec-elf-arm64.c | 10 4 files changed, 111 insertions(+) diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c index dcaca43..8346131 100644 --- a/kexec/arch/arm64/crashdump-arm64.c +++ b/kexec/arch/arm64/crashdump-arm64.c @@ -39,6 +39,39 @@ struct memory_ranges usablemem_rgns = { .ranges = _reserved_mem, }; +struct memory_range elfcorehdr_mem; + +static struct crash_elf_info elf_info = { + .class = ELFCLASS64, +#if (__BYTE_ORDER == __LITTLE_ENDIAN) + .data = ELFDATA2LSB, +#else + .data = ELFDATA2MSB, +#endif + .machine= EM_AARCH64, +}; + +/* + * Note: The returned value is correct only if !CONFIG_RANDOMIZE_BASE. + */ +static uint64_t get_kernel_page_offset(void) +{ + int i; + + if (elf_info.kern_vaddr_start == UINT64_MAX) + return UINT64_MAX; + + /* Current max virtual memory range is 48-bits. */ + for (i = 48; i > 0; i--) + if (!(elf_info.kern_vaddr_start & (1UL << i))) + break; + + if (i <= 0) + return UINT64_MAX; + else + return UINT64_MAX << i; +} + /* * iomem_range_callback() - callback called for each iomem region * @data: not used @@ -62,6 +95,10 @@ static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr), else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0) return mem_regions_add(_memory_rgns, base, length, RANGE_RAM); + else if (strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) == 0) + elf_info.kern_paddr_start = base; + else if (strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) == 0) + elf_info.kern_size = base + length - elf_info.kern_paddr_start; return 0; } @@ -115,5 +152,64 @@ static int crash_get_memory_ranges(void) dbgprint_mem_range("Coredump memory ranges", crash_memory_rgns.ranges, crash_memory_rgns.size); + /* +* For additional kernel code/data segment. +* kern_paddr_start/kern_size are determined in iomem_range_callback +*/ + elf_info.kern_vaddr_start = get_kernel_sym("_text"); + if (!elf_info.kern_vaddr_start) + elf_info.kern_vaddr_start = UINT64_MAX; + + return 0; +} + +/* + * load_crashdump_segments() - load the elf core header + * @info: kexec info structure + * + * This function creates and loads an additional segment of elf core header + : which is used to construct /proc/vmcore on crash dump kernel. + * + * Return 0 in case of success and -1 in case of error. + */ + +int load_crashdump_segments(struct kexec_info *info) +{ + unsigned long elfcorehdr; + unsigned long bufsz; + void *buf; + int err; + + /* +* First fetch all the memory (RAM) ranges that we are going to +* pass to the crash dump kernel during panic. +*/ + + err = crash_get_memory_ranges(); + + if (err) + return err; + + elf_info.page_offset = get_kernel_page_offset(); + dbgprintf("%s: page_offset: %016llx\n", __func__, + elf_info.page_offset); + + err = crash_create_elf64_headers(info, _info, + crash_memory_rgns.ranges, crash_memory_rgns.size, + , , ELF_CORE_HEADER_ALIGN); + + if (err) + return err; + + elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0, + crash_reserved_mem.start, crash_reserved_mem.end, + -1, 0); + + elfcorehdr_mem.start = elfcorehdr; + elfcorehdr_mem.end = elfcorehdr + bufsz - 1; + + dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__, + elfcorehdr_mem.start, elfcorehdr_mem.end); + return 0; } diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h index 07a0ed0..da75a2d 100644 --- a/kexec/arch/arm64/crashdump-arm64.h +++ b/kexec/arch/arm64/crashdump-arm64.h @@ -18,5 +18,8 @@ extern struct memory_ranges usablemem_rgns; extern struct memory_range crash_reserved_mem; +extern struct memory_range elfcorehdr_mem; + +extern int load_crashdump_segments(struct kexec_info *info); #endif /* CRASHDUMP_ARM64_H */ diff --git a/kexec/arch/arm64/iomem.h b/kexec/arch/arm64/iomem.h index 20cda87..d4864bb 100644 --- a/kexec/arch/arm64/iomem.h +++ b/kexec/arch/arm64/iomem.h
[PATCH v3 3/8] arm64: kdump: identify memory regions
The following regions need to be identified for later use: a) memory regions which belong to the 1st kernel b) usable memory reserved for crash dump kernel We go through /proc/iomem to find out a) and b) which are marked as "System RAM" and "Crash kernel", respectively. Signed-off-by: AKASHI Takahiro--- kexec/arch/arm64/Makefile | 2 + kexec/arch/arm64/crashdump-arm64.c | 100 - kexec/arch/arm64/crashdump-arm64.h | 14 +- kexec/arch/arm64/iomem.h | 1 + 4 files changed, 114 insertions(+), 3 deletions(-) diff --git a/kexec/arch/arm64/Makefile b/kexec/arch/arm64/Makefile index 37414dc..c2535c6 100644 --- a/kexec/arch/arm64/Makefile +++ b/kexec/arch/arm64/Makefile @@ -5,6 +5,8 @@ arm64_FS2DT_INCLUDE += -include $(srcdir)/kexec/arch/arm64/kexec-arm64.h \ arm64_DT_OPS += kexec/dt-ops.c +arm64_MEM_REGIONS = kexec/mem_regions.c + arm64_CPPFLAGS += -I $(srcdir)/kexec/ arm64_KEXEC_SRCS += \ diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c index d2272c8..dcaca43 100644 --- a/kexec/arch/arm64/crashdump-arm64.c +++ b/kexec/arch/arm64/crashdump-arm64.c @@ -1,5 +1,13 @@ /* * ARM64 crashdump. + * partly derived from arm implementation + * + * Copyright (c) 2014-2016 Linaro Limited + * Author: AKASHI Takahiro + * + * 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 _GNU_SOURCE @@ -10,12 +18,102 @@ #include "kexec.h" #include "crashdump.h" #include "crashdump-arm64.h" +#include "iomem.h" #include "kexec-arm64.h" #include "kexec-elf.h" +#include "mem_regions.h" -struct memory_ranges usablemem_rgns = {}; +/* memory ranges on crashed kernel */ +static struct memory_range crash_memory_ranges[CRASH_MAX_MEMORY_RANGES]; +static struct memory_ranges crash_memory_rgns = { + .size = 0, + .max_size = CRASH_MAX_MEMORY_RANGES, + .ranges = crash_memory_ranges, +}; + +/* memory range reserved for crashkernel */ +struct memory_range crash_reserved_mem; +struct memory_ranges usablemem_rgns = { + .size = 0, + .max_size = 1, + .ranges = _reserved_mem, +}; + +/* + * iomem_range_callback() - callback called for each iomem region + * @data: not used + * @nr: not used + * @str: name of the memory region + * @base: start address of the memory region + * @length: size of the memory region + * + * This function is called once for each memory region found in /proc/iomem. + * It locates system RAM and crashkernel reserved memory and places these to + * variables, respectively, crash_memory_ranges and crash_reserved_mem. + */ + +static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr), + char *str, unsigned long long base, + unsigned long long length) +{ + if (strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)) == 0) + return mem_regions_add(_rgns, + base, length, RANGE_RAM); + else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0) + return mem_regions_add(_memory_rgns, + base, length, RANGE_RAM); + + return 0; +} int is_crashkernel_mem_reserved(void) { + if (!crash_reserved_mem.end) + kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); + + return crash_reserved_mem.start != crash_reserved_mem.end; +} + +/* + * crash_get_memory_ranges() - read system physical memory + * + * Function reads through system physical memory and stores found memory + * regions in crash_memory_ranges. + * Regions are sorted in ascending order. + * + * Returns 0 in case of success and -1 otherwise (errno is set). + */ +static int crash_get_memory_ranges(void) +{ + /* +* First read all memory regions that can be considered as +* system memory including the crash area. +*/ + if (!usablemem_rgns.size) + kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL); + + /* allow only a single region for crash dump kernel */ + if (usablemem_rgns.size != 1) { + errno = EINVAL; + return -1; + } + + dbgprint_mem_range("Reserved memory range", _reserved_mem, 1); + + if (mem_regions_exclude(_memory_rgns, _reserved_mem)) { + fprintf(stderr, + "Error: Number of crash memory ranges excedeed the max limit\n"); + errno = ENOMEM; + return -1; + } + + /* +* Make sure that the memory regions are sorted. +*/ + mem_regions_sort(_memory_rgns); + + dbgprint_mem_range("Coredump memory ranges", + crash_memory_rgns.ranges, crash_memory_rgns.size); + return 0; }
[PATCH v3 2/8] kexec: generalize and rename get_kernel_stext_sym()
From: Pratyush Anandget_kernel_stext_sym() has been defined for both arm and i386. Other architecture might need some other kernel symbol address. Therefore rewrite this function as generic function to get any kernel symbol address. More over, kallsyms is not arch specific representation, therefore have common function for all arches. Signed-off-by: Pratyush Anand [created symbols.c] Signed-off-by: AKASHI Takahiro --- kexec/Makefile | 1 + kexec/arch/arm/crashdump-arm.c | 40 +--- kexec/arch/i386/crashdump-x86.c | 32 +--- kexec/kexec.h | 2 ++ kexec/symbols.c | 41 + 5 files changed, 46 insertions(+), 70 deletions(-) create mode 100644 kexec/symbols.c diff --git a/kexec/Makefile b/kexec/Makefile index 39f365f..2b4fb3d 100644 --- a/kexec/Makefile +++ b/kexec/Makefile @@ -26,6 +26,7 @@ KEXEC_SRCS_base += kexec/kernel_version.c KEXEC_SRCS_base += kexec/lzma.c KEXEC_SRCS_base += kexec/zlib.c KEXEC_SRCS_base += kexec/kexec-xen.c +KEXEC_SRCS_base += kexec/symbols.c KEXEC_GENERATED_SRCS += $(PURGATORY_HEX_C) diff --git a/kexec/arch/arm/crashdump-arm.c b/kexec/arch/arm/crashdump-arm.c index 4a89b5e..2bc898b 100644 --- a/kexec/arch/arm/crashdump-arm.c +++ b/kexec/arch/arm/crashdump-arm.c @@ -73,48 +73,10 @@ static struct crash_elf_info elf_info = { extern unsigned long long user_page_offset; -/* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ -static unsigned long long get_kernel_stext_sym(void) -{ - const char *kallsyms = "/proc/kallsyms"; - const char *stext = "_stext"; - char sym[128]; - char line[128]; - FILE *fp; - unsigned long long vaddr = 0; - char type; - - fp = fopen(kallsyms, "r"); - if (!fp) { - fprintf(stderr, "Cannot open %s\n", kallsyms); - return 0; - } - - while(fgets(line, sizeof(line), fp) != NULL) { - unsigned long long addr; - - if (sscanf(line, "%Lx %c %s", , , sym) != 3) - continue; - - if (strcmp(sym, stext) == 0) { - dbgprintf("kernel symbol %s vaddr = %#llx\n", stext, addr); - vaddr = addr; - break; - } - } - - fclose(fp); - - if (vaddr == 0) - fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); - - return vaddr; -} - static int get_kernel_page_offset(struct kexec_info *info, struct crash_elf_info *elf_info) { - unsigned long long stext_sym_addr = get_kernel_stext_sym(); + unsigned long long stext_sym_addr = get_kernel_sym("stext"); if (stext_sym_addr == 0) { if (user_page_offset != (-1ULL)) { elf_info->page_offset = user_page_offset; diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c index bbc0f35..664eb3b 100644 --- a/kexec/arch/i386/crashdump-x86.c +++ b/kexec/arch/i386/crashdump-x86.c @@ -102,36 +102,6 @@ static int get_kernel_paddr(struct kexec_info *UNUSED(info), return -1; } -/* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ -static unsigned long long get_kernel_stext_sym(void) -{ - const char *kallsyms = "/proc/kallsyms"; - const char *stext = "_stext"; - char sym[128]; - char line[128]; - FILE *fp; - unsigned long long vaddr; - char type; - - fp = fopen(kallsyms, "r"); - if (!fp) { - fprintf(stderr, "Cannot open %s\n", kallsyms); - return 0; - } - - while(fgets(line, sizeof(line), fp) != NULL) { - if (sscanf(line, "%Lx %c %s", , , sym) != 3) - continue; - if (strcmp(sym, stext) == 0) { - dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr); - return vaddr; - } - } - - fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); - return 0; -} - /* Retrieve info regarding virtual address kernel has been compiled for and * size of the kernel from /proc/kcore. Current /proc/kcore parsing from * from kexec-tools fails because of malformed elf notes. A kernel patch has @@ -182,7 +152,7 @@ static int get_kernel_vaddr_and_size(struct kexec_info *UNUSED(info), /* Traverse through the Elf headers and find the region where * _stext symbol is located in. That's where kernel is mapped */ - stext_sym = get_kernel_stext_sym(); + stext_sym = get_kernel_sym("stext"); for(phdr = ehdr.e_phdr; stext_sym && phdr != end_phdr; phdr++) { if (phdr->p_type == PT_LOAD) { unsigned long long saddr =
[PATCH v3 8/8] arm64: kdump: Add support for binary image files
From: Pratyush AnandThis patch adds support to use binary image ie arch/arm64/boot/Image with kdump. Signed-off-by: Pratyush Anand [takahiro.aka...@linaro.org: a bit reworked] Signed-off-by: AKASHI Takahiro --- kexec/arch/arm64/kexec-image-arm64.c | 12 1 file changed, 12 insertions(+) diff --git a/kexec/arch/arm64/kexec-image-arm64.c b/kexec/arch/arm64/kexec-image-arm64.c index 960ed96..982e431 100644 --- a/kexec/arch/arm64/kexec-image-arm64.c +++ b/kexec/arch/arm64/kexec-image-arm64.c @@ -4,7 +4,9 @@ #define _GNU_SOURCE +#include "crashdump-arm64.h" #include "kexec-arm64.h" +#include "kexec-syscall.h" #include int image_arm64_probe(const char *kernel_buf, off_t kernel_size) @@ -58,6 +60,16 @@ int image_arm64_load(int argc, char **argv, const char *kernel_buf, dbgprintf("%s: PE format: %s\n", __func__, (arm64_header_check_pe_sig(header) ? "yes" : "no")); + if (info->kexec_flags & KEXEC_ON_CRASH) { + /* create and initialize elf core header segment */ + result = load_crashdump_segments(info); + if (result) { + dbgprintf("%s: Creating eflcorehdr failed.\n", + __func__); + goto exit; + } + } + /* load the kernel */ add_segment_phys_virt(info, kernel_buf, kernel_size, kernel_segment + arm64_mem.text_offset, -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 7/8] arm64: kdump: add DT properties to crash dump kernel's dtb
We pass the following properties to crash dump kernel: /chosen/linux,elfcorehdr: elf core header segment, same as "elfcorehdr=" as on other archs /reserved-memory/crash_dump@xx: any memory regions to be dumped into /proc/vmcore Then, we are ready to support kdump. Signed-off-by: AKASHI Takahiro--- kexec/arch/arm64/crashdump-arm64.c | 141 - kexec/arch/arm64/crashdump-arm64.h | 2 + kexec/arch/arm64/kexec-arm64.c | 34 +++-- kexec/arch/arm64/kexec-elf-arm64.c | 5 -- 4 files changed, 171 insertions(+), 11 deletions(-) diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c index 9517329..01b9716 100644 --- a/kexec/arch/arm64/crashdump-arm64.c +++ b/kexec/arch/arm64/crashdump-arm64.c @@ -13,6 +13,7 @@ #define _GNU_SOURCE #include +#include #include #include "kexec.h" @@ -21,11 +22,12 @@ #include "iomem.h" #include "kexec-arm64.h" #include "kexec-elf.h" +#include "libfdt.h" #include "mem_regions.h" /* memory ranges on crashed kernel */ static struct memory_range crash_memory_ranges[CRASH_MAX_MEMORY_RANGES]; -static struct memory_ranges crash_memory_rgns = { +struct memory_ranges crash_memory_rgns = { .size = 0, .max_size = CRASH_MAX_MEMORY_RANGES, .ranges = crash_memory_ranges, @@ -236,3 +238,140 @@ void modify_ehdr_for_crashdump(struct mem_ehdr *ehdr) (-arm64_mem.phys_offset + crash_reserved_mem.start); } } + +static int dtb_add_reserved_memory(void *dtb_buf) +{ + int nodeoffset, rsvmem_node; + uint32_t cell_size; + uint64_t range[2]; + char name[30]; + int i, result = 0; + + rsvmem_node = fdt_path_offset(dtb_buf, "reserved-memory"); + if (rsvmem_node < 0) { + nodeoffset = fdt_path_offset(dtb_buf, "/"); + rsvmem_node = fdt_add_subnode(dtb_buf, nodeoffset, + "reserved-memory"); + if (rsvmem_node < 0) { + result = rsvmem_node; + goto on_error; + } + + cell_size = cpu_to_fdt32(2); + fdt_setprop(dtb_buf, rsvmem_node, "#address-cells", + _size, sizeof(cell_size)); + fdt_setprop(dtb_buf, rsvmem_node, "#size-cells", + _size, sizeof(cell_size)); + fdt_setprop(dtb_buf, rsvmem_node, "ranges", NULL, 0); + } + + for (i = 0; i < crash_memory_rgns.size; i++) { + sprintf(name, "crash_dump@%llx", + crash_memory_rgns.ranges[i].start); + nodeoffset = fdt_add_subnode(dtb_buf, rsvmem_node, name); + if (nodeoffset < 0) { + result = nodeoffset; + goto on_error; + } + + range[0] = cpu_to_fdt64(crash_memory_rgns.ranges[i].start); + range[1] = cpu_to_fdt64(crash_memory_rgns.ranges[i].end + - crash_memory_rgns.ranges[i].start + 1); + fdt_setprop(dtb_buf, nodeoffset, "reg", , sizeof(range)); + fdt_setprop(dtb_buf, nodeoffset, "no-map", NULL, 0); + } + +on_error: + return result; +} + +/* + * Increased size for extra properties: + * - linux,elfcorehdr + * linux,elfcoredhr = ; + * - reserved-memory node + * reserved-memory { + * #address-cells = <2>; + * #size-cells = <2>; + * ranges; + * crash_dump@xx { + *reg = ; + *no-map; + * }; + * ... + * } + */ +#define DTB_ELFCOREHDR_PROP_SIZE \ +(sizeof(struct fdt_property) \ + + FDT_TAGALIGN(sizeof(uint64_t) * 2)\ + + strlen("linux,elfcorehdr") + 1) +#define DTB_RESVMEM_NODE_SIZE \ +(sizeof(struct fdt_node_header)\ + + strlen("reserved-memory") + 1 \ + + sizeof(struct fdt_property) \ + + FDT_TAGALIGN(sizeof(uint32_t))\ + + strlen("#address-cells") + 1 \ + + sizeof(struct fdt_property) \ + + FDT_TAGALIGN(sizeof(uint32_t))\ + + strlen("#size-cells") + 1 \ + + sizeof(struct fdt_property) \ + + strlen("ranges") + 1) +#define DTB_RESVMEM_SUBNODE_SIZE \ +(sizeof(struct fdt_node_header)\ + + strlen("crash_dump@") + 1 \ + + sizeof(struct fdt_property) \ + + FDT_TAGALIGN(sizeof(uint64_t) * 2)\ + + strlen("reg") + 1 \ + + sizeof(struct
[PATCH v3 0/8] (kexec-tools) arm64: add kdump support
My kernel patches of kdump suport on arm64 are currently under reviews. This patchset is synced with them (v26 [1]) and provides necessary changes for kexec-tools. It should be applied on top of Geoff's kexec-tools patches v5[2] along with a bugfix[3]. [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-September/454588.html [2] http://lists.infradead.org/pipermail/kexec/2016-September/017110.html [3] http://lists.infradead.org/pipermail/kexec/2016-July/016664.html Changes for v3: - rebased on Geoff's v5 - fix a value of estimated PHYS_OFFSET - add a kernel code/data segment because they now reside out of linear mapping due to KASLR introduction - remove "linux,usable-memory-range" dependency, instead using "reserved-memory" node - add -mem-min/-mem-max support Changes for v2: - trim a temoprary buffer in setup_2nd_dtb() - add patch#6("kexec: generalize and rename get_kernel_stext_sym()") - update patch#7 from Pratyush (re-worked by akashi) AKASHI Takahiro (6): arm64: identify PHYS_OFFSET correctly arm64: kdump: identify memory regions arm64: kdump: add elf core header segment arm64: kdump: set up kernel image segment arm64: kdump: set up other segments arm64: kdump: add DT properties to crash dump kernel's dtb Pratyush Anand (2): kexec: generalize and rename get_kernel_stext_sym() arm64: kdump: Add support for binary image files kexec/Makefile | 1 + kexec/arch/arm/crashdump-arm.c | 40 +--- kexec/arch/arm64/Makefile| 2 + kexec/arch/arm64/crashdump-arm64.c | 358 ++- kexec/arch/arm64/crashdump-arm64.h | 20 +- kexec/arch/arm64/iomem.h | 10 + kexec/arch/arm64/kexec-arm64.c | 86 +++-- kexec/arch/arm64/kexec-elf-arm64.c | 25 ++- kexec/arch/arm64/kexec-image-arm64.c | 12 ++ kexec/arch/i386/crashdump-x86.c | 32 +--- kexec/kexec.h| 2 + kexec/symbols.c | 41 12 files changed, 534 insertions(+), 95 deletions(-) create mode 100644 kexec/arch/arm64/iomem.h create mode 100644 kexec/symbols.c -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 6/8] arm64: kdump: set up other segments
We make sure that all the other segments, initrd and device-tree blob, also be loaded into the reserved memory of crash dump kernel. Signed-off-by: AKASHI Takahiro--- kexec/arch/arm64/kexec-arm64.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c index 498b218..bcb4e76 100644 --- a/kexec/arch/arm64/kexec-arm64.c +++ b/kexec/arch/arm64/kexec-arm64.c @@ -373,7 +373,10 @@ int arm64_load_other_segments(struct kexec_info *info, /* Put the other segments after the image. */ hole_min = image_base + arm64_mem.image_size; - hole_max = ULONG_MAX; + if (info->kexec_flags & KEXEC_ON_CRASH) + hole_max = crash_reserved_mem.end; + else + hole_max = ULONG_MAX; if (arm64_opts.initrd) { initrd_buf = slurp_file(arm64_opts.initrd, _size); -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 1/8] arm64: identify PHYS_OFFSET correctly
Due to the kernel patch[1], the current code will not be able to identify the correct value of PHYS_OFFSET if some "reserved" memory region, which is likely to be UEFI runtime services code/data, exists at an address below the first "System RAM" regions. This patch fixes this issue. Signed-off-by: AKASHI Takahiro--- kexec/arch/arm64/iomem.h | 7 +++ kexec/arch/arm64/kexec-arm64.c | 22 +- 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 kexec/arch/arm64/iomem.h diff --git a/kexec/arch/arm64/iomem.h b/kexec/arch/arm64/iomem.h new file mode 100644 index 000..7fd66eb --- /dev/null +++ b/kexec/arch/arm64/iomem.h @@ -0,0 +1,7 @@ +#ifndef IOMEM_H +#define IOMEM_H + +#define SYSTEM_RAM "System RAM\n" +#define IOMEM_RESERVED "reserved\n" + +#endif diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c index 7183dac..bc96c76 100644 --- a/kexec/arch/arm64/kexec-arm64.c +++ b/kexec/arch/arm64/kexec-arm64.c @@ -21,6 +21,7 @@ #include "crashdump-arm64.h" #include "dt-ops.h" #include "fs2dt.h" +#include "iomem.h" #include "kexec-syscall.h" #include "arch/options.h" @@ -465,18 +466,28 @@ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, * get_memory_ranges_iomem_cb - Helper for get_memory_ranges_iomem. */ +static int count_memory_ranges; + static int get_memory_ranges_iomem_cb(void *data, int nr, char *str, unsigned long long base, unsigned long long length) { struct memory_range *r; - if (nr >= KEXEC_SEGMENT_MAX) + if (count_memory_ranges >= KEXEC_SEGMENT_MAX) return -1; - r = (struct memory_range *)data + nr; - r->type = RANGE_RAM; + r = (struct memory_range *)data + count_memory_ranges; + + if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM))) + r->type = RANGE_RAM; + else if (!strncmp(str, IOMEM_RESERVED, strlen(IOMEM_RESERVED))) + r->type = RANGE_RESERVED; + else + return 0; + r->start = base; r->end = base + length - 1; + count_memory_ranges++; set_phys_offset(r->start); @@ -493,9 +504,10 @@ static int get_memory_ranges_iomem_cb(void *data, int nr, char *str, static int get_memory_ranges_iomem(struct memory_range *array, unsigned int *count) { - *count = kexec_iomem_for_each_line("System RAM\n", - get_memory_ranges_iomem_cb, array); + count_memory_ranges = 0; + kexec_iomem_for_each_line(NULL, get_memory_ranges_iomem_cb, array); + *count = count_memory_ranges; if (!*count) { dbgprintf("%s: failed: No RAM found.\n", __func__); return -EFAILED; -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v26 7/7] Documentation: dt: chosen properties for arm64 kdump
From: James MorseAdd documentation for linux,crashkernel-base and crashkernel-size, linux,elfcorehdr used by arm64 kexec/kdump to decribe the kdump reserved area, and the elfcorehdr's location within it. Signed-off-by: James Morse [takahiro.aka...@linaro.org: added "linux,crashkernel-base" and "-size" ] Signed-off-by: AKASHI Takahiro --- Documentation/devicetree/bindings/chosen.txt | 30 1 file changed, 30 insertions(+) diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt index 6ae9d82..6257ee7 100644 --- a/Documentation/devicetree/bindings/chosen.txt +++ b/Documentation/devicetree/bindings/chosen.txt @@ -52,3 +52,33 @@ This property is set (currently only on PowerPC, and only needed on book3e) by some versions of kexec-tools to tell the new kernel that it is being booted by kexec, as the booting environment may differ (e.g. a different secondary CPU release mechanism) + +linux,crashkernel-base +linux,crashkernel-size +-- + +These properties (currently used on PowerPC and arm64) indicates +the base address and the size, respectively, of the reserved memory +range for crash dump kernel. +e.g. + +/ { + chosen { + linux,crashkernel-base = <0x9 0xf000>; + linux,crashkernel-size = <0x0 0x1000>; + }; +}; + +linux,elfcorehdr + + +This property (currently used only on arm64) holds the memory range, +the address and the size, of the elf core header which mainly describes +the panicked kernel's memory layout as PT_LOAD segments of elf format. +e.g. + +/ { + chosen { + linux,elfcorehdr = <0x9 0xf000 0x0 0x800>; + }; +}; -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v26 6/7] arm64: kdump: update a kernel doc
This patch adds arch specific descriptions about kdump usage on arm64 to kdump.txt. Signed-off-by: AKASHI TakahiroReviewed-by: Baoquan He Acked-by: Dave Young --- Documentation/kdump/kdump.txt | 16 +++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 88ff63d..c090531 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt @@ -18,7 +18,7 @@ memory image to a dump file on the local disk, or across the network to a remote system. Kdump and kexec are currently supported on the x86, x86_64, ppc64, ia64, -s390x and arm architectures. +s390x, arm and arm64 architectures. When the system kernel boots, it reserves a small section of memory for the dump-capture kernel. This ensures that ongoing Direct Memory Access @@ -249,6 +249,13 @@ Dump-capture kernel config options (Arch Dependent, arm) AUTO_ZRELADDR=y +Dump-capture kernel config options (Arch Dependent, arm64) +-- + +- Please note that kvm of the dump-capture kernel will not be enabled + on non-VHE systems even if it is configured. This is because the CPU + cannot be reset to EL2 on panic. + Extended crashkernel syntax === @@ -305,6 +312,8 @@ Boot into System Kernel kernel will automatically locate the crash kernel image within the first 512MB of RAM if X is not given. + On arm64, use "crashkernel=Y[@X]". Note that the start address of + the kernel, X if explicitly specified, must be aligned to 2MiB (0x20). Load the Dump-capture Kernel @@ -327,6 +336,8 @@ For s390x: - Use image or bzImage For arm: - Use zImage +For arm64: + - Use vmlinux or Image If you are using a uncompressed vmlinux image then use following command to load dump-capture kernel. @@ -370,6 +381,9 @@ For s390x: For arm: "1 maxcpus=1 reset_devices" +For arm64: + "1 maxcpus=1 reset_devices" + Notes on loading the dump-capture kernel: * By default, the ELF headers are stored in ELF64 format to support -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v26 5/7] arm64: kdump: enable kdump in the arm64 defconfig
Signed-off-by: AKASHI Takahiro--- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index eadf485..e181132 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -77,6 +77,7 @@ CONFIG_CMA=y CONFIG_SECCOMP=y CONFIG_XEN=y CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_CPU_IDLE=y -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v26 4/7] arm64: kdump: add VMCOREINFO's for user-space coredump tools
For the current crash utility, we need to know, at least, - kimage_voffset - PHYS_OFFSET to handle the contents of core dump file (/proc/vmcore) correctly due to the introduction of KASLR (CONFIG_RANDOMIZE_BASE) in v4.6. This patch puts them as VMCOREINFO's into the file. - VA_BITS is also added for makedumpfile command. More VMCOREINFO's may be added later. Signed-off-by: AKASHI Takahiro--- arch/arm64/kernel/machine_kexec.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index 8ac9dba8..38b4411 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -17,6 +17,7 @@ #include #include +#include #include #include "cpu-reset.h" @@ -260,3 +261,13 @@ void machine_crash_shutdown(struct pt_regs *regs) pr_info("Starting crashdump kernel...\n"); } + +void arch_crash_save_vmcoreinfo(void) +{ + VMCOREINFO_NUMBER(VA_BITS); + /* Please note VMCOREINFO_NUMBER() uses "%d", not "%x" */ + vmcoreinfo_append_str("NUMBER(kimage_voffset)=0x%llx\n", + kimage_voffset); + vmcoreinfo_append_str("NUMBER(PHYS_OFFSET)=0x%llx\n", + PHYS_OFFSET); +} -- 2.9.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v26 3/7] arm64: kdump: add kdump support
On crash dump kernel, all the information about primary kernel's system memory (core image) is available in elf core header. The primary kernel will set aside this header with reserve_elfcorehdr() at boot time and inform crash dump kernel of its location via a new device-tree property, "linux,elfcorehdr". Please note that all other architectures use traditional "elfcorehdr=" kernel parameter for this purpose. Then crash dump kernel will access the primary kernel's memory with copy_oldmem_page(), which reads one page by ioremap'ing it since it does not reside in linear mapping on crash dump kernel. We also need our own elfcorehdr_read() here since the header is placed within crash dump kernel's usable memory. Signed-off-by: AKASHI Takahiro--- arch/arm64/Kconfig | 11 +++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/crash_dump.c | 71 ++ arch/arm64/mm/init.c | 54 4 files changed, 137 insertions(+) create mode 100644 arch/arm64/kernel/crash_dump.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index bc3f00f..9c15c66 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -683,6 +683,17 @@ config KEXEC but it is independent of the system firmware. And like a reboot you can start any kernel with it, not just Linux. +config CRASH_DUMP + bool "Build kdump crash kernel" + help + Generate crash dump after being started by kexec. This should + be normally only set in special crash dump kernels which are + loaded in the main kernel with kexec-tools into a specially + reserved region and then later executed after a crash by + kdump/kexec. + + For more details see Documentation/kdump/kdump.txt + config XEN_DOM0 def_bool y depends on XEN diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 14f7b65..f1cbfc8 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -48,6 +48,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_CRASH_DUMP) += crash_dump.o obj-y += $(arm64-obj-y) vdso/ probes/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/crash_dump.c b/arch/arm64/kernel/crash_dump.c new file mode 100644 index 000..bc5b932 --- /dev/null +++ b/arch/arm64/kernel/crash_dump.c @@ -0,0 +1,71 @@ +/* + * Routines for doing kexec-based kdump + * + * Copyright (C) 2014 Linaro Limited + * Author: AKASHI Takahiro + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +/** + * copy_oldmem_page() - copy one page from old kernel memory + * @pfn: page frame number to be copied + * @buf: buffer where the copied page is placed + * @csize: number of bytes to copy + * @offset: offset in bytes into the page + * @userbuf: if set, @buf is in a user address space + * + * This function copies one page from old kernel memory into buffer pointed by + * @buf. If @buf is in userspace, set @userbuf to %1. Returns number of bytes + * copied or negative error in case of failure. + */ +ssize_t copy_oldmem_page(unsigned long pfn, char *buf, +size_t csize, unsigned long offset, +int userbuf) +{ + void *vaddr; + + if (!csize) + return 0; + + vaddr = memremap(__pfn_to_phys(pfn), PAGE_SIZE, MEMREMAP_WB); + if (!vaddr) + return -ENOMEM; + + if (userbuf) { + if (copy_to_user(buf, vaddr + offset, csize)) { + memunmap(vaddr); + return -EFAULT; + } + } else { + memcpy(buf, vaddr + offset, csize); + } + + memunmap(vaddr); + + return csize; +} + +/** + * elfcorehdr_read - read from ELF core header + * @buf: buffer where the data is placed + * @csize: number of bytes to read + * @ppos: address in the memory + * + * This function reads @count bytes from elf core header which exists + * on crash dump kernel's memory. + */ +ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos) +{ + memcpy(buf, phys_to_virt((phys_addr_t)*ppos), count); + return count; +} diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index dd273ec..e4d9c38 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -186,6
[PATCH v26 1/7] arm64: kdump: reserve memory for crash dump kernel
On the startup of primary kernel, the memory region used by crash dump kernel must be specified by "crashkernel=" kernel parameter. reserve_crashkernel() will allocate and reserve the region for later use. User space tools, like kexec-tools, will be able to find that region as - "Crash kernel" in /proc/iomem, or - "linux,crashkernel-base" and "linux,crashkernel-size" under /sys/firmware/devicetree/base/chosen Signed-off-by: AKASHI TakahiroSigned-off-by: Mark Salter Signed-off-by: Pratyush Anand Reviewed-by: James Morse --- arch/arm64/kernel/setup.c | 7 ++- arch/arm64/mm/init.c | 113 ++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 514b4e3..38589b5 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -225,6 +224,12 @@ static void __init request_standard_resources(void) kernel_data.end <= res->end) request_resource(res, _data); } + +#ifdef CONFIG_KEXEC_CORE + /* User space tools will find "Crash kernel" region in /proc/iomem. */ + if (crashk_res.end) + insert_resource(_resource, _res); +#endif } u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID }; diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index bbb7ee7..dd273ec 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -29,11 +29,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -76,6 +78,114 @@ static int __init early_initrd(char *p) early_param("initrd", early_initrd); #endif +#ifdef CONFIG_KEXEC_CORE +static unsigned long long crash_size, crash_base; +static struct property crash_base_prop = { + .name = "linux,crashkernel-base", + .length = sizeof(u64), + .value = _base +}; +static struct property crash_size_prop = { + .name = "linux,crashkernel-size", + .length = sizeof(u64), + .value = _size, +}; + +static int __init export_crashkernel(void) +{ + struct device_node *node; + int ret; + + if (!crashk_res.end) + return 0; + + crash_base = cpu_to_be64(crashk_res.start); + crash_size = cpu_to_be64(crashk_res.end - crashk_res.start + 1); + + /* Add /chosen/linux,crashkernel-* properties */ + node = of_find_node_by_path("/chosen"); + if (!node) + return -ENOENT; + + /* +* There might be existing crash kernel properties, but we can't +* be sure what's in them, so remove them. +*/ + of_remove_property(node, of_find_property(node, + "linux,crashkernel-base", NULL)); + of_remove_property(node, of_find_property(node, + "linux,crashkernel-size", NULL)); + + ret = of_add_property(node, _base_prop); + if (ret) + goto ret_err; + + ret = of_add_property(node, _size_prop); + if (ret) + goto ret_err; + + return 0; + +ret_err: + pr_warn("Exporting crashkernel region to device tree failed\n"); + return ret; +} +late_initcall(export_crashkernel); + +/* + * reserve_crashkernel() - reserves memory for crash kernel + * + * This function reserves memory area given in "crashkernel=" kernel command + * line parameter. The memory reserved is used by dump capture kernel when + * primary kernel is crashing. + */ +static void __init reserve_crashkernel(void) +{ + int ret; + + ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), + _size, _base); + /* no crashkernel= or invalid value specified */ + if (ret || !crash_size) + return; + + if (crash_base == 0) { + /* Current arm64 boot protocol requires 2MB alignment */ + crash_base = memblock_find_in_range(0, ARCH_LOW_ADDRESS_LIMIT, + crash_size, SZ_2M); + if (crash_base == 0) { + pr_warn("Unable to allocate crashkernel (size:%llx)\n", + crash_size); + return; + } + } else { + /* User specifies base address explicitly. */ + if (!memblock_is_region_memory(crash_base, crash_size) || + memblock_is_region_reserved(crash_base, crash_size)) { + pr_warn("crashkernel has wrong address or size\n"); + return; + } + + if (!IS_ALIGNED(crash_base, SZ_2M)) { + pr_warn("crashkernel base address is not 2MB
[PATCH v26 2/7] arm64: kdump: implement machine_crash_shutdown()
Primary kernel calls machine_crash_shutdown() to shut down non-boot cpus and save registers' status in per-cpu ELF notes before starting crash dump kernel. See kernel_kexec(). Even if not all secondary cpus have shut down, we do kdump anyway. As we don't have to make non-boot(crashed) cpus offline (to preserve correct status of cpus at crash dump) before shutting down, this patch also adds a variant of smp_send_stop(). Signed-off-by: AKASHI Takahiro--- arch/arm64/include/asm/hardirq.h | 2 +- arch/arm64/include/asm/kexec.h| 41 - arch/arm64/include/asm/smp.h | 2 ++ arch/arm64/kernel/machine_kexec.c | 56 -- arch/arm64/kernel/smp.c | 63 +++ 5 files changed, 159 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h index 8740297..1473fc2 100644 --- a/arch/arm64/include/asm/hardirq.h +++ b/arch/arm64/include/asm/hardirq.h @@ -20,7 +20,7 @@ #include #include -#define NR_IPI 6 +#define NR_IPI 7 typedef struct { unsigned int __softirq_pending; diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h index 04744dc..a908958 100644 --- a/arch/arm64/include/asm/kexec.h +++ b/arch/arm64/include/asm/kexec.h @@ -40,7 +40,46 @@ static inline void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) { - /* Empty routine needed to avoid build errors. */ + if (oldregs) { + memcpy(newregs, oldregs, sizeof(*newregs)); + } else { + u64 tmp1, tmp2; + + __asm__ __volatile__ ( + "stp x0, x1, [%2, #16 * 0]\n" + "stp x2, x3, [%2, #16 * 1]\n" + "stp x4, x5, [%2, #16 * 2]\n" + "stp x6, x7, [%2, #16 * 3]\n" + "stp x8, x9, [%2, #16 * 4]\n" + "stpx10, x11, [%2, #16 * 5]\n" + "stpx12, x13, [%2, #16 * 6]\n" + "stpx14, x15, [%2, #16 * 7]\n" + "stpx16, x17, [%2, #16 * 8]\n" + "stpx18, x19, [%2, #16 * 9]\n" + "stpx20, x21, [%2, #16 * 10]\n" + "stpx22, x23, [%2, #16 * 11]\n" + "stpx24, x25, [%2, #16 * 12]\n" + "stpx26, x27, [%2, #16 * 13]\n" + "stpx28, x29, [%2, #16 * 14]\n" + "mov %0, sp\n" + "stpx30, %0, [%2, #16 * 15]\n" + + "/* faked current PSTATE */\n" + "mrs %0, CurrentEL\n" + "mrs %1, DAIF\n" + "orr %0, %0, %1\n" + "mrs %1, NZCV\n" + "orr %0, %0, %1\n" + + /* pc */ + "adr %1, 1f\n" + "1:\n" + "stp %1, %0, [%2, #16 * 16]\n" + : "=r" (tmp1), "=r" (tmp2), "+r" (newregs) + : + : "memory" + ); + } } #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 0226447..6b0f2c7 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -136,6 +136,8 @@ static inline void cpu_panic_kernel(void) */ bool cpus_are_stuck_in_kernel(void); +extern void smp_send_crash_stop(void); + #endif /* ifndef __ASSEMBLY__ */ #endif /* ifndef __ASM_SMP_H */ diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index bc96c8a..8ac9dba8 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -9,6 +9,9 @@ * published by the Free Software Foundation. */ +#include +#include +#include #include #include @@ -22,6 +25,7 @@ extern const unsigned char arm64_relocate_new_kernel[]; extern const unsigned long arm64_relocate_new_kernel_size; +bool in_crash_kexec; static unsigned long kimage_start; /** @@ -148,7 +152,8 @@ void machine_kexec(struct kimage *kimage) /* * New cpus may have become stuck_in_kernel after we loaded the image. */ - BUG_ON(cpus_are_stuck_in_kernel() || (num_online_cpus() > 1)); + BUG_ON((cpus_are_stuck_in_kernel() || (num_online_cpus() > 1)) && + !WARN_ON(in_crash_kexec)); reboot_code_buffer_phys = page_to_phys(kimage->control_code_page); reboot_code_buffer = phys_to_virt(reboot_code_buffer_phys); @@ -200,13 +205,58 @@ void machine_kexec(struct kimage *kimage) * relocation is complete. */ - cpu_soft_restart(1, reboot_code_buffer_phys, kimage->head, +
[PATCH v26 0/7] arm64: add kdump support
v26-specific note: After a comment from Rob[0], an idea of adding "linux,usable-memory-range" was dropped. Instead, an existing "reserved-memory" node will be used to limit usable memory ranges on crash dump kernel. This works not only on UEFI/ACPI systems but also on DT-only systems, but if he really insists on using DT-specific "usable-memory" property, I will post additional patches for kexec-tools. Those would be redundant, though. Even in that case, the kernel will not have to be changed. This patch series adds kdump support on arm64. There are some prerequisite patches [1],[2]. To load a crash-dump kernel to the systems, a series of patches to kexec-tools, which have not yet been merged upstream, are needed. Please always use my latest kdump patches, v3 [3]. To examine vmcore (/proc/vmcore) on a crash-dump kernel, you can use - crash utility (coming v7.1.6 or later) [4] (Necessary patches have already been queued in the master.) [0] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/452582.html [1] "arm64: mark reserved memblock regions explicitly in iomem" http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/450433.html [2] "efi: arm64: treat regions with WT/WC set but WB cleared as memory" http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/451491.html [3] T.B.D. [4] https://github.com/crash-utility/crash.git Changes for v26 (Sep 7, 2016): o Use /reserved-memory instead of "linux,usable-memory-range" property (dropping v25's patch#2 and #3, updating ex-patch#9.) Changes for v25 (Aug 29, 2016): o Rebase to Linux-4.8-rc4 o Use memremap() instead of ioremap_cache() [patch#5] Changes for v24 (Aug 9, 2016): o Rebase to Linux-4.8-rc1 o Update descriptions about newly added DT proerties Changes for v23 (July 26, 2016): o Move memblock_reserve() to a single place in reserve_crashkernel() o Use cpu_park_loop() in ipi_cpu_crash_stop() o Always enforce ARCH_LOW_ADDRESS_LIMIT to the memory range of crash kernel o Re-implement fdt_enforce_memory_region() to remove non-reserve regions (for ACPI) from usable memory at crash kernel Changes for v22 (July 12, 2016): o Export "crashkernel-base" and "crashkernel-size" via device-tree, and add some descriptions about them in chosen.txt o Rename "usable-memory" to "usable-memory-range" to avoid inconsistency with powerpc's "usable-memory" o Make cosmetic changes regarding "ifdef" usage o Correct some wordings in kdump.txt Changes for v21 (July 6, 2016): o Remove kexec patches. o Rebase to arm64's for-next/core (Linux-4.7-rc4 based). o Clarify the description about kvm in kdump.txt. See the following link [3] for older changes: [3] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-June/438780.html AKASHI Takahiro (8): arm64: kdump: reserve memory for crash dump kernel memblock: add memblock_cap_memory_range() arm64: limit memory regions based on DT property, usable-memory-range arm64: kdump: implement machine_crash_shutdown() arm64: kdump: add kdump support arm64: kdump: add VMCOREINFO's for user-space coredump tools arm64: kdump: enable kdump in the arm64 defconfig arm64: kdump: update a kernel doc James Morse (1): Documentation: dt: chosen properties for arm64 kdump Documentation/devicetree/bindings/chosen.txt | 45 ++ Documentation/kdump/kdump.txt| 16 ++- arch/arm64/Kconfig | 11 ++ arch/arm64/configs/defconfig | 1 + arch/arm64/include/asm/hardirq.h | 2 +- arch/arm64/include/asm/kexec.h | 41 +- arch/arm64/include/asm/smp.h | 2 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/crash_dump.c | 71 ++ arch/arm64/kernel/machine_kexec.c| 67 - arch/arm64/kernel/setup.c| 7 +- arch/arm64/kernel/smp.c | 63 + arch/arm64/mm/init.c | 202 +++ include/linux/memblock.h | 1 + mm/memblock.c| 28 15 files changed, 551 insertions(+), 7 deletions(-) create mode 100644 arch/arm64/kernel/crash_dump.c -- 2.9.0 AKASHI Takahiro (6): arm64: kdump: reserve memory for crash dump kernel arm64: kdump: implement machine_crash_shutdown() arm64: kdump: add kdump support arm64: kdump: add VMCOREINFO's for user-space coredump tools arm64: kdump: enable kdump in the arm64 defconfig arm64: kdump: update a kernel doc James Morse (1): Documentation: dt: chosen properties for arm64 kdump Documentation/devicetree/bindings/chosen.txt | 30 + Documentation/kdump/kdump.txt| 16 ++- arch/arm64/Kconfig | 11 ++ arch/arm64/configs/defconfig | 1 + arch/arm64/include/asm/hardirq.h
Re: [PATCH v4 3/5] kexec_file: Allow skipping checksum calculation for some segments.
Thiago Jung Bauermannwrites: 2> Add skip_checksum member to struct kexec_buf to specify whether the > corresponding segment should be part of the checksum calculation. > > The next patch will add a way to update segments after a kimage is loaded. > Segments that will be updated in this way should not be checksummed, > otherwise they will cause the purgatory checksum verification to fail > when the machine is rebooted. > > As a bonus, we don't need to special-case the purgatory segment anymore > to avoid checksumming it. > > Places using struct kexec_buf get false as the default value for > skip_checksum since they all use designated initializers. Therefore, > there is no behavior change with this patch and all segments except the > purgatory are checksummed. What is the world. This fundamentally makes kexec unsafe to use. If any updates need to be made they should be made before they are part of the entire image checksum. No way should this be merged anywhere ever. Nacked-by: "Eric W. Biederman" > > Signed-off-by: Thiago Jung Bauermann > --- > include/linux/kexec.h | 23 ++- > kernel/kexec_file.c | 15 +++ > 2 files changed, 21 insertions(+), 17 deletions(-) > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > index 16561e96a6d7..edadff6c86ff 100644 > --- a/include/linux/kexec.h > +++ b/include/linux/kexec.h > @@ -100,6 +100,9 @@ struct kexec_segment { > size_t bufsz; > unsigned long mem; > size_t memsz; > + > + /* Whether this segment is ignored in the checksum calculation. */ > + bool skip_checksum; > }; > > #ifdef CONFIG_COMPAT > @@ -151,15 +154,16 @@ struct kexec_file_ops { > > /** > * struct kexec_buf - parameters for finding a place for a buffer in memory > - * @image: kexec image in which memory to search. > - * @buffer: Contents which will be copied to the allocated memory. > - * @bufsz: Size of @buffer. > - * @mem: On return will have address of the buffer in memory. > - * @memsz: Size for the buffer in memory. > - * @buf_align: Minimum alignment needed. > - * @buf_min: The buffer can't be placed below this address. > - * @buf_max: The buffer can't be placed above this address. > - * @top_down:Allocate from top of memory. > + * @image: kexec image in which memory to search. > + * @buffer: Contents which will be copied to the allocated memory. > + * @bufsz: Size of @buffer. > + * @mem: On return will have address of the buffer in memory. > + * @memsz: Size for the buffer in memory. > + * @buf_align: Minimum alignment needed. > + * @buf_min: The buffer can't be placed below this address. > + * @buf_max: The buffer can't be placed above this address. > + * @top_down:Allocate from top of memory. > + * @skip_checksum: Don't verify checksum for this buffer in purgatory. > */ > struct kexec_buf { > struct kimage *image; > @@ -171,6 +175,7 @@ struct kexec_buf { > unsigned long buf_min; > unsigned long buf_max; > bool top_down; > + bool skip_checksum; > }; > > int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > index f5684adfad07..0e90d1446cb0 100644 > --- a/kernel/kexec_file.c > +++ b/kernel/kexec_file.c > @@ -584,6 +584,7 @@ int kexec_add_buffer(struct kexec_buf *kbuf) > ksegment->bufsz = kbuf->bufsz; > ksegment->mem = kbuf->mem; > ksegment->memsz = kbuf->memsz; > + ksegment->skip_checksum = kbuf->skip_checksum; > kbuf->image->nr_segments++; > return 0; > } > @@ -598,7 +599,6 @@ static int kexec_calculate_store_digests(struct kimage > *image) > char *digest; > void *zero_buf; > struct kexec_sha_region *sha_regions; > - struct purgatory_info *pi = >purgatory_info; > > zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT); > zero_buf_sz = PAGE_SIZE; > @@ -638,11 +638,7 @@ static int kexec_calculate_store_digests(struct kimage > *image) > struct kexec_segment *ksegment; > > ksegment = >segment[i]; > - /* > - * Skip purgatory as it will be modified once we put digest > - * info in purgatory. > - */ > - if (ksegment->kbuf == pi->purgatory_buf) > + if (ksegment->skip_checksum) > continue; > > ret = crypto_shash_update(desc, ksegment->kbuf, > @@ -714,7 +710,7 @@ static int __kexec_load_purgatory(struct kimage *image, > unsigned long min, > Elf_Shdr *sechdrs = NULL; > struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1, > .buf_min = min, .buf_max = max, > - .top_down = top_down }; > +
Re: [PATCH v24 0/9] arm64: add kdump support
On 06/09/16 17:15, Manish Jaggi wrote: > >>> In my setup the GICD_CTRL[RWP] bit is not cleared in the >>> crashkernels' distributor init function. >> >> Which instance is failing? The initial one (just after the initial >> disable)? Or the one called from gic_dist_config()? >> > In crash kernel, when the GICD_CTRL is set to 0x0, RWP is not getting clear. > And is never cleared for any subsequent writes. That's weird. It means writes are still pending, and never drained. What happens if you put a dsb(sy) in the wait_for_rwp() loop? Thanks, M. -- Jazz is not dead. It just smells funny... ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
Re: [PATCH v24 0/9] arm64: add kdump support
On 09/06/2016 09:03 PM, Marc Zyngier wrote: > On 05/09/16 13:42, Manish Jaggi wrote: >> >> >> On 09/05/2016 01:45 PM, AKASHI Takahiro wrote: >>> [Cc: Marc] >>> >>> On Fri, Sep 02, 2016 at 06:23:25PM +0530, Manish Jaggi wrote: On 08/31/2016 11:01 AM, AKASHI Takahiro wrote: > Manish, > > Thank you for testing my kdump and reporting issues. > > On Wed, Aug 31, 2016 at 09:11:52AM +0530, Manish Jaggi wrote: >> Hi Akashi, >> >> On 08/09/2016 07:22 AM, AKASHI Takahiro wrote: >>> This patch series adds kdump support on arm64. >>> >>> To load a crash-dump kernel to the systems, a series of patches to >>> kexec-tools, which have not yet been merged upstream, are needed. >>> Please use my kdump patches [1]. >>> >>> To examine vmcore (/proc/vmcore) on a crash-dump kernel, you can use >>> - crash utility (coming v7.1.6 or later) [2] >>> (Necessary patches have already been queued in the master.) >>> >>> [1] T.B.D. >>> [2] https://github.com/crash-utility/crash.git >>> >>> Changes for v24 (Aug 9, 2016): >>> o Rebase to Linux-4.8-rc1 >>> o Update descriptions about newly added DT proerties >>> >>> Changes for v23 (July 26, 2016): >>> >>> o Move memblock_reserve() to a single place in reserve_crashkernel() >>> o Use cpu_park_loop() in ipi_cpu_crash_stop() >>> o Always enforce ARCH_LOW_ADDRESS_LIMIT to the memory range of crash >>> kernel >>> o Re-implement fdt_enforce_memory_region() to remove non-reserve >>> regions >>> (for ACPI) from usable memory at crash kernel >>> >>> Changes for v22 (July 12, 2016): >>> >>> o Export "crashkernel-base" and "crashkernel-size" via device-tree, >>> and add some descriptions about them in chosen.txt >>> o Rename "usable-memory" to "usable-memory-range" to avoid >>> inconsistency >>> with powerpc's "usable-memory" >>> o Make cosmetic changes regarding "ifdef" usage >>> o Correct some wordings in kdump.txt >>> >>> Changes for v21 (July 6, 2016): >>> >>> o Remove kexec patches. >>> o Rebase to arm64's for-next/core (Linux-4.7-rc4 based). >>> o Clarify the description about kvm in kdump.txt. >>> >>> See the following link [3] for older changes: >>> [3] >>> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-June/438780.html >>> >>> AKASHI Takahiro (8): >>> arm64: kdump: reserve memory for crash dump kernel >>> memblock: add memblock_cap_memory_range() >>> arm64: limit memory regions based on DT property, usable-memory-range >>> arm64: kdump: implement machine_crash_shutdown() >>> arm64: kdump: add kdump support >>> arm64: kdump: add VMCOREINFO's for user-space coredump tools >>> arm64: kdump: enable kdump in the arm64 defconfig >>> arm64: kdump: update a kernel doc >>> >>> James Morse (1): >>> Documentation: dt: chosen properties for arm64 kdump >>> >>> Documentation/devicetree/bindings/chosen.txt | 45 ++ >>> Documentation/kdump/kdump.txt| 16 ++- >>> arch/arm64/Kconfig | 11 ++ >>> arch/arm64/configs/defconfig | 1 + >>> arch/arm64/include/asm/hardirq.h | 2 +- >>> arch/arm64/include/asm/kexec.h | 41 +- >>> arch/arm64/include/asm/smp.h | 2 + >>> arch/arm64/kernel/Makefile | 1 + >>> arch/arm64/kernel/crash_dump.c | 71 ++ >>> arch/arm64/kernel/machine_kexec.c| 67 - >>> arch/arm64/kernel/setup.c| 7 +- >>> arch/arm64/kernel/smp.c | 63 + >>> arch/arm64/mm/init.c | 202 >>> +++ >>> include/linux/memblock.h | 1 + >>> mm/memblock.c| 28 >>> 15 files changed, 551 insertions(+), 7 deletions(-) >>> create mode 100644 arch/arm64/kernel/crash_dump.c >>> >> Couple of points >> a) Just a note, while testing, the crashkernel reserved memory should be >> less than ARCH_LOW_ADDRESS_LIMIT (=arm64_dma_phys_limit). > > I think that this is a common mistake not only for kdump, but also > for general kernels. > Since request_standard_resources() calls alloc_bootmem_low(), > the kernel will panic if any of usable "System RAM" is located > above ARCH_LOW_ADDRESS_LIMIT. > For kdump, using "crashkernel=SS" notation is a convenient way > to avoid this issue. > >> b) Has anyone tested this on a SoC with Gicv3 ITS ? >> Should the GICD/R be reset prior to switching to crash kernel ? >> I am seeing lot of GICv3: RWP timeout, gone fishing while crash kernel >> boots. >
Re: [PATCH v24 0/9] arm64: add kdump support
On 05/09/16 13:42, Manish Jaggi wrote: > > > On 09/05/2016 01:45 PM, AKASHI Takahiro wrote: >> [Cc: Marc] >> >> On Fri, Sep 02, 2016 at 06:23:25PM +0530, Manish Jaggi wrote: >>> >>> >>> On 08/31/2016 11:01 AM, AKASHI Takahiro wrote: Manish, Thank you for testing my kdump and reporting issues. On Wed, Aug 31, 2016 at 09:11:52AM +0530, Manish Jaggi wrote: > Hi Akashi, > > On 08/09/2016 07:22 AM, AKASHI Takahiro wrote: >> This patch series adds kdump support on arm64. >> >> To load a crash-dump kernel to the systems, a series of patches to >> kexec-tools, which have not yet been merged upstream, are needed. >> Please use my kdump patches [1]. >> >> To examine vmcore (/proc/vmcore) on a crash-dump kernel, you can use >> - crash utility (coming v7.1.6 or later) [2] >> (Necessary patches have already been queued in the master.) >> >> [1] T.B.D. >> [2] https://github.com/crash-utility/crash.git >> >> Changes for v24 (Aug 9, 2016): >> o Rebase to Linux-4.8-rc1 >> o Update descriptions about newly added DT proerties >> >> Changes for v23 (July 26, 2016): >> >> o Move memblock_reserve() to a single place in reserve_crashkernel() >> o Use cpu_park_loop() in ipi_cpu_crash_stop() >> o Always enforce ARCH_LOW_ADDRESS_LIMIT to the memory range of crash >> kernel >> o Re-implement fdt_enforce_memory_region() to remove non-reserve >> regions >> (for ACPI) from usable memory at crash kernel >> >> Changes for v22 (July 12, 2016): >> >> o Export "crashkernel-base" and "crashkernel-size" via device-tree, >> and add some descriptions about them in chosen.txt >> o Rename "usable-memory" to "usable-memory-range" to avoid >> inconsistency >> with powerpc's "usable-memory" >> o Make cosmetic changes regarding "ifdef" usage >> o Correct some wordings in kdump.txt >> >> Changes for v21 (July 6, 2016): >> >> o Remove kexec patches. >> o Rebase to arm64's for-next/core (Linux-4.7-rc4 based). >> o Clarify the description about kvm in kdump.txt. >> >> See the following link [3] for older changes: >> [3] >> http://lists.infradead.org/pipermail/linux-arm-kernel/2016-June/438780.html >> >> AKASHI Takahiro (8): >> arm64: kdump: reserve memory for crash dump kernel >> memblock: add memblock_cap_memory_range() >> arm64: limit memory regions based on DT property, usable-memory-range >> arm64: kdump: implement machine_crash_shutdown() >> arm64: kdump: add kdump support >> arm64: kdump: add VMCOREINFO's for user-space coredump tools >> arm64: kdump: enable kdump in the arm64 defconfig >> arm64: kdump: update a kernel doc >> >> James Morse (1): >> Documentation: dt: chosen properties for arm64 kdump >> >> Documentation/devicetree/bindings/chosen.txt | 45 ++ >> Documentation/kdump/kdump.txt| 16 ++- >> arch/arm64/Kconfig | 11 ++ >> arch/arm64/configs/defconfig | 1 + >> arch/arm64/include/asm/hardirq.h | 2 +- >> arch/arm64/include/asm/kexec.h | 41 +- >> arch/arm64/include/asm/smp.h | 2 + >> arch/arm64/kernel/Makefile | 1 + >> arch/arm64/kernel/crash_dump.c | 71 ++ >> arch/arm64/kernel/machine_kexec.c| 67 - >> arch/arm64/kernel/setup.c| 7 +- >> arch/arm64/kernel/smp.c | 63 + >> arch/arm64/mm/init.c | 202 >> +++ >> include/linux/memblock.h | 1 + >> mm/memblock.c| 28 >> 15 files changed, 551 insertions(+), 7 deletions(-) >> create mode 100644 arch/arm64/kernel/crash_dump.c >> > Couple of points > a) Just a note, while testing, the crashkernel reserved memory should be > less than ARCH_LOW_ADDRESS_LIMIT (=arm64_dma_phys_limit). I think that this is a common mistake not only for kdump, but also for general kernels. Since request_standard_resources() calls alloc_bootmem_low(), the kernel will panic if any of usable "System RAM" is located above ARCH_LOW_ADDRESS_LIMIT. For kdump, using "crashkernel=SS" notation is a convenient way to avoid this issue. > b) Has anyone tested this on a SoC with Gicv3 ITS ? > Should the GICD/R be reset prior to switching to crash kernel ? > I am seeing lot of GICv3: RWP timeout, gone fishing while crash kernel > boots. I've never seen this kind of messages. I usually do my testing on a fast model. "compatible" of interrupt-controller is "arm,gic-v3." >>> I
[PATCH v3 6/9] ima: store the builtin/custom template definitions in a list
The builtin and single custom templates are currently stored in an array. In preparation for being able to restore a measurement list containing multiple builtin/custom templates, this patch stores the builtin and custom templates as a linked list. This will permit defining more than one custom template per boot. Changelog v2: - fix lookup_template_desc() preemption imbalance (kernel test robot) Signed-off-by: Mimi Zohar--- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_main.c | 1 + security/integrity/ima/ima_template.c | 43 +++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 634d140..e8303c9 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -81,6 +81,7 @@ struct ima_template_field { /* IMA template descriptor definition */ struct ima_template_desc { + struct list_head list; char *name; char *fmt; int num_fields; @@ -136,6 +137,7 @@ int ima_restore_measurement_list(loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); +void ima_init_template_list(void); #ifdef CONFIG_KEXEC_FILE void ima_load_kexec_buffer(void); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 596ef61..592f318 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -418,6 +418,7 @@ static int __init init_ima(void) { int error; + ima_init_template_list(); hash_setup(CONFIG_IMA_DEFAULT_HASH); error = ima_init(); if (!error) { diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 7c90075..e1f9ce7 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -15,16 +15,20 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include "ima.h" #include "ima_template_lib.h" -static struct ima_template_desc defined_templates[] = { +static struct ima_template_desc builtin_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, {.name = "", .fmt = ""},/* placeholder for a custom format */ }; +static LIST_HEAD(defined_templates); +spinlock_t template_list; + static struct ima_template_field supported_fields[] = { {.field_id = "d", .field_init = ima_eventdigest_init, .field_show = ima_show_template_digest}, @@ -81,7 +85,7 @@ __setup("ima_template=", ima_template_setup); static int __init ima_template_fmt_setup(char *str) { - int num_templates = ARRAY_SIZE(defined_templates); + int num_templates = ARRAY_SIZE(builtin_templates); if (ima_template) return 1; @@ -92,22 +96,28 @@ static int __init ima_template_fmt_setup(char *str) return 1; } - defined_templates[num_templates - 1].fmt = str; - ima_template = defined_templates + num_templates - 1; + builtin_templates[num_templates - 1].fmt = str; + ima_template = builtin_templates + num_templates - 1; + return 1; } __setup("ima_template_fmt=", ima_template_fmt_setup); static struct ima_template_desc *lookup_template_desc(const char *name) { - int i; + struct ima_template_desc *template_desc; + int found = 0; - for (i = 0; i < ARRAY_SIZE(defined_templates); i++) { - if (strcmp(defined_templates[i].name, name) == 0) - return defined_templates + i; + rcu_read_lock(); + list_for_each_entry_rcu(template_desc, _templates, list) { + if ((strcmp(template_desc->name, name) == 0) || + (strcmp(template_desc->fmt, name) == 0)) { + found = 1; + break; + } } - - return NULL; + rcu_read_unlock(); + return found ? template_desc : NULL; } static struct ima_template_field *lookup_template_field(const char *field_id) @@ -183,6 +193,19 @@ static int template_desc_init_fields(const char *template_fmt, return 0; } +void __init ima_init_template_list(void) +{ + int i; + + spin_lock(_list); + for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) { + list_add_tail_rcu(_templates[i].list, + _templates); + } + spin_unlock(_list); + synchronize_rcu(); +} + struct ima_template_desc *ima_template_desc_current(void) { if (!ima_template) -- 2.1.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 8/9] ima: define a canonical binary_runtime_measurements list format
The IMA binary_runtime_measurements list is currently in platform native format. To allow restoring a measurement list carried across kexec with a different endianness than the targeted kernel, this patch defines little-endian as the canonical format. For big endian systems wanting to save/restore the measurement list from a system with a different endianness, a new boot command line parameter named "ima_canonical_fmt" is defined. Considerations: use of the "ima_canonical_fmt" boot command line option will break existing userspace applications on big endian systems expecting the binary_runtime_measurements list to be in platform native format. Changelog v3: - restore PCR value properly Signed-off-by: Mimi Zohar--- Documentation/kernel-parameters.txt | 4 security/integrity/ima/ima.h | 6 ++ security/integrity/ima/ima_fs.c | 28 +--- security/integrity/ima/ima_kexec.c| 11 +-- security/integrity/ima/ima_template.c | 24 ++-- security/integrity/ima/ima_template_lib.c | 7 +-- 6 files changed, 67 insertions(+), 13 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 46c030a..5e8037fc 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1580,6 +1580,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. The builtin appraise policy appraises all files owned by uid=0. + ima_canonical_fmt [IMA] + Use the canonical format for the binary runtime + measurements, instead of host native format. + ima_hash= [IMA] Format: { md5 | sha1 | rmd160 | sha256 | sha384 | sha512 | ... } diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e8303c9..eb0f4dd 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -112,6 +112,12 @@ struct ima_kexec_hdr { u64 count; }; +/* + * The default binary_runtime_measurements list format is defined as the + * platform native format. The canonical format is defined as little-endian. + */ +extern bool ima_canonical_fmt; + /* Internal IMA function definitions */ int ima_init(void); int ima_fs_init(void); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 66e5dd5..2bcad99 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -28,6 +28,16 @@ static DEFINE_MUTEX(ima_write_mutex); +bool ima_canonical_fmt; +static int __init default_canonical_fmt_setup(char *str) +{ +#ifdef __BIG_ENDIAN + ima_canonical_fmt = 1; +#endif + return 1; +} +__setup("ima_canonical_fmt", default_canonical_fmt_setup); + static int valid_policy = 1; #define TMPBUFLEN 12 static ssize_t ima_show_htable_value(char __user *buf, size_t count, @@ -122,7 +132,7 @@ int ima_measurements_show(struct seq_file *m, void *v) struct ima_queue_entry *qe = v; struct ima_template_entry *e; char *template_name; - int namelen; + u32 pcr, namelen, template_data_len; /* temporary fields */ bool is_ima_template = false; int i; @@ -139,25 +149,29 @@ int ima_measurements_show(struct seq_file *m, void *v) * PCR used defaults to the same (config option) in * little-endian format, unless set in policy */ - ima_putc(m, >pcr, sizeof(e->pcr)); + pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr); + ima_putc(m, , sizeof(e->pcr)); /* 2nd: template digest */ ima_putc(m, e->digest, TPM_DIGEST_SIZE); /* 3rd: template name size */ - namelen = strlen(template_name); + namelen = !ima_canonical_fmt ? strlen(template_name) : + cpu_to_le32(strlen(template_name)); ima_putc(m, , sizeof(namelen)); /* 4th: template name */ - ima_putc(m, template_name, namelen); + ima_putc(m, template_name, strlen(template_name)); /* 5th: template length (except for 'ima' template) */ if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0) is_ima_template = true; - if (!is_ima_template) - ima_putc(m, >template_data_len, -sizeof(e->template_data_len)); + if (!is_ima_template) { + template_data_len = !ima_canonical_fmt ? e->template_data_len : + cpu_to_le32(e->template_data_len); + ima_putc(m, _data_len, sizeof(e->template_data_len)); + } /* 6th: template specific data */ for (i = 0; i < e->template_desc->num_fields; i++) { diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 04a2e71..a76647e 100644 ---
[PATCH v3 4/9] ima: serialize the binary_runtime_measurements
The TPM PCRs are only reset on a hard reboot. In order to validate a TPM's quote after a soft reboot (eg. kexec -e), the IMA measurement list of the running kernel must be saved and restored on boot. This patch serializes the IMA measurement list in the binary_runtime_measurements format. Signed-off-by: Mimi Zohar--- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_fs.c| 2 +- security/integrity/ima/ima_kexec.c | 51 ++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index f9cd08e..634d140 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -133,6 +133,7 @@ void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); struct ima_template_desc *ima_template_desc_current(void); int ima_restore_measurement_entry(struct ima_template_entry *entry); int ima_restore_measurement_list(loff_t bufsize, void *buf); +int ima_measurements_show(struct seq_file *m, void *v); unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index c07a384..66e5dd5 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -116,7 +116,7 @@ void ima_putc(struct seq_file *m, void *data, int datalen) * [eventdata length] * eventdata[n]=template specific data */ -static int ima_measurements_show(struct seq_file *m, void *v) +int ima_measurements_show(struct seq_file *m, void *v) { /* the list never shrinks, so we don't need a lock here */ struct ima_queue_entry *qe = v; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 6a046ad..e77ca9d 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -23,6 +23,57 @@ #include "ima.h" +static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, +unsigned long segment_size) +{ + struct ima_queue_entry *qe; + struct seq_file file; + struct ima_kexec_hdr khdr = { + .version = 1, .buffer_size = 0, .count = 0}; + int ret = 0; + + /* segment size can't change between kexec load and execute */ + file.buf = vmalloc(segment_size); + if (!file.buf) { + ret = -ENOMEM; + goto out; + } + + file.size = segment_size; + file.read_pos = 0; + file.count = sizeof(khdr); /* reserved space */ + + list_for_each_entry_rcu(qe, _measurements, later) { + if (file.count < file.size) { + khdr.count++; + ima_measurements_show(, qe); + } else { + ret = -EINVAL; + break; + } + } + + if (ret < 0) + goto out; + + /* +* fill in reserved space with some buffer details +* (eg. version, buffer size, number of measurements) +*/ + khdr.buffer_size = file.count; + memcpy(file.buf, , sizeof(khdr)); + print_hex_dump(KERN_DEBUG, "ima dump: ", DUMP_PREFIX_NONE, + 16, 1, file.buf, + file.count < 100 ? file.count : 100, true); + + *buffer_size = file.count; + *buffer = file.buf; +out: + if (ret == -EINVAL) + vfree(file.buf); + return ret; +} + /* * Restore the measurement list from the previous kernel. */ -- 2.1.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 9/9] ima: platform-independent hash value
From: Andreas SteffenFor remote attestion it is important for the ima measurement values to be platform-independent. Therefore integer fields to be hashed must be converted to canonical format. Changelog: - Define canonical format as little endian (Mimi) Signed-off-by: Andreas Steffen Signed-off-by: Mimi Zohar --- security/integrity/ima/ima_crypto.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 38f2ed8..802d5d2 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -477,11 +477,13 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 }; u8 *data_to_hash = field_data[i].data; u32 datalen = field_data[i].len; + u32 datalen_to_hash = + !ima_canonical_fmt ? datalen : cpu_to_le32(datalen); if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { rc = crypto_shash_update(shash, - (const u8 *) _data[i].len, - sizeof(field_data[i].len)); + (const u8 *) _to_hash, + sizeof(datalen_to_hash)); if (rc) break; } else if (strcmp(td->fields[i]->field_id, "n") == 0) { -- 2.1.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 2/9] ima: permit duplicate measurement list entries
Measurements carried across kexec need to be added to the IMA measurement list, but should not prevent measurements of the newly booted kernel from being added to the measurement list. This patch adds support for allowing duplicate measurements. The "boot_aggregate" measurement entry is the delimiter between soft boots. Signed-off-by: Mimi Zohar--- security/integrity/ima/ima_queue.c | 15 +-- 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 4b1bb77..12d1b04 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -65,11 +65,12 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, } /* ima_add_template_entry helper function: - * - Add template entry to measurement list and hash table. + * - Add template entry to the measurement list and hash table, for + * all entries except those carried across kexec. * * (Called with ima_extend_list_mutex held.) */ -static int ima_add_digest_entry(struct ima_template_entry *entry) +static int ima_add_digest_entry(struct ima_template_entry *entry, int flags) { struct ima_queue_entry *qe; unsigned int key; @@ -85,8 +86,10 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) list_add_tail_rcu(>later, _measurements); atomic_long_inc(_htable.len); - key = ima_hash_key(entry->digest); - hlist_add_head_rcu(>hnext, _htable.queue[key]); + if (flags) { + key = ima_hash_key(entry->digest); + hlist_add_head_rcu(>hnext, _htable.queue[key]); + } return 0; } @@ -126,7 +129,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, } } - result = ima_add_digest_entry(entry); + result = ima_add_digest_entry(entry, 1); if (result < 0) { audit_cause = "ENOMEM"; audit_info = 0; @@ -155,7 +158,7 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry) int result = 0; mutex_lock(_extend_list_mutex); - result = ima_add_digest_entry(entry); + result = ima_add_digest_entry(entry, 0); mutex_unlock(_extend_list_mutex); return result; } -- 2.1.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v3 3/9] ima: maintain memory size needed for serializing the measurement list
In preparation for serializing the binary_runtime_measurements, this patch maintains the amount of memory required. Changelog v3: - include the ima_kexec_hdr size in the binary_runtime_measurement size. Signed-off-by: Mimi Zohar--- security/integrity/ima/Kconfig | 12 + security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_queue.c | 53 -- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 5487827..1c5a1c2 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -27,6 +27,18 @@ config IMA to learn more about IMA. If unsure, say N. +config IMA_KEXEC + bool "Enable carrying the IMA measurement list across a soft boot" + depends on IMA && TCG_TPM && KEXEC_FILE + default n + help + TPM PCRs are only reset on a hard reboot. In order to validate + a TPM's quote after a soft boot, the IMA measurement list of the + running kernel must be saved and restored on boot. + + Depending on the IMA policy, the measurement list can grow to + be very large. + config IMA_MEASURE_PCR_IDX int depends on IMA diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index e7b3755..f9cd08e 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -133,6 +133,7 @@ void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); struct ima_template_desc *ima_template_desc_current(void); int ima_restore_measurement_entry(struct ima_template_entry *entry); int ima_restore_measurement_list(loff_t bufsize, void *buf); +unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); #ifdef CONFIG_KEXEC_FILE diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 12d1b04..3a3cc2a 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -29,6 +29,11 @@ #define AUDIT_CAUSE_LEN_MAX 32 LIST_HEAD(ima_measurements); /* list of all measurements */ +#ifdef CONFIG_IMA_KEXEC +static unsigned long binary_runtime_size; +#else +static unsigned long binary_runtime_size = ULONG_MAX; +#endif /* key: inode (before secure-hashing a file) */ struct ima_h_table ima_htable = { @@ -64,6 +69,24 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, return ret; } +/* + * Calculate the memory required for serializing a single + * binary_runtime_measurement list entry, which contains a + * couple of variable length fields (e.g template name and data). + */ +static int get_binary_runtime_size(struct ima_template_entry *entry) +{ + int size = 0; + + size += sizeof(u32);/* pcr */ + size += sizeof(entry->digest); + size += sizeof(int);/* template name size field */ + size += strlen(entry->template_desc->name); + size += sizeof(entry->template_data_len); + size += entry->template_data_len; + return size; +} + /* ima_add_template_entry helper function: * - Add template entry to the measurement list and hash table, for * all entries except those carried across kexec. @@ -90,9 +113,30 @@ static int ima_add_digest_entry(struct ima_template_entry *entry, int flags) key = ima_hash_key(entry->digest); hlist_add_head_rcu(>hnext, _htable.queue[key]); } + + if (binary_runtime_size != ULONG_MAX) { + int size; + + size = get_binary_runtime_size(entry); + binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ? +binary_runtime_size + size : ULONG_MAX; + } return 0; } +/* + * Return the amount of memory required for serializing the + * entire binary_runtime_measurement list, including the ima_kexec_hdr + * structure. + */ +unsigned long ima_get_binary_runtime_size(void) +{ + if (binary_runtime_size >= (ULONG_MAX - sizeof(struct ima_kexec_hdr))) + return ULONG_MAX; + else + return binary_runtime_size + sizeof(struct ima_kexec_hdr); +}; + static int ima_pcr_extend(const u8 *hash, int pcr) { int result = 0; @@ -106,8 +150,13 @@ static int ima_pcr_extend(const u8 *hash, int pcr) return result; } -/* Add template entry to the measurement list and hash table, - * and extend the pcr. +/* + * Add template entry to the measurement list and hash table, and + * extend the pcr. + * + * On systems which support carrying the IMA measurement list across + * kexec, maintain the total memory size required for serializing the + * binary_runtime_measurements. */ int ima_add_template_entry(struct ima_template_entry *entry, int violation, const char *op, struct inode *inode, -- 2.1.0 ___ kexec
[PATCH v3 0/9] ima: carry the measurement list across kexec
The TPM PCRs are only reset on a hard reboot. In order to validate a TPM's quote after a soft reboot (eg. kexec -e), the IMA measurement list of the running kernel must be saved and then restored on the subsequent boot, possibly of a different architecture. The existing securityfs binary_runtime_measurements file conveniently provides a serialized format of the IMA measurement list. This patch set serializes the measurement list in this format and restores it. Up to now, the binary_runtime_measurements was defined as architecture native format. The assumption being that userspace could and would handle any architecture conversions. With the ability of carrying the measurement list across kexec, possibly from one architecture to a different one, the per boot architecture information is lost and with it the ability of recalculating the template digest hash. To resolve this problem, without breaking the existing ABI, this patch set introduces the boot command line option "ima_canonical_fmt", which is arbitrarily defined as little endian. The need for this boot command line option will be limited to the existing version 1 format of the binary_runtime_measurements. Subsequent formats will be defined as canonical format (eg. TPM 2.0 support for larger digests). This patch set pre-req's Thiago Bauermann's "kexec_file: Add buffer hand-over for the next kernel" patch set. These patches can also be found in the next-kexec-restore branch of: git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git Changelog v3: - Cleaned up the code for calculating the requested kexec segment size needed for the IMA measurement list, limiting the segment size to half of the totalram_pages. - Fixed kernel test robot reports as enumerated in the respective patch changelog. Changelog v2: - Canonical measurement list support added - Redefined the ima_kexec_hdr struct to use well defined sizes Mimi Andreas Steffen (1): ima: platform-independent hash value Mimi Zohar (7): ima: on soft reboot, restore the measurement list ima: permit duplicate measurement list entries ima: maintain memory size needed for serializing the measurement list ima: serialize the binary_runtime_measurements ima: store the builtin/custom template definitions in a list ima: support restoring multiple template formats ima: define a canonical binary_runtime_measurements list format Thiago Jung Bauermann (1): ima: on soft reboot, save the measurement list Documentation/kernel-parameters.txt | 4 + include/linux/ima.h | 12 ++ kernel/kexec_file.c | 4 + security/integrity/ima/Kconfig| 12 ++ security/integrity/ima/Makefile | 1 + security/integrity/ima/ima.h | 28 +++ security/integrity/ima/ima_crypto.c | 6 +- security/integrity/ima/ima_fs.c | 30 ++- security/integrity/ima/ima_init.c | 2 + security/integrity/ima/ima_kexec.c| 209 + security/integrity/ima/ima_main.c | 1 + security/integrity/ima/ima_queue.c| 76 +++- security/integrity/ima/ima_template.c | 293 -- security/integrity/ima/ima_template_lib.c | 7 +- 14 files changed, 653 insertions(+), 32 deletions(-) create mode 100644 security/integrity/ima/ima_kexec.c -- 2.1.0 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH] Cleanup: Use a negative number for uninitialized file descriptors
Do not use zero to denote an invalid file descriptor. First, zero is a valid value, although quite unlikely to be used for anything except standard input. Second, open(2) returns a negative value on failure, so there are already checks for a negative value in some places. The purpose of this patch is not to allow running in an evil environment (with closed stdin), but to aid in debugging by using a consistent value for uninitialized file descriptors which is also regarded as invalid by the kernel. For example, attempts to close a negative FD will fail (unlike an attempt to close FD 0). Signed-off-by: Petr Tesarik--- makedumpfile.c | 68 +- makedumpfile.h | 2 +- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/makedumpfile.c b/makedumpfile.c index 21784e8..d168dfd 100644 --- a/makedumpfile.c +++ b/makedumpfile.c @@ -3730,10 +3730,10 @@ free_for_parallel() return; for (i = 0; i < info->num_threads; i++) { - if (FD_MEMORY_PARALLEL(i) > 0) + if (FD_MEMORY_PARALLEL(i) >= 0) close(FD_MEMORY_PARALLEL(i)); - if (FD_BITMAP_MEMORY_PARALLEL(i) > 0) + if (FD_BITMAP_MEMORY_PARALLEL(i) >= 0) close(FD_BITMAP_MEMORY_PARALLEL(i)); } } @@ -4038,13 +4038,13 @@ out: void initialize_bitmap(struct dump_bitmap *bitmap) { - if (info->fd_bitmap) { + if (info->fd_bitmap >= 0) { bitmap->fd= info->fd_bitmap; bitmap->file_name = info->name_bitmap; bitmap->no_block = -1; memset(bitmap->buf, 0, BUFSIZE_BITMAP); } else { - bitmap->fd= 0; + bitmap->fd= -1; bitmap->file_name = NULL; bitmap->no_block = -1; memset(bitmap->buf, 0, info->bufsize_cyclic); @@ -4154,7 +4154,7 @@ set_bitmap_buffer(struct dump_bitmap *bitmap, mdf_pfn_t pfn, int val, struct cyc int set_bitmap(struct dump_bitmap *bitmap, mdf_pfn_t pfn, int val, struct cycle *cycle) { - if (bitmap->fd) { + if (bitmap->fd >= 0) { return set_bitmap_file(bitmap, pfn, val); } else { return set_bitmap_buffer(bitmap, pfn, val, cycle); @@ -4170,7 +4170,7 @@ sync_bitmap(struct dump_bitmap *bitmap) /* * The bitmap doesn't have the fd, it's a on-memory bitmap. */ - if (bitmap->fd == 0) + if (bitmap->fd < 0) return TRUE; /* * The bitmap buffer is not dirty, and it is not necessary @@ -5403,7 +5403,7 @@ create_1st_bitmap_buffer(struct cycle *cycle) int create_1st_bitmap(struct cycle *cycle) { - if (info->bitmap1->fd) { + if (info->bitmap1->fd >= 0) { return create_1st_bitmap_file(); } else { return create_1st_bitmap_buffer(cycle); @@ -5414,7 +5414,7 @@ static inline int is_in_segs(unsigned long long paddr) { if (info->flag_refiltering || info->flag_sadump) { - if (info->bitmap1->fd == 0) { + if (info->bitmap1->fd < 0) { initialize_1st_bitmap(info->bitmap1); create_1st_bitmap_file(); } @@ -5872,7 +5872,7 @@ copy_bitmap_file(void) int copy_bitmap(void) { - if (info->fd_bitmap) { + if (info->fd_bitmap >= 0) { return copy_bitmap_file(); } else { return copy_bitmap_buffer(); @@ -6313,7 +6313,7 @@ prepare_bitmap1_buffer(void) return FALSE; } - if (info->fd_bitmap) { + if (info->fd_bitmap >= 0) { if ((info->bitmap1->buf = (char *)malloc(BUFSIZE_BITMAP)) == NULL) { ERRMSG("Can't allocate memory for the 1st bitmaps's buffer. %s\n", strerror(errno)); @@ -6352,7 +6352,7 @@ prepare_bitmap2_buffer(void) strerror(errno)); return FALSE; } - if (info->fd_bitmap) { + if (info->fd_bitmap >= 0) { if ((info->bitmap2->buf = (char *)malloc(BUFSIZE_BITMAP)) == NULL) { ERRMSG("Can't allocate memory for the 2nd bitmaps's buffer. %s\n", strerror(errno)); @@ -7582,7 +7582,7 @@ kdump_thread_function_cyclic(void *arg) { fd_memory = FD_MEMORY_PARALLEL(kdump_thread_args->thread_num); - if (info->fd_bitmap) { + if (info->fd_bitmap >= 0) { bitmap_parallel.buf = malloc(BUFSIZE_BITMAP); if (bitmap_parallel.buf == NULL){ ERRMSG("Can't allocate memory for bitmap_parallel.buf. %s\n", @@ -7628,7 +7628,7 @@ kdump_thread_function_cyclic(void *arg) { pthread_mutex_lock(>current_pfn_mutex); for (pfn =
[PATCH v8 09/13] powerpc: Implement kexec_file_load.
arch_kexec_walk_mem and arch_kexec_apply_relocations_add are used by generic kexec code, while setup_purgatory is powerpc-specific and sets runtime variables needed by the powerpc purgatory implementation. Signed-off-by: Josh SklarSigned-off-by: Thiago Jung Bauermann --- arch/powerpc/Kconfig | 13 ++ arch/powerpc/include/asm/kexec.h | 7 + arch/powerpc/include/asm/systbl.h | 1 + arch/powerpc/include/asm/unistd.h | 2 +- arch/powerpc/include/uapi/asm/unistd.h | 1 + arch/powerpc/kernel/Makefile | 4 +- arch/powerpc/kernel/machine_kexec_64.c | 252 + 7 files changed, 278 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 140a1b84019a..41300c3a1bfe 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -460,6 +460,19 @@ config KEXEC interface is strongly in flux, so no good recommendation can be made. +config KEXEC_FILE + bool "kexec file based system call" + select KEXEC_CORE + select BUILD_BIN2C + depends on PPC64 + depends on CRYPTO=y + depends on CRYPTO_SHA256=y + help + This is a new version of the kexec system call. This call is + file based and takes in file descriptors as system call arguments + for kernel and initramfs as opposed to a list of segments as is the + case for the older kexec call. + config RELOCATABLE bool "Build a relocatable kernel" depends on (PPC64 && !COMPILE_TEST) || (FLATMEM && (44x || FSL_BOOKE)) diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index eca2f975bf44..0c7e020d935a 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -91,6 +91,13 @@ static inline bool kdump_in_progress(void) return crashing_cpu >= 0; } +#ifdef CONFIG_KEXEC_FILE +int setup_purgatory(struct kimage *image, const void *slave_code, + const void *fdt, unsigned long kernel_load_addr, + unsigned long fdt_load_addr, unsigned long stack_top, + int debug); +#endif /* CONFIG_KEXEC_FILE */ + #else /* !CONFIG_KEXEC_CORE */ static inline void crash_kexec_secondary(struct pt_regs *regs) { } diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 2fc5d4db503c..4b369d83fe9c 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -386,3 +386,4 @@ SYSCALL(mlock2) SYSCALL(copy_file_range) COMPAT_SYS_SPU(preadv2) COMPAT_SYS_SPU(pwritev2) +SYSCALL(kexec_file_load) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index cf12c580f6b2..a01e97d3f305 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -12,7 +12,7 @@ #include -#define NR_syscalls382 +#define NR_syscalls383 #define __NR__exit __NR_exit diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h index e9f5f41aa55a..2f26335a3c42 100644 --- a/arch/powerpc/include/uapi/asm/unistd.h +++ b/arch/powerpc/include/uapi/asm/unistd.h @@ -392,5 +392,6 @@ #define __NR_copy_file_range 379 #define __NR_preadv2 380 #define __NR_pwritev2 381 +#define __NR_kexec_file_load 382 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fd6b7b96d93d..fef0d730acc4 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -123,9 +123,11 @@ ifneq ($(CONFIG_PPC_INDIRECT_PIO),y) obj-y += iomap.o endif -ifeq ($(CONFIG_MODULES)$(CONFIG_WORD_SIZE),y64) +ifneq ($(CONFIG_MODULES)$(CONFIG_KEXEC_FILE),) +ifeq ($(CONFIG_WORD_SIZE),64) obj-y += elf_util.o elf_util_64.o endif +endif obj64-$(CONFIG_PPC_TRANSACTIONAL_MEM) += tm.o diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 4c780a342282..1e678dc5096a 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -31,6 +33,12 @@ #include #include +#define SLAVE_CODE_SIZE256 + +#ifdef CONFIG_KEXEC_FILE +static struct kexec_file_ops *kexec_file_loaders[] = { }; +#endif + #ifdef CONFIG_PPC_BOOK3E int default_machine_kexec_prepare(struct kimage *image) { @@ -432,3 +440,247 @@ static int __init export_htab_values(void) } late_initcall(export_htab_values); #endif /* CONFIG_PPC_STD_MMU_64 */ + +#ifdef CONFIG_KEXEC_FILE +int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, + unsigned long buf_len) +{ + int i, ret = -ENOEXEC; + struct kexec_file_ops *fops; + + /* We
[PATCH v8 02/13] kexec_file: Change kexec_add_buffer to take kexec_buf as argument.
This is done to simplify the kexec_add_buffer argument list. Adapt all callers to set up a kexec_buf to pass to kexec_add_buffer. In addition, change the type of kexec_buf.buffer from char * to void *. There is no particular reason for it to be a char *, and the change allows us to get rid of 3 existing casts to char * in the code. Signed-off-by: Thiago Jung BauermannAcked-by: Dave Young Acked-by: Balbir Singh --- arch/x86/kernel/crash.c | 37 arch/x86/kernel/kexec-bzimage64.c | 48 +++-- include/linux/kexec.h | 8 +--- kernel/kexec_file.c | 88 ++- 4 files changed, 87 insertions(+), 94 deletions(-) diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 9616cf76940c..38a1cdf6aa05 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -615,9 +615,9 @@ static int determine_backup_region(u64 start, u64 end, void *arg) int crash_load_segments(struct kimage *image) { - unsigned long src_start, src_sz, elf_sz; - void *elf_addr; int ret; + struct kexec_buf kbuf = { .image = image, .buf_min = 0, + .buf_max = ULONG_MAX, .top_down = false }; /* * Determine and load a segment for backup area. First 640K RAM @@ -631,43 +631,44 @@ int crash_load_segments(struct kimage *image) if (ret < 0) return ret; - src_start = image->arch.backup_src_start; - src_sz = image->arch.backup_src_sz; - /* Add backup segment. */ - if (src_sz) { + if (image->arch.backup_src_sz) { + kbuf.buffer = _zero_bytes; + kbuf.bufsz = sizeof(crash_zero_bytes); + kbuf.memsz = image->arch.backup_src_sz; + kbuf.buf_align = PAGE_SIZE; /* * Ideally there is no source for backup segment. This is * copied in purgatory after crash. Just add a zero filled * segment for now to make sure checksum logic works fine. */ - ret = kexec_add_buffer(image, (char *)_zero_bytes, - sizeof(crash_zero_bytes), src_sz, - PAGE_SIZE, 0, -1, 0, - >arch.backup_load_addr); + ret = kexec_add_buffer(); if (ret) return ret; + image->arch.backup_load_addr = kbuf.mem; pr_debug("Loaded backup region at 0x%lx backup_start=0x%lx memsz=0x%lx\n", -image->arch.backup_load_addr, src_start, src_sz); +image->arch.backup_load_addr, +image->arch.backup_src_start, kbuf.memsz); } /* Prepare elf headers and add a segment */ - ret = prepare_elf_headers(image, _addr, _sz); + ret = prepare_elf_headers(image, , ); if (ret) return ret; - image->arch.elf_headers = elf_addr; - image->arch.elf_headers_sz = elf_sz; + image->arch.elf_headers = kbuf.buffer; + image->arch.elf_headers_sz = kbuf.bufsz; - ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz, - ELF_CORE_HEADER_ALIGN, 0, -1, 0, - >arch.elf_load_addr); + kbuf.memsz = kbuf.bufsz; + kbuf.buf_align = ELF_CORE_HEADER_ALIGN; + ret = kexec_add_buffer(); if (ret) { vfree((void *)image->arch.elf_headers); return ret; } + image->arch.elf_load_addr = kbuf.mem; pr_debug("Loaded ELF headers at 0x%lx bufsz=0x%lx memsz=0x%lx\n", -image->arch.elf_load_addr, elf_sz, elf_sz); +image->arch.elf_load_addr, kbuf.bufsz, kbuf.bufsz); return ret; } diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index f2356bda2b05..4b3a75329fb6 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -331,17 +331,17 @@ static void *bzImage64_load(struct kimage *image, char *kernel, struct setup_header *header; int setup_sects, kern16_size, ret = 0; - unsigned long setup_header_size, params_cmdline_sz, params_misc_sz; + unsigned long setup_header_size, params_cmdline_sz; struct boot_params *params; unsigned long bootparam_load_addr, kernel_load_addr, initrd_load_addr; unsigned long purgatory_load_addr; - unsigned long kernel_bufsz, kernel_memsz, kernel_align; - char *kernel_buf; struct bzimage64_data *ldata; struct kexec_entry64_regs regs64; void *stack; unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr); unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset; + struct
[PATCH v8 08/13] powerpc: Add functions to read ELF files of any endianness.
A little endian kernel might need to kexec a big endian kernel (the opposite is less likely but could happen as well), so we can't just cast the buffer with the binary to ELF structs and use them as is done elsewhere. This patch adds functions which do byte-swapping as necessary when populating the ELF structs. These functions will be used in the next patch in the series. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/include/asm/elf_util.h | 18 ++ arch/powerpc/kernel/Makefile| 2 +- arch/powerpc/kernel/elf_util.c | 476 3 files changed, 495 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/elf_util.h b/arch/powerpc/include/asm/elf_util.h index 5a27e8ceb88a..18703d56eabd 100644 --- a/arch/powerpc/include/asm/elf_util.h +++ b/arch/powerpc/include/asm/elf_util.h @@ -20,7 +20,14 @@ #include struct elf_info { + /* +* Where the ELF binary contents are kept. +* Memory managed by the user of the struct. +*/ + const char *buffer; + const struct elfhdr *ehdr; + const struct elf_phdr *proghdrs; struct elf_shdr *sechdrs; /* Index of stubs section. */ @@ -64,6 +71,17 @@ static inline unsigned long my_r2(const struct elf_info *elf_info) return elf_info->sechdrs[elf_info->toc_section].sh_addr + 0x8000; } +static inline bool elf_is_elf_file(const struct elfhdr *ehdr) +{ + return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0; +} + +int elf_read_from_buffer(const char *buf, size_t len, struct elfhdr *ehdr, +struct elf_info *elf_info); +void elf_init_elf_info(const struct elfhdr *ehdr, struct elf_shdr *sechdrs, + struct elf_info *elf_info); +void elf_free_info(struct elf_info *elf_info); + int elf64_apply_relocate_add(const struct elf_info *elf_info, const char *strtab, const Elf64_Rela *rela, unsigned int num_rela, void *syms_base, diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 4ff806f6f3fd..fd6b7b96d93d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -124,7 +124,7 @@ obj-y += iomap.o endif ifeq ($(CONFIG_MODULES)$(CONFIG_WORD_SIZE),y64) -obj-y += elf_util_64.o +obj-y += elf_util.o elf_util_64.o endif obj64-$(CONFIG_PPC_TRANSACTIONAL_MEM) += tm.o diff --git a/arch/powerpc/kernel/elf_util.c b/arch/powerpc/kernel/elf_util.c new file mode 100644 index ..1df4a116ad90 --- /dev/null +++ b/arch/powerpc/kernel/elf_util.c @@ -0,0 +1,476 @@ +/* + * Utility functions to work with ELF files. + * + * Copyright (C) 2016, IBM Corporation + * + * Based on kexec-tools' kexec-elf.c. Heavily modified for the + * kernel by Thiago Jung Bauermann . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License). + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#if ELF_CLASS == ELFCLASS32 +#define elf_addr_to_cpuelf32_to_cpu + +#ifndef Elf_Rel +#define Elf_RelElf32_Rel +#endif /* Elf_Rel */ +#else /* ELF_CLASS == ELFCLASS32 */ +#define elf_addr_to_cpuelf64_to_cpu + +#ifndef Elf_Rel +#define Elf_RelElf64_Rel +#endif /* Elf_Rel */ + +static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le64_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be64_to_cpu(value); + + return value; +} +#endif /* ELF_CLASS == ELFCLASS32 */ + +static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le16_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be16_to_cpu(value); + + return value; +} + +static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le32_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be32_to_cpu(value); + + return value; +} + +/** + * elf_is_ehdr_sane - check that it is safe to use the ELF header + * @buf_len: size of the buffer in which the ELF file is loaded. + */ +static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len) +{ +
[PATCH v8 01/13] kexec_file: Allow arch-specific memory walking for kexec_add_buffer
Allow architectures to specify a different memory walking function for kexec_add_buffer. x86 uses iomem to track reserved memory ranges, but PowerPC uses the memblock subsystem. Signed-off-by: Thiago Jung BauermannAcked-by: Dave Young Acked-by: Balbir Singh --- include/linux/kexec.h | 29 - kernel/kexec_file.c | 30 ++ kernel/kexec_internal.h | 16 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index d743baaa..2d6a1ab3b630 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -148,7 +148,34 @@ struct kexec_file_ops { kexec_verify_sig_t *verify_sig; #endif }; -#endif + +/** + * struct kexec_buf - parameters for finding a place for a buffer in memory + * @image: kexec image in which memory to search. + * @buffer:Contents which will be copied to the allocated memory. + * @bufsz: Size of @buffer. + * @mem: On return will have address of the buffer in memory. + * @memsz: Size for the buffer in memory. + * @buf_align: Minimum alignment needed. + * @buf_min: The buffer can't be placed below this address. + * @buf_max: The buffer can't be placed above this address. + * @top_down: Allocate from top of memory. + */ +struct kexec_buf { + struct kimage *image; + char *buffer; + unsigned long bufsz; + unsigned long mem; + unsigned long memsz; + unsigned long buf_align; + unsigned long buf_min; + unsigned long buf_max; + bool top_down; +}; + +int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, + int (*func)(u64, u64, void *)); +#endif /* CONFIG_KEXEC_FILE */ struct kimage { kimage_entry_t head; diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 037c321c5618..f865674bff51 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -428,6 +428,27 @@ static int locate_mem_hole_callback(u64 start, u64 end, void *arg) return locate_mem_hole_bottom_up(start, end, kbuf); } +/** + * arch_kexec_walk_mem - call func(data) on free memory regions + * @kbuf: Context info for the search. Also passed to @func. + * @func: Function to call for each memory region. + * + * Return: The memory walk will stop when func returns a non-zero value + * and that value will be returned. If all free regions are visited without + * func returning non-zero, then zero will be returned. + */ +int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, + int (*func)(u64, u64, void *)) +{ + if (kbuf->image->type == KEXEC_TYPE_CRASH) + return walk_iomem_res_desc(crashk_res.desc, + IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY, + crashk_res.start, crashk_res.end, + kbuf, func); + else + return walk_system_ram_res(0, ULONG_MAX, kbuf, func); +} + /* * Helper function for placing a buffer in a kexec segment. This assumes * that kexec_mutex is held. @@ -474,14 +495,7 @@ int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz, kbuf->top_down = top_down; /* Walk the RAM ranges and allocate a suitable range for the buffer */ - if (image->type == KEXEC_TYPE_CRASH) - ret = walk_iomem_res_desc(crashk_res.desc, - IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY, - crashk_res.start, crashk_res.end, kbuf, - locate_mem_hole_callback); - else - ret = walk_system_ram_res(0, -1, kbuf, - locate_mem_hole_callback); + ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback); if (ret != 1) { /* A suitable memory range could not be found for buffer */ return -EADDRNOTAVAIL; diff --git a/kernel/kexec_internal.h b/kernel/kexec_internal.h index 0a52315d9c62..4cef7e4706b0 100644 --- a/kernel/kexec_internal.h +++ b/kernel/kexec_internal.h @@ -20,22 +20,6 @@ struct kexec_sha_region { unsigned long len; }; -/* - * Keeps track of buffer parameters as provided by caller for requesting - * memory placement of buffer. - */ -struct kexec_buf { - struct kimage *image; - char *buffer; - unsigned long bufsz; - unsigned long mem; - unsigned long memsz; - unsigned long buf_align; - unsigned long buf_min; - unsigned long buf_max; - bool top_down; /* allocate from top of memory hole */ -}; - void kimage_file_post_load_cleanup(struct kimage *image); #else /* CONFIG_KEXEC_FILE */ static inline void kimage_file_post_load_cleanup(struct kimage *image) { } -- 1.9.1
[PATCH v8 04/13] powerpc: Change places using CONFIG_KEXEC to use CONFIG_KEXEC_CORE instead.
Commit 2965faa5e03d ("kexec: split kexec_load syscall from kexec core code") introduced CONFIG_KEXEC_CORE so that CONFIG_KEXEC means whether the kexec_load system call should be compiled-in and CONFIG_KEXEC_FILE means whether the kexec_file_load system call should be compiled-in. These options can be set independently from each other. Since until now powerpc only supported kexec_load, CONFIG_KEXEC and CONFIG_KEXEC_CORE were synonyms. That is not the case anymore, so we need to make a distinction. Almost all places where CONFIG_KEXEC was being used should be using CONFIG_KEXEC_CORE instead, since kexec_file_load also needs that code compiled in. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/debug.h | 2 +- arch/powerpc/include/asm/kexec.h | 6 +++--- arch/powerpc/include/asm/machdep.h| 4 ++-- arch/powerpc/include/asm/smp.h| 2 +- arch/powerpc/kernel/Makefile | 4 ++-- arch/powerpc/kernel/head_64.S | 2 +- arch/powerpc/kernel/misc_32.S | 2 +- arch/powerpc/kernel/misc_64.S | 6 +++--- arch/powerpc/kernel/prom.c| 2 +- arch/powerpc/kernel/setup_64.c| 4 ++-- arch/powerpc/kernel/smp.c | 6 +++--- arch/powerpc/kernel/traps.c | 2 +- arch/powerpc/platforms/85xx/corenet_generic.c | 2 +- arch/powerpc/platforms/85xx/smp.c | 8 arch/powerpc/platforms/cell/spu_base.c| 2 +- arch/powerpc/platforms/powernv/setup.c| 6 +++--- arch/powerpc/platforms/ps3/setup.c| 4 ++-- arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/setup.c| 4 ++-- 20 files changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 927d2ab2ce08..140a1b84019a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -494,7 +494,7 @@ config CRASH_DUMP config FA_DUMP bool "Firmware-assisted dump" - depends on PPC64 && PPC_RTAS && CRASH_DUMP && KEXEC + depends on PPC64 && PPC_RTAS && CRASH_DUMP && KEXEC_CORE help A robust mechanism to get reliable kernel crash dump with assistance from firmware. This approach does not use kexec, diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h index a954e4975049..86308f177f2d 100644 --- a/arch/powerpc/include/asm/debug.h +++ b/arch/powerpc/include/asm/debug.h @@ -10,7 +10,7 @@ struct pt_regs; extern struct dentry *powerpc_debugfs_root; -#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC_CORE) extern int (*__debugger)(struct pt_regs *regs); extern int (*__debugger_ipi)(struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index a46f5f45570c..eca2f975bf44 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -53,7 +53,7 @@ typedef void (*crash_shutdown_t)(void); -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * This function is responsible for capturing register states if coming @@ -91,7 +91,7 @@ static inline bool kdump_in_progress(void) return crashing_cpu >= 0; } -#else /* !CONFIG_KEXEC */ +#else /* !CONFIG_KEXEC_CORE */ static inline void crash_kexec_secondary(struct pt_regs *regs) { } static inline int overlaps_crashkernel(unsigned long start, unsigned long size) @@ -116,7 +116,7 @@ static inline bool kdump_in_progress(void) return false; } -#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_KEXEC_CORE */ #endif /* ! __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KEXEC_H */ diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 0420b388dd83..3200a4403de3 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -183,7 +183,7 @@ struct machdep_calls { */ void (*machine_shutdown)(void); -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE void (*kexec_cpu_down)(int crash_shutdown, int secondary); /* Called to do what every setup is needed on image and the @@ -198,7 +198,7 @@ struct machdep_calls { * no return. */ void (*machine_kexec)(struct kimage *image); -#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_KEXEC_CORE */ #ifdef CONFIG_SUSPEND /* These are called to disable and enable, respectively, IRQs when diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 0d02c11dc331..32db16d2e7ad 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -176,7 +176,7 @@ static inline void set_hard_smp_processor_id(int cpu, int phys) #endif /* !CONFIG_SMP */ #endif /* !CONFIG_PPC64 */ -#if defined(CONFIG_PPC64) &&
[PATCH v8 12/13] powerpc: Add purgatory for kexec_file_load implementation.
This purgatory implementation comes from kexec-tools, almost unchanged. The only changes were that the sha256_regions global variable was renamed to sha_regions to match what kexec_file_load expects, and to use the sha256.c file from x86's purgatory to avoid adding yet another SHA-256 implementation. Also, some formatting warnings found by checkpatch.pl were fixed. In order to use boot/string.S in ppc64 big endian mode, the functions defined in it need to have dot symbols so that they can be called from C code. Therefore, change the file to use a DOTSYM macro if one is defined, so that the purgatory can add those dot symbols. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/Makefile | 1 + arch/powerpc/boot/string.S| 67 ++-- arch/powerpc/purgatory/.gitignore | 2 + arch/powerpc/purgatory/Makefile | 48 + arch/powerpc/purgatory/console-ppc64.c| 38 +++ arch/powerpc/purgatory/crashdump-ppc64.h | 42 arch/powerpc/purgatory/crashdump_backup.c | 36 +++ arch/powerpc/purgatory/crtsavres.S| 5 + arch/powerpc/purgatory/hvCall.S | 27 + arch/powerpc/purgatory/hvCall.h | 8 ++ arch/powerpc/purgatory/kexec-sha256.h | 11 ++ arch/powerpc/purgatory/ppc64_asm.h| 20 arch/powerpc/purgatory/printf.c | 164 ++ arch/powerpc/purgatory/purgatory-ppc64.c | 41 arch/powerpc/purgatory/purgatory-ppc64.h | 6 ++ arch/powerpc/purgatory/purgatory.c| 62 +++ arch/powerpc/purgatory/purgatory.h| 11 ++ arch/powerpc/purgatory/sha256.c | 6 ++ arch/powerpc/purgatory/sha256.h | 1 + arch/powerpc/purgatory/string.S | 2 + arch/powerpc/purgatory/v2wrap.S | 134 21 files changed, 703 insertions(+), 29 deletions(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 1934707bf321..0fb28cc8eb38 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -256,6 +256,7 @@ core-y += arch/powerpc/kernel/ \ core-$(CONFIG_XMON)+= arch/powerpc/xmon/ core-$(CONFIG_KVM) += arch/powerpc/kvm/ core-$(CONFIG_PERF_EVENTS) += arch/powerpc/perf/ +core-$(CONFIG_KEXEC_FILE) += arch/powerpc/purgatory/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/powerpc/boot/string.S b/arch/powerpc/boot/string.S index acc9428f2789..b54bbad5f83d 100644 --- a/arch/powerpc/boot/string.S +++ b/arch/powerpc/boot/string.S @@ -11,9 +11,18 @@ #include "ppc_asm.h" +/* + * The ppc64 kexec purgatory uses this file and packages it in ELF64, + * so it needs dot symbols for the ppc64 big endian ABI. This macro + * allows it to create those symbols. + */ +#ifndef DOTSYM +#define DOTSYM(a) a +#endif + .text - .globl strcpy -strcpy: + .globl DOTSYM(strcpy) +DOTSYM(strcpy): addir5,r3,-1 addir4,r4,-1 1: lbzur0,1(r4) @@ -22,8 +31,8 @@ strcpy: bne 1b blr - .globl strncpy -strncpy: + .globl DOTSYM(strncpy) +DOTSYM(strncpy): cmpwi 0,r5,0 beqlr mtctr r5 @@ -35,8 +44,8 @@ strncpy: bdnzf 2,1b/* dec ctr, branch if ctr != 0 && !cr0.eq */ blr - .globl strcat -strcat: + .globl DOTSYM(strcat) +DOTSYM(strcat): addir5,r3,-1 addir4,r4,-1 1: lbzur0,1(r5) @@ -49,8 +58,8 @@ strcat: bne 1b blr - .globl strchr -strchr: + .globl DOTSYM(strchr) +DOTSYM(strchr): addir3,r3,-1 1: lbzur0,1(r3) cmpw0,r0,r4 @@ -60,8 +69,8 @@ strchr: li r3,0 blr - .globl strcmp -strcmp: + .globl DOTSYM(strcmp) +DOTSYM(strcmp): addir5,r3,-1 addir4,r4,-1 1: lbzur3,1(r5) @@ -72,8 +81,8 @@ strcmp: beq 1b blr - .globl strncmp -strncmp: + .globl DOTSYM(strncmp) +DOTSYM(strncmp): mtctr r5 addir5,r3,-1 addir4,r4,-1 @@ -85,8 +94,8 @@ strncmp: bdnzt eq,1b blr - .globl strlen -strlen: + .globl DOTSYM(strlen) +DOTSYM(strlen): addir4,r3,-1 1: lbzur0,1(r4) cmpwi 0,r0,0 @@ -94,8 +103,8 @@ strlen: subfr3,r3,r4 blr - .globl memset -memset: + .globl DOTSYM(memset) +DOTSYM(memset): rlwimi r4,r4,8,16,23 rlwimi r4,r4,16,0,15 addir6,r3,-4 @@ -120,14 +129,14 @@ memset: bdnz8b blr - .globl memmove -memmove: + .globl DOTSYM(memmove) +DOTSYM(memmove): cmplw 0,r3,r4 - bgt backwards_memcpy + bgt DOTSYM(backwards_memcpy) /* fall through */ - .globl memcpy -memcpy: + .globl
[PATCH v8 10/13] powerpc: Add code to work with device trees in kexec_file_load.
kexec_file_load needs to set up the device tree that will be used by the next kernel and check whether it provides a console that can be used by the purgatory. [a...@linux-foundation.org: coding-style fixes] Signed-off-by: Thiago Jung BauermannSigned-off-by: Andrew Morton --- arch/powerpc/include/asm/kexec.h | 3 + arch/powerpc/kernel/machine_kexec_64.c | 221 + 2 files changed, 224 insertions(+) diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index 0c7e020d935a..73f88b5f9bd1 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -96,6 +96,9 @@ int setup_purgatory(struct kimage *image, const void *slave_code, const void *fdt, unsigned long kernel_load_addr, unsigned long fdt_load_addr, unsigned long stack_top, int debug); +int setup_new_fdt(void *fdt, unsigned long initrd_load_addr, + unsigned long initrd_len, const char *cmdline); +bool find_debug_console(const void *fdt); #endif /* CONFIG_KEXEC_FILE */ #else /* !CONFIG_KEXEC_CORE */ diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 1e678dc5096a..31c5090705e0 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -683,4 +683,225 @@ int setup_purgatory(struct kimage *image, const void *slave_code, return 0; } +/* + * setup_new_fdt() - modify /chosen and memory reservation for the next kernel + * @fdt: + * @initrd_load_addr: Address where the next initrd will be loaded. + * @initrd_len:Size of the next initrd, or 0 if there will be none. + * @cmdline: Command line for the next kernel, or NULL if there will + * be none. + * + * Return: 0 on success, or negative errno on error. + */ +int setup_new_fdt(void *fdt, unsigned long initrd_load_addr, + unsigned long initrd_len, const char *cmdline) +{ + uint64_t oldfdt_addr; + int i, ret, chosen_node; + const void *prop; + + /* Remove memory reservation for the current device tree. */ + oldfdt_addr = __pa(initial_boot_params); + for (i = 0; i < fdt_num_mem_rsv(fdt); i++) { + uint64_t rsv_start, rsv_size; + + ret = fdt_get_mem_rsv(fdt, i, _start, _size); + if (ret) { + pr_err("Malformed device tree.\n"); + return -EINVAL; + } + + if (rsv_start == oldfdt_addr && + rsv_size == fdt_totalsize(initial_boot_params)) { + ret = fdt_del_mem_rsv(fdt, i); + if (ret) { + pr_err("Error deleting fdt reservation.\n"); + return -EINVAL; + } + + pr_debug("Removed old device tree reservation.\n"); + break; + } + } + + chosen_node = fdt_path_offset(fdt, "/chosen"); + if (chosen_node == -FDT_ERR_NOTFOUND) { + chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), + "chosen"); + if (chosen_node < 0) { + pr_err("Error creating /chosen.\n"); + return -EINVAL; + } + } else if (chosen_node < 0) { + pr_err("Malformed device tree: error reading /chosen.\n"); + return -EINVAL; + } + + /* Did we boot using an initrd? */ + prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL); + if (prop) { + uint64_t tmp_start, tmp_end, tmp_size, tmp_sizepg; + + tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop)); + + prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", NULL); + if (!prop) { + pr_err("Malformed device tree.\n"); + return -EINVAL; + } + tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop)); + + /* +* kexec reserves exact initrd size, while firmware may +* reserve a multiple of PAGE_SIZE, so check for both. +*/ + tmp_size = tmp_end - tmp_start; + tmp_sizepg = round_up(tmp_size, PAGE_SIZE); + + /* Remove memory reservation for the current initrd. */ + for (i = 0; i < fdt_num_mem_rsv(fdt); i++) { + uint64_t rsv_start, rsv_size; + + ret = fdt_get_mem_rsv(fdt, i, _start, _size); + if (ret) { + pr_err("Malformed device tree.\n"); + return -EINVAL; + } + + if
[PATCH v8 13/13] powerpc: Enable CONFIG_KEXEC_FILE in powerpc server defconfigs.
Enable CONFIG_KEXEC_FILE in powernv_defconfig, ppc64_defconfig and pseries_defconfig. It depends on CONFIG_CRYPTO_SHA256=y, so add that as well. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/configs/powernv_defconfig | 2 ++ arch/powerpc/configs/ppc64_defconfig | 2 ++ arch/powerpc/configs/pseries_defconfig | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig index dce352e9153b..319e1fb7b0c9 100644 --- a/arch/powerpc/configs/powernv_defconfig +++ b/arch/powerpc/configs/powernv_defconfig @@ -47,6 +47,7 @@ CONFIG_BINFMT_MISC=m CONFIG_PPC_TRANSACTIONAL_MEM=y CONFIG_HOTPLUG_CPU=y CONFIG_KEXEC=y +CONFIG_KEXEC_FILE=y CONFIG_IRQ_ALL_CPUS=y CONFIG_NUMA=y CONFIG_MEMORY_HOTPLUG=y @@ -298,6 +299,7 @@ CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_ANUBIS=m diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 0a8d250cb97e..a0355ccc7f55 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -44,6 +44,7 @@ CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m CONFIG_PPC_TRANSACTIONAL_MEM=y CONFIG_KEXEC=y +CONFIG_KEXEC_FILE=y CONFIG_CRASH_DUMP=y CONFIG_IRQ_ALL_CPUS=y CONFIG_MEMORY_HOTREMOVE=y @@ -333,6 +334,7 @@ CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_ANUBIS=m diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 654aeffc57ef..23af4a72930e 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -50,6 +50,7 @@ CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m CONFIG_PPC_TRANSACTIONAL_MEM=y CONFIG_KEXEC=y +CONFIG_KEXEC_FILE=y CONFIG_IRQ_ALL_CPUS=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y @@ -300,6 +301,7 @@ CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_ANUBIS=m -- 1.9.1 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v8 11/13] powerpc: Add support for loading ELF kernels with kexec_file_load.
This uses all the infrastructure built up by the previous patches in the series to load an ELF vmlinux file and an initrd. It uses the flattened device tree at initial_boot_params as a base and adjusts memory reservations and its /chosen node for the next kernel. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/include/asm/kexec_elf_64.h | 10 ++ arch/powerpc/kernel/Makefile| 1 + arch/powerpc/kernel/kexec_elf_64.c | 282 arch/powerpc/kernel/machine_kexec_64.c | 5 +- 4 files changed, 297 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/kexec_elf_64.h b/arch/powerpc/include/asm/kexec_elf_64.h new file mode 100644 index ..30da6bc0ccf8 --- /dev/null +++ b/arch/powerpc/include/asm/kexec_elf_64.h @@ -0,0 +1,10 @@ +#ifndef __POWERPC_KEXEC_ELF_64_H__ +#define __POWERPC_KEXEC_ELF_64_H__ + +#ifdef CONFIG_KEXEC_FILE + +extern struct kexec_file_ops kexec_elf64_ops; + +#endif /* CONFIG_KEXEC_FILE */ + +#endif /* __POWERPC_KEXEC_ELF_64_H__ */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index fef0d730acc4..d12a84003283 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \ obj-$(CONFIG_PCI_MSI) += msi.o obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o crash.o \ machine_kexec_$(CONFIG_WORD_SIZE).o +obj-$(CONFIG_KEXEC_FILE) += kexec_elf_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_AUDIT)+= audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c new file mode 100644 index ..3cc8ebce1a86 --- /dev/null +++ b/arch/powerpc/kernel/kexec_elf_64.c @@ -0,0 +1,282 @@ +/* + * Load ELF vmlinux file for the kexec_file_load syscall. + * + * Copyright (C) 2004 Adam Litke (a...@us.ibm.com) + * Copyright (C) 2004 IBM Corp. + * Copyright (C) 2005 R Sharada (shar...@in.ibm.com) + * Copyright (C) 2006 Mohan Kumar M (mo...@in.ibm.com) + * Copyright (C) 2016 IBM Corporation + * + * Based on kexec-tools' kexec-elf-exec.c and kexec-elf-ppc64.c. + * Heavily modified for the kernel by + * Thiago Jung Bauermann . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License). + * + * 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. + */ + +#define pr_fmt(fmt)"kexec_elf: " fmt + +#include +#include +#include +#include +#include +#include +#include + +extern size_t kexec_purgatory_size; + +#define PURGATORY_STACK_SIZE (16 * 1024) + +/** + * build_elf_exec_info - read ELF executable and check that we can use it + */ +static int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr, + struct elf_info *elf_info) +{ + int i; + int ret; + + ret = elf_read_from_buffer(buf, len, ehdr, elf_info); + if (ret) + return ret; + + /* Big endian vmlinux has type ET_DYN. */ + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { + pr_err("Not an ELF executable.\n"); + goto error; + } else if (!elf_info->proghdrs) { + pr_err("No ELF program header.\n"); + goto error; + } + + for (i = 0; i < ehdr->e_phnum; i++) { + /* +* Kexec does not support loading interpreters. +* In addition this check keeps us from attempting +* to kexec ordinay executables. +*/ + if (elf_info->proghdrs[i].p_type == PT_INTERP) { + pr_err("Requires an ELF interpreter.\n"); + goto error; + } + } + + return 0; +error: + elf_free_info(elf_info); + return -ENOEXEC; +} + +static int elf64_probe(const char *buf, unsigned long len) +{ + struct elfhdr ehdr; + struct elf_info elf_info; + int ret; + + ret = build_elf_exec_info(buf, len, , _info); + if (ret) + return ret; + + elf_free_info(_info); + + return elf_check_arch() ? 0 : -ENOEXEC; +} + +/** + * elf_exec_load - load ELF executable image + * @lowest_load_addr: On return, will be the address where the first PT_LOAD + * section will be loaded in memory. + * + * Return: + * 0 on success, negative value on failure. + */ +static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr, +struct elf_info
[PATCH v8 03/13] kexec_file: Factor out kexec_locate_mem_hole from kexec_add_buffer.
kexec_locate_mem_hole will be used by the PowerPC kexec_file_load implementation to find free memory for the purgatory stack. Signed-off-by: Thiago Jung BauermannAcked-by: Dave Young --- include/linux/kexec.h | 1 + kernel/kexec_file.c | 25 - 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index be39903edae1..d419d0e51fe5 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -176,6 +176,7 @@ struct kexec_buf { int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *)); extern int kexec_add_buffer(struct kexec_buf *kbuf); +int kexec_locate_mem_hole(struct kexec_buf *kbuf); #endif /* CONFIG_KEXEC_FILE */ struct kimage { diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index efd2c094af7e..0c2df7f73792 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -450,6 +450,23 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, } /** + * kexec_locate_mem_hole - find free memory for the purgatory or the next kernel + * @kbuf: Parameters for the memory search. + * + * On success, kbuf->mem will have the start address of the memory region found. + * + * Return: 0 on success, negative errno on error. + */ +int kexec_locate_mem_hole(struct kexec_buf *kbuf) +{ + int ret; + + ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback); + + return ret == 1 ? 0 : -EADDRNOTAVAIL; +} + +/** * kexec_add_buffer - place a buffer in a kexec segment * @kbuf: Buffer contents and memory parameters. * @@ -489,11 +506,9 @@ int kexec_add_buffer(struct kexec_buf *kbuf) kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE); /* Walk the RAM ranges and allocate a suitable range for the buffer */ - ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback); - if (ret != 1) { - /* A suitable memory range could not be found for buffer */ - return -EADDRNOTAVAIL; - } + ret = kexec_locate_mem_hole(kbuf); + if (ret) + return ret; /* Found a suitable memory range */ ksegment = >image->segment[kbuf->image->nr_segments]; -- 1.9.1 ___ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
[PATCH v8 07/13] powerpc: Adapt elf64_apply_relocate_add for kexec_file_load.
Extend elf64_apply_relocate_add to support relative symbols. This is necessary because there is a difference between how the module loading mechanism and the kexec purgatory loading code use Elf64_Sym.st_value at relocation time: the former changes st_value to point to the absolute memory address before relocating the module, while the latter does that adjustment during relocation of the purgatory. Also, add a check_symbols argument so that the kexec code can be stricter about undefined symbols. Finally, add relocation types used by the purgatory. [a...@linux-foundation.org: coding-style fixes] Signed-off-by: Thiago Jung BauermannSigned-off-by: Andrew Morton --- arch/powerpc/include/asm/elf_util.h | 2 + arch/powerpc/kernel/elf_util_64.c | 100 +--- arch/powerpc/kernel/module_64.c | 6 ++- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/include/asm/elf_util.h b/arch/powerpc/include/asm/elf_util.h index a012ba03282d..5a27e8ceb88a 100644 --- a/arch/powerpc/include/asm/elf_util.h +++ b/arch/powerpc/include/asm/elf_util.h @@ -20,6 +20,7 @@ #include struct elf_info { + const struct elfhdr *ehdr; struct elf_shdr *sechdrs; /* Index of stubs section. */ @@ -67,6 +68,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, const char *strtab, const Elf64_Rela *rela, unsigned int num_rela, void *syms_base, void *loc_base, Elf64_Addr addr_base, +bool relative_symbols, bool check_symbols, const char *obj_name); #endif /* _ASM_POWERPC_ELF_UTIL_H */ diff --git a/arch/powerpc/kernel/elf_util_64.c b/arch/powerpc/kernel/elf_util_64.c index 8e5d400ac9f2..1b17df71fb8d 100644 --- a/arch/powerpc/kernel/elf_util_64.c +++ b/arch/powerpc/kernel/elf_util_64.c @@ -74,6 +74,8 @@ static void squash_toc_save_inst(const char *name, unsigned long addr) { } * @syms_base: Contents of the associated symbol table. * @loc_base: Contents of the section to which relocations apply. * @addr_base: The address where the section will be loaded in memory. + * @relative_symbols: Are the symbols' st_value members relative? + * @check_symbols: Fail if an unexpected symbol is found? * @obj_name: The name of the ELF binary, for information messages. * * Applies RELA relocations to an ELF file already at its final location @@ -84,12 +86,15 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, const char *strtab, const Elf64_Rela *rela, unsigned int num_rela, void *syms_base, void *loc_base, Elf64_Addr addr_base, +bool relative_symbols, bool check_symbols, const char *obj_name) { unsigned int i; unsigned long *location; unsigned long address; + unsigned long sec_base; unsigned long value; + int reloc_type; const char *name; Elf64_Sym *sym; @@ -116,15 +121,44 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, else name = ""; - pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n", - location, (long)ELF64_R_TYPE(rela[i].r_info), - name, (unsigned long)sym->st_value, + reloc_type = ELF64_R_TYPE(rela[i].r_info); + + pr_debug("RELOC at %p: %i-type as %s (0x%lx) + %li\n", + location, reloc_type, name, (unsigned long)sym->st_value, (long)rela[i].r_addend); + if (check_symbols) { + /* +* TOC symbols appear as undefined but should be +* resolved as well, so allow them to be processed. +*/ + if (sym->st_shndx == SHN_UNDEF && + strcmp(name, ".TOC.") != 0 && + reloc_type != R_PPC64_TOC) { + pr_err("Undefined symbol: %s\n", name); + return -ENOEXEC; + } else if (sym->st_shndx == SHN_COMMON) { + pr_err("Symbol '%s' in common section.\n", + name); + return -ENOEXEC; + } + } + + if (relative_symbols && sym->st_shndx != SHN_ABS) { + if (sym->st_shndx >= elf_info->ehdr->e_shnum) { + pr_err("Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return
[PATCH v8 05/13] powerpc: Factor out relocation code from module_64.c to elf_util_64.c.
The kexec_file_load system call needs to relocate the purgatory, so factor out the module relocation code so that it can be shared. This patch's purpose is to move the ELF relocation logic from apply_relocate_add to elf_util_64.c with as few changes as possible. The following changes were needed: To avoid having module-specific code in a general purpose utility function, struct elf_info was created to contain the information needed for ELF binaries manipulation. my_r2, stub_for_addr and create_stub were changed to use it instead of having to receive a struct module, since they are called from elf64_apply_relocate_add. local_entry_offset and squash_toc_save_inst were only used by apply_rellocate_add, so they were moved to elf_util_64.c as well. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/include/asm/elf_util.h | 70 arch/powerpc/include/asm/module.h | 14 +- arch/powerpc/kernel/Makefile| 4 + arch/powerpc/kernel/elf_util_64.c | 269 +++ arch/powerpc/kernel/module_64.c | 312 5 files changed, 386 insertions(+), 283 deletions(-) diff --git a/arch/powerpc/include/asm/elf_util.h b/arch/powerpc/include/asm/elf_util.h new file mode 100644 index ..37372559fe62 --- /dev/null +++ b/arch/powerpc/include/asm/elf_util.h @@ -0,0 +1,70 @@ +/* + * Utility functions to work with ELF files. + * + * Copyright (C) 2016, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * 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. + */ + +#ifndef _ASM_POWERPC_ELF_UTIL_H +#define _ASM_POWERPC_ELF_UTIL_H + +#include + +struct elf_info { + struct elf_shdr *sechdrs; + + /* Index of stubs section. */ + unsigned int stubs_section; + /* Index of TOC section. */ + unsigned int toc_section; +}; + +#ifdef __powerpc64__ +#ifdef PPC64_ELF_ABI_v2 + +/* An address is simply the address of the function. */ +typedef unsigned long func_desc_t; +#else + +/* An address is address of the OPD entry, which contains address of fn. */ +typedef struct ppc64_opd_entry func_desc_t; +#endif /* PPC64_ELF_ABI_v2 */ + +/* Like PPC32, we need little trampolines to do > 24-bit jumps (into + the kernel itself). But on PPC64, these need to be used for every + jump, actually, to reset r2 (TOC+0x8000). */ +struct ppc64_stub_entry +{ + /* 28 byte jump instruction sequence (7 instructions). We only +* need 6 instructions on ABIv2 but we always allocate 7 so +* so we don't have to modify the trampoline load instruction. */ + u32 jump[7]; + /* Used by ftrace to identify stubs */ + u32 magic; + /* Data for the above code */ + func_desc_t funcdata; +}; +#endif + +/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this + gives the value maximum span in an instruction which uses a signed + offset) */ +static inline unsigned long my_r2(const struct elf_info *elf_info) +{ + return elf_info->sechdrs[elf_info->toc_section].sh_addr + 0x8000; +} + +int elf64_apply_relocate_add(const struct elf_info *elf_info, +const char *strtab, unsigned int symindex, +unsigned int relsec, const char *obj_name); + +#endif /* _ASM_POWERPC_ELF_UTIL_H */ diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index cd4ffd86765f..f2073115d518 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -12,7 +12,14 @@ #include #include #include +#include +/* Both low and high 16 bits are added as SIGNED additions, so if low + 16 bits has high bit set, high 16 bits must be adjusted. These + macros do that (stolen from binutils). */ +#define PPC_LO(v) ((v) & 0x) +#define PPC_HI(v) (((v) >> 16) & 0x) +#define PPC_HA(v) PPC_HI ((v) + 0x8000) #ifndef __powerpc64__ /* @@ -33,8 +40,7 @@ struct ppc_plt_entry { struct mod_arch_specific { #ifdef __powerpc64__ - unsigned int stubs_section; /* Index of stubs section in module */ - unsigned int toc_section; /* What section is the TOC? */ + struct elf_info elf_info; bool toc_fixed; /* Have we fixed up .TOC.? */ #ifdef CONFIG_DYNAMIC_FTRACE unsigned long toc; @@ -90,6 +96,10 @@ static inline int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sec } #endif +unsigned long stub_for_addr(const struct elf_info *elf_info, unsigned long addr, + const char *obj_name);
[PATCH v8 00/13] kexec_file_load implementation for PowerPC
When Stephen Rothwell added this patch series to the linux-next tree, he found out that it fails to cross build a ppc64 LE kernel using a ppc64 BE host. This version of the series fixes that problem with a change in arch/powerpc/purgatory/Makefile. While I was at it I noticed that it is not necessary to build the purgatory during archprepare, so I was able to simplify the changes to arch/powerpc/Makefile. Both changes are in patch 12. It is the only patch that changed relative to v7, all others are exactly the same. I tested building (and booting the resulting kernel) natively on ppc64 LE and BE, cross-building from ppc64 BE to LE and vice-versa, and from x86 to ppc64 LE and BE. Original cover letter: This patch series implements the kexec_file_load system call on PowerPC. This system call moves the reading of the kernel, initrd and the device tree from the userspace kexec tool to the kernel. This is needed if you want to do one or both of the following: 1. only allow loading of signed kernels. 2. "measure" (i.e., record the hashes of) the kernel, initrd, kernel command line and other boot inputs for the Integrity Measurement Architecture subsystem. The above are the functions kexec already has built into kexec_file_load. Yesterday I posted a set of patches which allows a third feature: 3. have IMA pass-on its event log (where integrity measurements are registered) accross kexec to the second kernel, so that the event history is preserved. Because OpenPower uses an intermediary Linux instance as a boot loader (skiroot), feature 1 is needed to implement secure boot for the platform, while features 2 and 3 are needed to implement trusted boot. This patch series starts by removing an x86 assumption from kexec_file: kexec_add_buffer uses iomem to find reserved memory ranges, but PowerPC uses the memblock subsystem. A hook is added so that each arch can specify how memory ranges can be found. Also, the memory-walking logic in kexec_add_buffer is useful in this implementation to find a free area for the purgatory's stack, so the next patch moves that logic to kexec_locate_mem_hole. The kexec_file_load system call needs to apply relocations to the purgatory but adding code for that would duplicate functionality with the module loading mechanism, which also needs to apply relocations to the kernel modules. Therefore, this patch series factors out the module relocation code so that it can be shared. One thing that is still missing is crashkernel support, which I intend to submit shortly. For now, arch_kexec_kernel_image_probe rejects crash kernels. This code is based on kexec-tools, but with many modifications to adapt it to the kernel environment and facilities. Except the purgatory, which only has minimal changes. Changes for v8: - Rebased on top of v4.8-rc5. - Patch "powerpc: Add purgatory for kexec_file_load implementation." - Fix cross build from ppc64 LE to BE and vice-versa. - Don't build the purgatory during archprepare. Changes for v7: - Rebased on top of v4.8-rc4. - Patch "powerpc: Change places using CONFIG_KEXEC to use CONFIG_KEXEC_CORE instead." - New patch. Fixes build when CONFIG_KEXEC=n and CONFIG_KEXEC_FILE=y. - Patch "powerpc: Adapt elf64_apply_relocate_add for kexec_file_load." - Fixed checkpatch warning "else is not generally useful after a break or return". - Fixed checkpatch warnings about line length. (Andrew Morton) - Patch "powerpc: Add code to work with device trees in kexec_file_load." - Remove space before tabs in doc comment for setup_new_fdt. (Andrew Morton) - Fixed checkpatch warnings about line length. - Patch "powerpc: Add support for loading ELF kernels with kexec_file_load." - Removed duplicate #include . Changes for v6: - Based directly on top of v4.8-rc1. - Patch "powerpc: Adapt elf64_apply_relocate_add for kexec_file_load." - Allow undefined symbols if they are relocations for the TOC in the big endian ABI. - Fixed build error in this patch by adding the ehdr member to elf_info here instead of in the next patch. - Initialize elf_info.ehdr in module_64.c:module_frob_arch_sections. - Patch "powerpc: Add code to work with device trees in kexec_file_load." - Changed find_debug_console to look for /chosen instead of receiving its offset as an argument. - setup_new_fdt: no need to find /chosen again after deleting the memory reservation for initrd. - Patch "powerpc: Add support for loading ELF kernels with kexec_file_load." - Don't pass the offset to /chosen to find_debug_console. - Patch "powerpc: Allow userspace to set device tree properties in kexec_file_load" - Dropped patch. - Patch "powerpc: Add purgatory for kexec_file_load implementation." - Make boot/string.S use the DOTSYM macro so that it can be used by the ppc64 big endian purgatory. - Use -mcall-aixdesc to compile the purgatory on big endian ppc64. Changes for v5: - Rebased series on v4.8-rc1 + the extend kexec_file_load series.
[PATCH v8 06/13] powerpc: Generalize elf64_apply_relocate_add.
When apply_relocate_add is called, modules are already loaded at their final location in memory so Elf64_Shdr.sh_addr can be used for accessing the section contents as well as the base address for relocations. This is not the case for kexec's purgatory, because it will only be copied to its final location right before being executed. Therefore, it needs to be relocated while it is still in a temporary buffer. In this case, Elf64_Shdr.sh_addr can't be used to access the sections' contents. This patch allows elf64_apply_relocate_add to be used when the ELF binary is not yet at its final location by adding an addr_base argument to specify the address at which the section will be loaded, and rela, loc_base and syms_base to point to the sections' contents. Signed-off-by: Thiago Jung Bauermann--- arch/powerpc/include/asm/elf_util.h | 6 ++-- arch/powerpc/kernel/elf_util_64.c | 63 + arch/powerpc/kernel/module_64.c | 17 -- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/include/asm/elf_util.h b/arch/powerpc/include/asm/elf_util.h index 37372559fe62..a012ba03282d 100644 --- a/arch/powerpc/include/asm/elf_util.h +++ b/arch/powerpc/include/asm/elf_util.h @@ -64,7 +64,9 @@ static inline unsigned long my_r2(const struct elf_info *elf_info) } int elf64_apply_relocate_add(const struct elf_info *elf_info, -const char *strtab, unsigned int symindex, -unsigned int relsec, const char *obj_name); +const char *strtab, const Elf64_Rela *rela, +unsigned int num_rela, void *syms_base, +void *loc_base, Elf64_Addr addr_base, +const char *obj_name); #endif /* _ASM_POWERPC_ELF_UTIL_H */ diff --git a/arch/powerpc/kernel/elf_util_64.c b/arch/powerpc/kernel/elf_util_64.c index decad2c34f38..8e5d400ac9f2 100644 --- a/arch/powerpc/kernel/elf_util_64.c +++ b/arch/powerpc/kernel/elf_util_64.c @@ -69,33 +69,56 @@ static void squash_toc_save_inst(const char *name, unsigned long addr) { } * elf64_apply_relocate_add - apply 64 bit RELA relocations * @elf_info: Support information for the ELF binary being relocated. * @strtab:String table for the associated symbol table. - * @symindex: Section header index for the associated symbol table. - * @relsec:Section header index for the relocations to apply. + * @rela: Contents of the section with the relocations to apply. + * @num_rela: Number of relocation entries in the section. + * @syms_base: Contents of the associated symbol table. + * @loc_base: Contents of the section to which relocations apply. + * @addr_base: The address where the section will be loaded in memory. * @obj_name: The name of the ELF binary, for information messages. + * + * Applies RELA relocations to an ELF file already at its final location + * in memory (in which case loc_base == addr_base), or still in a temporary + * buffer. */ int elf64_apply_relocate_add(const struct elf_info *elf_info, -const char *strtab, unsigned int symindex, -unsigned int relsec, const char *obj_name) +const char *strtab, const Elf64_Rela *rela, +unsigned int num_rela, void *syms_base, +void *loc_base, Elf64_Addr addr_base, +const char *obj_name) { unsigned int i; - Elf64_Shdr *sechdrs = elf_info->sechdrs; - Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; - Elf64_Sym *sym; unsigned long *location; + unsigned long address; unsigned long value; + const char *name; + Elf64_Sym *sym; + + for (i = 0; i < num_rela; i++) { + /* +* rels[i].r_offset contains the byte offset from the beginning +* of section to the storage unit affected. +* +* This is the location to update in the temporary buffer where +* the section is currently loaded. The section will finally +* be loaded to a different address later, pointed to by +* addr_base. +*/ + location = loc_base + rela[i].r_offset; + + /* Final address of the location. */ + address = addr_base + rela[i].r_offset; + /* This is the symbol the relocation is referring to. */ + sym = (Elf64_Sym *) syms_base + ELF64_R_SYM(rela[i].r_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - +