mkexynosspl.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2012 Samsung Electronics
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <sys/stat.h>
  12. #include <compiler.h>
  13. #define CHECKSUM_OFFSET (14*1024-4)
  14. #define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP \
  15. | S_IWGRP | S_IROTH | S_IWOTH)
  16. /*
  17. * Requirement for the fixed size SPL header:
  18. * IROM code reads first (CHECKSUM_OFFSET + 4) bytes from boot device. It then
  19. * calculates the checksum of CHECKSUM_OFFSET bytes and compares with data at
  20. * CHECKSUM_OFFSET location.
  21. *
  22. * Requirement for the variable size SPL header:
  23. * IROM code reads the below header to find out the size of the blob (total
  24. * size, header size included) and its checksum. Then it reads the rest of the
  25. * blob [i.e size - sizeof(struct var_size_header) bytes], calculates the
  26. * checksum and compares it with value read from the header.
  27. */
  28. struct var_size_header {
  29. uint32_t spl_size;
  30. uint32_t spl_checksum;
  31. uint32_t reserved[2];
  32. };
  33. static const char *prog_name;
  34. static void write_to_file(int ofd, void *buffer, int size)
  35. {
  36. if (write(ofd, buffer, size) == size)
  37. return;
  38. fprintf(stderr, "%s: Failed to write to output file: %s\n",
  39. prog_name, strerror(errno));
  40. exit(EXIT_FAILURE);
  41. }
  42. /*
  43. * The argv is expected to include one optional parameter and two filenames:
  44. * [--vs] IN OUT
  45. *
  46. * --vs - turns on the variable size SPL mode
  47. * IN - the u-boot SPL binary, usually u-boot-spl.bin
  48. * OUT - the prepared SPL blob, usually ${BOARD}-spl.bin
  49. *
  50. * This utility first reads the "u-boot-spl.bin" into a buffer. In case of
  51. * fixed size SPL the buffer size is exactly CHECKSUM_OFFSET (such that
  52. * smaller u-boot-spl.bin gets padded with 0xff bytes, the larger than limit
  53. * u-boot-spl.bin causes an error). For variable size SPL the buffer size is
  54. * eqaul to size of the IN file.
  55. *
  56. * Then it calculates checksum of the buffer by just summing up all bytes.
  57. * Then
  58. *
  59. * - for fixed size SPL the buffer is written into the output file and the
  60. * checksum is appended to the file in little endian format, which results
  61. * in checksum added exactly at CHECKSUM_OFFSET.
  62. *
  63. * - for variable size SPL the checksum and file size are stored in the
  64. * var_size_header structure (again, in little endian format) and the
  65. * structure is written into the output file. Then the buffer is written
  66. * into the output file.
  67. */
  68. int main(int argc, char **argv)
  69. {
  70. unsigned char *buffer;
  71. int i, ifd, ofd;
  72. uint32_t checksum = 0;
  73. off_t len;
  74. int var_size_flag, read_size, count;
  75. struct stat stat;
  76. const int if_index = argc - 2; /* Input file name index in argv. */
  77. const int of_index = argc - 1; /* Output file name index in argv. */
  78. /* Strip path off the program name. */
  79. prog_name = strrchr(argv[0], '/');
  80. if (prog_name)
  81. prog_name++;
  82. else
  83. prog_name = argv[0];
  84. if ((argc < 3) ||
  85. (argc > 4) ||
  86. ((argc == 4) && strcmp(argv[1], "--vs"))) {
  87. fprintf(stderr, "Usage: %s [--vs] <infile> <outfile>\n",
  88. prog_name);
  89. exit(EXIT_FAILURE);
  90. }
  91. /* four args mean variable size SPL wrapper is required */
  92. var_size_flag = (argc == 4);
  93. ifd = open(argv[if_index], O_RDONLY);
  94. if (ifd < 0) {
  95. fprintf(stderr, "%s: Can't open %s: %s\n",
  96. prog_name, argv[if_index], strerror(errno));
  97. exit(EXIT_FAILURE);
  98. }
  99. ofd = open(argv[of_index], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
  100. if (ofd < 0) {
  101. fprintf(stderr, "%s: Can't open %s: %s\n",
  102. prog_name, argv[of_index], strerror(errno));
  103. exit(EXIT_FAILURE);
  104. }
  105. if (fstat(ifd, &stat)) {
  106. fprintf(stderr, "%s: Unable to get size of %s: %s\n",
  107. prog_name, argv[if_index], strerror(errno));
  108. exit(EXIT_FAILURE);
  109. }
  110. len = stat.st_size;
  111. if (var_size_flag) {
  112. read_size = len;
  113. count = len;
  114. } else {
  115. if (len > CHECKSUM_OFFSET) {
  116. fprintf(stderr,
  117. "%s: %s is too big (exceeds %d bytes)\n",
  118. prog_name, argv[if_index], CHECKSUM_OFFSET);
  119. exit(EXIT_FAILURE);
  120. }
  121. count = CHECKSUM_OFFSET;
  122. read_size = len;
  123. }
  124. buffer = malloc(count);
  125. if (!buffer) {
  126. fprintf(stderr,
  127. "%s: Failed to allocate %d bytes to store %s\n",
  128. prog_name, count, argv[if_index]);
  129. exit(EXIT_FAILURE);
  130. }
  131. if (read(ifd, buffer, read_size) != read_size) {
  132. fprintf(stderr, "%s: Can't read %s: %s\n",
  133. prog_name, argv[if_index], strerror(errno));
  134. exit(EXIT_FAILURE);
  135. }
  136. /* Pad if needed with 0xff to make flashing faster. */
  137. if (read_size < count)
  138. memset((char *)buffer + read_size, 0xff, count - read_size);
  139. for (i = 0, checksum = 0; i < count; i++)
  140. checksum += buffer[i];
  141. checksum = cpu_to_le32(checksum);
  142. if (var_size_flag) {
  143. /* Prepare and write out the variable size SPL header. */
  144. struct var_size_header vsh;
  145. uint32_t spl_size;
  146. memset(&vsh, 0, sizeof(vsh));
  147. memcpy(&vsh.spl_checksum, &checksum, sizeof(checksum));
  148. spl_size = cpu_to_le32(count + sizeof(struct var_size_header));
  149. memcpy(&vsh.spl_size, &spl_size, sizeof(spl_size));
  150. write_to_file(ofd, &vsh, sizeof(vsh));
  151. }
  152. write_to_file(ofd, buffer, count);
  153. /* For fixed size SPL checksum is appended in the end. */
  154. if (!var_size_flag)
  155. write_to_file(ofd, &checksum, sizeof(checksum));
  156. close(ifd);
  157. close(ofd);
  158. free(buffer);
  159. return EXIT_SUCCESS;
  160. }