// SPDX-License-Identifier: GPL-2.0-only1/*2* powerpc code to implement the kexec_file_load syscall3*4* Copyright (C) 2004 Adam Litke ([email protected])5* Copyright (C) 2004 IBM Corp.6* Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation7* Copyright (C) 2005 R Sharada ([email protected])8* Copyright (C) 2006 Mohan Kumar M ([email protected])9* Copyright (C) 2016 IBM Corporation10*11* Based on kexec-tools' kexec-elf-ppc64.c, fs2dt.c.12* Heavily modified for the kernel by13* Thiago Jung Bauermann <[email protected]>.14*/1516#include <linux/slab.h>17#include <linux/kexec.h>18#include <linux/of_fdt.h>19#include <linux/libfdt.h>20#include <asm/setup.h>2122#define SLAVE_CODE_SIZE 256 /* First 0x100 bytes */2324/**25* setup_kdump_cmdline - Prepend "elfcorehdr=<addr> " to command line26* of kdump kernel for exporting the core.27* @image: Kexec image28* @cmdline: Command line parameters to update.29* @cmdline_len: Length of the cmdline parameters.30*31* kdump segment must be setup before calling this function.32*33* Returns new cmdline buffer for kdump kernel on success, NULL otherwise.34*/35char *setup_kdump_cmdline(struct kimage *image, char *cmdline,36unsigned long cmdline_len)37{38int elfcorehdr_strlen;39char *cmdline_ptr;4041cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);42if (!cmdline_ptr)43return NULL;4445elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ",46image->elf_load_addr);4748if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) {49pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n");50kfree(cmdline_ptr);51return NULL;52}5354memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len);55// Ensure it's nul terminated56cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0';57return cmdline_ptr;58}5960/**61* setup_purgatory - initialize the purgatory's global variables62* @image: kexec image.63* @slave_code: Slave code for the purgatory.64* @fdt: Flattened device tree for the next kernel.65* @kernel_load_addr: Address where the kernel is loaded.66* @fdt_load_addr: Address where the flattened device tree is loaded.67*68* Return: 0 on success, or negative errno on error.69*/70int setup_purgatory(struct kimage *image, const void *slave_code,71const void *fdt, unsigned long kernel_load_addr,72unsigned long fdt_load_addr)73{74unsigned int *slave_code_buf, master_entry;75int ret;7677slave_code_buf = kmalloc(SLAVE_CODE_SIZE, GFP_KERNEL);78if (!slave_code_buf)79return -ENOMEM;8081/* Get the slave code from the new kernel and put it in purgatory. */82ret = kexec_purgatory_get_set_symbol(image, "purgatory_start",83slave_code_buf, SLAVE_CODE_SIZE,84true);85if (ret) {86kfree(slave_code_buf);87return ret;88}8990master_entry = slave_code_buf[0];91memcpy(slave_code_buf, slave_code, SLAVE_CODE_SIZE);92slave_code_buf[0] = master_entry;93ret = kexec_purgatory_get_set_symbol(image, "purgatory_start",94slave_code_buf, SLAVE_CODE_SIZE,95false);96kfree(slave_code_buf);9798ret = kexec_purgatory_get_set_symbol(image, "kernel", &kernel_load_addr,99sizeof(kernel_load_addr), false);100if (ret)101return ret;102ret = kexec_purgatory_get_set_symbol(image, "dt_offset", &fdt_load_addr,103sizeof(fdt_load_addr), false);104if (ret)105return ret;106107return 0;108}109110111