1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * kexec_file for riscv, use vmlinux as the dump-capture kernel image. 4 * 5 * Copyright (C) 2021 Huawei Technologies Co, Ltd. 6 * 7 * Author: Liao Chang (liaochang1@huawei.com) 8 */ 9 #include <linux/kexec.h> 10 #include <linux/elf.h> 11 #include <linux/slab.h> 12 #include <linux/of.h> 13 #include <linux/libfdt.h> 14 #include <linux/types.h> 15 #include <linux/memblock.h> 16 #include <linux/pfn.h> 17 #include <linux/vmalloc.h> 18 #include <asm/setup.h> 19 #include <asm/insn.h> 20 21 const struct kexec_file_ops * const kexec_file_loaders[] = { 22 &elf_kexec_ops, 23 &image_kexec_ops, 24 NULL 25 }; 26 27 int arch_kimage_file_post_load_cleanup(struct kimage *image) 28 { 29 kvfree(image->arch.fdt); 30 image->arch.fdt = NULL; 31 32 vfree(image->elf_headers); 33 image->elf_headers = NULL; 34 image->elf_headers_sz = 0; 35 36 return kexec_image_post_load_cleanup_default(image); 37 } 38 39 #ifdef CONFIG_CRASH_DUMP 40 static int get_nr_ram_ranges_callback(struct resource *res, void *arg) 41 { 42 unsigned int *nr_ranges = arg; 43 44 (*nr_ranges)++; 45 return 0; 46 } 47 48 unsigned int arch_get_system_nr_ranges(void) 49 { 50 unsigned int nr_ranges = 2 + crashk_cma_cnt; /* For exclusion of crashkernel region */ 51 52 walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); 53 54 return nr_ranges; 55 } 56 57 static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) 58 { 59 struct crash_mem *cmem = arg; 60 61 cmem->ranges[cmem->nr_ranges].start = res->start; 62 cmem->ranges[cmem->nr_ranges].end = res->end; 63 cmem->nr_ranges++; 64 65 return 0; 66 } 67 68 int arch_crash_populate_cmem(struct crash_mem *cmem) 69 { 70 return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback); 71 } 72 73 static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, 74 unsigned long cmdline_len) 75 { 76 int elfcorehdr_strlen; 77 char *cmdline_ptr; 78 79 cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); 80 if (!cmdline_ptr) 81 return NULL; 82 83 elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ", 84 image->elf_load_addr); 85 86 if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { 87 pr_err("Appending elfcorehdr=<addr> exceeds cmdline size\n"); 88 kfree(cmdline_ptr); 89 return NULL; 90 } 91 92 memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); 93 /* Ensure it's nul terminated */ 94 cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0'; 95 return cmdline_ptr; 96 } 97 #endif 98 99 #define RISCV_IMM_BITS 12 100 #define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS) 101 #define RISCV_CONST_HIGH_PART(x) \ 102 (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1)) 103 #define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x)) 104 105 #define ENCODE_ITYPE_IMM(x) \ 106 (RV_X(x, 0, 12) << 20) 107 #define ENCODE_BTYPE_IMM(x) \ 108 ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \ 109 (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) 110 #define ENCODE_UTYPE_IMM(x) \ 111 (RV_X(x, 12, 20) << 12) 112 #define ENCODE_JTYPE_IMM(x) \ 113 ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \ 114 (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) 115 #define ENCODE_CBTYPE_IMM(x) \ 116 ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \ 117 (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) 118 #define ENCODE_CJTYPE_IMM(x) \ 119 ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \ 120 (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \ 121 (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) 122 #define ENCODE_UJTYPE_IMM(x) \ 123 (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \ 124 (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32)) 125 #define ENCODE_UITYPE_IMM(x) \ 126 (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32)) 127 128 #define CLEAN_IMM(type, x) \ 129 ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x)) 130 131 int arch_kexec_apply_relocations_add(struct purgatory_info *pi, 132 Elf_Shdr *section, 133 const Elf_Shdr *relsec, 134 const Elf_Shdr *symtab) 135 { 136 const char *strtab, *name, *shstrtab; 137 const Elf_Shdr *sechdrs; 138 Elf64_Rela *relas; 139 int i, r_type; 140 141 /* String & section header string table */ 142 sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; 143 strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset; 144 shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; 145 146 relas = (void *)pi->ehdr + relsec->sh_offset; 147 148 for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) { 149 const Elf_Sym *sym; /* symbol to relocate */ 150 unsigned long addr; /* final location after relocation */ 151 unsigned long val; /* relocated symbol value */ 152 unsigned long sec_base; /* relocated symbol value */ 153 void *loc; /* tmp location to modify */ 154 155 sym = (void *)pi->ehdr + symtab->sh_offset; 156 sym += ELF64_R_SYM(relas[i].r_info); 157 158 if (sym->st_name) 159 name = strtab + sym->st_name; 160 else 161 name = shstrtab + sechdrs[sym->st_shndx].sh_name; 162 163 loc = pi->purgatory_buf; 164 loc += section->sh_offset; 165 loc += relas[i].r_offset; 166 167 if (sym->st_shndx == SHN_ABS) 168 sec_base = 0; 169 else if (sym->st_shndx >= pi->ehdr->e_shnum) { 170 pr_err("Invalid section %d for symbol %s\n", 171 sym->st_shndx, name); 172 return -ENOEXEC; 173 } else 174 sec_base = pi->sechdrs[sym->st_shndx].sh_addr; 175 176 val = sym->st_value; 177 val += sec_base; 178 val += relas[i].r_addend; 179 180 addr = section->sh_addr + relas[i].r_offset; 181 182 r_type = ELF64_R_TYPE(relas[i].r_info); 183 184 switch (r_type) { 185 case R_RISCV_BRANCH: 186 *(u32 *)loc = CLEAN_IMM(BTYPE, *(u32 *)loc) | 187 ENCODE_BTYPE_IMM(val - addr); 188 break; 189 case R_RISCV_JAL: 190 *(u32 *)loc = CLEAN_IMM(JTYPE, *(u32 *)loc) | 191 ENCODE_JTYPE_IMM(val - addr); 192 break; 193 /* 194 * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I 195 * sym is expected to be next to R_RISCV_PCREL_HI20 196 * in purgatory relsec. Handle it like R_RISCV_CALL 197 * sym, instead of searching the whole relsec. 198 */ 199 case R_RISCV_PCREL_HI20: 200 case R_RISCV_CALL_PLT: 201 case R_RISCV_CALL: 202 *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) | 203 ENCODE_UJTYPE_IMM(val - addr); 204 break; 205 case R_RISCV_RVC_BRANCH: 206 *(u32 *)loc = CLEAN_IMM(CBTYPE, *(u32 *)loc) | 207 ENCODE_CBTYPE_IMM(val - addr); 208 break; 209 case R_RISCV_RVC_JUMP: 210 *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) | 211 ENCODE_CJTYPE_IMM(val - addr); 212 break; 213 case R_RISCV_ADD16: 214 *(u16 *)loc += val; 215 break; 216 case R_RISCV_SUB16: 217 *(u16 *)loc -= val; 218 break; 219 case R_RISCV_ADD32: 220 *(u32 *)loc += val; 221 break; 222 case R_RISCV_SUB32: 223 *(u32 *)loc -= val; 224 break; 225 /* It has been applied by R_RISCV_PCREL_HI20 sym */ 226 case R_RISCV_PCREL_LO12_I: 227 case R_RISCV_ALIGN: 228 case R_RISCV_RELAX: 229 break; 230 case R_RISCV_64: 231 *(u64 *)loc = val; 232 break; 233 default: 234 pr_err("Unknown rela relocation: %d\n", r_type); 235 return -ENOEXEC; 236 } 237 } 238 return 0; 239 } 240 241 242 int load_extra_segments(struct kimage *image, unsigned long kernel_start, 243 unsigned long kernel_len, char *initrd, 244 unsigned long initrd_len, char *cmdline, 245 unsigned long cmdline_len) 246 { 247 int ret; 248 void *fdt; 249 unsigned long initrd_pbase = 0UL; 250 struct kexec_buf kbuf = {}; 251 char *modified_cmdline = NULL; 252 253 kbuf.image = image; 254 kbuf.buf_min = kernel_start + kernel_len; 255 kbuf.buf_max = PFN_PHYS(max_low_pfn); 256 257 #ifdef CONFIG_CRASH_DUMP 258 /* Add elfcorehdr */ 259 if (image->type == KEXEC_TYPE_CRASH) { 260 void *headers; 261 unsigned long headers_sz; 262 ret = crash_prepare_headers(true, &headers, &headers_sz, NULL); 263 if (ret) { 264 pr_err("Preparing elf core header failed\n"); 265 goto out; 266 } 267 268 kbuf.buffer = headers; 269 kbuf.bufsz = headers_sz; 270 kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 271 kbuf.memsz = headers_sz; 272 kbuf.buf_align = ELF_CORE_HEADER_ALIGN; 273 kbuf.top_down = true; 274 275 ret = kexec_add_buffer(&kbuf); 276 if (ret) { 277 vfree(headers); 278 goto out; 279 } 280 image->elf_headers = headers; 281 image->elf_load_addr = kbuf.mem; 282 image->elf_headers_sz = headers_sz; 283 284 kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", 285 image->elf_load_addr, kbuf.bufsz, kbuf.memsz); 286 287 /* Setup cmdline for kdump kernel case */ 288 modified_cmdline = setup_kdump_cmdline(image, cmdline, 289 cmdline_len); 290 if (!modified_cmdline) { 291 pr_err("Setting up cmdline for kdump kernel failed\n"); 292 ret = -EINVAL; 293 goto out; 294 } 295 cmdline = modified_cmdline; 296 } 297 #endif 298 299 #ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY 300 /* Add purgatory to the image */ 301 kbuf.top_down = true; 302 kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 303 ret = kexec_load_purgatory(image, &kbuf); 304 if (ret) { 305 pr_err("Error loading purgatory ret=%d\n", ret); 306 goto out; 307 } 308 kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf.mem); 309 310 ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", 311 &kernel_start, 312 sizeof(kernel_start), 0); 313 if (ret) 314 pr_err("Error update purgatory ret=%d\n", ret); 315 #endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */ 316 317 /* Add the initrd to the image */ 318 if (initrd != NULL) { 319 kbuf.buffer = initrd; 320 kbuf.bufsz = kbuf.memsz = initrd_len; 321 kbuf.buf_align = PAGE_SIZE; 322 kbuf.top_down = true; 323 kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 324 ret = kexec_add_buffer(&kbuf); 325 if (ret) 326 goto out; 327 initrd_pbase = kbuf.mem; 328 kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase); 329 } 330 331 /* Add the DTB to the image */ 332 fdt = of_kexec_alloc_and_setup_fdt(image, initrd_pbase, 333 initrd_len, cmdline, 0); 334 if (!fdt) { 335 pr_err("Error setting up the new device tree.\n"); 336 ret = -EINVAL; 337 goto out; 338 } 339 340 fdt_pack(fdt); 341 kbuf.buffer = fdt; 342 kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt); 343 kbuf.buf_align = PAGE_SIZE; 344 kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 345 kbuf.top_down = true; 346 ret = kexec_add_buffer(&kbuf); 347 if (ret) { 348 pr_err("Error add DTB kbuf ret=%d\n", ret); 349 goto out_free_fdt; 350 } 351 /* Cache the fdt buffer address for memory cleanup */ 352 image->arch.fdt = fdt; 353 kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf.mem); 354 goto out; 355 356 out_free_fdt: 357 kvfree(fdt); 358 out: 359 kfree(modified_cmdline); 360 return ret; 361 } 362