1 // SPDX-License-Identifier: GPL-2.0-only
3 * Load ELF vmlinux file for the kexec_file_load syscall.
5 * Copyright (C) 2021 Huawei Technologies Co, Ltd.
7 * Author: Liao Chang (liaochang1@huawei.com)
9 * Based on kexec-tools' kexec-elf-riscv.c, heavily modified
13 #define pr_fmt(fmt) "kexec_image: " fmt
15 #include <linux/elf.h>
16 #include <linux/kexec.h>
17 #include <linux/slab.h>
19 #include <linux/libfdt.h>
20 #include <linux/types.h>
21 #include <linux/memblock.h>
22 #include <linux/vmalloc.h>
23 #include <asm/setup.h>
25 int arch_kimage_file_post_load_cleanup(struct kimage
*image
)
27 kvfree(image
->arch
.fdt
);
28 image
->arch
.fdt
= NULL
;
30 vfree(image
->elf_headers
);
31 image
->elf_headers
= NULL
;
32 image
->elf_headers_sz
= 0;
34 return kexec_image_post_load_cleanup_default(image
);
37 static int riscv_kexec_elf_load(struct kimage
*image
, struct elfhdr
*ehdr
,
38 struct kexec_elf_info
*elf_info
, unsigned long old_pbase
,
39 unsigned long new_pbase
)
44 struct kexec_buf kbuf
;
45 const struct elf_phdr
*phdr
;
49 for (i
= 0; i
< ehdr
->e_phnum
; i
++) {
50 phdr
= &elf_info
->proghdrs
[i
];
51 if (phdr
->p_type
!= PT_LOAD
)
54 size
= phdr
->p_filesz
;
55 if (size
> phdr
->p_memsz
)
58 kbuf
.buffer
= (void *) elf_info
->buffer
+ phdr
->p_offset
;
60 kbuf
.buf_align
= phdr
->p_align
;
61 kbuf
.mem
= phdr
->p_paddr
- old_pbase
+ new_pbase
;
62 kbuf
.memsz
= phdr
->p_memsz
;
63 kbuf
.top_down
= false;
64 ret
= kexec_add_buffer(&kbuf
);
73 * Go through the available phsyical memory regions and find one that hold
74 * an image of the specified size.
76 static int elf_find_pbase(struct kimage
*image
, unsigned long kernel_len
,
77 struct elfhdr
*ehdr
, struct kexec_elf_info
*elf_info
,
78 unsigned long *old_pbase
, unsigned long *new_pbase
)
82 struct kexec_buf kbuf
;
83 const struct elf_phdr
*phdr
;
84 unsigned long lowest_paddr
= ULONG_MAX
;
85 unsigned long lowest_vaddr
= ULONG_MAX
;
87 for (i
= 0; i
< ehdr
->e_phnum
; i
++) {
88 phdr
= &elf_info
->proghdrs
[i
];
89 if (phdr
->p_type
!= PT_LOAD
)
92 if (lowest_paddr
> phdr
->p_paddr
)
93 lowest_paddr
= phdr
->p_paddr
;
95 if (lowest_vaddr
> phdr
->p_vaddr
)
96 lowest_vaddr
= phdr
->p_vaddr
;
100 kbuf
.buf_min
= lowest_paddr
;
101 kbuf
.buf_max
= ULONG_MAX
;
104 * Current riscv boot protocol requires 2MB alignment for
105 * RV64 and 4MB alignment for RV32
108 kbuf
.buf_align
= PMD_SIZE
;
109 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
110 kbuf
.memsz
= ALIGN(kernel_len
, PAGE_SIZE
);
111 kbuf
.top_down
= false;
112 ret
= arch_kexec_locate_mem_hole(&kbuf
);
114 *old_pbase
= lowest_paddr
;
115 *new_pbase
= kbuf
.mem
;
116 image
->start
= ehdr
->e_entry
- lowest_vaddr
+ kbuf
.mem
;
121 #ifdef CONFIG_CRASH_DUMP
122 static int get_nr_ram_ranges_callback(struct resource
*res
, void *arg
)
124 unsigned int *nr_ranges
= arg
;
130 static int prepare_elf64_ram_headers_callback(struct resource
*res
, void *arg
)
132 struct crash_mem
*cmem
= arg
;
134 cmem
->ranges
[cmem
->nr_ranges
].start
= res
->start
;
135 cmem
->ranges
[cmem
->nr_ranges
].end
= res
->end
;
141 static int prepare_elf_headers(void **addr
, unsigned long *sz
)
143 struct crash_mem
*cmem
;
144 unsigned int nr_ranges
;
147 nr_ranges
= 1; /* For exclusion of crashkernel region */
148 walk_system_ram_res(0, -1, &nr_ranges
, get_nr_ram_ranges_callback
);
150 cmem
= kmalloc(struct_size(cmem
, ranges
, nr_ranges
), GFP_KERNEL
);
154 cmem
->max_nr_ranges
= nr_ranges
;
156 ret
= walk_system_ram_res(0, -1, cmem
, prepare_elf64_ram_headers_callback
);
160 /* Exclude crashkernel region */
161 ret
= crash_exclude_mem_range(cmem
, crashk_res
.start
, crashk_res
.end
);
163 ret
= crash_prepare_elf64_headers(cmem
, true, addr
, sz
);
170 static char *setup_kdump_cmdline(struct kimage
*image
, char *cmdline
,
171 unsigned long cmdline_len
)
173 int elfcorehdr_strlen
;
176 cmdline_ptr
= kzalloc(COMMAND_LINE_SIZE
, GFP_KERNEL
);
180 elfcorehdr_strlen
= sprintf(cmdline_ptr
, "elfcorehdr=0x%lx ",
181 image
->elf_load_addr
);
183 if (elfcorehdr_strlen
+ cmdline_len
> COMMAND_LINE_SIZE
) {
184 pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n");
189 memcpy(cmdline_ptr
+ elfcorehdr_strlen
, cmdline
, cmdline_len
);
190 /* Ensure it's nul terminated */
191 cmdline_ptr
[COMMAND_LINE_SIZE
- 1] = '\0';
196 static void *elf_kexec_load(struct kimage
*image
, char *kernel_buf
,
197 unsigned long kernel_len
, char *initrd
,
198 unsigned long initrd_len
, char *cmdline
,
199 unsigned long cmdline_len
)
203 unsigned long old_kernel_pbase
= ULONG_MAX
;
204 unsigned long new_kernel_pbase
= 0UL;
205 unsigned long initrd_pbase
= 0UL;
206 unsigned long kernel_start
;
208 struct kexec_buf kbuf
;
209 struct kexec_elf_info elf_info
;
210 char *modified_cmdline
= NULL
;
212 ret
= kexec_build_elf_info(kernel_buf
, kernel_len
, &ehdr
, &elf_info
);
216 ret
= elf_find_pbase(image
, kernel_len
, &ehdr
, &elf_info
,
217 &old_kernel_pbase
, &new_kernel_pbase
);
220 kernel_start
= image
->start
;
222 /* Add the kernel binary to the image */
223 ret
= riscv_kexec_elf_load(image
, &ehdr
, &elf_info
,
224 old_kernel_pbase
, new_kernel_pbase
);
229 kbuf
.buf_min
= new_kernel_pbase
+ kernel_len
;
230 kbuf
.buf_max
= ULONG_MAX
;
232 #ifdef CONFIG_CRASH_DUMP
234 if (image
->type
== KEXEC_TYPE_CRASH
) {
236 unsigned long headers_sz
;
237 ret
= prepare_elf_headers(&headers
, &headers_sz
);
239 pr_err("Preparing elf core header failed\n");
243 kbuf
.buffer
= headers
;
244 kbuf
.bufsz
= headers_sz
;
245 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
246 kbuf
.memsz
= headers_sz
;
247 kbuf
.buf_align
= ELF_CORE_HEADER_ALIGN
;
248 kbuf
.top_down
= true;
250 ret
= kexec_add_buffer(&kbuf
);
255 image
->elf_headers
= headers
;
256 image
->elf_load_addr
= kbuf
.mem
;
257 image
->elf_headers_sz
= headers_sz
;
259 kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
260 image
->elf_load_addr
, kbuf
.bufsz
, kbuf
.memsz
);
262 /* Setup cmdline for kdump kernel case */
263 modified_cmdline
= setup_kdump_cmdline(image
, cmdline
,
265 if (!modified_cmdline
) {
266 pr_err("Setting up cmdline for kdump kernel failed\n");
270 cmdline
= modified_cmdline
;
274 #ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY
275 /* Add purgatory to the image */
276 kbuf
.top_down
= true;
277 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
278 ret
= kexec_load_purgatory(image
, &kbuf
);
280 pr_err("Error loading purgatory ret=%d\n", ret
);
283 kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf
.mem
);
285 ret
= kexec_purgatory_get_set_symbol(image
, "riscv_kernel_entry",
287 sizeof(kernel_start
), 0);
289 pr_err("Error update purgatory ret=%d\n", ret
);
290 #endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */
292 /* Add the initrd to the image */
293 if (initrd
!= NULL
) {
294 kbuf
.buffer
= initrd
;
295 kbuf
.bufsz
= kbuf
.memsz
= initrd_len
;
296 kbuf
.buf_align
= PAGE_SIZE
;
297 kbuf
.top_down
= true;
298 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
299 ret
= kexec_add_buffer(&kbuf
);
302 initrd_pbase
= kbuf
.mem
;
303 kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase
);
306 /* Add the DTB to the image */
307 fdt
= of_kexec_alloc_and_setup_fdt(image
, initrd_pbase
,
308 initrd_len
, cmdline
, 0);
310 pr_err("Error setting up the new device tree.\n");
317 kbuf
.bufsz
= kbuf
.memsz
= fdt_totalsize(fdt
);
318 kbuf
.buf_align
= PAGE_SIZE
;
319 kbuf
.mem
= KEXEC_BUF_MEM_UNKNOWN
;
320 kbuf
.top_down
= true;
321 ret
= kexec_add_buffer(&kbuf
);
323 pr_err("Error add DTB kbuf ret=%d\n", ret
);
326 /* Cache the fdt buffer address for memory cleanup */
327 image
->arch
.fdt
= fdt
;
328 kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf
.mem
);
334 kfree(modified_cmdline
);
335 kexec_free_elf_info(&elf_info
);
336 return ret
? ERR_PTR(ret
) : NULL
;
339 #define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1))
340 #define RISCV_IMM_BITS 12
341 #define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS)
342 #define RISCV_CONST_HIGH_PART(x) \
343 (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1))
344 #define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x))
346 #define ENCODE_ITYPE_IMM(x) \
347 (RV_X(x, 0, 12) << 20)
348 #define ENCODE_BTYPE_IMM(x) \
349 ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \
350 (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
351 #define ENCODE_UTYPE_IMM(x) \
352 (RV_X(x, 12, 20) << 12)
353 #define ENCODE_JTYPE_IMM(x) \
354 ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \
355 (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
356 #define ENCODE_CBTYPE_IMM(x) \
357 ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \
358 (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12))
359 #define ENCODE_CJTYPE_IMM(x) \
360 ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \
361 (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \
362 (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12))
363 #define ENCODE_UJTYPE_IMM(x) \
364 (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \
365 (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32))
366 #define ENCODE_UITYPE_IMM(x) \
367 (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32))
369 #define CLEAN_IMM(type, x) \
370 ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x))
372 int arch_kexec_apply_relocations_add(struct purgatory_info
*pi
,
374 const Elf_Shdr
*relsec
,
375 const Elf_Shdr
*symtab
)
377 const char *strtab
, *name
, *shstrtab
;
378 const Elf_Shdr
*sechdrs
;
382 /* String & section header string table */
383 sechdrs
= (void *)pi
->ehdr
+ pi
->ehdr
->e_shoff
;
384 strtab
= (char *)pi
->ehdr
+ sechdrs
[symtab
->sh_link
].sh_offset
;
385 shstrtab
= (char *)pi
->ehdr
+ sechdrs
[pi
->ehdr
->e_shstrndx
].sh_offset
;
387 relas
= (void *)pi
->ehdr
+ relsec
->sh_offset
;
389 for (i
= 0; i
< relsec
->sh_size
/ sizeof(*relas
); i
++) {
390 const Elf_Sym
*sym
; /* symbol to relocate */
391 unsigned long addr
; /* final location after relocation */
392 unsigned long val
; /* relocated symbol value */
393 unsigned long sec_base
; /* relocated symbol value */
394 void *loc
; /* tmp location to modify */
396 sym
= (void *)pi
->ehdr
+ symtab
->sh_offset
;
397 sym
+= ELF64_R_SYM(relas
[i
].r_info
);
400 name
= strtab
+ sym
->st_name
;
402 name
= shstrtab
+ sechdrs
[sym
->st_shndx
].sh_name
;
404 loc
= pi
->purgatory_buf
;
405 loc
+= section
->sh_offset
;
406 loc
+= relas
[i
].r_offset
;
408 if (sym
->st_shndx
== SHN_ABS
)
410 else if (sym
->st_shndx
>= pi
->ehdr
->e_shnum
) {
411 pr_err("Invalid section %d for symbol %s\n",
412 sym
->st_shndx
, name
);
415 sec_base
= pi
->sechdrs
[sym
->st_shndx
].sh_addr
;
419 val
+= relas
[i
].r_addend
;
421 addr
= section
->sh_addr
+ relas
[i
].r_offset
;
423 r_type
= ELF64_R_TYPE(relas
[i
].r_info
);
427 *(u32
*)loc
= CLEAN_IMM(BTYPE
, *(u32
*)loc
) |
428 ENCODE_BTYPE_IMM(val
- addr
);
431 *(u32
*)loc
= CLEAN_IMM(JTYPE
, *(u32
*)loc
) |
432 ENCODE_JTYPE_IMM(val
- addr
);
435 * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I
436 * sym is expected to be next to R_RISCV_PCREL_HI20
437 * in purgatory relsec. Handle it like R_RISCV_CALL
438 * sym, instead of searching the whole relsec.
440 case R_RISCV_PCREL_HI20
:
441 case R_RISCV_CALL_PLT
:
443 *(u64
*)loc
= CLEAN_IMM(UITYPE
, *(u64
*)loc
) |
444 ENCODE_UJTYPE_IMM(val
- addr
);
446 case R_RISCV_RVC_BRANCH
:
447 *(u32
*)loc
= CLEAN_IMM(CBTYPE
, *(u32
*)loc
) |
448 ENCODE_CBTYPE_IMM(val
- addr
);
450 case R_RISCV_RVC_JUMP
:
451 *(u32
*)loc
= CLEAN_IMM(CJTYPE
, *(u32
*)loc
) |
452 ENCODE_CJTYPE_IMM(val
- addr
);
466 /* It has been applied by R_RISCV_PCREL_HI20 sym */
467 case R_RISCV_PCREL_LO12_I
:
472 pr_err("Unknown rela relocation: %d\n", r_type
);
479 const struct kexec_file_ops elf_kexec_ops
= {
480 .probe
= kexec_elf_probe
,
481 .load
= elf_kexec_load
,