[PATCH 1/4] tools: zynqmpimage: show info on partition 0

The zynqmpimage_print_header() skips printing the first partition. This is because the image header can contain duplicate fields as the first partition. However some fields, like the partition attributes, are only present in the partition table. It is also possible for the first partition to not be declared in the image header, if the image is not a bootloader image.
Signed-off-by: Brandon Maier brandon.maier@collins.com ---
tools/zynqmpimage.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index bb54f41a153..05af1e81a24 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -262,9 +262,7 @@ void zynqmpimage_print_header(const void *ptr, struct image_tool_params *params) for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) { next = le32_to_cpu(ph->next_partition_offset) * 4;
- /* Partition 0 is the base image itself */ - if (i) - print_partition(ptr, ph); + print_partition(ptr, ph);
ph = (void *)ptr + next; }

Two of the partition size fields are not printed. Currently only the "total" size is displayed, which is the size of the image data (encrypted), padding, expansion, and authentication data. Add the "unencrypted data" size, which is the original size of the data before being encrypted. And "encrypted data" size, which is just the encrypted data.
To avoid printing useless information, only print the encrypted and unencrypted sizes if they are different from the total.
Signed-off-by: Brandon Maier brandon.maier@collins.com ---
tools/zynqmpimage.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 05af1e81a24..2795a2b9a77 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -139,6 +139,8 @@ static void print_partition(const void *ptr, const struct partition_header *ph) { uint32_t attr = le32_to_cpu(ph->attributes); unsigned long len = le32_to_cpu(ph->len) * 4; + unsigned long len_enc = le32_to_cpu(ph->len_enc) * 4; + unsigned long len_unenc = le32_to_cpu(ph->len_unenc) * 4; const char *part_owner; const char *dest_devs[0x8] = { "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown", @@ -163,6 +165,10 @@ static void print_partition(const void *ptr, const struct partition_header *ph)
printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4); printf(" Size : %lu (0x%lx) bytes\n", len, len); + if (len != len_unenc) + printf(" Size Data : %lu (0x%lx) bytes\n", len_unenc, len_unenc); + if (len_unenc != len_enc) + printf(" Size Enc : %lu (0x%lx) bytes\n", len_unenc, len_unenc); printf(" Load : 0x%08llx", (unsigned long long)le64_to_cpu(ph->load_address)); if (ph->load_address != ph->entry_point)

Extract partitions from a Xilinx Boot Image using dumpimage.
Add helper for_each_zynqmp_part() to reuse the partition walking code between the printing and extracting functions.
Signed-off-by: Brandon Maier brandon.maier@collins.com ---
tools/zynqmpimage.c | 57 +++++++++++++++++++++++++++++--------------- tools/zynqmpimage.h | 58 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 19 deletions(-)
diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 2795a2b9a77..307edd63ebb 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -218,6 +218,7 @@ static void print_partition(const void *ptr, const struct partition_header *ph) void zynqmpimage_print_header(const void *ptr, struct image_tool_params *params) { struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; + struct partition_header *ph; int i;
printf("Image Type : Xilinx ZynqMP Boot Image support\n"); @@ -255,23 +256,8 @@ void zynqmpimage_print_header(const void *ptr, struct image_tool_params *params) le32_to_cpu(zynqhdr->register_init[i].data)); }
- if (zynqhdr->image_header_table_offset) { - struct image_header_table *iht = (void *)ptr + - zynqhdr->image_header_table_offset; - struct partition_header *ph; - uint32_t ph_offset; - uint32_t next; - int i; - - ph_offset = le32_to_cpu(iht->partition_header_offset) * 4; - ph = (void *)ptr + ph_offset; - for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) { - next = le32_to_cpu(ph->next_partition_offset) * 4; - - print_partition(ptr, ph); - - ph = (void *)ptr + next; - } + for_each_zynqmp_part(zynqhdr, i, ph) { + print_partition(ptr, ph); }
free(dynamic_header); @@ -296,7 +282,7 @@ static int zynqmpimage_check_params(struct image_tool_params *params) return -1; }
- return !(params->lflag || params->dflag); + return !(params->lflag || params->dflag || params->outfile); }
static int zynqmpimage_check_image_types(uint8_t type) @@ -431,6 +417,39 @@ static void zynqmpimage_set_header(void *ptr, struct stat *sbuf, int ifd, zynqhdr->checksum = zynqmpimage_checksum(zynqhdr); }
+static int zynqmpimage_partition_extract(struct zynqmp_header *zynqhdr, + const struct partition_header *ph, + const char *filename) +{ + ulong data = (ulong)zynqmp_get_offset(zynqhdr, ph->offset); + unsigned long len = le32_to_cpu(ph->len_enc) * 4; + + return imagetool_save_subimage(filename, data, len); +} + +/** + * zynqmpimage_extract_contents - retrieve a sub-image component from the image + * @ptr: pointer to the image header + * @params: command line parameters + * + * returns: + * zero in case of success or a negative value if fail. + */ +static int zynqmpimage_extract_contents(void *ptr, struct image_tool_params *params) +{ + struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; + struct partition_header *ph; + int i; + + for_each_zynqmp_part(zynqhdr, i, ph) { + if (i == params->pflag) + return zynqmpimage_partition_extract(ptr, ph, params->outfile); + } + + printf("No partition found\n"); + return -1; +} + static int zynqmpimage_vrec_header(struct image_tool_params *params, struct image_type_params *tparams) { @@ -484,7 +503,7 @@ U_BOOT_IMAGE_TYPE( zynqmpimage_verify_header, zynqmpimage_print_header, zynqmpimage_set_header, - NULL, + zynqmpimage_extract_contents, zynqmpimage_check_image_types, NULL, zynqmpimage_vrec_header diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h index ca7489835a8..32be0d125fd 100644 --- a/tools/zynqmpimage.h +++ b/tools/zynqmpimage.h @@ -135,4 +135,62 @@ struct zynqmp_header { void zynqmpimage_default_header(struct zynqmp_header *ptr); void zynqmpimage_print_header(const void *ptr, struct image_tool_params *params);
+static inline struct image_header_table * +zynqmp_get_iht(const struct zynqmp_header *zynqhdr) +{ + if (!zynqhdr->image_header_table_offset) + return NULL; + return (struct image_header_table *)((void *)zynqhdr + zynqhdr->image_header_table_offset); +} + +static inline void *zynqmp_get_offset(const struct zynqmp_header *zynqhdr, + uint32_t offset) +{ + uint32_t offset_cpu = le32_to_cpu(offset); + + if (!offset_cpu) + return NULL; + return (void *)zynqhdr + offset_cpu * 4; +} + +static inline struct partition_header * +zynqmp_part_first(const struct zynqmp_header *zynqhdr) +{ + struct image_header_table *iht; + + iht = zynqmp_get_iht(zynqhdr); + if (!iht) + return NULL; + + return zynqmp_get_offset(zynqhdr, iht->partition_header_offset); +} + +static inline struct partition_header * +zynqmp_part_next(const struct zynqmp_header *zynqhdr, + const struct partition_header *ph) +{ + return zynqmp_get_offset(zynqhdr, ph->next_partition_offset); +} + +static inline size_t zynqmp_part_count(const struct zynqmp_header *zynqhdr) +{ + struct image_header_table *iht; + + iht = zynqmp_get_iht(zynqhdr); + if (!iht) + return 0; + + return le32_to_cpu(iht->nr_parts); +} + +#define _for_each_zynqmp_part(_zynqhdr, _iter, _ph, _start, _count) \ + for (_iter = 0, _ph = _start; \ + _iter < (_count) && _ph; \ + _iter++, _ph = zynqmp_part_next(_zynqhdr, _ph)) + +#define for_each_zynqmp_part(_zynqhdr, _iter, _ph) \ + _for_each_zynqmp_part(_zynqhdr, _iter, _ph, \ + zynqmp_part_first(_zynqhdr), \ + zynqmp_part_count(_zynqhdr)) + #endif /* _ZYNQMPIMAGE_H_ */

Each partition may belong to an image, which has a name. That name can be useful for debugging as it helps identify where the partition came from.
Signed-off-by: Brandon Maier brandon.maier@collins.com ---
tools/zynqmpimage.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ tools/zynqmpimage.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+)
diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 307edd63ebb..4db9877127e 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -135,6 +135,53 @@ static int zynqmpimage_verify_header(unsigned char *ptr, int image_size, return 0; }
+static struct image_header * +find_partition_image(const struct zynqmp_header *zynqhdr, + const struct partition_header *ph) +{ + struct partition_header *ph_walk; + struct image_header *ih; + int i; + + for_each_zynqmp_image(zynqhdr, ih) { + for_each_zynqmp_part_in_image(zynqhdr, i, ph_walk, ih) { + if (ph == ph_walk) + return ih; + } + } + + return NULL; +} + +static void print_partition_name(const struct zynqmp_header *zynqhdr, + const struct partition_header *ph) +{ + const struct image_header *ih; + size_t word_len; + char *name; + int i; + + ih = find_partition_image(zynqhdr, ph); + if (!ih) + return; + + /* Name is stored in big-endian words, find the terminating word and + * byte-swap into a new buffer + */ + word_len = strlen((char *)ih->image_name); + word_len = ALIGN(word_len + 1, 4); + + name = calloc(1, word_len); + if (!name) + return; + + for (i = 0; i < word_len / 4; i++) + ((uint32_t *)name)[i] = uswap_32(ih->image_name[i]); + + printf(" Image name : %s\n", name); + free(name); +} + static void print_partition(const void *ptr, const struct partition_header *ph) { uint32_t attr = le32_to_cpu(ph->attributes); @@ -163,6 +210,7 @@ static void print_partition(const void *ptr, const struct partition_header *ph) dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8], dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]);
+ print_partition_name(ptr, ph); printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4); printf(" Size : %lu (0x%lx) bytes\n", len, len); if (len != len_unenc) diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h index 32be0d125fd..7c47dc0763b 100644 --- a/tools/zynqmpimage.h +++ b/tools/zynqmpimage.h @@ -51,6 +51,14 @@ struct image_header_table { uint32_t checksum; /* 0x3c */ };
+struct image_header { + uint32_t next_image_header_offset; /* 0x00 */ + uint32_t corresponding_partition_header; /* 0x04 */ + uint32_t __reserved1; /* 0x08 */ + uint32_t partition_count; /* 0x0c */ + uint32_t image_name[]; /* 0x10 */ +}; + #define PART_ATTR_VEC_LOCATION 0x800000 #define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 #define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 @@ -193,4 +201,45 @@ static inline size_t zynqmp_part_count(const struct zynqmp_header *zynqhdr) zynqmp_part_first(_zynqhdr), \ zynqmp_part_count(_zynqhdr))
+static inline struct partition_header * +zynqmp_part_in_image_first(const struct zynqmp_header *zynqhdr, + const struct image_header *ih) +{ + return zynqmp_get_offset(zynqhdr, ih->corresponding_partition_header); +} + +static inline size_t zynqmp_part_in_image_count(const struct image_header *ih) +{ + return le32_to_cpu(ih->partition_count); +} + +#define for_each_zynqmp_part_in_image(_zynqhdr, _iter, _ph, _ih) \ + _for_each_zynqmp_part(_zynqhdr, _iter, _ph, \ + zynqmp_part_in_image_first(_zynqhdr, _ih), \ + zynqmp_part_in_image_count(_ih)) + +static inline struct image_header * +zynqmp_image_first(const struct zynqmp_header *zynqhdr) +{ + struct image_header_table *iht; + + iht = zynqmp_get_iht(zynqhdr); + if (!iht) + return NULL; + + return zynqmp_get_offset(zynqhdr, iht->image_header_offset); +} + +static inline struct image_header * +zynqmp_image_next(const struct zynqmp_header *zynqhdr, + const struct image_header *ih) +{ + return zynqmp_get_offset(zynqhdr, ih->next_image_header_offset); +} + +#define for_each_zynqmp_image(_zynqhdr, _ih) \ + for (_ih = zynqmp_image_first(_zynqhdr); \ + _ih; \ + _ih = zynqmp_image_next(_zynqhdr, _ih)) + #endif /* _ZYNQMPIMAGE_H_ */

On 1/4/24 19:50, Brandon Maier wrote:
The zynqmpimage_print_header() skips printing the first partition. This is because the image header can contain duplicate fields as the first partition. However some fields, like the partition attributes, are only present in the partition table. It is also possible for the first partition to not be declared in the image header, if the image is not a bootloader image.
Signed-off-by: Brandon Maier brandon.maier@collins.com
tools/zynqmpimage.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index bb54f41a153..05af1e81a24 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -262,9 +262,7 @@ void zynqmpimage_print_header(const void *ptr, struct image_tool_params *params) for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) { next = le32_to_cpu(ph->next_partition_offset) * 4;
/* Partition 0 is the base image itself */
if (i)
print_partition(ptr, ph);
print_partition(ptr, ph); ph = (void *)ptr + next;
}
Applied all. With also removing "This contributor prefers not to receive mails noreply@example.com" from my reply.
M
participants (2)
-
Brandon Maier
-
Michal Simek