// SPDX-License-Identifier: GPL-2.0-only /* * Coredump functionality for Remoteproc framework. * * Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
/** * rproc_coredump_add_segment() - add segment of device memory to coredump * @rproc: handle of a remote processor * @da: device address * @size: size of segment * * Add device memory to the list of segments to be included in a coredump for * the remoteproc. * * Return: 0 on success, negative errno on error.
*/ int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size)
{ struct rproc_dump_segment *segment;
segment = kzalloc(sizeof(*segment), GFP_KERNEL); if (!segment) return -ENOMEM;
/** * rproc_coredump_add_custom_segment() - add custom coredump segment * @rproc: handle of a remote processor * @da: device address * @size: size of segment * @dumpfn: custom dump function called for each segment during coredump * @priv: private data * * Add device memory to the list of segments to be included in the coredump * and associate the segment with the given custom dump function and private * data. * * Return: 0 on success, negative errno on error.
*/ int rproc_coredump_add_custom_segment(struct rproc *rproc,
dma_addr_t da, size_t size, void (*dumpfn)(struct rproc *rproc, struct rproc_dump_segment *segment, void *dest, size_t offset,
size_t size), void *priv)
{ struct rproc_dump_segment *segment;
segment = kzalloc(sizeof(*segment), GFP_KERNEL); if (!segment) return -ENOMEM;
/** * rproc_coredump_set_elf_info() - set coredump elf information * @rproc: handle of a remote processor * @class: elf class for coredump elf file * @machine: elf machine for coredump elf file * * Set elf information which will be used for coredump elf file. * * Return: 0 on success, negative errno on error.
*/ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine)
{ if (class != ELFCLASS64 && class != ELFCLASS32) return -EINVAL;
/* Copy the vmalloc'ed header first. */ if (offset < header_sz) {
copy_sz = memory_read_from_buffer(buffer, count, &offset,
elfcore, header_sz);
return copy_sz;
}
/* * Find out the segment memory chunk to be copied based on offset. * Keep copying data until count bytes are read.
*/ while (bytes_left) {
seg = rproc_coredump_find_segment(offset - header_sz,
&rproc->dump_segments,
&seg_data); /* EOF check */ if (!seg) {
dev_info(&rproc->dev, "Ramdump done, %lld bytes read",
offset); break;
}
/** * rproc_coredump() - perform coredump * @rproc: rproc handle * * This function will generate an ELF header for the registered segments * and create a devcoredump device associated with rproc. Based on the * coredump configuration this function will directly copy the segments * from device memory to userspace or copy segments from device memory to * a separate buffer, which can then be read by userspace. * The first approach avoids using extra vmalloc memory. But it will stall * recovery flow until dump is read by userspace.
*/ void rproc_coredump(struct rproc *rproc)
{ struct rproc_dump_segment *segment; void *phdr; void *ehdr;
size_t data_size;
size_t offset; void *data;
u8 class = rproc->elf_class; int phnum = 0; struct rproc_coredump_state dump_state; enum rproc_dump_mechanism dump_conf = rproc->dump_conf;
if (list_empty(&rproc->dump_segments) ||
dump_conf == RPROC_COREDUMP_DISABLED) return;
if (class == ELFCLASSNONE) {
dev_err(&rproc->dev, "ELF class is not set\n"); return;
}
data_size = elf_size_of_hdr(class);
list_for_each_entry(segment, &rproc->dump_segments, node) { /* * For default configuration buffer includes headers & segments. * For inline dump buffer just includes headers as segments are * directly read from device memory.
*/
data_size += elf_size_of_phdr(class); if (dump_conf == RPROC_COREDUMP_ENABLED)
data_size += segment->size;
phnum++;
}
data = vmalloc(data_size); if (!data) return;
ehdr = data;
memset(ehdr, 0, elf_size_of_hdr(class)); /* e_ident field is common for both elf32 and elf64 */
elf_hdr_init_ident(ehdr, class);
/* Initialize the dump state struct to be used by rproc_coredump_read */
dump_state.rproc = rproc;
dump_state.header = data;
init_completion(&dump_state.dump_done);
/* * Wait until the dump is read and free is called. Data is freed * by devcoredump framework automatically after 5 minutes.
*/
wait_for_completion(&dump_state.dump_done);
}
EXPORT_SYMBOL_GPL(rproc_coredump);
/** * rproc_coredump_using_sections() - perform coredump using section headers * @rproc: rproc handle * * This function will generate an ELF header for the registered sections of * segments and create a devcoredump device associated with rproc. Based on * the coredump configuration this function will directly copy the segments * from device memory to userspace or copy segments from device memory to * a separate buffer, which can then be read by userspace. * The first approach avoids using extra vmalloc memory. But it will stall * recovery flow until dump is read by userspace.
*/ void rproc_coredump_using_sections(struct rproc *rproc)
{ struct rproc_dump_segment *segment; void *shdr; void *ehdr;
size_t data_size;
size_t strtbl_size = 0;
size_t strtbl_index = 1;
size_t offset; void *data;
u8 class = rproc->elf_class; int shnum; struct rproc_coredump_state dump_state; unsignedint dump_conf = rproc->dump_conf; char *str_tbl = "STR_TBL";
if (list_empty(&rproc->dump_segments) ||
dump_conf == RPROC_COREDUMP_DISABLED) return;
if (class == ELFCLASSNONE) {
dev_err(&rproc->dev, "ELF class is not set\n"); return;
}
/* * We allocate two extra section headers. The first one is null. * Second section header is for the string table. Also space is * allocated for string table.
*/
data_size = elf_size_of_hdr(class) + 2 * elf_size_of_shdr(class);
shnum = 2;
/* the extra byte is for the null character at index 0 */
strtbl_size += strlen(str_tbl) + 2;
/* * The zeroth index of the section header is reserved and is rarely used. * Set the section header as null (SHN_UNDEF) and move to the next one.
*/
shdr = data + elf_hdr_get_e_shoff(class, ehdr);
memset(shdr, 0, elf_size_of_shdr(class));
shdr += elf_size_of_shdr(class);
/* No need to copy segments for inline dumps */ if (dump_conf == RPROC_COREDUMP_ENABLED)
rproc_copy_segment(rproc, data + offset, segment, 0,
segment->size);
offset += elf_shdr_get_sh_size(class, shdr);
shdr += elf_size_of_shdr(class);
}
/* Initialize the dump state struct to be used by rproc_coredump_read */
dump_state.rproc = rproc;
dump_state.header = data;
init_completion(&dump_state.dump_done);
/* Wait until the dump is read and free is called. Data is freed * by devcoredump framework automatically after 5 minutes.
*/
wait_for_completion(&dump_state.dump_done);
}
EXPORT_SYMBOL(rproc_coredump_using_sections);
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.