183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2d9b58b30SMichal Simek /*
3d9b58b30SMichal Simek * Copyright (C) 2016 Michal Simek <michals@xilinx.com>
4d9b58b30SMichal Simek * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com>
5d9b58b30SMichal Simek *
6d9b58b30SMichal Simek * The following Boot Header format/structures and values are defined in the
7d9b58b30SMichal Simek * following documents:
8df4950e3SJean-Francois Dagenais * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4)
9e9dbfb32SAlexander Graf * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16)
10d9b58b30SMichal Simek *
11d9b58b30SMichal Simek * Expected Header Size = 0x9C0
12d9b58b30SMichal Simek * Forced as 'little' endian, 32-bit words
13d9b58b30SMichal Simek *
14d9b58b30SMichal Simek * 0x 0 - Interrupt table (8 words)
15d9b58b30SMichal Simek * ... (Default value = 0xeafffffe)
16d9b58b30SMichal Simek * 0x 1f
17d9b58b30SMichal Simek * 0x 20 - Width detection
18d9b58b30SMichal Simek * * DEFAULT_WIDTHDETECTION 0xaa995566
19d9b58b30SMichal Simek * 0x 24 - Image identifier
20d9b58b30SMichal Simek * * DEFAULT_IMAGEIDENTIFIER 0x584c4e58
21d9b58b30SMichal Simek * 0x 28 - Encryption
22d9b58b30SMichal Simek * * 0x00000000 - None
23d9b58b30SMichal Simek * * 0xa5c3c5a3 - eFuse
24d9b58b30SMichal Simek * * 0xa5c3c5a7 - obfuscated key in eFUSE
25d9b58b30SMichal Simek * * 0x3a5c3c5a - bbRam
26d9b58b30SMichal Simek * * 0xa35c7ca5 - obfuscated key in boot header
27d9b58b30SMichal Simek * 0x 2C - Image load
28d9b58b30SMichal Simek * 0x 30 - Image offset
29d9b58b30SMichal Simek * 0x 34 - PFW image length
30d9b58b30SMichal Simek * 0x 38 - Total PFW image length
31d9b58b30SMichal Simek * 0x 3C - Image length
32d9b58b30SMichal Simek * 0x 40 - Total image length
33d9b58b30SMichal Simek * 0x 44 - Image attributes
34d9b58b30SMichal Simek * 0x 48 - Header checksum
35d9b58b30SMichal Simek * 0x 4c - Obfuscated key
36d9b58b30SMichal Simek * ...
37d9b58b30SMichal Simek * 0x 68
38d9b58b30SMichal Simek * 0x 6c - Reserved
39d9b58b30SMichal Simek * 0x 70 - User defined
40d9b58b30SMichal Simek * ...
41d9b58b30SMichal Simek * 0x 9c
42d9b58b30SMichal Simek * 0x a0 - Secure header initialization vector
43d9b58b30SMichal Simek * ...
44d9b58b30SMichal Simek * 0x a8
45d9b58b30SMichal Simek * 0x ac - Obfuscated key initialization vector
46d9b58b30SMichal Simek * ...
47d9b58b30SMichal Simek * 0x b4
48d9b58b30SMichal Simek * 0x b8 - Register Initialization, 511 Address and Data word pairs
49d9b58b30SMichal Simek * * List is terminated with an address of 0xffffffff or
50d9b58b30SMichal Simek * ... * at the max number of entries
51d9b58b30SMichal Simek * 0x8b4
52d9b58b30SMichal Simek * 0x8b8 - Reserved
53d9b58b30SMichal Simek * ...
54d9b58b30SMichal Simek * 0x9bf
55d9b58b30SMichal Simek * 0x9c0 - Data/Image starts here or above
56d9b58b30SMichal Simek */
57d9b58b30SMichal Simek
58d9b58b30SMichal Simek #include "imagetool.h"
59d9b58b30SMichal Simek #include "mkimage.h"
60e384cdf8SAlexander Graf #include "zynqmpimage.h"
61d9b58b30SMichal Simek #include <image.h>
62d9b58b30SMichal Simek
63d9b58b30SMichal Simek static struct zynqmp_header zynqmpimage_header;
64c85a6b79SMichal Simek static void *dynamic_header;
65c85a6b79SMichal Simek static FILE *fpmu;
66d9b58b30SMichal Simek
zynqmpimage_checksum(struct zynqmp_header * ptr)67d9b58b30SMichal Simek static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr)
68d9b58b30SMichal Simek {
69d9b58b30SMichal Simek uint32_t checksum = 0;
70d9b58b30SMichal Simek
71d9b58b30SMichal Simek if (ptr == NULL)
72d9b58b30SMichal Simek return 0;
73d9b58b30SMichal Simek
74d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->width_detection);
75d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->image_identifier);
76d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->encryption);
77d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->image_load);
78d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->image_offset);
79d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->pfw_image_length);
80d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->total_pfw_image_length);
81d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->image_size);
82d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->image_stored_size);
83d9b58b30SMichal Simek checksum += le32_to_cpu(ptr->image_attributes);
84d9b58b30SMichal Simek checksum = ~checksum;
85d9b58b30SMichal Simek
86d9b58b30SMichal Simek return cpu_to_le32(checksum);
87d9b58b30SMichal Simek }
88d9b58b30SMichal Simek
zynqmpimage_default_header(struct zynqmp_header * ptr)89*6915dcf3SAlexander Graf void zynqmpimage_default_header(struct zynqmp_header *ptr)
90d9b58b30SMichal Simek {
91d9b58b30SMichal Simek int i;
92d9b58b30SMichal Simek
93d9b58b30SMichal Simek if (ptr == NULL)
94d9b58b30SMichal Simek return;
95d9b58b30SMichal Simek
96d9b58b30SMichal Simek ptr->width_detection = HEADER_WIDTHDETECTION;
97e9dbfb32SAlexander Graf ptr->image_attributes = HEADER_CPU_SELECT_A53_64BIT;
98d9b58b30SMichal Simek ptr->image_identifier = HEADER_IMAGEIDENTIFIER;
99d9b58b30SMichal Simek ptr->encryption = cpu_to_le32(ENCRYPTION_NONE);
100d9b58b30SMichal Simek
101d9b58b30SMichal Simek /* Setup not-supported/constant/reserved fields */
102d9b58b30SMichal Simek for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++)
103d9b58b30SMichal Simek ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT;
104d9b58b30SMichal Simek
105d9b58b30SMichal Simek for (i = 0; i < HEADER_REGINITS; i++) {
106d9b58b30SMichal Simek ptr->register_init[i].address = HEADER_REGINIT_NULL;
107d9b58b30SMichal Simek ptr->register_init[i].data = 0;
108d9b58b30SMichal Simek }
109d9b58b30SMichal Simek
110d9b58b30SMichal Simek /*
111d9b58b30SMichal Simek * Certain reserved fields are required to be set to 0, ensure they are
112d9b58b30SMichal Simek * set as such.
113d9b58b30SMichal Simek */
114d9b58b30SMichal Simek ptr->pfw_image_length = 0x0;
115d9b58b30SMichal Simek ptr->total_pfw_image_length = 0x0;
116d9b58b30SMichal Simek }
117d9b58b30SMichal Simek
118d9b58b30SMichal Simek /* mkimage glue functions */
zynqmpimage_verify_header(unsigned char * ptr,int image_size,struct image_tool_params * params)119d9b58b30SMichal Simek static int zynqmpimage_verify_header(unsigned char *ptr, int image_size,
120d9b58b30SMichal Simek struct image_tool_params *params)
121d9b58b30SMichal Simek {
122d9b58b30SMichal Simek struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
123d9b58b30SMichal Simek
124d9b58b30SMichal Simek if (image_size < sizeof(struct zynqmp_header))
125d9b58b30SMichal Simek return -1;
126d9b58b30SMichal Simek
127d9b58b30SMichal Simek if (zynqhdr->width_detection != HEADER_WIDTHDETECTION)
128d9b58b30SMichal Simek return -1;
129d9b58b30SMichal Simek if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER)
130d9b58b30SMichal Simek return -1;
131d9b58b30SMichal Simek
132d9b58b30SMichal Simek if (zynqmpimage_checksum(zynqhdr) != zynqhdr->checksum)
133d9b58b30SMichal Simek return -1;
134d9b58b30SMichal Simek
135d9b58b30SMichal Simek return 0;
136d9b58b30SMichal Simek }
137d9b58b30SMichal Simek
print_partition(const void * ptr,const struct partition_header * ph)138e9dbfb32SAlexander Graf static void print_partition(const void *ptr, const struct partition_header *ph)
139e9dbfb32SAlexander Graf {
140e9dbfb32SAlexander Graf uint32_t attr = le32_to_cpu(ph->attributes);
141e9dbfb32SAlexander Graf unsigned long len = le32_to_cpu(ph->len) * 4;
142e9dbfb32SAlexander Graf const char *part_owner;
143e9dbfb32SAlexander Graf const char *dest_devs[0x8] = {
144e9dbfb32SAlexander Graf "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown",
145e9dbfb32SAlexander Graf "unknown"
146e9dbfb32SAlexander Graf };
147e9dbfb32SAlexander Graf
148e9dbfb32SAlexander Graf switch (attr & PART_ATTR_PART_OWNER_MASK) {
149e9dbfb32SAlexander Graf case PART_ATTR_PART_OWNER_FSBL:
150e9dbfb32SAlexander Graf part_owner = "FSBL";
151e9dbfb32SAlexander Graf break;
152e9dbfb32SAlexander Graf case PART_ATTR_PART_OWNER_UBOOT:
153e9dbfb32SAlexander Graf part_owner = "U-Boot";
154e9dbfb32SAlexander Graf break;
155e9dbfb32SAlexander Graf default:
156e9dbfb32SAlexander Graf part_owner = "Unknown";
157e9dbfb32SAlexander Graf break;
158e9dbfb32SAlexander Graf }
159e9dbfb32SAlexander Graf
160e9dbfb32SAlexander Graf printf("%s payload on CPU %s (%s):\n", part_owner,
161e9dbfb32SAlexander Graf dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8],
162e9dbfb32SAlexander Graf dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]);
163e9dbfb32SAlexander Graf
164e9dbfb32SAlexander Graf printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4);
165e9dbfb32SAlexander Graf printf(" Size : %lu (0x%lx) bytes\n", len, len);
166e9dbfb32SAlexander Graf printf(" Load : 0x%08llx",
167e9dbfb32SAlexander Graf (unsigned long long)le64_to_cpu(ph->load_address));
168e9dbfb32SAlexander Graf if (ph->load_address != ph->entry_point)
169e9dbfb32SAlexander Graf printf(" (entry=0x%08llx)\n",
170e9dbfb32SAlexander Graf (unsigned long long)le64_to_cpu(ph->entry_point));
171e9dbfb32SAlexander Graf else
172e9dbfb32SAlexander Graf printf("\n");
173e9dbfb32SAlexander Graf printf(" Attributes : ");
174e9dbfb32SAlexander Graf
175e9dbfb32SAlexander Graf if (attr & PART_ATTR_VEC_LOCATION)
176e9dbfb32SAlexander Graf printf("vec ");
177e9dbfb32SAlexander Graf
178e9dbfb32SAlexander Graf if (attr & PART_ATTR_ENCRYPTED)
179e9dbfb32SAlexander Graf printf("encrypted ");
180e9dbfb32SAlexander Graf
181e9dbfb32SAlexander Graf switch (attr & PART_ATTR_CHECKSUM_MASK) {
182e9dbfb32SAlexander Graf case PART_ATTR_CHECKSUM_MD5:
183e9dbfb32SAlexander Graf printf("md5 ");
184e9dbfb32SAlexander Graf break;
185e9dbfb32SAlexander Graf case PART_ATTR_CHECKSUM_SHA2:
186e9dbfb32SAlexander Graf printf("sha2 ");
187e9dbfb32SAlexander Graf break;
188e9dbfb32SAlexander Graf case PART_ATTR_CHECKSUM_SHA3:
189e9dbfb32SAlexander Graf printf("sha3 ");
190e9dbfb32SAlexander Graf break;
191e9dbfb32SAlexander Graf }
192e9dbfb32SAlexander Graf
193e9dbfb32SAlexander Graf if (attr & PART_ATTR_BIG_ENDIAN)
194e9dbfb32SAlexander Graf printf("BigEndian ");
195e9dbfb32SAlexander Graf
196e9dbfb32SAlexander Graf if (attr & PART_ATTR_RSA_SIG)
197e9dbfb32SAlexander Graf printf("RSA ");
198e9dbfb32SAlexander Graf
199e9dbfb32SAlexander Graf if (attr & PART_ATTR_A53_EXEC_AARCH32)
200e9dbfb32SAlexander Graf printf("AArch32 ");
201e9dbfb32SAlexander Graf
202e9dbfb32SAlexander Graf if (attr & PART_ATTR_TARGET_EL_MASK)
203e9dbfb32SAlexander Graf printf("EL%d ", (attr & PART_ATTR_TARGET_EL_MASK) >> 1);
204e9dbfb32SAlexander Graf
205e9dbfb32SAlexander Graf if (attr & PART_ATTR_TZ_SECURE)
206e9dbfb32SAlexander Graf printf("secure ");
207e9dbfb32SAlexander Graf printf("\n");
208e9dbfb32SAlexander Graf
209e9dbfb32SAlexander Graf printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum));
210e9dbfb32SAlexander Graf }
211e9dbfb32SAlexander Graf
zynqmpimage_print_header(const void * ptr)212*6915dcf3SAlexander Graf void zynqmpimage_print_header(const void *ptr)
213d9b58b30SMichal Simek {
214d9b58b30SMichal Simek struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
215d9b58b30SMichal Simek int i;
216d9b58b30SMichal Simek
217d28baea0SMichal Simek printf("Image Type : Xilinx ZynqMP Boot Image support\n");
218d9b58b30SMichal Simek printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset));
219d9b58b30SMichal Simek printf("Image Size : %lu bytes (%lu bytes packed)\n",
220d9b58b30SMichal Simek (unsigned long)le32_to_cpu(zynqhdr->image_size),
221d9b58b30SMichal Simek (unsigned long)le32_to_cpu(zynqhdr->image_stored_size));
222c85a6b79SMichal Simek
223c85a6b79SMichal Simek if (zynqhdr->pfw_image_length)
224c85a6b79SMichal Simek printf("PMUFW Size : %lu bytes (%lu bytes packed)\n",
225c85a6b79SMichal Simek (unsigned long)le32_to_cpu(zynqhdr->pfw_image_length),
226c85a6b79SMichal Simek (unsigned long)le32_to_cpu(
227c85a6b79SMichal Simek zynqhdr->total_pfw_image_length));
228c85a6b79SMichal Simek
229d9b58b30SMichal Simek printf("Image Load : 0x%08x\n", le32_to_cpu(zynqhdr->image_load));
230d9b58b30SMichal Simek printf("Checksum : 0x%08x\n", le32_to_cpu(zynqhdr->checksum));
231d9b58b30SMichal Simek
232d9b58b30SMichal Simek for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) {
233d9b58b30SMichal Simek if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT)
234d9b58b30SMichal Simek continue;
235d9b58b30SMichal Simek
236d9b58b30SMichal Simek printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i,
237d9b58b30SMichal Simek le32_to_cpu(zynqhdr->interrupt_vectors[i]));
238d9b58b30SMichal Simek }
239d9b58b30SMichal Simek
240d9b58b30SMichal Simek for (i = 0; i < HEADER_REGINITS; i++) {
241d9b58b30SMichal Simek if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL)
242d9b58b30SMichal Simek break;
243d9b58b30SMichal Simek
244d9b58b30SMichal Simek if (i == 0)
245d9b58b30SMichal Simek printf("Custom Register Initialization:\n");
246d9b58b30SMichal Simek
247d9b58b30SMichal Simek printf(" @ 0x%08x -> 0x%08x\n",
248d9b58b30SMichal Simek le32_to_cpu(zynqhdr->register_init[i].address),
249d9b58b30SMichal Simek le32_to_cpu(zynqhdr->register_init[i].data));
250d9b58b30SMichal Simek }
251c85a6b79SMichal Simek
252e9dbfb32SAlexander Graf if (zynqhdr->image_header_table_offset) {
253e9dbfb32SAlexander Graf struct image_header_table *iht = (void *)ptr +
254e9dbfb32SAlexander Graf zynqhdr->image_header_table_offset;
255e9dbfb32SAlexander Graf struct partition_header *ph;
256e9dbfb32SAlexander Graf uint32_t ph_offset;
257e9dbfb32SAlexander Graf uint32_t next;
258e9dbfb32SAlexander Graf int i;
259e9dbfb32SAlexander Graf
260e9dbfb32SAlexander Graf ph_offset = le32_to_cpu(iht->partition_header_offset) * 4;
261e9dbfb32SAlexander Graf ph = (void *)ptr + ph_offset;
262e9dbfb32SAlexander Graf for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) {
263e9dbfb32SAlexander Graf next = le32_to_cpu(ph->next_partition_offset) * 4;
264e9dbfb32SAlexander Graf
265e9dbfb32SAlexander Graf /* Partition 0 is the base image itself */
266e9dbfb32SAlexander Graf if (i)
267e9dbfb32SAlexander Graf print_partition(ptr, ph);
268e9dbfb32SAlexander Graf
269e9dbfb32SAlexander Graf ph = (void *)ptr + next;
270e9dbfb32SAlexander Graf }
271e9dbfb32SAlexander Graf }
272e9dbfb32SAlexander Graf
273c85a6b79SMichal Simek free(dynamic_header);
274d9b58b30SMichal Simek }
275d9b58b30SMichal Simek
zynqmpimage_check_params(struct image_tool_params * params)276d9b58b30SMichal Simek static int zynqmpimage_check_params(struct image_tool_params *params)
277d9b58b30SMichal Simek {
278d9b58b30SMichal Simek if (!params)
279d9b58b30SMichal Simek return 0;
280d9b58b30SMichal Simek
281d9b58b30SMichal Simek if (params->addr != 0x0) {
282d9b58b30SMichal Simek fprintf(stderr, "Error: Load Address cannot be specified.\n");
283d9b58b30SMichal Simek return -1;
284d9b58b30SMichal Simek }
285d9b58b30SMichal Simek
286d9b58b30SMichal Simek /*
287d9b58b30SMichal Simek * If the entry point is specified ensure it is 64 byte aligned.
288d9b58b30SMichal Simek */
289d9b58b30SMichal Simek if (params->eflag && (params->ep % 64 != 0)) {
290d9b58b30SMichal Simek fprintf(stderr,
291d9b58b30SMichal Simek "Error: Entry Point must be aligned to a 64-byte boundary.\n");
292d9b58b30SMichal Simek return -1;
293d9b58b30SMichal Simek }
294d9b58b30SMichal Simek
295d9b58b30SMichal Simek return !(params->lflag || params->dflag);
296d9b58b30SMichal Simek }
297d9b58b30SMichal Simek
zynqmpimage_check_image_types(uint8_t type)298d9b58b30SMichal Simek static int zynqmpimage_check_image_types(uint8_t type)
299d9b58b30SMichal Simek {
300d9b58b30SMichal Simek if (type == IH_TYPE_ZYNQMPIMAGE)
301d9b58b30SMichal Simek return EXIT_SUCCESS;
302d9b58b30SMichal Simek return EXIT_FAILURE;
303d9b58b30SMichal Simek }
304d9b58b30SMichal Simek
fsize(FILE * fp)3056d0cbbd5SMichal Simek static uint32_t fsize(FILE *fp)
306c85a6b79SMichal Simek {
3076d0cbbd5SMichal Simek int size, ret, origin;
308c85a6b79SMichal Simek
3096d0cbbd5SMichal Simek origin = ftell(fp);
3106d0cbbd5SMichal Simek if (origin < 0) {
3116d0cbbd5SMichal Simek fprintf(stderr, "Incorrect file size\n");
3126d0cbbd5SMichal Simek fclose(fp);
3136d0cbbd5SMichal Simek exit(2);
3146d0cbbd5SMichal Simek }
3156d0cbbd5SMichal Simek
3166d0cbbd5SMichal Simek ret = fseek(fp, 0L, SEEK_END);
3176d0cbbd5SMichal Simek if (ret) {
3186d0cbbd5SMichal Simek fprintf(stderr, "Incorrect file SEEK_END\n");
3196d0cbbd5SMichal Simek fclose(fp);
3206d0cbbd5SMichal Simek exit(3);
3216d0cbbd5SMichal Simek }
3226d0cbbd5SMichal Simek
323c85a6b79SMichal Simek size = ftell(fp);
3246d0cbbd5SMichal Simek if (size < 0) {
3256d0cbbd5SMichal Simek fprintf(stderr, "Incorrect file size\n");
3266d0cbbd5SMichal Simek fclose(fp);
3276d0cbbd5SMichal Simek exit(4);
3286d0cbbd5SMichal Simek }
329c85a6b79SMichal Simek
330c85a6b79SMichal Simek /* going back */
3316d0cbbd5SMichal Simek ret = fseek(fp, origin, SEEK_SET);
3326d0cbbd5SMichal Simek if (ret) {
3336d0cbbd5SMichal Simek fprintf(stderr, "Incorrect file SEEK_SET to %d\n", origin);
3346d0cbbd5SMichal Simek fclose(fp);
3356d0cbbd5SMichal Simek exit(3);
3366d0cbbd5SMichal Simek }
337c85a6b79SMichal Simek
338c85a6b79SMichal Simek return size;
339c85a6b79SMichal Simek }
340c85a6b79SMichal Simek
zynqmpimage_pmufw(struct zynqmp_header * zynqhdr,const char * filename)341c85a6b79SMichal Simek static void zynqmpimage_pmufw(struct zynqmp_header *zynqhdr,
342c85a6b79SMichal Simek const char *filename)
343c85a6b79SMichal Simek {
344c85a6b79SMichal Simek uint32_t size;
345c85a6b79SMichal Simek
346c85a6b79SMichal Simek /* Setup PMU fw size */
347c85a6b79SMichal Simek zynqhdr->pfw_image_length = fsize(fpmu);
348c85a6b79SMichal Simek zynqhdr->total_pfw_image_length = zynqhdr->pfw_image_length;
349c85a6b79SMichal Simek
350c85a6b79SMichal Simek zynqhdr->image_size -= zynqhdr->pfw_image_length;
351c85a6b79SMichal Simek zynqhdr->image_stored_size -= zynqhdr->total_pfw_image_length;
352c85a6b79SMichal Simek
353c85a6b79SMichal Simek /* Read the whole PMUFW to the header */
354c85a6b79SMichal Simek size = fread(&zynqhdr->__reserved4[66], 1,
355c85a6b79SMichal Simek zynqhdr->pfw_image_length, fpmu);
356c85a6b79SMichal Simek if (size != zynqhdr->pfw_image_length) {
357c85a6b79SMichal Simek fprintf(stderr, "Cannot read PMUFW file: %s\n", filename);
358c85a6b79SMichal Simek fclose(fpmu);
359c85a6b79SMichal Simek exit(1);
360c85a6b79SMichal Simek }
361c85a6b79SMichal Simek
362c85a6b79SMichal Simek fclose(fpmu);
363c85a6b79SMichal Simek }
364c85a6b79SMichal Simek
zynqmpimage_parse_initparams(struct zynqmp_header * zynqhdr,const char * filename)3653b646080SMike Looijmans static void zynqmpimage_parse_initparams(struct zynqmp_header *zynqhdr,
3663b646080SMike Looijmans const char *filename)
3673b646080SMike Looijmans {
36856c7e801SMichal Simek FILE *fp;
3693b646080SMike Looijmans struct zynqmp_reginit reginit;
3703b646080SMike Looijmans unsigned int reg_count = 0;
371ebe0f53fSMichal Simek int r, err;
37256c7e801SMichal Simek struct stat path_stat;
3733b646080SMike Looijmans
37456c7e801SMichal Simek /* Expect a table of register-value pairs, e.g. "0x12345678 0x4321" */
37556c7e801SMichal Simek fp = fopen(filename, "r");
3763b646080SMike Looijmans if (!fp) {
3773b646080SMike Looijmans fprintf(stderr, "Cannot open initparams file: %s\n", filename);
3783b646080SMike Looijmans exit(1);
3793b646080SMike Looijmans }
380ebe0f53fSMichal Simek
381ebe0f53fSMichal Simek err = fstat(fileno(fp), &path_stat);
382ac71d410SMichal Simek if (err) {
383ac71d410SMichal Simek fclose(fp);
384ebe0f53fSMichal Simek return;
385ac71d410SMichal Simek }
386ebe0f53fSMichal Simek
387ac71d410SMichal Simek if (!S_ISREG(path_stat.st_mode)) {
388ac71d410SMichal Simek fclose(fp);
389ebe0f53fSMichal Simek return;
390ac71d410SMichal Simek }
391ebe0f53fSMichal Simek
3923b646080SMike Looijmans do {
3933b646080SMike Looijmans r = fscanf(fp, "%x %x", ®init.address, ®init.data);
3943b646080SMike Looijmans if (r == 2) {
3953b646080SMike Looijmans zynqhdr->register_init[reg_count] = reginit;
3963b646080SMike Looijmans ++reg_count;
3973b646080SMike Looijmans }
3983b646080SMike Looijmans r = fscanf(fp, "%*[^\n]\n"); /* Skip to next line */
3993b646080SMike Looijmans } while ((r != EOF) && (reg_count < HEADER_REGINITS));
4003b646080SMike Looijmans fclose(fp);
4013b646080SMike Looijmans }
4023b646080SMike Looijmans
zynqmpimage_set_header(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)403d9b58b30SMichal Simek static void zynqmpimage_set_header(void *ptr, struct stat *sbuf, int ifd,
404d9b58b30SMichal Simek struct image_tool_params *params)
405d9b58b30SMichal Simek {
406d9b58b30SMichal Simek struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
407d9b58b30SMichal Simek zynqmpimage_default_header(zynqhdr);
408d9b58b30SMichal Simek
409d9b58b30SMichal Simek /* place image directly after header */
410d9b58b30SMichal Simek zynqhdr->image_offset =
411d9b58b30SMichal Simek cpu_to_le32((uint32_t)sizeof(struct zynqmp_header));
412d9b58b30SMichal Simek zynqhdr->image_size = cpu_to_le32(params->file_size -
413d9b58b30SMichal Simek sizeof(struct zynqmp_header));
414d9b58b30SMichal Simek zynqhdr->image_stored_size = zynqhdr->image_size;
415d9b58b30SMichal Simek zynqhdr->image_load = 0xfffc0000;
416d9b58b30SMichal Simek if (params->eflag)
417d9b58b30SMichal Simek zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep);
418d9b58b30SMichal Simek
419c85a6b79SMichal Simek /* PMUFW */
420c85a6b79SMichal Simek if (fpmu)
421c85a6b79SMichal Simek zynqmpimage_pmufw(zynqhdr, params->imagename);
422c85a6b79SMichal Simek
4233b646080SMike Looijmans /* User can pass in text file with init list */
4243b646080SMike Looijmans if (strlen(params->imagename2))
4253b646080SMike Looijmans zynqmpimage_parse_initparams(zynqhdr, params->imagename2);
4263b646080SMike Looijmans
427d9b58b30SMichal Simek zynqhdr->checksum = zynqmpimage_checksum(zynqhdr);
428d9b58b30SMichal Simek }
429d9b58b30SMichal Simek
zynqmpimage_vrec_header(struct image_tool_params * params,struct image_type_params * tparams)430c85a6b79SMichal Simek static int zynqmpimage_vrec_header(struct image_tool_params *params,
431c85a6b79SMichal Simek struct image_type_params *tparams)
432c85a6b79SMichal Simek {
433c85a6b79SMichal Simek struct stat path_stat;
434c85a6b79SMichal Simek char *filename = params->imagename;
435c85a6b79SMichal Simek int err;
436c85a6b79SMichal Simek
437c85a6b79SMichal Simek /* Handle static case without PMUFW */
438c85a6b79SMichal Simek tparams->header_size = sizeof(struct zynqmp_header);
439c85a6b79SMichal Simek tparams->hdr = (void *)&zynqmpimage_header;
440c85a6b79SMichal Simek
441c85a6b79SMichal Simek /* PMUFW name is passed via params->imagename */
442c85a6b79SMichal Simek if (strlen(filename) == 0)
443c85a6b79SMichal Simek return EXIT_SUCCESS;
444c85a6b79SMichal Simek
445c85a6b79SMichal Simek fpmu = fopen(filename, "r");
446c85a6b79SMichal Simek if (!fpmu) {
447c85a6b79SMichal Simek fprintf(stderr, "Cannot open PMUFW file: %s\n", filename);
448c85a6b79SMichal Simek return EXIT_FAILURE;
449c85a6b79SMichal Simek }
450c85a6b79SMichal Simek
451c85a6b79SMichal Simek err = fstat(fileno(fpmu), &path_stat);
452c85a6b79SMichal Simek if (err) {
453c85a6b79SMichal Simek fclose(fpmu);
454c85a6b79SMichal Simek fpmu = NULL;
455c85a6b79SMichal Simek return EXIT_FAILURE;
456c85a6b79SMichal Simek }
457c85a6b79SMichal Simek
458c85a6b79SMichal Simek if (!S_ISREG(path_stat.st_mode)) {
459c85a6b79SMichal Simek fclose(fpmu);
460c85a6b79SMichal Simek fpmu = NULL;
461c85a6b79SMichal Simek return EXIT_FAILURE;
462c85a6b79SMichal Simek }
463c85a6b79SMichal Simek
464c85a6b79SMichal Simek /* Increase header size by PMUFW file size */
465c85a6b79SMichal Simek tparams->header_size += fsize(fpmu);
466c85a6b79SMichal Simek
467c85a6b79SMichal Simek /* Allocate buffer with space for PMUFW */
468c85a6b79SMichal Simek dynamic_header = calloc(1, tparams->header_size);
469c85a6b79SMichal Simek tparams->hdr = dynamic_header;
470c85a6b79SMichal Simek
471c85a6b79SMichal Simek return EXIT_SUCCESS;
472c85a6b79SMichal Simek }
473c85a6b79SMichal Simek
474d9b58b30SMichal Simek U_BOOT_IMAGE_TYPE(
475d9b58b30SMichal Simek zynqmpimage,
476d9b58b30SMichal Simek "Xilinx ZynqMP Boot Image support",
477d9b58b30SMichal Simek sizeof(struct zynqmp_header),
478d9b58b30SMichal Simek (void *)&zynqmpimage_header,
479d9b58b30SMichal Simek zynqmpimage_check_params,
480d9b58b30SMichal Simek zynqmpimage_verify_header,
481d9b58b30SMichal Simek zynqmpimage_print_header,
482d9b58b30SMichal Simek zynqmpimage_set_header,
483d9b58b30SMichal Simek NULL,
484d9b58b30SMichal Simek zynqmpimage_check_image_types,
485d9b58b30SMichal Simek NULL,
486c85a6b79SMichal Simek zynqmpimage_vrec_header
487d9b58b30SMichal Simek );
488