File Index
Files and directories
Sign in
FILE

kexec_elf.c

File preview with syntax highlighting.

linux-6.19.14/arch/loongarch/kernel/kexec_elf.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Load ELF vmlinux file for the kexec_file_load syscall.
  4 *
  5 * Author: Youling Tang <tangyouling@kylinos.cn>
  6 * Copyright (C) 2025 KylinSoft Corporation.
  7 */
  8
  9#define pr_fmt(fmt)	"kexec_file(ELF): " fmt
 10
 11#include <linux/elf.h>
 12#include <linux/kexec.h>
 13#include <linux/slab.h>
 14#include <linux/types.h>
 15#include <linux/memblock.h>
 16#include <asm/setup.h>
 17
 18#define elf_kexec_probe kexec_elf_probe
 19
 20static int _elf_kexec_load(struct kimage *image,
 21			   struct elfhdr *ehdr, struct kexec_elf_info *elf_info,
 22			   struct kexec_buf *kbuf, unsigned long *text_offset)
 23{
 24	int i, ret = -1;
 25
 26	/* Read in the PT_LOAD segments. */
 27	for (i = 0; i < ehdr->e_phnum; i++) {
 28		size_t size;
 29		const struct elf_phdr *phdr;
 30
 31		phdr = &elf_info->proghdrs[i];
 32		if (phdr->p_type != PT_LOAD)
 33			continue;
 34
 35		size = phdr->p_filesz;
 36		if (size > phdr->p_memsz)
 37			size = phdr->p_memsz;
 38
 39		kbuf->buffer = (void *)elf_info->buffer + phdr->p_offset;
 40		kbuf->bufsz = size;
 41		kbuf->buf_align = phdr->p_align;
 42		*text_offset = __pa(phdr->p_paddr);
 43		kbuf->buf_min = *text_offset;
 44		kbuf->memsz = ALIGN(phdr->p_memsz, SZ_64K);
 45		kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
 46		ret = kexec_add_buffer(kbuf);
 47		if (ret < 0)
 48			break;
 49	}
 50
 51	return ret;
 52}
 53
 54static void *elf_kexec_load(struct kimage *image,
 55			    char *kernel, unsigned long kernel_len,
 56			    char *initrd, unsigned long initrd_len,
 57			    char *cmdline, unsigned long cmdline_len)
 58{
 59	int ret;
 60	unsigned long text_offset, kernel_segment_number;
 61	struct elfhdr ehdr;
 62	struct kexec_buf kbuf = {};
 63	struct kexec_elf_info elf_info;
 64	struct kexec_segment *kernel_segment;
 65
 66	ret = kexec_build_elf_info(kernel, kernel_len, &ehdr, &elf_info);
 67	if (ret < 0)
 68		return ERR_PTR(ret);
 69
 70	/*
 71	 * Load the kernel
 72	 * FIXME: Non-relocatable kernel rejected for kexec_file (require CONFIG_RELOCATABLE)
 73	 */
 74	kbuf.image = image;
 75	kbuf.buf_max = ULONG_MAX;
 76	kbuf.top_down = false;
 77
 78	kernel_segment_number = image->nr_segments;
 79
 80	ret = _elf_kexec_load(image, &ehdr, &elf_info, &kbuf, &text_offset);
 81	if (ret < 0)
 82		goto out;
 83
 84	/* Load additional data */
 85	kernel_segment = &image->segment[kernel_segment_number];
 86	ret = load_other_segments(image, kernel_segment->mem, kernel_segment->memsz,
 87				  initrd, initrd_len, cmdline, cmdline_len);
 88	if (ret < 0)
 89		goto out;
 90
 91	/* Make sure the second kernel jumps to the correct "kernel_entry". */
 92	image->start = kernel_segment->mem + __pa(ehdr.e_entry) - text_offset;
 93
 94	kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
 95		      kernel_segment->mem, kbuf.bufsz, kernel_segment->memsz);
 96
 97out:
 98	kexec_free_elf_info(&elf_info);
 99	return ret ? ERR_PTR(ret) : NULL;
100}
101
102const struct kexec_file_ops kexec_elf_ops = {
103	.probe = elf_kexec_probe,
104	.load  = elf_kexec_load,
105};
~/ Read-only file preview.