xref: /openbmc/u-boot/tools/zynqmpimage.c (revision 3b52847a451a81001b578353e793d7d9739b69d6)
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", &reginit.address, &reginit.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