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