btrfs-progs: don't use <execinfo.h> with uClibc
[buildroot-gz.git] / package / mkpimage / mkpimage.c
blobd7fe1b1b69f77b451a44f82de6c41540e07b84ad
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <getopt.h>
4 #include <stdlib.h>
5 #include <stdint.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <endian.h>
13 #define VALIDATION_WORD 0x31305341
15 #define BRANCH_INST 0xea /* ARM opcode for "b" (unconditional branch) */
17 #define MAX_V0IMAGE_SIZE (60 * 1024 - 4)
18 /* Max size without authentication is 224 KB, due to memory used by
19 * the ROM boot code as a workspace out of the 256 KB of OCRAM */
20 #define MAX_V1IMAGE_SIZE (224 * 1024 - 4)
22 static int add_barebox_header;
24 struct socfpga_header {
25 uint8_t validation_word[4];
26 uint8_t version;
27 uint8_t flags;
28 union {
29 struct {
30 uint8_t program_length[2];
31 uint8_t spare[2];
32 uint8_t checksum[2];
33 uint8_t start_vector[4];
34 } v0;
35 struct {
36 uint8_t header_length[2];
37 uint8_t program_length[4];
38 uint8_t entry_offset[4];
39 uint8_t spare[2];
40 uint8_t checksum[2];
41 } v1;
45 static uint32_t bb_header[] = {
46 0xea00007e, /* b 0x200 */
47 0xeafffffe, /* 1: b 1b */
48 0xeafffffe, /* 1: b 1b */
49 0xeafffffe, /* 1: b 1b */
50 0xeafffffe, /* 1: b 1b */
51 0xeafffffe, /* 1: b 1b */
52 0xeafffffe, /* 1: b 1b */
53 0xeafffffe, /* 1: b 1b */
54 0x65726162, /* 'bare' */
55 0x00786f62, /* 'box\0' */
56 0x00000000, /* padding */
57 0x00000000, /* padding */
58 0x00000000, /* padding */
59 0x00000000, /* padding */
60 0x00000000, /* padding */
61 0x00000000, /* padding */
62 0x00000000, /* socfpga header */
63 0x00000000, /* socfpga header */
64 0x00000000, /* socfpga header */
65 0xea00006b, /* entry. b 0x200 (offset may be adjusted) */
68 static int read_full(int fd, void *buf, size_t size)
70 size_t insize = size;
71 int now;
72 int total = 0;
74 while (size) {
75 now = read(fd, buf, size);
76 if (now == 0)
77 return total;
78 if (now < 0)
79 return now;
80 total += now;
81 size -= now;
82 buf += now;
85 return insize;
88 static int write_full(int fd, void *buf, size_t size)
90 size_t insize = size;
91 int now;
93 while (size) {
94 now = write(fd, buf, size);
95 if (now <= 0)
96 return now;
97 size -= now;
98 buf += now;
101 return insize;
104 static const uint32_t crc_table[256] = {
105 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
106 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
107 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
108 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
109 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
110 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
111 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
112 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
113 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
114 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
115 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
116 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
117 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
118 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
119 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
120 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
121 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
122 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
123 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
124 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
125 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
126 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
127 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
128 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
129 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
130 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
131 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
132 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
133 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
134 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
135 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
136 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
137 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
138 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
139 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
140 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
141 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
142 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
143 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
144 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
145 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
146 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
147 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
150 uint32_t crc32(uint32_t crc, void *_buf, int length)
152 uint8_t *buf = _buf;
154 while (length--)
155 crc = crc << 8 ^ crc_table[(crc >> 24 ^ *(buf++)) & 0xff];
157 return crc;
160 /* Create an ARM relative branch instuction
161 * branch is where the instruction will be placed and dest points to where
162 * it should branch too. */
163 static void branch(uint8_t *branch, uint8_t *dest)
165 int offset = dest - branch - 8; /* PC is offset +8 bytes on ARM */
167 branch[0] = (offset >> 2) & 0xff; /* instruction uses offset/4 */
168 branch[1] = (offset >> 10) & 0xff;
169 branch[2] = (offset >> 18) & 0xff;
170 branch[3] = BRANCH_INST;
173 /* start_addr is where the socfpga header's start instruction should branch to.
174 * It should be relative to the start of buf */
175 static int add_socfpga_header(void *buf, size_t size, unsigned start_addr, unsigned version)
177 struct socfpga_header *header = buf + 0x40;
178 void *entry;
179 uint8_t *bufp, *sumendp;
180 uint32_t *crc;
181 unsigned checksum;
183 if (size & 0x3) {
184 fprintf(stderr, "%s: size must be multiple of 4\n", __func__);
185 return -EINVAL;
188 /* Absolute address of entry point in buf */
189 entry = buf + start_addr;
190 if (version == 0) {
191 sumendp = &header->v0.checksum[0];
192 } else {
193 sumendp = &header->v1.checksum[0];
195 /* The ROM loader can't handle a negative offset */
196 if (entry < (void*)header) {
197 /* add a trampoline branch inst after end of the header */
198 uint8_t *trampoline = (void*)(header + 1);
199 branch(trampoline, entry);
201 /* and then make the trampoline the entry point */
202 entry = trampoline;
204 /* Calculate start address as offset relative to start of header */
205 start_addr = entry - (void*)header;
208 header->validation_word[0] = VALIDATION_WORD & 0xff;
209 header->validation_word[1] = (VALIDATION_WORD >> 8) & 0xff;
210 header->validation_word[2] = (VALIDATION_WORD >> 16) & 0xff;
211 header->validation_word[3] = (VALIDATION_WORD >> 24) & 0xff;
212 header->version = version;
213 header->flags = 0;
215 if (version == 0) {
216 header->v0.program_length[0] = (size >> 2) & 0xff; /* length in words */
217 header->v0.program_length[1] = (size >> 10) & 0xff;
218 header->v0.spare[0] = 0;
219 header->v0.spare[1] = 0;
220 branch(header->v0.start_vector, entry);
221 } else {
222 header->v1.header_length[0] = (sizeof(*header) >> 0) & 0xff;
223 header->v1.header_length[1] = (sizeof(*header) >> 8) & 0xff;
224 header->v1.program_length[0] = (size >> 0) & 0xff;
225 header->v1.program_length[1] = (size >> 8) & 0xff;
226 header->v1.program_length[2] = (size >> 16) & 0xff;
227 header->v1.program_length[3] = (size >> 24) & 0xff;
228 header->v1.entry_offset[0] = (start_addr >> 0) & 0xff;
229 header->v1.entry_offset[1] = (start_addr >> 8) & 0xff;
230 header->v1.entry_offset[2] = (start_addr >> 16) & 0xff;
231 header->v1.entry_offset[3] = (start_addr >> 24) & 0xff;
232 header->v1.spare[0] = 0;
233 header->v1.spare[1] = 0;
236 /* Sum from beginning of header to start of checksum field */
237 checksum = 0;
238 for (bufp = (uint8_t*)header; bufp < sumendp; bufp++)
239 checksum += *bufp;
241 if (version == 0) {
242 header->v0.checksum[0] = checksum & 0xff;;
243 header->v0.checksum[1] = (checksum >> 8) & 0xff;;
244 } else {
245 header->v1.checksum[0] = checksum & 0xff;;
246 header->v1.checksum[1] = (checksum >> 8) & 0xff;;
249 crc = buf + size - sizeof(uint32_t);
251 *crc = crc32(0xffffffff, buf, size - sizeof(uint32_t));
252 *crc ^= 0xffffffff;
254 return 0;
257 static void usage(const char *prgname)
259 fprintf(stderr, "usage: %s [-hb] [-v version] <infile> -o <outfile>\n", prgname);
262 int main(int argc, char *argv[])
264 int opt, ret;
265 const char *outfile = NULL, *infile;
266 struct stat s;
267 void *buf;
268 int fd;
269 int max_image_size, min_image_size = 80;
270 int addsize = 0, pad;
271 unsigned int version = 0;
273 while ((opt = getopt(argc, argv, "o:hbv:")) != -1) {
274 switch (opt) {
275 case 'v':
276 version = atoi(optarg);
277 if (version > 1) {
278 printf("Versions supported: 0 or 1\n");
279 usage(argv[0]);
280 exit(1);
282 break;
283 case 'b':
284 add_barebox_header = 1;
285 min_image_size = 0;
286 addsize = 512;
287 break;
288 case 'h':
289 usage(argv[0]);
290 exit(0);
291 case 'o':
292 outfile = optarg;
293 break;
294 default:
295 usage(argv[0]);
296 exit(1);
299 if (version == 0) {
300 max_image_size = MAX_V0IMAGE_SIZE;
301 } else {
302 max_image_size = MAX_V1IMAGE_SIZE;
304 max_image_size -= addsize;
306 if (optind == argc || !outfile) {
307 usage(argv[0]);
308 exit(1);
310 infile = argv[optind];
312 ret = stat(infile, &s);
313 if (ret) {
314 perror("stat");
315 exit(1);
318 if (s.st_size < min_image_size) {
319 fprintf(stderr, "input image too small. Minimum is %d bytes\n",
320 min_image_size);
321 exit(1);
324 if (s.st_size > max_image_size) {
325 fprintf(stderr, "input image too big. Maximum is %d bytes, got %ld bytes\n",
326 max_image_size, s.st_size);
327 exit(1);
330 fd = open(infile, O_RDONLY);
331 if (fd == -1) {
332 perror("open infile");
333 exit(1);
336 pad = s.st_size & 0x3;
337 if (pad)
338 pad = 4 - pad;
340 buf = calloc(s.st_size + 4 + addsize + pad, 1);
341 if (!buf) {
342 perror("malloc");
343 exit(1);
346 ret = read_full(fd, buf + addsize, s.st_size);
347 if (ret < 0) {
348 perror("read infile");
349 exit(1);
352 close(fd);
354 if (add_barebox_header) {
355 memcpy(buf, bb_header, sizeof(bb_header));
358 ret = add_socfpga_header(buf, s.st_size + 4 + addsize + pad, addsize,
359 version);
360 if (ret)
361 exit(1);
363 fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
364 if (fd < 0) {
365 perror("open outfile");
366 exit(1);
369 ret = write_full(fd, buf, s.st_size + 4 + addsize + pad);
370 if (ret < 0) {
371 perror("write outfile");
372 exit(1);
375 exit(0);