1 /*
2 * Copyright (c) 2014 Brian Swetland
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <errno.h>
16
17 #include <lib/mincrypt/sha256.h>
18
19 #include "bootimage.h"
20
21 struct bootimage {
22 bootentry entry[64];
23 void *data[64];
24 uint32_t offset[64];
25 uint32_t length[64];
26 unsigned count;
27 uint32_t next_offset;
28 };
29
bootimage_init(void)30 bootimage *bootimage_init(void) {
31 bootimage *img;
32
33 if ((img = malloc(sizeof(bootimage))) == NULL) {
34 return NULL;
35 }
36 memset(img, 0, sizeof(bootimage));
37 img->count = 2;
38 img->next_offset = 4096;
39 memset(img->entry, 0, 4096);
40 img->entry[0].file.kind = KIND_FILE;
41 img->entry[0].file.type = TYPE_BOOT_IMAGE;
42 img->entry[0].file.offset = 0;
43 img->entry[0].file.length = 4096;
44 img->entry[1].info.kind = KIND_BOOT_INFO;
45 img->entry[1].info.version = BOOT_VERSION;
46 memcpy(img->entry[0].file.name, BOOT_MAGIC, BOOT_MAGIC_LENGTH);
47 return img;
48 }
49
bootimage_add_string(bootimage * img,unsigned kind,const char * s)50 bootentry_data *bootimage_add_string(bootimage *img, unsigned kind, const char *s) {
51 unsigned n = img->count;
52 int len = strlen(s);
53 if (img->count == 64) return NULL;
54 if (len > 59) return NULL;
55 img->count++;
56
57 img->entry[n].data.kind = kind;
58 strcpy((char *) img->entry[n].data.u.b, s);
59 return &(img->entry[n].data);
60 }
61
bootimage_add_filedata(bootimage * img,unsigned type,void * data,unsigned len)62 bootentry_file *bootimage_add_filedata(bootimage *img, unsigned type, void *data, unsigned len) {
63 unsigned n = img->count;
64 if (img->count == 64) return NULL;
65 img->count++;
66
67 // align to page boundary
68 img->next_offset = (img->next_offset + 4095) & (~4095);
69
70 img->entry[n].file.kind = KIND_FILE;
71 img->entry[n].file.type = type;
72 img->entry[n].file.offset = img->next_offset;
73 img->entry[n].file.length = len;
74 SHA256_hash(data, len, img->entry[n].file.sha256);
75
76 img->data[n] = data;
77 img->offset[n] = img->next_offset;
78 img->length[n] = len;
79
80 img->next_offset += len;
81
82 return &(img->entry[n].file);
83 }
84
bootimage_done(bootimage * img)85 void bootimage_done(bootimage *img) {
86 unsigned sz = img->next_offset;
87 if (sz & 4095) {
88 sz += (4096 - (sz & 4095));
89 }
90 img->entry[1].info.image_size = sz;
91 img->entry[1].info.entry_count = img->count;
92 SHA256_hash((void *) &(img->entry[1]), 4096 - 64, img->entry[0].file.sha256);
93 }
94
writex(int fd,void * data,size_t len)95 static int writex(int fd, void *data, size_t len) {
96 int r;
97 char *x = data;
98 while (len > 0) {
99 r = write(fd, x, len);
100 if (r < 0) {
101 if (errno == EINTR) {
102 continue;
103 }
104 return -1;
105 }
106 len -= r;
107 x += r;
108 }
109 return 0;
110 }
111
112 static uint8_t filler[4096] = { 0, };
113
bootimage_write(bootimage * img,int fd)114 int bootimage_write(bootimage *img, int fd) {
115 unsigned off = 4096;
116 unsigned n, s;
117 if (writex(fd, img->entry, 4096)) {
118 return -1;
119 }
120 for (n = 1; n < 64; n++) {
121 if (img->offset[n] == 0) continue;
122 if (img->offset[n] < off) return -1;
123 s = img->offset[n] - off;
124 if (s > 4095) return -1;
125 if (writex(fd, filler, s)) {
126 return -1;
127 }
128 off += s;
129 if (writex(fd, img->data[n], img->length[n])) {
130 return -1;
131 }
132 off += img->length[n];
133 }
134 if (off & 4095) {
135 if (writex(fd, filler, 4096 - (off & 4095))) return -1;
136 }
137 return 0;
138 }
139
load_file(const char * fn,size_t * len)140 static void *load_file(const char *fn, size_t *len) {
141 off_t sz;
142 void *data = NULL;
143 char *x;
144 int fd, r;
145
146 if ((fd = open(fn, O_RDONLY)) < 0) {
147 return NULL;
148 }
149
150 if ((sz = lseek(fd, 0, SEEK_END)) < 0) {
151 goto fail;
152 }
153 if (lseek(fd, 0, SEEK_SET) != 0) {
154 goto fail;
155 }
156
157 if ((data = malloc(sz)) == NULL) {
158 goto fail;
159 }
160 x = data;
161 if (len) {
162 *len = sz;
163 }
164 while (sz > 0) {
165 r = read(fd, x, sz);
166 if (r < 0) {
167 if (errno == EINTR) {
168 continue;
169 }
170 goto fail;
171 }
172 sz -= r;
173 x += r;
174 }
175 close(fd);
176 return data;
177
178 fail:
179 if (data) {
180 free(data);
181 }
182 close(fd);
183 return NULL;
184 }
185
bootimage_add_file(bootimage * img,unsigned type,const char * fn)186 bootentry_file *bootimage_add_file(bootimage *img, unsigned type, const char *fn) {
187 unsigned char *data;
188 size_t len;
189
190 if ((data = load_file(fn, &len)) == NULL) {
191 fprintf(stderr, "error: cannot load '%s'\n", fn);
192 return NULL;
193 }
194
195 /* if fpga image, trim everything before ffffffaa995566 and wordwise endian swap */
196 if (type == TYPE_FPGA_IMAGE) {
197 static const unsigned char pat[] = { 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 };
198
199 size_t i;
200 if (len < sizeof(pat)) {
201 free(data);
202 fprintf(stderr, "error: fpga image too short\n");
203 return NULL;
204 }
205
206 for (i = 0; i < len - sizeof(pat); i++) {
207 if (!memcmp(data + i, pat, sizeof(pat))) {
208 /* we've found the pattern, trim everything before it */
209 memmove(data, data + i, len - i);
210 len -= i;
211 }
212 }
213
214 /* wordwise endian swap */
215 #define SWAP_32(x) \
216 (((uint32_t)(x) << 24) | (((uint32_t)(x) & 0xff00) << 8) |(((uint32_t)(x) & 0x00ff0000) >> 8) | ((uint32_t)(x) >> 24))
217 uint32_t *w = (uint32_t *)data;
218 for (i = 0; i < len / 4; i++) {
219 *w = SWAP_32(*w);
220 w++;
221 }
222 #undef SWAP_32
223 }
224
225 return bootimage_add_filedata(img, type, data, len);
226 }
227
228