remoteproc_coredump.c 14 KB

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