1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Coredump functionality for Remoteproc framework. 4 * 5 * Copyright (c) 2020, The Linux Foundation. All rights reserved. 6 */ 7 8 #include <linux/completion.h> 9 #include <linux/devcoredump.h> 10 #include <linux/device.h> 11 #include <linux/kernel.h> 12 #include <linux/remoteproc.h> 13 #include "remoteproc_internal.h" 14 #include "remoteproc_elf_helpers.h" 15 16 struct rproc_coredump_state { 17 struct rproc *rproc; 18 void *header; 19 struct completion dump_done; 20 }; 21 22 /** 23 * rproc_coredump_cleanup() - clean up dump_segments list 24 * @rproc: the remote processor handle 25 */ 26 void rproc_coredump_cleanup(struct rproc *rproc) 27 { 28 struct rproc_dump_segment *entry, *tmp; 29 30 list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) { 31 list_del(&entry->node); 32 kfree(entry); 33 } 34 } 35 EXPORT_SYMBOL_GPL(rproc_coredump_cleanup); 36 37 /** 38 * rproc_coredump_add_segment() - add segment of device memory to coredump 39 * @rproc: handle of a remote processor 40 * @da: device address 41 * @size: size of segment 42 * 43 * Add device memory to the list of segments to be included in a coredump for 44 * the remoteproc. 45 * 46 * Return: 0 on success, negative errno on error. 47 */ 48 int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) 49 { 50 struct rproc_dump_segment *segment; 51 52 segment = kzalloc(sizeof(*segment), GFP_KERNEL); 53 if (!segment) 54 return -ENOMEM; 55 56 segment->da = da; 57 segment->size = size; 58 59 list_add_tail(&segment->node, &rproc->dump_segments); 60 61 return 0; 62 } 63 EXPORT_SYMBOL(rproc_coredump_add_segment); 64 65 /** 66 * rproc_coredump_add_custom_segment() - add custom coredump segment 67 * @rproc: handle of a remote processor 68 * @da: device address 69 * @size: size of segment 70 * @dumpfn: custom dump function called for each segment during coredump 71 * @priv: private data 72 * 73 * Add device memory to the list of segments to be included in the coredump 74 * and associate the segment with the given custom dump function and private 75 * data. 76 * 77 * Return: 0 on success, negative errno on error. 78 */ 79 int rproc_coredump_add_custom_segment(struct rproc *rproc, 80 dma_addr_t da, size_t size, 81 void (*dumpfn)(struct rproc *rproc, 82 struct rproc_dump_segment *segment, 83 void *dest, size_t offset, 84 size_t size), 85 void *priv) 86 { 87 struct rproc_dump_segment *segment; 88 89 segment = kzalloc(sizeof(*segment), GFP_KERNEL); 90 if (!segment) 91 return -ENOMEM; 92 93 segment->da = da; 94 segment->size = size; 95 segment->priv = priv; 96 segment->dump = dumpfn; 97 98 list_add_tail(&segment->node, &rproc->dump_segments); 99 100 return 0; 101 } 102 EXPORT_SYMBOL(rproc_coredump_add_custom_segment); 103 104 /** 105 * rproc_coredump_set_elf_info() - set coredump elf information 106 * @rproc: handle of a remote processor 107 * @class: elf class for coredump elf file 108 * @machine: elf machine for coredump elf file 109 * 110 * Set elf information which will be used for coredump elf file. 111 * 112 * Return: 0 on success, negative errno on error. 113 */ 114 int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) 115 { 116 if (class != ELFCLASS64 && class != ELFCLASS32) 117 return -EINVAL; 118 119 rproc->elf_class = class; 120 rproc->elf_machine = machine; 121 122 return 0; 123 } 124 EXPORT_SYMBOL(rproc_coredump_set_elf_info); 125 126 static void rproc_coredump_free(void *data) 127 { 128 struct rproc_coredump_state *dump_state = data; 129 130 vfree(dump_state->header); 131 complete(&dump_state->dump_done); 132 } 133 134 static void *rproc_coredump_find_segment(loff_t user_offset, 135 struct list_head *segments, 136 size_t *data_left) 137 { 138 struct rproc_dump_segment *segment; 139 140 list_for_each_entry(segment, segments, node) { 141 if (user_offset < segment->size) { 142 *data_left = segment->size - user_offset; 143 return segment; 144 } 145 user_offset -= segment->size; 146 } 147 148 *data_left = 0; 149 return NULL; 150 } 151 152 static void rproc_copy_segment(struct rproc *rproc, void *dest, 153 struct rproc_dump_segment *segment, 154 size_t offset, size_t size) 155 { 156 bool is_iomem = false; 157 void *ptr; 158 159 if (segment->dump) { 160 segment->dump(rproc, segment, dest, offset, size); 161 } else { 162 ptr = rproc_da_to_va(rproc, segment->da + offset, size, &is_iomem); 163 if (!ptr) { 164 dev_err(&rproc->dev, 165 "invalid copy request for segment %pad with offset %zu and size %zu)\n", 166 &segment->da, offset, size); 167 memset(dest, 0xff, size); 168 } else { 169 if (is_iomem) 170 memcpy_fromio(dest, (void const __iomem *)ptr, size); 171 else 172 memcpy(dest, ptr, size); 173 } 174 } 175 } 176 177 static ssize_t rproc_coredump_read(char *buffer, loff_t offset, size_t count, 178 void *data, size_t header_sz) 179 { 180 size_t seg_data, bytes_left = count; 181 ssize_t copy_sz; 182 struct rproc_dump_segment *seg; 183 struct rproc_coredump_state *dump_state = data; 184 struct rproc *rproc = dump_state->rproc; 185 void *elfcore = dump_state->header; 186 187 /* Copy the vmalloc'ed header first. */ 188 if (offset < header_sz) { 189 copy_sz = memory_read_from_buffer(buffer, count, &offset, 190 elfcore, header_sz); 191 192 return copy_sz; 193 } 194 195 /* 196 * Find out the segment memory chunk to be copied based on offset. 197 * Keep copying data until count bytes are read. 198 */ 199 while (bytes_left) { 200 seg = rproc_coredump_find_segment(offset - header_sz, 201 &rproc->dump_segments, 202 &seg_data); 203 /* EOF check */ 204 if (!seg) { 205 dev_info(&rproc->dev, "Ramdump done, %lld bytes read", 206 offset); 207 break; 208 } 209 210 copy_sz = min_t(size_t, bytes_left, seg_data); 211 212 rproc_copy_segment(rproc, buffer, seg, seg->size - seg_data, 213 copy_sz); 214 215 offset += copy_sz; 216 buffer += copy_sz; 217 bytes_left -= copy_sz; 218 } 219 220 return count - bytes_left; 221 } 222 223 /** 224 * rproc_coredump() - perform coredump 225 * @rproc: rproc handle 226 * 227 * This function will generate an ELF header for the registered segments 228 * and create a devcoredump device associated with rproc. Based on the 229 * coredump configuration this function will directly copy the segments 230 * from device memory to userspace or copy segments from device memory to 231 * a separate buffer, which can then be read by userspace. 232 * The first approach avoids using extra vmalloc memory. But it will stall 233 * recovery flow until dump is read by userspace. 234 */ 235 void rproc_coredump(struct rproc *rproc) 236 { 237 struct rproc_dump_segment *segment; 238 void *phdr; 239 void *ehdr; 240 size_t data_size; 241 size_t offset; 242 void *data; 243 u8 class = rproc->elf_class; 244 int phnum = 0; 245 struct rproc_coredump_state dump_state; 246 enum rproc_dump_mechanism dump_conf = rproc->dump_conf; 247 248 if (list_empty(&rproc->dump_segments) || 249 dump_conf == RPROC_COREDUMP_DISABLED) 250 return; 251 252 if (class == ELFCLASSNONE) { 253 dev_err(&rproc->dev, "ELF class is not set\n"); 254 return; 255 } 256 257 data_size = elf_size_of_hdr(class); 258 list_for_each_entry(segment, &rproc->dump_segments, node) { 259 /* 260 * For default configuration buffer includes headers & segments. 261 * For inline dump buffer just includes headers as segments are 262 * directly read from device memory. 263 */ 264 data_size += elf_size_of_phdr(class); 265 if (dump_conf == RPROC_COREDUMP_ENABLED) 266 data_size += segment->size; 267 268 phnum++; 269 } 270 271 data = vmalloc(data_size); 272 if (!data) 273 return; 274 275 ehdr = data; 276 277 memset(ehdr, 0, elf_size_of_hdr(class)); 278 /* e_ident field is common for both elf32 and elf64 */ 279 elf_hdr_init_ident(ehdr, class); 280 281 elf_hdr_set_e_type(class, ehdr, ET_CORE); 282 elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine); 283 elf_hdr_set_e_version(class, ehdr, EV_CURRENT); 284 elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr); 285 elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class)); 286 elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class)); 287 elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class)); 288 elf_hdr_set_e_phnum(class, ehdr, phnum); 289 290 phdr = data + elf_hdr_get_e_phoff(class, ehdr); 291 offset = elf_hdr_get_e_phoff(class, ehdr); 292 offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr); 293 294 list_for_each_entry(segment, &rproc->dump_segments, node) { 295 memset(phdr, 0, elf_size_of_phdr(class)); 296 elf_phdr_set_p_type(class, phdr, PT_LOAD); 297 elf_phdr_set_p_offset(class, phdr, offset); 298 elf_phdr_set_p_vaddr(class, phdr, segment->da); 299 elf_phdr_set_p_paddr(class, phdr, segment->da); 300 elf_phdr_set_p_filesz(class, phdr, segment->size); 301 elf_phdr_set_p_memsz(class, phdr, segment->size); 302 elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X); 303 elf_phdr_set_p_align(class, phdr, 0); 304 305 if (dump_conf == RPROC_COREDUMP_ENABLED) 306 rproc_copy_segment(rproc, data + offset, segment, 0, 307 segment->size); 308 309 offset += elf_phdr_get_p_filesz(class, phdr); 310 phdr += elf_size_of_phdr(class); 311 } 312 if (dump_conf == RPROC_COREDUMP_ENABLED) { 313 dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); 314 return; 315 } 316 317 /* Initialize the dump state struct to be used by rproc_coredump_read */ 318 dump_state.rproc = rproc; 319 dump_state.header = data; 320 init_completion(&dump_state.dump_done); 321 322 dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, 323 rproc_coredump_read, rproc_coredump_free); 324 325 /* 326 * Wait until the dump is read and free is called. Data is freed 327 * by devcoredump framework automatically after 5 minutes. 328 */ 329 wait_for_completion(&dump_state.dump_done); 330 } 331 EXPORT_SYMBOL_GPL(rproc_coredump); 332 333 /** 334 * rproc_coredump_using_sections() - perform coredump using section headers 335 * @rproc: rproc handle 336 * 337 * This function will generate an ELF header for the registered sections of 338 * segments and create a devcoredump device associated with rproc. Based on 339 * the coredump configuration this function will directly copy the segments 340 * from device memory to userspace or copy segments from device memory to 341 * a separate buffer, which can then be read by userspace. 342 * The first approach avoids using extra vmalloc memory. But it will stall 343 * recovery flow until dump is read by userspace. 344 */ 345 void rproc_coredump_using_sections(struct rproc *rproc) 346 { 347 struct rproc_dump_segment *segment; 348 void *shdr; 349 void *ehdr; 350 size_t data_size; 351 size_t strtbl_size = 0; 352 size_t strtbl_index = 1; 353 size_t offset; 354 void *data; 355 u8 class = rproc->elf_class; 356 int shnum; 357 struct rproc_coredump_state dump_state; 358 unsigned int dump_conf = rproc->dump_conf; 359 char *str_tbl = "STR_TBL"; 360 361 if (list_empty(&rproc->dump_segments) || 362 dump_conf == RPROC_COREDUMP_DISABLED) 363 return; 364 365 if (class == ELFCLASSNONE) { 366 dev_err(&rproc->dev, "ELF class is not set\n"); 367 return; 368 } 369 370 /* 371 * We allocate two extra section headers. The first one is null. 372 * Second section header is for the string table. Also space is 373 * allocated for string table. 374 */ 375 data_size = elf_size_of_hdr(class) + 2 * elf_size_of_shdr(class); 376 shnum = 2; 377 378 /* the extra byte is for the null character at index 0 */ 379 strtbl_size += strlen(str_tbl) + 2; 380 381 list_for_each_entry(segment, &rproc->dump_segments, node) { 382 data_size += elf_size_of_shdr(class); 383 strtbl_size += strlen(segment->priv) + 1; 384 if (dump_conf == RPROC_COREDUMP_ENABLED) 385 data_size += segment->size; 386 shnum++; 387 } 388 389 data_size += strtbl_size; 390 391 data = vmalloc(data_size); 392 if (!data) 393 return; 394 395 ehdr = data; 396 memset(ehdr, 0, elf_size_of_hdr(class)); 397 /* e_ident field is common for both elf32 and elf64 */ 398 elf_hdr_init_ident(ehdr, class); 399 400 elf_hdr_set_e_type(class, ehdr, ET_CORE); 401 elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine); 402 elf_hdr_set_e_version(class, ehdr, EV_CURRENT); 403 elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr); 404 elf_hdr_set_e_shoff(class, ehdr, elf_size_of_hdr(class)); 405 elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class)); 406 elf_hdr_set_e_shentsize(class, ehdr, elf_size_of_shdr(class)); 407 elf_hdr_set_e_shnum(class, ehdr, shnum); 408 elf_hdr_set_e_shstrndx(class, ehdr, 1); 409 410 /* 411 * The zeroth index of the section header is reserved and is rarely used. 412 * Set the section header as null (SHN_UNDEF) and move to the next one. 413 */ 414 shdr = data + elf_hdr_get_e_shoff(class, ehdr); 415 memset(shdr, 0, elf_size_of_shdr(class)); 416 shdr += elf_size_of_shdr(class); 417 418 /* Initialize the string table. */ 419 offset = elf_hdr_get_e_shoff(class, ehdr) + 420 elf_size_of_shdr(class) * elf_hdr_get_e_shnum(class, ehdr); 421 memset(data + offset, 0, strtbl_size); 422 423 /* Fill in the string table section header. */ 424 memset(shdr, 0, elf_size_of_shdr(class)); 425 elf_shdr_set_sh_type(class, shdr, SHT_STRTAB); 426 elf_shdr_set_sh_offset(class, shdr, offset); 427 elf_shdr_set_sh_size(class, shdr, strtbl_size); 428 elf_shdr_set_sh_entsize(class, shdr, 0); 429 elf_shdr_set_sh_flags(class, shdr, 0); 430 elf_shdr_set_sh_name(class, shdr, elf_strtbl_add(str_tbl, ehdr, class, &strtbl_index)); 431 offset += elf_shdr_get_sh_size(class, shdr); 432 shdr += elf_size_of_shdr(class); 433 434 list_for_each_entry(segment, &rproc->dump_segments, node) { 435 memset(shdr, 0, elf_size_of_shdr(class)); 436 elf_shdr_set_sh_type(class, shdr, SHT_PROGBITS); 437 elf_shdr_set_sh_offset(class, shdr, offset); 438 elf_shdr_set_sh_addr(class, shdr, segment->da); 439 elf_shdr_set_sh_size(class, shdr, segment->size); 440 elf_shdr_set_sh_entsize(class, shdr, 0); 441 elf_shdr_set_sh_flags(class, shdr, SHF_WRITE); 442 elf_shdr_set_sh_name(class, shdr, 443 elf_strtbl_add(segment->priv, ehdr, class, &strtbl_index)); 444 445 /* No need to copy segments for inline dumps */ 446 if (dump_conf == RPROC_COREDUMP_ENABLED) 447 rproc_copy_segment(rproc, data + offset, segment, 0, 448 segment->size); 449 offset += elf_shdr_get_sh_size(class, shdr); 450 shdr += elf_size_of_shdr(class); 451 } 452 453 if (dump_conf == RPROC_COREDUMP_ENABLED) { 454 dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); 455 return; 456 } 457 458 /* Initialize the dump state struct to be used by rproc_coredump_read */ 459 dump_state.rproc = rproc; 460 dump_state.header = data; 461 init_completion(&dump_state.dump_done); 462 463 dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, 464 rproc_coredump_read, rproc_coredump_free); 465 466 /* Wait until the dump is read and free is called. Data is freed 467 * by devcoredump framework automatically after 5 minutes. 468 */ 469 wait_for_completion(&dump_state.dump_done); 470 } 471 EXPORT_SYMBOL(rproc_coredump_using_sections); 472