diff --git a/include/zephyr/debug/coredump.h b/include/zephyr/debug/coredump.h index 9b298d64e99..ce36d072215 100644 --- a/include/zephyr/debug/coredump.h +++ b/include/zephyr/debug/coredump.h @@ -7,6 +7,9 @@ #ifndef ZEPHYR_INCLUDE_DEBUG_COREDUMP_H_ #define ZEPHYR_INCLUDE_DEBUG_COREDUMP_H_ +#include +#include + /* Query ID */ enum coredump_query_id { /* @@ -24,6 +27,14 @@ enum coredump_query_id { */ COREDUMP_QUERY_HAS_STORED_DUMP, + /* + * Returns coredump raw size from backend. + * 0 if none. + * -ENOTSUP if this query is not supported. + * Otherwise, error code from backend. + */ + COREDUMP_QUERY_GET_STORED_DUMP_SIZE, + COREDUMP_QUERY_MAX }; @@ -55,9 +66,41 @@ enum coredump_cmd_id { */ COREDUMP_CMD_ERASE_STORED_DUMP, + /* + * Copy the raw stored coredump. + * + * Returns copied size if successful + * 0 if stored coredump is not found + * -ENOTSUP if this command is not supported. + * Otherwise, error code from backend. + */ + COREDUMP_CMD_COPY_STORED_DUMP, + + /* + * Invalidate the stored coredump. This is faster than + * erasing the whole partition. + * + * Returns 0 if successful. + * -ENOTSUP if this command is not supported. + * Otherwise, error code from backend. + */ + COREDUMP_CMD_INVALIDATE_STORED_DUMP, + COREDUMP_CMD_MAX }; +/* Coredump copy command argument definition */ +struct coredump_cmd_copy_arg { + /* Copy offset */ + off_t offset; + + /* Copy destination buffer */ + uint8_t *buffer; + + /* Copy length */ + size_t length; +}; + #ifdef CONFIG_DEBUG_COREDUMP #include diff --git a/subsys/debug/coredump/coredump_backend_flash_partition.c b/subsys/debug/coredump/coredump_backend_flash_partition.c index 76e9f99673f..0e91e076586 100644 --- a/subsys/debug/coredump/coredump_backend_flash_partition.c +++ b/subsys/debug/coredump/coredump_backend_flash_partition.c @@ -42,6 +42,7 @@ LOG_MODULE_REGISTER(coredump, CONFIG_KERNEL_LOG_LEVEL); #define FLASH_WRITE_SIZE DT_PROP(FLASH_CONTROLLER, write_block_size) #define FLASH_BUF_SIZE FLASH_WRITE_SIZE +#define FLASH_ERASE_SIZE DT_PROP(FLASH_CONTROLLER, erase_block_size) #define FLASH_PARTITION FLASH_AREA_ID(coredump_partition) @@ -273,7 +274,100 @@ out: } /** - * @brief Erase the stored coredump from flash partition. + * @brief Get the stored coredump in flash partition. + * + * This reads the stored coredump data and copies the raw data + * to the destination buffer. + * + * If the destination buffer is NULL, the offset and length are + * ignored and the entire dump size is returned. + * + * @param off offset of partition to begin reading + * @param dst buffer to read data into (can be NULL) + * @param len number of bytes to read + * @return dump size if successful; 0 if stored coredump is not found + * or is not valid; error otherwise + */ +static int get_stored_dump(off_t off, uint8_t *dst, size_t len) +{ + int ret; + struct flash_hdr_t hdr; + + ret = partition_open(); + if (ret != 0) { + goto out; + } + + /* Read header */ + ret = data_read(0, (uint8_t *)&hdr, sizeof(hdr), NULL, NULL); + if (ret != 0) { + goto out; + } + + /* Verify header signature */ + if ((hdr.id[0] != 'C') && (hdr.id[1] != 'D')) { + ret = 0; + goto out; + } + + /* Error encountered while dumping, so non-existent */ + if (hdr.error != 0) { + ret = 0; + goto out; + } + + /* Return the dump size if no destination buffer available */ + if (!dst) { + ret = (int)hdr.size; + goto out; + } + + /* Offset larger than dump size */ + if (off >= hdr.size) { + ret = 0; + goto out; + } + + /* Start reading the data, skip write-aligned header */ + off += ROUND_UP(sizeof(struct flash_hdr_t), FLASH_WRITE_SIZE); + + ret = data_read(off, dst, len, NULL, NULL); + if (ret == 0) { + ret = (int)len; + } +out: + partition_close(); + + return ret; +} + +/** + * @brief Erase the stored coredump header from flash partition. + * + * This erases the stored coredump header from the flash partition, + * invalidating the coredump data. + * + * @return 0 if successful; error otherwise + */ +static int erase_coredump_header(void) +{ + int ret; + + ret = partition_open(); + if (ret == 0) { + /* Erase header block */ + ret = flash_area_erase(backend_ctx.flash_area, 0, + ROUND_UP(sizeof(struct flash_hdr_t), + FLASH_ERASE_SIZE)); + } + + partition_close(); + + return ret; +} + +/** + * @brief Erase the stored coredump in flash partition. * * This erases the stored coredump data from the flash partition. * @@ -458,6 +552,9 @@ static int coredump_flash_backend_query(enum coredump_query_id query_id, case COREDUMP_QUERY_HAS_STORED_DUMP: ret = process_stored_dump(cb_calc_buf_checksum, NULL); break; + case COREDUMP_QUERY_GET_STORED_DUMP_SIZE: + ret = get_stored_dump(0, NULL, 0); + break; default: ret = -ENOTSUP; break; @@ -489,6 +586,21 @@ static int coredump_flash_backend_cmd(enum coredump_cmd_id cmd_id, case COREDUMP_CMD_ERASE_STORED_DUMP: ret = erase_flash_partition(); break; + case COREDUMP_CMD_COPY_STORED_DUMP: + if (arg) { + struct coredump_cmd_copy_arg *copy_arg + = (struct coredump_cmd_copy_arg *)arg; + + ret = get_stored_dump(copy_arg->offset, + copy_arg->buffer, + copy_arg->length); + } else { + ret = -EINVAL; + } + break; + case COREDUMP_CMD_INVALIDATE_STORED_DUMP: + ret = erase_coredump_header(); + break; default: ret = -ENOTSUP; break;