Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1191cf49 authored by Sven Schnelle's avatar Sven Schnelle Committed by Helge Deller
Browse files

parisc: add support for kexec_file_load() syscall



Signed-off-by: default avatarSven Schnelle <svens@stackframe.org>
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
parent 3be6e58c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -359,6 +359,16 @@ config KEXEC
	  shutdown, so do not be surprised if this code does not
	  initially work for you.

config KEXEC_FILE
	bool "kexec file based system call"
	select KEXEC_CORE
	select KEXEC_ELF
	help
	  This enables the kexec_file_load() System call. This is
	  file based and takes file descriptors as system call argument
	  for kernel and initramfs as opposed to list of segments as
	  accepted by previous system call.

endmenu


+1 −0
Original line number Diff line number Diff line
@@ -38,3 +38,4 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_KGDB)			+= kgdb.o
obj-$(CONFIG_KPROBES)			+= kprobes.o
obj-$(CONFIG_KEXEC)			+= kexec.o relocate_kernel.o
obj-$(CONFIG_KEXEC_FILE)		+= kexec_file.o
+7 −0
Original line number Diff line number Diff line
@@ -40,6 +40,13 @@ static void kexec_image_info(const struct kimage *kimage)

	for (i = 0; i < kimage->nr_segments; i++)
		kexec_show_segment_info(kimage, i);

#ifdef CONFIG_KEXEC_FILE
	if (kimage->file_mode) {
		pr_debug("cmdline: %.*s\n", (int)kimage->cmdline_buf_len,
			 kimage->cmdline_buf);
	}
#endif
}

void machine_kexec_cleanup(struct kimage *kimage)
+86 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Load ELF vmlinux file for the kexec_file_load syscall.
 *
 * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
 *
 */
#include <linux/elf.h>
#include <linux/kexec.h>
#include <linux/libfdt.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
#include <linux/slab.h>
#include <linux/types.h>

static void *elf_load(struct kimage *image, char *kernel_buf,
			unsigned long kernel_len, char *initrd,
			unsigned long initrd_len, char *cmdline,
			unsigned long cmdline_len)
{
	int ret, i;
	unsigned long kernel_load_addr;
	struct elfhdr ehdr;
	struct kexec_elf_info elf_info;
	struct kexec_buf kbuf = { .image = image, .buf_min = 0,
				  .buf_max = -1UL, };

	ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
	if (ret)
		goto out;

	ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr);
	if (ret)
		goto out;

	image->start = __pa(elf_info.ehdr->e_entry);

	for (i = 0; i < image->nr_segments; i++)
		image->segment[i].mem = __pa(image->segment[i].mem);

	pr_debug("Loaded the kernel at 0x%lx, entry at 0x%lx\n",
		 kernel_load_addr, image->start);

	if (initrd != NULL) {
		kbuf.buffer = initrd;
		kbuf.bufsz = kbuf.memsz = initrd_len;
		kbuf.buf_align = PAGE_SIZE;
		kbuf.top_down = false;
		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
		ret = kexec_add_buffer(&kbuf);
		if (ret)
			goto out;

		pr_debug("Loaded initrd at 0x%lx\n", kbuf.mem);
		image->arch.initrd_start = kbuf.mem;
		image->arch.initrd_end = kbuf.mem + initrd_len;
	}

	if (cmdline != NULL) {
		kbuf.buffer = cmdline;
		kbuf.bufsz = kbuf.memsz = ALIGN(cmdline_len, 8);
		kbuf.buf_align = PAGE_SIZE;
		kbuf.top_down = false;
		kbuf.buf_min = PAGE0->mem_free + PAGE_SIZE;
		kbuf.buf_max = kernel_load_addr;
		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
		ret = kexec_add_buffer(&kbuf);
		if (ret)
			goto out;

		pr_debug("Loaded cmdline at 0x%lx\n", kbuf.mem);
		image->arch.cmdline = kbuf.mem;
	}
out:
	return NULL;
}

const struct kexec_file_ops kexec_elf_ops = {
	.probe = kexec_elf_probe,
	.load = elf_load,
};

const struct kexec_file_ops * const kexec_file_loaders[] = {
	&kexec_elf_ops,
	NULL
};