^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * powerpc code to implement the kexec_file_load syscall
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2004 Adam Litke (agl@us.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2004 IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2005 R Sharada (sharada@in.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2016 IBM Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Based on kexec-tools' kexec-elf-ppc64.c, fs2dt.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Heavily modified for the kernel by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kexec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/of_fdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/libfdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/ima.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define SLAVE_CODE_SIZE 256 /* First 0x100 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * setup_kdump_cmdline - Prepend "elfcorehdr=<addr> " to command line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * of kdump kernel for exporting the core.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * @image: Kexec image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * @cmdline: Command line parameters to update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * @cmdline_len: Length of the cmdline parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * kdump segment must be setup before calling this function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Returns new cmdline buffer for kdump kernel on success, NULL otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned long cmdline_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int elfcorehdr_strlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) char *cmdline_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (!cmdline_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) image->arch.elfcorehdr_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) kfree(cmdline_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) // Ensure it's nul terminated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return cmdline_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * setup_purgatory - initialize the purgatory's global variables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * @image: kexec image.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * @slave_code: Slave code for the purgatory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * @fdt: Flattened device tree for the next kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @kernel_load_addr: Address where the kernel is loaded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * @fdt_load_addr: Address where the flattened device tree is loaded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * Return: 0 on success, or negative errno on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int setup_purgatory(struct kimage *image, const void *slave_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) const void *fdt, unsigned long kernel_load_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned long fdt_load_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned int *slave_code_buf, master_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) slave_code_buf = kmalloc(SLAVE_CODE_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (!slave_code_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Get the slave code from the new kernel and put it in purgatory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ret = kexec_purgatory_get_set_symbol(image, "purgatory_start",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) slave_code_buf, SLAVE_CODE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) kfree(slave_code_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) master_entry = slave_code_buf[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) memcpy(slave_code_buf, slave_code, SLAVE_CODE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) slave_code_buf[0] = master_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ret = kexec_purgatory_get_set_symbol(image, "purgatory_start",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) slave_code_buf, SLAVE_CODE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) kfree(slave_code_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ret = kexec_purgatory_get_set_symbol(image, "kernel", &kernel_load_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) sizeof(kernel_load_addr), false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ret = kexec_purgatory_get_set_symbol(image, "dt_offset", &fdt_load_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) sizeof(fdt_load_addr), false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * delete_fdt_mem_rsv - delete memory reservation with given address and size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * Return: 0 on success, or negative errno on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int i, ret, num_rsvs = fdt_num_mem_rsv(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) for (i = 0; i < num_rsvs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) uint64_t rsv_start, rsv_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ret = fdt_get_mem_rsv(fdt, i, &rsv_start, &rsv_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pr_err("Malformed device tree.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (rsv_start == start && rsv_size == size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ret = fdt_del_mem_rsv(fdt, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) pr_err("Error deleting device tree reservation.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * setup_new_fdt - modify /chosen and memory reservation for the next kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * @image: kexec image being loaded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @fdt: Flattened device tree for the next kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * @initrd_load_addr: Address where the next initrd will be loaded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * @initrd_len: Size of the next initrd, or 0 if there will be none.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * @cmdline: Command line for the next kernel, or NULL if there will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * be none.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * Return: 0 on success, or negative errno on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int setup_new_fdt(const struct kimage *image, void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) unsigned long initrd_load_addr, unsigned long initrd_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) const char *cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) int ret, chosen_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) const void *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Remove memory reservation for the current device tree. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) ret = delete_fdt_mem_rsv(fdt, __pa(initial_boot_params),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) fdt_totalsize(initial_boot_params));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) pr_debug("Removed old device tree reservation.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) else if (ret != -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) chosen_node = fdt_path_offset(fdt, "/chosen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (chosen_node == -FDT_ERR_NOTFOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) "chosen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (chosen_node < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) pr_err("Error creating /chosen.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) } else if (chosen_node < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) pr_err("Malformed device tree: error reading /chosen.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* Did we boot using an initrd? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) uint64_t tmp_start, tmp_end, tmp_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) pr_err("Malformed device tree.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * kexec reserves exact initrd size, while firmware may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * reserve a multiple of PAGE_SIZE, so check for both.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) tmp_size = tmp_end - tmp_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) ret = delete_fdt_mem_rsv(fdt, tmp_start, tmp_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (ret == -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) ret = delete_fdt_mem_rsv(fdt, tmp_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) round_up(tmp_size, PAGE_SIZE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) pr_debug("Removed old initrd reservation.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) else if (ret != -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* If there's no new initrd, delete the old initrd's info. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (initrd_len == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) ret = fdt_delprop(fdt, chosen_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) "linux,initrd-start");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) pr_err("Error deleting linux,initrd-start.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ret = fdt_delprop(fdt, chosen_node, "linux,initrd-end");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) pr_err("Error deleting linux,initrd-end.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (initrd_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) ret = fdt_setprop_u64(fdt, chosen_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) "linux,initrd-start",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) initrd_load_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* initrd-end is the first address after the initrd image. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ret = fdt_setprop_u64(fdt, chosen_node, "linux,initrd-end",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) initrd_load_addr + initrd_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ret = fdt_add_mem_rsv(fdt, initrd_load_addr, initrd_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) pr_err("Error reserving initrd memory: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) fdt_strerror(ret));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (cmdline != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ret = fdt_setprop_string(fdt, chosen_node, "bootargs", cmdline);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ret = fdt_delprop(fdt, chosen_node, "bootargs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (ret && ret != -FDT_ERR_NOTFOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pr_err("Error deleting bootargs.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (image->type == KEXEC_TYPE_CRASH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * Avoid elfcorehdr from being stomped on in kdump kernel by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * setting up memory reserve map.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) ret = fdt_add_mem_rsv(fdt, image->arch.elfcorehdr_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) image->arch.elf_headers_sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) pr_err("Error reserving elfcorehdr memory: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) fdt_strerror(ret));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) ret = setup_ima_buffer(image, fdt, chosen_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) pr_err("Error setting up the new device tree.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) pr_err("Error setting up the new device tree.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }