xref: /openbmc/u-boot/tools/zynqimage.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
266eef1e7SNathan Rossi /*
366eef1e7SNathan Rossi  * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com>
466eef1e7SNathan Rossi  *
566eef1e7SNathan Rossi  * The following Boot Header format/structures and values are defined in the
666eef1e7SNathan Rossi  * following documents:
766eef1e7SNathan Rossi  *   * Xilinx Zynq-7000 Technical Reference Manual (Section 6.3)
866eef1e7SNathan Rossi  *   * Xilinx Zynq-7000 Software Developers Guide (Appendix A.7 and A.8)
966eef1e7SNathan Rossi  *
1066eef1e7SNathan Rossi  * Expected Header Size = 0x8C0
1166eef1e7SNathan Rossi  * Forced as 'little' endian, 32-bit words
1266eef1e7SNathan Rossi  *
1366eef1e7SNathan Rossi  *  0x  0 - Interrupt Table (8 words)
1466eef1e7SNathan Rossi  *  ...     (Default value = 0xeafffffe)
1566eef1e7SNathan Rossi  *  0x 1f
1666eef1e7SNathan Rossi  *  0x 20 - Width Detection
1766eef1e7SNathan Rossi  *         * DEFAULT_WIDTHDETECTION    0xaa995566
1866eef1e7SNathan Rossi  *  0x 24 - Image Identifier
1966eef1e7SNathan Rossi  *         * DEFAULT_IMAGEIDENTIFIER   0x584c4e58
2066eef1e7SNathan Rossi  *  0x 28 - Encryption
2166eef1e7SNathan Rossi  *         * 0x00000000 - None
2266eef1e7SNathan Rossi  *         * 0xa5c3c5a3 - eFuse
2366eef1e7SNathan Rossi  *         * 0x3a5c3c5a - bbRam
2466eef1e7SNathan Rossi  *  0x 2C - User Field
2566eef1e7SNathan Rossi  *  0x 30 - Image Offset
2666eef1e7SNathan Rossi  *  0x 34 - Image Size
2766eef1e7SNathan Rossi  *  0x 38 - Reserved (0x00000000) (according to spec)
2866eef1e7SNathan Rossi  *          * FSBL defines this field for Image Destination Address.
2966eef1e7SNathan Rossi  *  0x 3C - Image Load
3066eef1e7SNathan Rossi  *  0x 40 - Image Stored Size
3166eef1e7SNathan Rossi  *  0x 44 - Reserved (0x00000000) (according to spec)
3266eef1e7SNathan Rossi  *          * FSBL defines this field for QSPI configuration Data.
3366eef1e7SNathan Rossi  *  0x 48 - Checksum
3466eef1e7SNathan Rossi  *  0x 4c - Unused (21 words)
3566eef1e7SNathan Rossi  *  ...
3666eef1e7SNathan Rossi  *  0x 9c
3766eef1e7SNathan Rossi  *  0x a0 - Register Initialization, 256 Address and Data word pairs
3866eef1e7SNathan Rossi  *         * List is terminated with an address of 0xffffffff or
3966eef1e7SNathan Rossi  *  ...    * at the max number of entries
4066eef1e7SNathan Rossi  *  0x89c
4166eef1e7SNathan Rossi  *  0x8a0 - Unused (8 words)
4266eef1e7SNathan Rossi  *  ...
4366eef1e7SNathan Rossi  *  0x8bf
4466eef1e7SNathan Rossi  *  0x8c0 - Data/Image starts here or above
4566eef1e7SNathan Rossi  */
4666eef1e7SNathan Rossi 
4766eef1e7SNathan Rossi #include "imagetool.h"
4866eef1e7SNathan Rossi #include "mkimage.h"
4966eef1e7SNathan Rossi #include <image.h>
5066eef1e7SNathan Rossi 
5166eef1e7SNathan Rossi #define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe))
5266eef1e7SNathan Rossi #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff))
5366eef1e7SNathan Rossi #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566))
5466eef1e7SNathan Rossi #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58))
5566eef1e7SNathan Rossi 
5666eef1e7SNathan Rossi enum {
5766eef1e7SNathan Rossi 	ENCRYPTION_EFUSE = 0xa5c3c5a3,
5866eef1e7SNathan Rossi 	ENCRYPTION_BBRAM = 0x3a5c3c5a,
5966eef1e7SNathan Rossi 	ENCRYPTION_NONE = 0x0,
6066eef1e7SNathan Rossi };
6166eef1e7SNathan Rossi 
6266eef1e7SNathan Rossi struct zynq_reginit {
6366eef1e7SNathan Rossi 	uint32_t address;
6466eef1e7SNathan Rossi 	uint32_t data;
6566eef1e7SNathan Rossi };
6666eef1e7SNathan Rossi 
6766eef1e7SNathan Rossi #define HEADER_INTERRUPT_VECTORS 8
6866eef1e7SNathan Rossi #define HEADER_REGINITS 256
6966eef1e7SNathan Rossi 
7066eef1e7SNathan Rossi struct zynq_header {
7166eef1e7SNathan Rossi 	uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */
7266eef1e7SNathan Rossi 	uint32_t width_detection; /* 0x20 */
7366eef1e7SNathan Rossi 	uint32_t image_identifier; /* 0x24 */
7466eef1e7SNathan Rossi 	uint32_t encryption; /* 0x28 */
7566eef1e7SNathan Rossi 	uint32_t user_field; /* 0x2c */
7666eef1e7SNathan Rossi 	uint32_t image_offset; /* 0x30 */
7766eef1e7SNathan Rossi 	uint32_t image_size; /* 0x34 */
7866eef1e7SNathan Rossi 	uint32_t __reserved1; /* 0x38 */
7966eef1e7SNathan Rossi 	uint32_t image_load; /* 0x3c */
8066eef1e7SNathan Rossi 	uint32_t image_stored_size; /* 0x40 */
8166eef1e7SNathan Rossi 	uint32_t __reserved2; /* 0x44 */
8266eef1e7SNathan Rossi 	uint32_t checksum; /* 0x48 */
8366eef1e7SNathan Rossi 	uint32_t __reserved3[21]; /* 0x4c */
8466eef1e7SNathan Rossi 	struct zynq_reginit register_init[HEADER_REGINITS]; /* 0xa0 */
8566eef1e7SNathan Rossi 	uint32_t __reserved4[8]; /* 0x8a0 */
8666eef1e7SNathan Rossi };
8766eef1e7SNathan Rossi 
8866eef1e7SNathan Rossi static struct zynq_header zynqimage_header;
8966eef1e7SNathan Rossi 
zynqimage_checksum(struct zynq_header * ptr)9066eef1e7SNathan Rossi static uint32_t zynqimage_checksum(struct zynq_header *ptr)
9166eef1e7SNathan Rossi {
9266eef1e7SNathan Rossi 	uint32_t checksum = 0;
9366eef1e7SNathan Rossi 
9466eef1e7SNathan Rossi 	if (ptr == NULL)
9566eef1e7SNathan Rossi 		return 0;
9666eef1e7SNathan Rossi 
9766eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->width_detection);
9866eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->image_identifier);
9966eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->encryption);
10066eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->user_field);
10166eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->image_offset);
10266eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->image_size);
10366eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->__reserved1);
10466eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->image_load);
10566eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->image_stored_size);
10666eef1e7SNathan Rossi 	checksum += le32_to_cpu(ptr->__reserved2);
10766eef1e7SNathan Rossi 	checksum = ~checksum;
10866eef1e7SNathan Rossi 
10966eef1e7SNathan Rossi 	return cpu_to_le32(checksum);
11066eef1e7SNathan Rossi }
11166eef1e7SNathan Rossi 
zynqimage_default_header(struct zynq_header * ptr)11266eef1e7SNathan Rossi static void zynqimage_default_header(struct zynq_header *ptr)
11366eef1e7SNathan Rossi {
11466eef1e7SNathan Rossi 	int i;
11566eef1e7SNathan Rossi 
11666eef1e7SNathan Rossi 	if (ptr == NULL)
11766eef1e7SNathan Rossi 		return;
11866eef1e7SNathan Rossi 
11966eef1e7SNathan Rossi 	ptr->width_detection = HEADER_WIDTHDETECTION;
12066eef1e7SNathan Rossi 	ptr->image_identifier = HEADER_IMAGEIDENTIFIER;
12166eef1e7SNathan Rossi 	ptr->encryption = cpu_to_le32(ENCRYPTION_NONE);
12266eef1e7SNathan Rossi 
12366eef1e7SNathan Rossi 	/* Setup not-supported/constant/reserved fields */
12466eef1e7SNathan Rossi 	for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++)
12566eef1e7SNathan Rossi 		ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT;
12666eef1e7SNathan Rossi 
12766eef1e7SNathan Rossi 	for (i = 0; i < HEADER_REGINITS; i++) {
12866eef1e7SNathan Rossi 		ptr->register_init[i].address = HEADER_REGINIT_NULL;
12966eef1e7SNathan Rossi 		ptr->register_init[i].data = HEADER_REGINIT_NULL;
13066eef1e7SNathan Rossi 	}
13166eef1e7SNathan Rossi 
13266eef1e7SNathan Rossi 	/*
13366eef1e7SNathan Rossi 	 * Certain reserved fields are required to be set to 0, ensure they are
13466eef1e7SNathan Rossi 	 * set as such.
13566eef1e7SNathan Rossi 	 */
13666eef1e7SNathan Rossi 	ptr->__reserved1 = 0x0;
13766eef1e7SNathan Rossi 	ptr->__reserved2 = 0x0;
13866eef1e7SNathan Rossi }
13966eef1e7SNathan Rossi 
14066eef1e7SNathan Rossi /* mkimage glue functions */
zynqimage_verify_header(unsigned char * ptr,int image_size,struct image_tool_params * params)14166eef1e7SNathan Rossi static int zynqimage_verify_header(unsigned char *ptr, int image_size,
14266eef1e7SNathan Rossi 		struct image_tool_params *params)
14366eef1e7SNathan Rossi {
14466eef1e7SNathan Rossi 	struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
14566eef1e7SNathan Rossi 
14666eef1e7SNathan Rossi 	if (image_size < sizeof(struct zynq_header))
14766eef1e7SNathan Rossi 		return -1;
14866eef1e7SNathan Rossi 
149d28baea0SMichal Simek 	if (zynqhdr->__reserved1 != 0)
150d28baea0SMichal Simek 		return -1;
151d28baea0SMichal Simek 
152d28baea0SMichal Simek 	if (zynqhdr->__reserved2 != 0)
153d28baea0SMichal Simek 		return -1;
154d28baea0SMichal Simek 
15566eef1e7SNathan Rossi 	if (zynqhdr->width_detection != HEADER_WIDTHDETECTION)
15666eef1e7SNathan Rossi 		return -1;
15766eef1e7SNathan Rossi 	if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER)
15866eef1e7SNathan Rossi 		return -1;
15966eef1e7SNathan Rossi 
16066eef1e7SNathan Rossi 	if (zynqimage_checksum(zynqhdr) != zynqhdr->checksum)
16166eef1e7SNathan Rossi 		return -1;
16266eef1e7SNathan Rossi 
16366eef1e7SNathan Rossi 	return 0;
16466eef1e7SNathan Rossi }
16566eef1e7SNathan Rossi 
zynqimage_print_header(const void * ptr)16666eef1e7SNathan Rossi static void zynqimage_print_header(const void *ptr)
16766eef1e7SNathan Rossi {
16866eef1e7SNathan Rossi 	struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
16966eef1e7SNathan Rossi 	int i;
17066eef1e7SNathan Rossi 
17166eef1e7SNathan Rossi 	printf("Image Type   : Xilinx Zynq Boot Image support\n");
17266eef1e7SNathan Rossi 	printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset));
17366eef1e7SNathan Rossi 	printf("Image Size   : %lu bytes (%lu bytes packed)\n",
17466eef1e7SNathan Rossi 	       (unsigned long)le32_to_cpu(zynqhdr->image_size),
17566eef1e7SNathan Rossi 	       (unsigned long)le32_to_cpu(zynqhdr->image_stored_size));
17666eef1e7SNathan Rossi 	printf("Image Load   : 0x%08x\n", le32_to_cpu(zynqhdr->image_load));
17766eef1e7SNathan Rossi 	printf("User Field   : 0x%08x\n", le32_to_cpu(zynqhdr->user_field));
17866eef1e7SNathan Rossi 	printf("Checksum     : 0x%08x\n", le32_to_cpu(zynqhdr->checksum));
17966eef1e7SNathan Rossi 
18066eef1e7SNathan Rossi 	for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) {
18166eef1e7SNathan Rossi 		if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT)
18266eef1e7SNathan Rossi 			continue;
18366eef1e7SNathan Rossi 
18466eef1e7SNathan Rossi 		printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i,
18566eef1e7SNathan Rossi 		       le32_to_cpu(zynqhdr->interrupt_vectors[i]));
18666eef1e7SNathan Rossi 	}
18766eef1e7SNathan Rossi 
18866eef1e7SNathan Rossi 	for (i = 0; i < HEADER_REGINITS; i++) {
18966eef1e7SNathan Rossi 		if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL)
19066eef1e7SNathan Rossi 			break;
19166eef1e7SNathan Rossi 
19266eef1e7SNathan Rossi 		if (i == 0)
19366eef1e7SNathan Rossi 			printf("Custom Register Initialization:\n");
19466eef1e7SNathan Rossi 
19566eef1e7SNathan Rossi 		printf("    @ 0x%08x -> 0x%08x\n",
19666eef1e7SNathan Rossi 		       le32_to_cpu(zynqhdr->register_init[i].address),
19766eef1e7SNathan Rossi 		       le32_to_cpu(zynqhdr->register_init[i].data));
19866eef1e7SNathan Rossi 	}
19966eef1e7SNathan Rossi }
20066eef1e7SNathan Rossi 
zynqimage_check_params(struct image_tool_params * params)20166eef1e7SNathan Rossi static int zynqimage_check_params(struct image_tool_params *params)
20266eef1e7SNathan Rossi {
20366eef1e7SNathan Rossi 	if (!params)
20466eef1e7SNathan Rossi 		return 0;
20566eef1e7SNathan Rossi 
20666eef1e7SNathan Rossi 	if (params->addr != 0x0) {
20766eef1e7SNathan Rossi 		fprintf(stderr, "Error: Load Address cannot be specified.\n");
20866eef1e7SNathan Rossi 		return -1;
20966eef1e7SNathan Rossi 	}
21066eef1e7SNathan Rossi 
21166eef1e7SNathan Rossi 	/*
21266eef1e7SNathan Rossi 	 * If the entry point is specified ensure it is 64 byte aligned.
21366eef1e7SNathan Rossi 	 */
21466eef1e7SNathan Rossi 	if (params->eflag && (params->ep % 64 != 0)) {
21566eef1e7SNathan Rossi 		fprintf(stderr,
21666eef1e7SNathan Rossi 			"Error: Entry Point must be aligned to a 64-byte boundary.\n");
21766eef1e7SNathan Rossi 		return -1;
21866eef1e7SNathan Rossi 	}
21966eef1e7SNathan Rossi 
220bc366050SNathan Rossi 	return !(params->lflag || params->dflag);
22166eef1e7SNathan Rossi }
22266eef1e7SNathan Rossi 
zynqimage_check_image_types(uint8_t type)22366eef1e7SNathan Rossi static int zynqimage_check_image_types(uint8_t type)
22466eef1e7SNathan Rossi {
22566eef1e7SNathan Rossi 	if (type == IH_TYPE_ZYNQIMAGE)
22666eef1e7SNathan Rossi 		return EXIT_SUCCESS;
22766eef1e7SNathan Rossi 	return EXIT_FAILURE;
22866eef1e7SNathan Rossi }
22966eef1e7SNathan Rossi 
zynqimage_parse_initparams(struct zynq_header * zynqhdr,const char * filename)2303b646080SMike Looijmans static void zynqimage_parse_initparams(struct zynq_header *zynqhdr,
2313b646080SMike Looijmans 	const char *filename)
2323b646080SMike Looijmans {
233ebe0f53fSMichal Simek 	FILE *fp;
2343b646080SMike Looijmans 	struct zynq_reginit reginit;
2353b646080SMike Looijmans 	unsigned int reg_count = 0;
236ebe0f53fSMichal Simek 	int r, err;
237ebe0f53fSMichal Simek 	struct stat path_stat;
2383b646080SMike Looijmans 
239ebe0f53fSMichal Simek 	/* Expect a table of register-value pairs, e.g. "0x12345678 0x4321" */
240ebe0f53fSMichal Simek 	fp = fopen(filename, "r");
2413b646080SMike Looijmans 	if (!fp) {
2423b646080SMike Looijmans 		fprintf(stderr, "Cannot open initparams file: %s\n", filename);
2433b646080SMike Looijmans 		exit(1);
2443b646080SMike Looijmans 	}
245ebe0f53fSMichal Simek 
246ebe0f53fSMichal Simek 	err = fstat(fileno(fp), &path_stat);
247ac71d410SMichal Simek 	if (err) {
248ac71d410SMichal Simek 		fclose(fp);
249ebe0f53fSMichal Simek 		return;
250ac71d410SMichal Simek 	}
251ebe0f53fSMichal Simek 
252ac71d410SMichal Simek 	if (!S_ISREG(path_stat.st_mode)) {
253ac71d410SMichal Simek 		fclose(fp);
254ebe0f53fSMichal Simek 		return;
255ac71d410SMichal Simek 	}
256ebe0f53fSMichal Simek 
2573b646080SMike Looijmans 	do {
2583b646080SMike Looijmans 		r = fscanf(fp, "%x %x", &reginit.address, &reginit.data);
2593b646080SMike Looijmans 		if (r == 2) {
2603b646080SMike Looijmans 			zynqhdr->register_init[reg_count] = reginit;
2613b646080SMike Looijmans 			++reg_count;
2623b646080SMike Looijmans 		}
2633b646080SMike Looijmans 		r = fscanf(fp, "%*[^\n]\n"); /* Skip to next line */
2643b646080SMike Looijmans 	} while ((r != EOF) && (reg_count < HEADER_REGINITS));
2653b646080SMike Looijmans 	fclose(fp);
2663b646080SMike Looijmans }
2673b646080SMike Looijmans 
zynqimage_set_header(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)26866eef1e7SNathan Rossi static void zynqimage_set_header(void *ptr, struct stat *sbuf, int ifd,
26966eef1e7SNathan Rossi 		struct image_tool_params *params)
27066eef1e7SNathan Rossi {
27166eef1e7SNathan Rossi 	struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
27266eef1e7SNathan Rossi 	zynqimage_default_header(zynqhdr);
27366eef1e7SNathan Rossi 
27466eef1e7SNathan Rossi 	/* place image directly after header */
27566eef1e7SNathan Rossi 	zynqhdr->image_offset =
27666eef1e7SNathan Rossi 		cpu_to_le32((uint32_t)sizeof(struct zynq_header));
27766eef1e7SNathan Rossi 	zynqhdr->image_size = cpu_to_le32((uint32_t)sbuf->st_size);
27866eef1e7SNathan Rossi 	zynqhdr->image_stored_size = zynqhdr->image_size;
27966eef1e7SNathan Rossi 	zynqhdr->image_load = 0x0;
28066eef1e7SNathan Rossi 	if (params->eflag)
28166eef1e7SNathan Rossi 		zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep);
28266eef1e7SNathan Rossi 
2833b646080SMike Looijmans 	/* User can pass in text file with init list */
2843b646080SMike Looijmans 	if (strlen(params->imagename2))
2853b646080SMike Looijmans 		zynqimage_parse_initparams(zynqhdr, params->imagename2);
2863b646080SMike Looijmans 
28766eef1e7SNathan Rossi 	zynqhdr->checksum = zynqimage_checksum(zynqhdr);
28866eef1e7SNathan Rossi }
28966eef1e7SNathan Rossi 
29066eef1e7SNathan Rossi U_BOOT_IMAGE_TYPE(
29166eef1e7SNathan Rossi 	zynqimage,
29266eef1e7SNathan Rossi 	"Xilinx Zynq Boot Image support",
29366eef1e7SNathan Rossi 	sizeof(struct zynq_header),
29466eef1e7SNathan Rossi 	(void *)&zynqimage_header,
29566eef1e7SNathan Rossi 	zynqimage_check_params,
29666eef1e7SNathan Rossi 	zynqimage_verify_header,
29766eef1e7SNathan Rossi 	zynqimage_print_header,
29866eef1e7SNathan Rossi 	zynqimage_set_header,
29966eef1e7SNathan Rossi 	NULL,
30066eef1e7SNathan Rossi 	zynqimage_check_image_types,
30166eef1e7SNathan Rossi 	NULL,
30266eef1e7SNathan Rossi 	NULL
30366eef1e7SNathan Rossi );
304