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