1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Load ELF vmlinux file for the kexec_file_load syscall. 4 * 5 * Copyright (C) 2021 Huawei Technologies Co, Ltd. 6 * 7 * Author: Liao Chang (liaochang1@huawei.com) 8 * 9 * Based on kexec-tools' kexec-elf-riscv.c, heavily modified 10 * for kernel. 11 */ 12 13 #include <linux/elf.h> 14 #include <linux/kexec.h> 15 #include <linux/slab.h> 16 #include <linux/of.h> 17 #include <linux/libfdt.h> 18 #include <linux/types.h> 19 #include <linux/memblock.h> 20 #include <linux/minmax.h> 21 #include <asm/setup.h> 22 23 static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, 24 struct kexec_elf_info *elf_info, unsigned long old_pbase, 25 unsigned long new_pbase) 26 { 27 int i; 28 int ret = 0; 29 struct kexec_buf kbuf = {}; 30 const struct elf_phdr *phdr; 31 32 kbuf.image = image; 33 34 for (i = 0; i < ehdr->e_phnum; i++) { 35 phdr = &elf_info->proghdrs[i]; 36 if (phdr->p_type != PT_LOAD) 37 continue; 38 39 kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; 40 kbuf.bufsz = min(phdr->p_filesz, phdr->p_memsz); 41 kbuf.buf_align = phdr->p_align; 42 kbuf.mem = phdr->p_paddr - old_pbase + new_pbase; 43 kbuf.memsz = phdr->p_memsz; 44 kbuf.top_down = false; 45 ret = kexec_add_buffer(&kbuf); 46 if (ret) 47 break; 48 } 49 50 return ret; 51 } 52 53 /* 54 * Go through the available phsyical memory regions and find one that hold 55 * an image of the specified size. 56 */ 57 static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, 58 struct elfhdr *ehdr, struct kexec_elf_info *elf_info, 59 unsigned long *old_pbase, unsigned long *new_pbase) 60 { 61 int i; 62 int ret; 63 struct kexec_buf kbuf = {}; 64 const struct elf_phdr *phdr; 65 unsigned long lowest_paddr = ULONG_MAX; 66 unsigned long lowest_vaddr = ULONG_MAX; 67 68 for (i = 0; i < ehdr->e_phnum; i++) { 69 phdr = &elf_info->proghdrs[i]; 70 if (phdr->p_type != PT_LOAD) 71 continue; 72 73 if (lowest_paddr > phdr->p_paddr) 74 lowest_paddr = phdr->p_paddr; 75 76 if (lowest_vaddr > phdr->p_vaddr) 77 lowest_vaddr = phdr->p_vaddr; 78 } 79 80 kbuf.image = image; 81 kbuf.buf_min = lowest_paddr; 82 kbuf.buf_max = ULONG_MAX; 83 84 /* 85 * Current riscv boot protocol requires 2MB alignment for 86 * RV64 and 4MB alignment for RV32 87 * 88 */ 89 kbuf.buf_align = PMD_SIZE; 90 kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 91 kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); 92 kbuf.cma = NULL; 93 kbuf.top_down = false; 94 ret = arch_kexec_locate_mem_hole(&kbuf); 95 if (!ret) { 96 *old_pbase = lowest_paddr; 97 *new_pbase = kbuf.mem; 98 image->start = ehdr->e_entry - lowest_vaddr + kbuf.mem; 99 } 100 return ret; 101 } 102 103 static void *elf_kexec_load(struct kimage *image, char *kernel_buf, 104 unsigned long kernel_len, char *initrd, 105 unsigned long initrd_len, char *cmdline, 106 unsigned long cmdline_len) 107 { 108 int ret; 109 unsigned long old_kernel_pbase = ULONG_MAX; 110 unsigned long new_kernel_pbase = 0UL; 111 struct elfhdr ehdr; 112 struct kexec_elf_info elf_info; 113 114 ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); 115 if (ret) 116 return ERR_PTR(ret); 117 118 ret = elf_find_pbase(image, kernel_len, &ehdr, &elf_info, 119 &old_kernel_pbase, &new_kernel_pbase); 120 if (ret) 121 goto out; 122 123 /* Add the kernel binary to the image */ 124 ret = riscv_kexec_elf_load(image, &ehdr, &elf_info, 125 old_kernel_pbase, new_kernel_pbase); 126 if (ret) 127 goto out; 128 129 ret = load_extra_segments(image, image->start, kernel_len, 130 initrd, initrd_len, cmdline, cmdline_len); 131 out: 132 kexec_free_elf_info(&elf_info); 133 return ret ? ERR_PTR(ret) : NULL; 134 } 135 136 const struct kexec_file_ops elf_kexec_ops = { 137 .probe = kexec_elf_probe, 138 .load = elf_kexec_load, 139 }; 140