Path: blob/master/arch/arm64/kernel/machine_kexec_file.c
26442 views
// SPDX-License-Identifier: GPL-2.01/*2* kexec_file for arm643*4* Copyright (C) 2018 Linaro Limited5* Author: AKASHI Takahiro <[email protected]>6*7* Most code is derived from arm64 port of kexec-tools8*/910#define pr_fmt(fmt) "kexec_file: " fmt1112#include <linux/ioport.h>13#include <linux/kernel.h>14#include <linux/kexec.h>15#include <linux/libfdt.h>16#include <linux/memblock.h>17#include <linux/of.h>18#include <linux/of_fdt.h>19#include <linux/slab.h>20#include <linux/string.h>21#include <linux/types.h>22#include <linux/vmalloc.h>2324const struct kexec_file_ops * const kexec_file_loaders[] = {25&kexec_image_ops,26NULL27};2829int arch_kimage_file_post_load_cleanup(struct kimage *image)30{31kvfree(image->arch.dtb);32image->arch.dtb = NULL;3334vfree(image->elf_headers);35image->elf_headers = NULL;36image->elf_headers_sz = 0;3738return kexec_image_post_load_cleanup_default(image);39}4041#ifdef CONFIG_CRASH_DUMP42static int prepare_elf_headers(void **addr, unsigned long *sz)43{44struct crash_mem *cmem;45unsigned int nr_ranges;46int ret;47u64 i;48phys_addr_t start, end;4950nr_ranges = 2; /* for exclusion of crashkernel region */51for_each_mem_range(i, &start, &end)52nr_ranges++;5354cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);55if (!cmem)56return -ENOMEM;5758cmem->max_nr_ranges = nr_ranges;59cmem->nr_ranges = 0;60for_each_mem_range(i, &start, &end) {61cmem->ranges[cmem->nr_ranges].start = start;62cmem->ranges[cmem->nr_ranges].end = end - 1;63cmem->nr_ranges++;64}6566/* Exclude crashkernel region */67ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);68if (ret)69goto out;7071if (crashk_low_res.end) {72ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);73if (ret)74goto out;75}7677ret = crash_prepare_elf64_headers(cmem, true, addr, sz);7879out:80kfree(cmem);81return ret;82}83#endif8485/*86* Tries to add the initrd and DTB to the image. If it is not possible to find87* valid locations, this function will undo changes to the image and return non88* zero.89*/90int load_other_segments(struct kimage *image,91unsigned long kernel_load_addr,92unsigned long kernel_size,93char *initrd, unsigned long initrd_len,94char *cmdline)95{96struct kexec_buf kbuf;97void *dtb = NULL;98unsigned long initrd_load_addr = 0, dtb_len,99orig_segments = image->nr_segments;100int ret = 0;101102kbuf.image = image;103/* not allocate anything below the kernel */104kbuf.buf_min = kernel_load_addr + kernel_size;105106#ifdef CONFIG_CRASH_DUMP107/* load elf core header */108void *headers;109unsigned long headers_sz;110if (image->type == KEXEC_TYPE_CRASH) {111ret = prepare_elf_headers(&headers, &headers_sz);112if (ret) {113pr_err("Preparing elf core header failed\n");114goto out_err;115}116117kbuf.buffer = headers;118kbuf.bufsz = headers_sz;119kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;120kbuf.memsz = headers_sz;121kbuf.buf_align = SZ_64K; /* largest supported page size */122kbuf.buf_max = ULONG_MAX;123kbuf.top_down = true;124125ret = kexec_add_buffer(&kbuf);126if (ret) {127vfree(headers);128goto out_err;129}130image->elf_headers = headers;131image->elf_load_addr = kbuf.mem;132image->elf_headers_sz = headers_sz;133134kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",135image->elf_load_addr, kbuf.bufsz, kbuf.memsz);136}137#endif138139/* load initrd */140if (initrd) {141kbuf.buffer = initrd;142kbuf.bufsz = initrd_len;143kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;144kbuf.memsz = initrd_len;145kbuf.buf_align = 0;146/* within 1GB-aligned window of up to 32GB in size */147kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)148+ (unsigned long)SZ_1G * 32;149kbuf.top_down = false;150151ret = kexec_add_buffer(&kbuf);152if (ret)153goto out_err;154initrd_load_addr = kbuf.mem;155156kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",157initrd_load_addr, kbuf.bufsz, kbuf.memsz);158}159160/* load dtb */161dtb = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr,162initrd_len, cmdline, 0);163if (!dtb) {164pr_err("Preparing for new dtb failed\n");165ret = -EINVAL;166goto out_err;167}168169/* trim it */170fdt_pack(dtb);171dtb_len = fdt_totalsize(dtb);172kbuf.buffer = dtb;173kbuf.bufsz = dtb_len;174kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;175kbuf.memsz = dtb_len;176/* not across 2MB boundary */177kbuf.buf_align = SZ_2M;178kbuf.buf_max = ULONG_MAX;179kbuf.top_down = true;180181ret = kexec_add_buffer(&kbuf);182if (ret)183goto out_err;184image->arch.dtb = dtb;185image->arch.dtb_mem = kbuf.mem;186187kexec_dprintk("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",188kbuf.mem, kbuf.bufsz, kbuf.memsz);189190return 0;191192out_err:193image->nr_segments = orig_segments;194kvfree(dtb);195return ret;196}197198199