xref: /openbmc/u-boot/tools/mkexynosspl.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
281e35203SChander Kashyap /*
381e35203SChander Kashyap  * Copyright (C) 2012 Samsung Electronics
481e35203SChander Kashyap  */
581e35203SChander Kashyap 
681e35203SChander Kashyap #include <stdio.h>
781e35203SChander Kashyap #include <stdlib.h>
881e35203SChander Kashyap #include <unistd.h>
981e35203SChander Kashyap #include <fcntl.h>
1081e35203SChander Kashyap #include <errno.h>
1181e35203SChander Kashyap #include <string.h>
1281e35203SChander Kashyap #include <sys/stat.h>
1381e35203SChander Kashyap #include <compiler.h>
1481e35203SChander Kashyap 
1581e35203SChander Kashyap #define CHECKSUM_OFFSET		(14*1024-4)
1681e35203SChander Kashyap #define FILE_PERM		(S_IRUSR | S_IWUSR | S_IRGRP \
1781e35203SChander Kashyap 				| S_IWGRP | S_IROTH | S_IWOTH)
1881e35203SChander Kashyap /*
190fcac1abSRajeshwari Birje  * Requirement for the fixed size SPL header:
200fcac1abSRajeshwari Birje  * IROM code reads first (CHECKSUM_OFFSET + 4) bytes from boot device. It then
210fcac1abSRajeshwari Birje  * calculates the checksum of CHECKSUM_OFFSET bytes and compares with data at
220fcac1abSRajeshwari Birje  * CHECKSUM_OFFSET location.
2381e35203SChander Kashyap  *
240fcac1abSRajeshwari Birje  * Requirement for the variable size SPL header:
2581e35203SChander Kashyap 
260fcac1abSRajeshwari Birje  * IROM code reads the below header to find out the size of the blob (total
270fcac1abSRajeshwari Birje  * size, header size included) and its checksum. Then it reads the rest of the
280fcac1abSRajeshwari Birje  * blob [i.e size - sizeof(struct var_size_header) bytes], calculates the
290fcac1abSRajeshwari Birje  * checksum and compares it with value read from the header.
300fcac1abSRajeshwari Birje  */
310fcac1abSRajeshwari Birje struct var_size_header {
320fcac1abSRajeshwari Birje 	uint32_t spl_size;
330fcac1abSRajeshwari Birje 	uint32_t spl_checksum;
340fcac1abSRajeshwari Birje 	uint32_t reserved[2];
350fcac1abSRajeshwari Birje };
360fcac1abSRajeshwari Birje 
370fcac1abSRajeshwari Birje static const char *prog_name;
380fcac1abSRajeshwari Birje 
write_to_file(int ofd,void * buffer,int size)390fcac1abSRajeshwari Birje static void write_to_file(int ofd, void *buffer, int size)
400fcac1abSRajeshwari Birje {
410fcac1abSRajeshwari Birje 	if (write(ofd, buffer, size) == size)
420fcac1abSRajeshwari Birje 		return;
430fcac1abSRajeshwari Birje 
440fcac1abSRajeshwari Birje 	fprintf(stderr, "%s: Failed to write to output file: %s\n",
450fcac1abSRajeshwari Birje 		prog_name, strerror(errno));
460fcac1abSRajeshwari Birje 	exit(EXIT_FAILURE);
470fcac1abSRajeshwari Birje }
480fcac1abSRajeshwari Birje 
490fcac1abSRajeshwari Birje /*
500fcac1abSRajeshwari Birje  * The argv is expected to include one optional parameter and two filenames:
510fcac1abSRajeshwari Birje  * [--vs] IN OUT
520fcac1abSRajeshwari Birje  *
530fcac1abSRajeshwari Birje  * --vs - turns on the variable size SPL mode
540fcac1abSRajeshwari Birje  * IN  - the u-boot SPL binary, usually u-boot-spl.bin
550fcac1abSRajeshwari Birje  * OUT - the prepared SPL blob, usually ${BOARD}-spl.bin
560fcac1abSRajeshwari Birje  *
570fcac1abSRajeshwari Birje  * This utility first reads the "u-boot-spl.bin" into a buffer. In case of
580fcac1abSRajeshwari Birje  * fixed size SPL the buffer size is exactly CHECKSUM_OFFSET (such that
590fcac1abSRajeshwari Birje  * smaller u-boot-spl.bin gets padded with 0xff bytes, the larger than limit
600fcac1abSRajeshwari Birje  * u-boot-spl.bin causes an error). For variable size SPL the buffer size is
610fcac1abSRajeshwari Birje  * eqaul to size of the IN file.
620fcac1abSRajeshwari Birje  *
630fcac1abSRajeshwari Birje  * Then it calculates checksum of the buffer by just summing up all bytes.
640fcac1abSRajeshwari Birje  * Then
650fcac1abSRajeshwari Birje  *
660fcac1abSRajeshwari Birje  * - for fixed size SPL the buffer is written into the output file and the
670fcac1abSRajeshwari Birje  *   checksum is appended to the file in little endian format, which results
680fcac1abSRajeshwari Birje  *   in checksum added exactly at CHECKSUM_OFFSET.
690fcac1abSRajeshwari Birje  *
700fcac1abSRajeshwari Birje  * - for variable size SPL the checksum and file size are stored in the
710fcac1abSRajeshwari Birje  *   var_size_header structure (again, in little endian format) and the
720fcac1abSRajeshwari Birje  *   structure is written into the output file. Then the buffer is written
730fcac1abSRajeshwari Birje  *   into the output file.
740fcac1abSRajeshwari Birje  */
main(int argc,char ** argv)7581e35203SChander Kashyap int main(int argc, char **argv)
7681e35203SChander Kashyap {
770fcac1abSRajeshwari Birje 	unsigned char *buffer;
7881e35203SChander Kashyap 	int i, ifd, ofd;
7981e35203SChander Kashyap 	uint32_t checksum = 0;
8081e35203SChander Kashyap 	off_t	len;
810fcac1abSRajeshwari Birje 	int	var_size_flag, read_size, count;
8281e35203SChander Kashyap 	struct stat stat;
830fcac1abSRajeshwari Birje 	const int if_index = argc - 2; /* Input file name index in argv. */
840fcac1abSRajeshwari Birje 	const int of_index = argc - 1; /* Output file name index in argv. */
8581e35203SChander Kashyap 
860fcac1abSRajeshwari Birje 	/* Strip path off the program name. */
870fcac1abSRajeshwari Birje 	prog_name = strrchr(argv[0], '/');
880fcac1abSRajeshwari Birje 	if (prog_name)
890fcac1abSRajeshwari Birje 		prog_name++;
900fcac1abSRajeshwari Birje 	else
910fcac1abSRajeshwari Birje 		prog_name = argv[0];
920fcac1abSRajeshwari Birje 
930fcac1abSRajeshwari Birje 	if ((argc < 3) ||
940fcac1abSRajeshwari Birje 	    (argc > 4) ||
950fcac1abSRajeshwari Birje 	    ((argc == 4) && strcmp(argv[1], "--vs"))) {
960fcac1abSRajeshwari Birje 		fprintf(stderr, "Usage: %s [--vs] <infile> <outfile>\n",
970fcac1abSRajeshwari Birje 			prog_name);
9881e35203SChander Kashyap 		exit(EXIT_FAILURE);
9981e35203SChander Kashyap 	}
10081e35203SChander Kashyap 
1010fcac1abSRajeshwari Birje 	/* four args mean variable size SPL wrapper is required */
1020fcac1abSRajeshwari Birje 	var_size_flag = (argc == 4);
1030fcac1abSRajeshwari Birje 
1040fcac1abSRajeshwari Birje 	ifd = open(argv[if_index], O_RDONLY);
10581e35203SChander Kashyap 	if (ifd < 0) {
10681e35203SChander Kashyap 		fprintf(stderr, "%s: Can't open %s: %s\n",
1070fcac1abSRajeshwari Birje 			prog_name, argv[if_index], strerror(errno));
10881e35203SChander Kashyap 		exit(EXIT_FAILURE);
10981e35203SChander Kashyap 	}
11081e35203SChander Kashyap 
1110fcac1abSRajeshwari Birje 	ofd = open(argv[of_index], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
112310ae37eSThomas Huth 	if (ofd < 0) {
11381e35203SChander Kashyap 		fprintf(stderr, "%s: Can't open %s: %s\n",
1140fcac1abSRajeshwari Birje 			prog_name, argv[of_index], strerror(errno));
11581e35203SChander Kashyap 		exit(EXIT_FAILURE);
11681e35203SChander Kashyap 	}
11781e35203SChander Kashyap 
11881e35203SChander Kashyap 	if (fstat(ifd, &stat)) {
11981e35203SChander Kashyap 		fprintf(stderr, "%s: Unable to get size of %s: %s\n",
1200fcac1abSRajeshwari Birje 			prog_name, argv[if_index], strerror(errno));
12181e35203SChander Kashyap 		exit(EXIT_FAILURE);
12281e35203SChander Kashyap 	}
12381e35203SChander Kashyap 
12481e35203SChander Kashyap 	len = stat.st_size;
12581e35203SChander Kashyap 
1260fcac1abSRajeshwari Birje 	if (var_size_flag) {
1270fcac1abSRajeshwari Birje 		read_size = len;
1280fcac1abSRajeshwari Birje 		count = len;
1290fcac1abSRajeshwari Birje 	} else {
1300fcac1abSRajeshwari Birje 		if (len > CHECKSUM_OFFSET) {
1310fcac1abSRajeshwari Birje 			fprintf(stderr,
1320fcac1abSRajeshwari Birje 				"%s: %s is too big (exceeds %d bytes)\n",
1330fcac1abSRajeshwari Birje 				prog_name, argv[if_index], CHECKSUM_OFFSET);
1340fcac1abSRajeshwari Birje 			exit(EXIT_FAILURE);
1350fcac1abSRajeshwari Birje 		}
1360fcac1abSRajeshwari Birje 		count = CHECKSUM_OFFSET;
1370fcac1abSRajeshwari Birje 		read_size = len;
1380fcac1abSRajeshwari Birje 	}
13981e35203SChander Kashyap 
1400fcac1abSRajeshwari Birje 	buffer = malloc(count);
1410fcac1abSRajeshwari Birje 	if (!buffer) {
1420fcac1abSRajeshwari Birje 		fprintf(stderr,
1430fcac1abSRajeshwari Birje 			"%s: Failed to allocate %d bytes to store %s\n",
1440fcac1abSRajeshwari Birje 			prog_name, count, argv[if_index]);
14581e35203SChander Kashyap 		exit(EXIT_FAILURE);
14681e35203SChander Kashyap 	}
14781e35203SChander Kashyap 
1480fcac1abSRajeshwari Birje 	if (read(ifd, buffer, read_size) != read_size) {
1490fcac1abSRajeshwari Birje 		fprintf(stderr, "%s: Can't read %s: %s\n",
1500fcac1abSRajeshwari Birje 			prog_name, argv[if_index], strerror(errno));
1510fcac1abSRajeshwari Birje 		exit(EXIT_FAILURE);
1520fcac1abSRajeshwari Birje 	}
15381e35203SChander Kashyap 
1540fcac1abSRajeshwari Birje 	/* Pad if needed with 0xff to make flashing faster. */
1550fcac1abSRajeshwari Birje 	if (read_size < count)
1560fcac1abSRajeshwari Birje 		memset((char *)buffer + read_size, 0xff, count - read_size);
1570fcac1abSRajeshwari Birje 
1580fcac1abSRajeshwari Birje 	for (i = 0, checksum = 0; i < count; i++)
1590fcac1abSRajeshwari Birje 		checksum += buffer[i];
16081e35203SChander Kashyap 	checksum = cpu_to_le32(checksum);
16181e35203SChander Kashyap 
1620fcac1abSRajeshwari Birje 	if (var_size_flag) {
1630fcac1abSRajeshwari Birje 		/* Prepare and write out the variable size SPL header. */
1640fcac1abSRajeshwari Birje 		struct var_size_header vsh;
1650fcac1abSRajeshwari Birje 		uint32_t spl_size;
16681e35203SChander Kashyap 
1670fcac1abSRajeshwari Birje 		memset(&vsh, 0, sizeof(vsh));
1680fcac1abSRajeshwari Birje 		memcpy(&vsh.spl_checksum, &checksum, sizeof(checksum));
16981e35203SChander Kashyap 
1700fcac1abSRajeshwari Birje 		spl_size = cpu_to_le32(count + sizeof(struct var_size_header));
1710fcac1abSRajeshwari Birje 		memcpy(&vsh.spl_size, &spl_size, sizeof(spl_size));
1720fcac1abSRajeshwari Birje 		write_to_file(ofd, &vsh, sizeof(vsh));
17381e35203SChander Kashyap 	}
17481e35203SChander Kashyap 
1750fcac1abSRajeshwari Birje 	write_to_file(ofd, buffer, count);
1760fcac1abSRajeshwari Birje 
1770fcac1abSRajeshwari Birje 	/* For fixed size SPL checksum is appended in the end. */
1780fcac1abSRajeshwari Birje 	if (!var_size_flag)
1790fcac1abSRajeshwari Birje 		write_to_file(ofd, &checksum, sizeof(checksum));
1800fcac1abSRajeshwari Birje 
18181e35203SChander Kashyap 	close(ifd);
18281e35203SChander Kashyap 	close(ofd);
1830fcac1abSRajeshwari Birje 	free(buffer);
18481e35203SChander Kashyap 
18581e35203SChander Kashyap 	return EXIT_SUCCESS;
18681e35203SChander Kashyap }
187