[PATCH v2 09/20] fip: add fip_image_open()
Sascha Hauer
s.hauer at pengutronix.de
Wed Feb 12 06:09:22 PST 2025
This adds a fip_image_open() function as an alternative to fip_parse().
Unline fip_parse() the new function:
- Allows to specify an offset with the file for reading a FIP image from
partitions
- Does not read past the image when the FIP image is on a partition
which is bigger than the FIP image
- less memory consumption
fip_image_open() is mainly useful for reading a FIP image without the
intent of modifying it.
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
include/fiptool.h | 4 ++
lib/fip.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/include/fiptool.h b/include/fiptool.h
index 6a12466c29..bc42f7edd6 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -30,12 +30,14 @@ struct fip_image_desc {
struct fip_image {
struct fip_toc_entry toc_e;
void *buffer;
+ bool buf_no_free;
};
struct fip_state {
struct list_head descs;
size_t nr_image_descs;
int verbose;
+ void *buffer;
};
#define pr_verbose(...) do { \
@@ -92,4 +94,6 @@ extern toc_entry_t plat_def_toc_entries[];
#define fip_for_each_desc_safe(fip, e, tmp) \
list_for_each_entry_safe(e, tmp, &(fip)->descs, list)
+struct fip_state *fip_image_open(const char *filename, size_t offset);
+
#endif /* FIPTOOL_H */
diff --git a/lib/fip.c b/lib/fip.c
index 075cd0e1e6..39b0fd20aa 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -58,7 +58,8 @@ void fip_free_image_desc(struct fip_image_desc *desc)
free(desc->cmdline_name);
free(desc->action_arg);
if (desc->image) {
- free(desc->image->buffer);
+ if (!desc->image->buf_no_free)
+ free(desc->image->buffer);
free(desc->image);
}
free(desc);
@@ -92,6 +93,7 @@ void fip_free(struct fip_state *fip)
ASSERT(fip->nr_image_descs == 0);
+ free(fip->buffer);
free(fip);
}
@@ -430,3 +432,131 @@ int fip_update(struct fip_state *fip)
return 0;
}
+
+/*
+ * fip_image_open - open a FIP image for readonly access
+ * @filename: The filename of the FIP image
+ * @offset: The offset of the FIP image in the file
+ *
+ * This opens a FIP image for readonly access. This is an alternative
+ * implementation for fip_parse() with these differences:
+ * - suitable for reading FIP images from raw partitions. This function
+ * only reads the FIP image, even when the partition is bigger than the
+ * image
+ * - Allows to specify an offset within the partition where the FIP image
+ * starts
+ * - Do not memdup the images from the full FIP image
+ *
+ * This function is for easy readonly access to the images within the FIP
+ * image. Do not call any of the above FIP manipulation functions other than
+ * fip_free() on an image opened with this function.
+ */
+struct fip_state *fip_image_open(const char *filename, size_t offset)
+{
+ fip_toc_header_t toc_header;
+ int ret;
+ int fd;
+ struct fip_state *fip_state;
+ LIST_HEAD(entries);
+ size_t fip_headers_size, total = 0;
+ struct fip_image_desc *desc;
+ off_t pos;
+ int n_entries = 0;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return ERR_PTR(fd);
+
+ fip_state = fip_new();
+
+ pos = lseek(fd, offset, SEEK_SET);
+ if (pos != offset) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = read_full(fd, &toc_header, sizeof(toc_header));
+ if (ret < 0)
+ goto err;
+
+ if (ret < sizeof(toc_header)) {
+ ret = -ENODATA;
+ goto err;
+ }
+
+ if (toc_header.name != TOC_HEADER_NAME) {
+ pr_err("%s is not a FIP file: unknown magic = 0x%08x\n",
+ filename, toc_header.name);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* read all toc entries */
+ while (1) {
+ struct fip_image_desc *desc = xzalloc(sizeof(*desc));
+ struct fip_image *image = xzalloc(sizeof(*image));
+ struct fip_toc_entry *toc_entry = &image->toc_e;
+
+ desc->image = image;
+
+ ret = read_full(fd, toc_entry, sizeof(*toc_entry));
+ if (ret < 0)
+ goto err;
+ if (ret < sizeof(*toc_entry)) {
+ ret = -ENODATA;
+ goto err;
+ }
+
+ list_add_tail(&desc->list, &fip_state->descs);
+
+ pr_debug("Read TOC entry %pU %llu %llu\n", &toc_entry->uuid,
+ toc_entry->offset_address, toc_entry->size);
+
+ /* Found the ToC terminator, we are done. */
+ if (uuid_is_null(&toc_entry->uuid))
+ break;
+ }
+
+ /* determine buffer size */
+ fip_for_each_desc(fip_state, desc) {
+ uint64_t this_end = desc->image->toc_e.offset_address + desc->image->toc_e.size;
+
+ if (this_end > total)
+ total = this_end;
+ n_entries++;
+ }
+
+ fip_headers_size = n_entries * sizeof(struct fip_toc_entry) + sizeof(fip_toc_header_t);
+
+ total -= fip_headers_size;
+
+ fip_state->buffer = malloc(total);
+ if (!fip_state->buffer) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = read_full(fd, fip_state->buffer, total);
+ if (ret < 0)
+ goto err;
+
+ if (ret < total) {
+ ret = -ENODATA;
+ goto err;
+ }
+
+ close(fd);
+
+ fip_for_each_desc(fip_state, desc) {
+ desc->image->buffer = fip_state->buffer +
+ desc->image->toc_e.offset_address - fip_headers_size;
+ desc->image->buf_no_free = true;
+ }
+
+ return fip_state;
+err:
+ close(fd);
+ fip_free(fip_state);
+
+ return ERR_PTR(ret);
+}
--
2.39.5
More information about the barebox
mailing list