Commit e9dbfb32edaf4159e92299346db58041a7baab93

Authored by Alexander Graf
Committed by Michal Simek
1 parent ffdf528007

tools: zynqmpimage: Add partition read support

The zynqmp image format has support for inline partitions which are
used by FSBL to describe payloads that are loaded by FSBL itself.

While we can't create images that contain partitions (yet), we should
still at least be able to examine them and show the user what's inside
when we analyze an image created by bootgen.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

Showing 1 changed file with 173 additions and 2 deletions Side-by-side Diff

... ... @@ -6,6 +6,7 @@
6 6 * The following Boot Header format/structures and values are defined in the
7 7 * following documents:
8 8 * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4)
  9 + * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16)
9 10 *
10 11 * Expected Header Size = 0x9C0
11 12 * Forced as 'little' endian, 32-bit words
... ... @@ -62,6 +63,7 @@
62 63 #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff))
63 64 #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566))
64 65 #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58))
  66 +#define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10)
65 67  
66 68 enum {
67 69 ENCRYPTION_EFUSE = 0xa5c3c5a3,
... ... @@ -79,6 +81,78 @@
79 81 #define HEADER_INTERRUPT_VECTORS 8
80 82 #define HEADER_REGINITS 256
81 83  
  84 +struct image_header_table {
  85 + uint32_t version; /* 0x00 */
  86 + uint32_t nr_parts; /* 0x04 */
  87 + uint32_t partition_header_offset; /* 0x08, divided by 4 */
  88 + uint32_t image_header_offset; /* 0x0c, divided by 4 */
  89 + uint32_t auth_certificate_offset; /* 0x10 */
  90 + uint32_t boot_device; /* 0x14 */
  91 + uint32_t __reserved1[9]; /* 0x18 - 0x38 */
  92 + uint32_t checksum; /* 0x3c */
  93 +};
  94 +
  95 +#define PART_ATTR_VEC_LOCATION 0x800000
  96 +#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000
  97 +#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000
  98 +#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000
  99 +#define PART_ATTR_BIG_ENDIAN 0x040000
  100 +#define PART_ATTR_PART_OWNER_MASK 0x030000
  101 +#define PART_ATTR_PART_OWNER_FSBL 0x000000
  102 +#define PART_ATTR_PART_OWNER_UBOOT 0x010000
  103 +#define PART_ATTR_RSA_SIG 0x008000
  104 +#define PART_ATTR_CHECKSUM_MASK 0x007000
  105 +#define PART_ATTR_CHECKSUM_NONE 0x000000
  106 +#define PART_ATTR_CHECKSUM_MD5 0x001000
  107 +#define PART_ATTR_CHECKSUM_SHA2 0x002000
  108 +#define PART_ATTR_CHECKSUM_SHA3 0x003000
  109 +#define PART_ATTR_DEST_CPU_SHIFT 8
  110 +#define PART_ATTR_DEST_CPU_MASK 0x000f00
  111 +#define PART_ATTR_DEST_CPU_NONE 0x000000
  112 +#define PART_ATTR_DEST_CPU_A53_0 0x000100
  113 +#define PART_ATTR_DEST_CPU_A53_1 0x000200
  114 +#define PART_ATTR_DEST_CPU_A53_2 0x000300
  115 +#define PART_ATTR_DEST_CPU_A53_3 0x000400
  116 +#define PART_ATTR_DEST_CPU_R5_0 0x000500
  117 +#define PART_ATTR_DEST_CPU_R5_1 0x000600
  118 +#define PART_ATTR_DEST_CPU_R5_L 0x000700
  119 +#define PART_ATTR_DEST_CPU_PMU 0x000800
  120 +#define PART_ATTR_ENCRYPTED 0x000080
  121 +#define PART_ATTR_DEST_DEVICE_SHIFT 4
  122 +#define PART_ATTR_DEST_DEVICE_MASK 0x000070
  123 +#define PART_ATTR_DEST_DEVICE_NONE 0x000000
  124 +#define PART_ATTR_DEST_DEVICE_PS 0x000010
  125 +#define PART_ATTR_DEST_DEVICE_PL 0x000020
  126 +#define PART_ATTR_DEST_DEVICE_PMU 0x000030
  127 +#define PART_ATTR_DEST_DEVICE_XIP 0x000040
  128 +#define PART_ATTR_A53_EXEC_AARCH32 0x000008
  129 +#define PART_ATTR_TARGET_EL_SHIFT 1
  130 +#define PART_ATTR_TARGET_EL_MASK 0x000006
  131 +#define PART_ATTR_TZ_SECURE 0x000001
  132 +
  133 +static const char *dest_cpus[0x10] = {
  134 + "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1",
  135 + "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown",
  136 + "unknown", "unknown", "unknown"
  137 +};
  138 +
  139 +struct partition_header {
  140 + uint32_t len_enc; /* 0x00, divided by 4 */
  141 + uint32_t len_unenc; /* 0x04, divided by 4 */
  142 + uint32_t len; /* 0x08, divided by 4 */
  143 + uint32_t next_partition_offset; /* 0x0c */
  144 + uint64_t entry_point; /* 0x10 */
  145 + uint64_t load_address; /* 0x18 */
  146 + uint32_t offset; /* 0x20, divided by 4 */
  147 + uint32_t attributes; /* 0x24 */
  148 + uint32_t __reserved1; /* 0x28 */
  149 + uint32_t checksum_offset; /* 0x2c, divided by 4 */
  150 + uint32_t __reserved2; /* 0x30 */
  151 + uint32_t auth_certificate_offset; /* 0x34 */
  152 + uint32_t __reserved3; /* 0x38 */
  153 + uint32_t checksum; /* 0x3c */
  154 +};
  155 +
82 156 struct zynqmp_header {
83 157 uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */
84 158 uint32_t width_detection; /* 0x20 */
... ... @@ -92,7 +166,9 @@
92 166 uint32_t image_stored_size; /* 0x40 */
93 167 uint32_t image_attributes; /* 0x44 */
94 168 uint32_t checksum; /* 0x48 */
95   - uint32_t __reserved1[27]; /* 0x4c */
  169 + uint32_t __reserved1[19]; /* 0x4c */
  170 + uint32_t image_header_table_offset; /* 0x98 */
  171 + uint32_t __reserved2[7]; /* 0x9c */
96 172 struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */
97 173 uint32_t __reserved4[66]; /* 0x9c0 */
98 174 };
... ... @@ -131,7 +207,7 @@
131 207 return;
132 208  
133 209 ptr->width_detection = HEADER_WIDTHDETECTION;
134   - ptr->image_attributes = 0x800;
  210 + ptr->image_attributes = HEADER_CPU_SELECT_A53_64BIT;
135 211 ptr->image_identifier = HEADER_IMAGEIDENTIFIER;
136 212 ptr->encryption = cpu_to_le32(ENCRYPTION_NONE);
137 213  
... ... @@ -172,6 +248,80 @@
172 248 return 0;
173 249 }
174 250  
  251 +static void print_partition(const void *ptr, const struct partition_header *ph)
  252 +{
  253 + uint32_t attr = le32_to_cpu(ph->attributes);
  254 + unsigned long len = le32_to_cpu(ph->len) * 4;
  255 + const char *part_owner;
  256 + const char *dest_devs[0x8] = {
  257 + "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown",
  258 + "unknown"
  259 + };
  260 +
  261 + switch (attr & PART_ATTR_PART_OWNER_MASK) {
  262 + case PART_ATTR_PART_OWNER_FSBL:
  263 + part_owner = "FSBL";
  264 + break;
  265 + case PART_ATTR_PART_OWNER_UBOOT:
  266 + part_owner = "U-Boot";
  267 + break;
  268 + default:
  269 + part_owner = "Unknown";
  270 + break;
  271 + }
  272 +
  273 + printf("%s payload on CPU %s (%s):\n", part_owner,
  274 + dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8],
  275 + dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]);
  276 +
  277 + printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4);
  278 + printf(" Size : %lu (0x%lx) bytes\n", len, len);
  279 + printf(" Load : 0x%08llx",
  280 + (unsigned long long)le64_to_cpu(ph->load_address));
  281 + if (ph->load_address != ph->entry_point)
  282 + printf(" (entry=0x%08llx)\n",
  283 + (unsigned long long)le64_to_cpu(ph->entry_point));
  284 + else
  285 + printf("\n");
  286 + printf(" Attributes : ");
  287 +
  288 + if (attr & PART_ATTR_VEC_LOCATION)
  289 + printf("vec ");
  290 +
  291 + if (attr & PART_ATTR_ENCRYPTED)
  292 + printf("encrypted ");
  293 +
  294 + switch (attr & PART_ATTR_CHECKSUM_MASK) {
  295 + case PART_ATTR_CHECKSUM_MD5:
  296 + printf("md5 ");
  297 + break;
  298 + case PART_ATTR_CHECKSUM_SHA2:
  299 + printf("sha2 ");
  300 + break;
  301 + case PART_ATTR_CHECKSUM_SHA3:
  302 + printf("sha3 ");
  303 + break;
  304 + }
  305 +
  306 + if (attr & PART_ATTR_BIG_ENDIAN)
  307 + printf("BigEndian ");
  308 +
  309 + if (attr & PART_ATTR_RSA_SIG)
  310 + printf("RSA ");
  311 +
  312 + if (attr & PART_ATTR_A53_EXEC_AARCH32)
  313 + printf("AArch32 ");
  314 +
  315 + if (attr & PART_ATTR_TARGET_EL_MASK)
  316 + printf("EL%d ", (attr & PART_ATTR_TARGET_EL_MASK) >> 1);
  317 +
  318 + if (attr & PART_ATTR_TZ_SECURE)
  319 + printf("secure ");
  320 + printf("\n");
  321 +
  322 + printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum));
  323 +}
  324 +
175 325 static void zynqmpimage_print_header(const void *ptr)
176 326 {
177 327 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
... ... @@ -210,6 +360,27 @@
210 360 printf(" @ 0x%08x -> 0x%08x\n",
211 361 le32_to_cpu(zynqhdr->register_init[i].address),
212 362 le32_to_cpu(zynqhdr->register_init[i].data));
  363 + }
  364 +
  365 + if (zynqhdr->image_header_table_offset) {
  366 + struct image_header_table *iht = (void *)ptr +
  367 + zynqhdr->image_header_table_offset;
  368 + struct partition_header *ph;
  369 + uint32_t ph_offset;
  370 + uint32_t next;
  371 + int i;
  372 +
  373 + ph_offset = le32_to_cpu(iht->partition_header_offset) * 4;
  374 + ph = (void *)ptr + ph_offset;
  375 + for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) {
  376 + next = le32_to_cpu(ph->next_partition_offset) * 4;
  377 +
  378 + /* Partition 0 is the base image itself */
  379 + if (i)
  380 + print_partition(ptr, ph);
  381 +
  382 + ph = (void *)ptr + next;
  383 + }
213 384 }
214 385  
215 386 free(dynamic_header);