0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/slab.h>
0018 #include <linux/kexec.h>
0019 #include <linux/of_fdt.h>
0020 #include <linux/libfdt.h>
0021 #include <asm/setup.h>
0022
0023 #define SLAVE_CODE_SIZE 256
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
0037 unsigned long cmdline_len)
0038 {
0039 int elfcorehdr_strlen;
0040 char *cmdline_ptr;
0041
0042 cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
0043 if (!cmdline_ptr)
0044 return NULL;
0045
0046 elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ",
0047 image->elf_load_addr);
0048
0049 if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) {
0050 pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n");
0051 kfree(cmdline_ptr);
0052 return NULL;
0053 }
0054
0055 memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len);
0056
0057 cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0';
0058 return cmdline_ptr;
0059 }
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 int setup_purgatory(struct kimage *image, const void *slave_code,
0072 const void *fdt, unsigned long kernel_load_addr,
0073 unsigned long fdt_load_addr)
0074 {
0075 unsigned int *slave_code_buf, master_entry;
0076 int ret;
0077
0078 slave_code_buf = kmalloc(SLAVE_CODE_SIZE, GFP_KERNEL);
0079 if (!slave_code_buf)
0080 return -ENOMEM;
0081
0082
0083 ret = kexec_purgatory_get_set_symbol(image, "purgatory_start",
0084 slave_code_buf, SLAVE_CODE_SIZE,
0085 true);
0086 if (ret) {
0087 kfree(slave_code_buf);
0088 return ret;
0089 }
0090
0091 master_entry = slave_code_buf[0];
0092 memcpy(slave_code_buf, slave_code, SLAVE_CODE_SIZE);
0093 slave_code_buf[0] = master_entry;
0094 ret = kexec_purgatory_get_set_symbol(image, "purgatory_start",
0095 slave_code_buf, SLAVE_CODE_SIZE,
0096 false);
0097 kfree(slave_code_buf);
0098
0099 ret = kexec_purgatory_get_set_symbol(image, "kernel", &kernel_load_addr,
0100 sizeof(kernel_load_addr), false);
0101 if (ret)
0102 return ret;
0103 ret = kexec_purgatory_get_set_symbol(image, "dt_offset", &fdt_load_addr,
0104 sizeof(fdt_load_addr), false);
0105 if (ret)
0106 return ret;
0107
0108 return 0;
0109 }