]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ti-u-boot/ti-u-boot.git/blob - tools/zynqmpimage.c
Prepare v2024.04
[ti-u-boot/ti-u-boot.git] / tools / zynqmpimage.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Michal Simek <michals@xilinx.com>
4  * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com>
5  *
6  * The following Boot Header format/structures and values are defined in the
7  * following documents:
8  *   * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4)
9  *   * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16)
10  *
11  * Expected Header Size = 0x9C0
12  * Forced as 'little' endian, 32-bit words
13  *
14  *  0x  0 - Interrupt table (8 words)
15  *  ...     (Default value = 0xeafffffe)
16  *  0x 1f
17  *  0x 20 - Width detection
18  *         * DEFAULT_WIDTHDETECTION    0xaa995566
19  *  0x 24 - Image identifier
20  *         * DEFAULT_IMAGEIDENTIFIER   0x584c4e58
21  *  0x 28 - Encryption
22  *         * 0x00000000 - None
23  *         * 0xa5c3c5a3 - eFuse
24  *         * 0xa5c3c5a7 - obfuscated key in eFUSE
25  *         * 0x3a5c3c5a - bbRam
26  *         * 0xa35c7ca5 - obfuscated key in boot header
27  *  0x 2C - Image load
28  *  0x 30 - Image offset
29  *  0x 34 - PFW image length
30  *  0x 38 - Total PFW image length
31  *  0x 3C - Image length
32  *  0x 40 - Total image length
33  *  0x 44 - Image attributes
34  *  0x 48 - Header checksum
35  *  0x 4c - Obfuscated key
36  *  ...
37  *  0x 68
38  *  0x 6c - Reserved
39  *  0x 70 - User defined
40  *  ...
41  *  0x 9c
42  *  0x a0 - Secure header initialization vector
43  *  ...
44  *  0x a8
45  *  0x ac - Obfuscated key initialization vector
46  *  ...
47  *  0x b4
48  *  0x b8 - Register Initialization, 511 Address and Data word pairs
49  *         * List is terminated with an address of 0xffffffff or
50  *  ...    * at the max number of entries
51  *  0x8b4
52  *  0x8b8 - Reserved
53  *  ...
54  *  0x9bf
55  *  0x9c0 - Data/Image starts here or above
56  */
58 #include "imagetool.h"
59 #include "mkimage.h"
60 #include "zynqmpimage.h"
61 #include <image.h>
63 static struct zynqmp_header zynqmpimage_header;
64 static void *dynamic_header;
65 static FILE *fpmu;
67 static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr)
68 {
69         uint32_t checksum = 0;
71         if (ptr == NULL)
72                 return 0;
74         checksum += le32_to_cpu(ptr->width_detection);
75         checksum += le32_to_cpu(ptr->image_identifier);
76         checksum += le32_to_cpu(ptr->encryption);
77         checksum += le32_to_cpu(ptr->image_load);
78         checksum += le32_to_cpu(ptr->image_offset);
79         checksum += le32_to_cpu(ptr->pfw_image_length);
80         checksum += le32_to_cpu(ptr->total_pfw_image_length);
81         checksum += le32_to_cpu(ptr->image_size);
82         checksum += le32_to_cpu(ptr->image_stored_size);
83         checksum += le32_to_cpu(ptr->image_attributes);
84         checksum = ~checksum;
86         return cpu_to_le32(checksum);
87 }
89 void zynqmpimage_default_header(struct zynqmp_header *ptr)
90 {
91         int i;
93         if (ptr == NULL)
94                 return;
96         ptr->width_detection = HEADER_WIDTHDETECTION;
97         ptr->image_attributes = HEADER_CPU_SELECT_A53_64BIT;
98         ptr->image_identifier = HEADER_IMAGEIDENTIFIER;
99         ptr->encryption = cpu_to_le32(ENCRYPTION_NONE);
101         /* Setup not-supported/constant/reserved fields */
102         for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++)
103                 ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT;
105         for (i = 0; i < HEADER_REGINITS; i++) {
106                 ptr->register_init[i].address = HEADER_REGINIT_NULL;
107                 ptr->register_init[i].data = 0;
108         }
110         /*
111          * Certain reserved fields are required to be set to 0, ensure they are
112          * set as such.
113          */
114         ptr->pfw_image_length = 0x0;
115         ptr->total_pfw_image_length = 0x0;
118 /* mkimage glue functions */
119 static int zynqmpimage_verify_header(unsigned char *ptr, int image_size,
120                 struct image_tool_params *params)
122         struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
124         if (image_size < sizeof(struct zynqmp_header))
125                 return -1;
127         if (zynqhdr->width_detection != HEADER_WIDTHDETECTION)
128                 return -1;
129         if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER)
130                 return -1;
132         if (zynqmpimage_checksum(zynqhdr) != zynqhdr->checksum)
133                 return -1;
135         return 0;
138 static void print_partition(const void *ptr, const struct partition_header *ph)
140         uint32_t attr = le32_to_cpu(ph->attributes);
141         unsigned long len = le32_to_cpu(ph->len) * 4;
142         const char *part_owner;
143         const char *dest_devs[0x8] = {
144                 "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown",
145                 "unknown"
146         };
148         switch (attr & PART_ATTR_PART_OWNER_MASK) {
149         case PART_ATTR_PART_OWNER_FSBL:
150                 part_owner = "FSBL";
151                 break;
152         case PART_ATTR_PART_OWNER_UBOOT:
153                 part_owner = "U-Boot";
154                 break;
155         default:
156                 part_owner = "Unknown";
157                 break;
158         }
160         printf("%s payload on CPU %s (%s):\n", part_owner,
161                dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8],
162                dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]);
164         printf("    Offset     : 0x%08x\n", le32_to_cpu(ph->offset) * 4);
165         printf("    Size       : %lu (0x%lx) bytes\n", len, len);
166         printf("    Load       : 0x%08llx",
167                (unsigned long long)le64_to_cpu(ph->load_address));
168         if (ph->load_address != ph->entry_point)
169                 printf(" (entry=0x%08llx)\n",
170                        (unsigned long long)le64_to_cpu(ph->entry_point));
171         else
172                 printf("\n");
173         printf("    Attributes : ");
175         if (attr & PART_ATTR_VEC_LOCATION)
176                 printf("vec ");
178         if (attr & PART_ATTR_ENCRYPTED)
179                 printf("encrypted ");
181         switch (attr & PART_ATTR_CHECKSUM_MASK) {
182         case PART_ATTR_CHECKSUM_MD5:
183                 printf("md5 ");
184                 break;
185         case PART_ATTR_CHECKSUM_SHA2:
186                 printf("sha2 ");
187                 break;
188         case PART_ATTR_CHECKSUM_SHA3:
189                 printf("sha3 ");
190                 break;
191         }
193         if (attr & PART_ATTR_BIG_ENDIAN)
194                 printf("BigEndian ");
196         if (attr & PART_ATTR_RSA_SIG)
197                 printf("RSA ");
199         if (attr & PART_ATTR_A53_EXEC_AARCH32)
200                 printf("AArch32 ");
202         if (attr & PART_ATTR_TARGET_EL_MASK)
203                 printf("EL%d ", (attr & PART_ATTR_TARGET_EL_MASK) >> 1);
205         if (attr & PART_ATTR_TZ_SECURE)
206                 printf("secure ");
207         printf("\n");
209         printf("    Checksum   : 0x%08x\n", le32_to_cpu(ph->checksum));
212 void zynqmpimage_print_header(const void *ptr)
214         struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
215         int i;
217         printf("Image Type   : Xilinx ZynqMP Boot Image support\n");
218         printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset));
219         printf("Image Size   : %lu bytes (%lu bytes packed)\n",
220                (unsigned long)le32_to_cpu(zynqhdr->image_size),
221                (unsigned long)le32_to_cpu(zynqhdr->image_stored_size));
223         if (zynqhdr->pfw_image_length)
224                 printf("PMUFW Size   : %lu bytes (%lu bytes packed)\n",
225                        (unsigned long)le32_to_cpu(zynqhdr->pfw_image_length),
226                        (unsigned long)le32_to_cpu(
227                                 zynqhdr->total_pfw_image_length));
229         printf("Image Load   : 0x%08x\n", le32_to_cpu(zynqhdr->image_load));
230         printf("Checksum     : 0x%08x\n", le32_to_cpu(zynqhdr->checksum));
232         for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) {
233                 if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT)
234                         continue;
236                 printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i,
237                        le32_to_cpu(zynqhdr->interrupt_vectors[i]));
238         }
240         for (i = 0; i < HEADER_REGINITS; i++) {
241                 if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL)
242                         break;
244                 if (i == 0)
245                         printf("Custom Register Initialization:\n");
247                 printf("    @ 0x%08x -> 0x%08x\n",
248                        le32_to_cpu(zynqhdr->register_init[i].address),
249                        le32_to_cpu(zynqhdr->register_init[i].data));
250         }
252         if (zynqhdr->image_header_table_offset) {
253                 struct image_header_table *iht = (void *)ptr +
254                         zynqhdr->image_header_table_offset;
255                 struct partition_header *ph;
256                 uint32_t ph_offset;
257                 uint32_t next;
258                 int i;
260                 ph_offset = le32_to_cpu(iht->partition_header_offset) * 4;
261                 ph = (void *)ptr + ph_offset;
262                 for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) {
263                         next = le32_to_cpu(ph->next_partition_offset) * 4;
265                         /* Partition 0 is the base image itself */
266                         if (i)
267                                 print_partition(ptr, ph);
269                         ph = (void *)ptr + next;
270                 }
271         }
273         free(dynamic_header);
276 static int zynqmpimage_check_params(struct image_tool_params *params)
278         if (!params)
279                 return 0;
281         if (params->addr != 0x0) {
282                 fprintf(stderr, "Error: Load Address cannot be specified.\n");
283                 return -1;
284         }
286         /*
287          * If the entry point is specified ensure it is 64 byte aligned.
288          */
289         if (params->eflag && (params->ep % 64 != 0)) {
290                 fprintf(stderr,
291                         "Error: Entry Point must be aligned to a 64-byte boundary.\n");
292                 return -1;
293         }
295         return !(params->lflag || params->dflag);
298 static int zynqmpimage_check_image_types(uint8_t type)
300         if (type == IH_TYPE_ZYNQMPIMAGE)
301                 return EXIT_SUCCESS;
302         return EXIT_FAILURE;
305 static uint32_t fsize(FILE *fp)
307         int size, ret, origin;
309         origin = ftell(fp);
310         if (origin < 0) {
311                 fprintf(stderr, "Incorrect file size\n");
312                 fclose(fp);
313                 exit(2);
314         }
316         ret = fseek(fp, 0L, SEEK_END);
317         if (ret) {
318                 fprintf(stderr, "Incorrect file SEEK_END\n");
319                 fclose(fp);
320                 exit(3);
321         }
323         size = ftell(fp);
324         if (size < 0) {
325                 fprintf(stderr, "Incorrect file size\n");
326                 fclose(fp);
327                 exit(4);
328         }
330         /* going back */
331         ret = fseek(fp, origin, SEEK_SET);
332         if (ret) {
333                 fprintf(stderr, "Incorrect file SEEK_SET to %d\n", origin);
334                 fclose(fp);
335                 exit(3);
336         }
338         return size;
341 static void zynqmpimage_pmufw(struct zynqmp_header *zynqhdr,
342                               const char *filename)
344         uint32_t size;
346         /* Setup PMU fw size */
347         zynqhdr->pfw_image_length = fsize(fpmu);
348         zynqhdr->total_pfw_image_length = zynqhdr->pfw_image_length;
350         zynqhdr->image_size -= zynqhdr->pfw_image_length;
351         zynqhdr->image_stored_size -= zynqhdr->total_pfw_image_length;
353         /* Read the whole PMUFW to the header */
354         size = fread(&zynqhdr->__reserved4[66], 1,
355                      zynqhdr->pfw_image_length, fpmu);
356         if (size != zynqhdr->pfw_image_length) {
357                 fprintf(stderr, "Cannot read PMUFW file: %s\n", filename);
358                 fclose(fpmu);
359                 exit(1);
360         }
362         fclose(fpmu);
365 static void zynqmpimage_parse_initparams(struct zynqmp_header *zynqhdr,
366         const char *filename)
368         FILE *fp;
369         struct zynqmp_reginit reginit;
370         unsigned int reg_count = 0;
371         int r, err;
372         struct stat path_stat;
374         /* Expect a table of register-value pairs, e.g. "0x12345678 0x4321" */
375         fp = fopen(filename, "r");
376         if (!fp) {
377                 fprintf(stderr, "Cannot open initparams file: %s\n", filename);
378                 exit(1);
379         }
381         err = fstat(fileno(fp), &path_stat);
382         if (err) {
383                 fclose(fp);
384                 return;
385         }
387         if (!S_ISREG(path_stat.st_mode)) {
388                 fclose(fp);
389                 return;
390         }
392         do {
393                 r = fscanf(fp, "%x %x", &reginit.address, &reginit.data);
394                 if (r == 2) {
395                         zynqhdr->register_init[reg_count] = reginit;
396                         ++reg_count;
397                 }
398                 r = fscanf(fp, "%*[^\n]\n"); /* Skip to next line */
399         } while ((r != EOF) && (reg_count < HEADER_REGINITS));
400         fclose(fp);
403 static void zynqmpimage_set_header(void *ptr, struct stat *sbuf, int ifd,
404                 struct image_tool_params *params)
406         struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
407         zynqmpimage_default_header(zynqhdr);
409         /* place image directly after header */
410         zynqhdr->image_offset =
411                 cpu_to_le32((uint32_t)sizeof(struct zynqmp_header));
412         zynqhdr->image_size = cpu_to_le32(params->file_size -
413                                           sizeof(struct zynqmp_header));
414         zynqhdr->image_stored_size = zynqhdr->image_size;
415         zynqhdr->image_load = 0xfffc0000;
416         if (params->eflag)
417                 zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep);
419         /* PMUFW */
420         if (fpmu)
421                 zynqmpimage_pmufw(zynqhdr, params->imagename);
423         /* User can pass in text file with init list */
424         if (strlen(params->imagename2))
425                 zynqmpimage_parse_initparams(zynqhdr, params->imagename2);
427         zynqhdr->checksum = zynqmpimage_checksum(zynqhdr);
430 static int zynqmpimage_vrec_header(struct image_tool_params *params,
431                                    struct image_type_params *tparams)
433         struct stat path_stat;
434         char *filename = params->imagename;
435         int err;
437         /* Handle static case without PMUFW */
438         tparams->header_size = sizeof(struct zynqmp_header);
439         tparams->hdr = (void *)&zynqmpimage_header;
441         /* PMUFW name is passed via params->imagename */
442         if (strlen(filename) == 0)
443                 return EXIT_SUCCESS;
445         fpmu = fopen(filename, "r");
446         if (!fpmu) {
447                 fprintf(stderr, "Cannot open PMUFW file: %s\n", filename);
448                 return EXIT_FAILURE;
449         }
451         err = fstat(fileno(fpmu), &path_stat);
452         if (err) {
453                 fclose(fpmu);
454                 fpmu = NULL;
455                 return EXIT_FAILURE;
456         }
458         if (!S_ISREG(path_stat.st_mode)) {
459                 fclose(fpmu);
460                 fpmu = NULL;
461                 return EXIT_FAILURE;
462         }
464         /* Increase header size by PMUFW file size */
465         tparams->header_size += fsize(fpmu);
467         /* Allocate buffer with space for PMUFW */
468         dynamic_header = calloc(1, tparams->header_size);
469         tparams->hdr = dynamic_header;
471         return EXIT_SUCCESS;
474 U_BOOT_IMAGE_TYPE(
475         zynqmpimage,
476         "Xilinx ZynqMP Boot Image support",
477         sizeof(struct zynqmp_header),
478         (void *)&zynqmpimage_header,
479         zynqmpimage_check_params,
480         zynqmpimage_verify_header,
481         zynqmpimage_print_header,
482         zynqmpimage_set_header,
483         NULL,
484         zynqmpimage_check_image_types,
485         NULL,
486         zynqmpimage_vrec_header
487 );