From: Youling Tang <tangyoul...@kylinos.cn> Add inird loading support and pass it to the second kernel via the cmdline 'initrd=start,size'.
Signed-off-by: Youling Tang <tangyoul...@kylinos.cn> --- arch/loongarch/kernel/machine_kexec_file.c | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c index bc91ae0afa4c..e1240644f529 100644 --- a/arch/loongarch/kernel/machine_kexec_file.c +++ b/arch/loongarch/kernel/machine_kexec_file.c @@ -34,13 +34,84 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image) return kexec_image_post_load_cleanup_default(image); } +/* Adds the "initrd=start,size" command line parameter to command line. */ +static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmplen, + char *modified_cmdline, unsigned long initrd) +{ + int initrd_strlen; + + initrd_strlen = sprintf(modified_cmdline + (*cmdline_tmplen), "initrd=0x%lx,0x%lx ", + initrd, image->initrd_buf_len); + *cmdline_tmplen += initrd_strlen; +} + +/* + * Tries to add the initrd to the image. If it is not possible to find + * valid locations, this function will undo changes to the image and return non + * zero. + */ int load_other_segments(struct kimage *image, unsigned long kernel_load_addr, unsigned long kernel_size, char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len) { + struct kexec_buf kbuf; + unsigned long orig_segments = image->nr_segments; + char *modified_cmdline = NULL; + unsigned long cmdline_tmplen = 0; + unsigned long initrd_load_addr = 0; + int ret = 0; + + + kbuf.image = image; + /* not allocate anything below the kernel */ + kbuf.buf_min = kernel_load_addr + kernel_size; + + modified_cmdline = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); + if (!modified_cmdline) + return -EINVAL; + + /* Ensure it's nul terminated */ + modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; + + /* load initrd */ + if (initrd) { + kbuf.buffer = initrd; + kbuf.bufsz = initrd_len; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = initrd_len; + kbuf.buf_align = 0; + /* within 1GB-aligned window of up to 32GB in size */ + kbuf.buf_max = round_down(kernel_load_addr, SZ_1G) + + (unsigned long)SZ_1G * 32; + kbuf.top_down = false; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out_err; + initrd_load_addr = kbuf.mem; + + kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + initrd_load_addr, kbuf.bufsz, kbuf.memsz); + + /* Add the initrd=start,size parameter to the command line */ + cmdline_add_initrd(image, &cmdline_tmplen, modified_cmdline, initrd_load_addr); + } + + if (cmdline_len + cmdline_tmplen > COMMAND_LINE_SIZE) { + pr_err("Appending kdump cmdline exceeds cmdline size\n"); + ret = -EINVAL; + goto out_err; + } + memcpy(modified_cmdline + cmdline_tmplen, cmdline, cmdline_len); + cmdline = modified_cmdline; image->arch.cmdline_ptr = (unsigned long)cmdline; return 0; + +out_err: + image->nr_segments = orig_segments; + kfree(modified_cmdline); + return ret; } -- 2.34.1