Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/loongarch/kernel/kexec_elf.c
29521 views
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 <[email protected]>
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
20
static 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
54
static 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
97
out:
98
kexec_free_elf_info(&elf_info);
99
return ret ? ERR_PTR(ret) : NULL;
100
}
101
102
const struct kexec_file_ops kexec_elf_ops = {
103
.probe = elf_kexec_probe,
104
.load = elf_kexec_load,
105
};
106
107