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 errno = NO_ERROR;
100 r = write(fd, x, len);
101 if (r < 0) {
102 if (errno == EINTR) {
103 continue;
104 }
105 return -1;
106 }
107 len -= r;
108 x += r;
109 }
110 return 0;
111 }
112
113 static uint8_t filler[4096] = { 0, };
114
bootimage_write(bootimage * img,int fd)115 int bootimage_write(bootimage *img, int fd) {
116 unsigned off = 4096;
117 unsigned n, s;
118 if (writex(fd, img->entry, 4096)) {
119 return -1;
120 }
121 for (n = 1; n < 64; n++) {
122 if (img->offset[n] == 0) continue;
123 if (img->offset[n] < off) return -1;
124 s = img->offset[n] - off;
125 if (s > 4095) return -1;
126 if (writex(fd, filler, s)) {
127 return -1;
128 }
129 off += s;
130 if (writex(fd, img->data[n], img->length[n])) {
131 return -1;
132 }
133 off += img->length[n];
134 }
135 if (off & 4095) {
136 if (writex(fd, filler, 4096 - (off & 4095))) return -1;
137 }
138 return 0;
139 }
140
load_file(const char * fn,size_t * len)141 static void *load_file(const char *fn, size_t *len) {
142 off_t sz;
143 void *data = NULL;
144 char *x;
145 int fd, r;
146
147 if ((fd = open(fn, O_RDONLY)) < 0) {
148 return NULL;
149 }
150
151 if ((sz = lseek(fd, 0, SEEK_END)) < 0) {
152 goto fail;
153 }
154 if (lseek(fd, 0, SEEK_SET) != 0) {
155 goto fail;
156 }
157
158 if ((data = malloc(sz)) == NULL) {
159 goto fail;
160 }
161 x = data;
162 if (len) {
163 *len = sz;
164 }
165 while (sz > 0) {
166 errno = NO_ERROR;
167 r = read(fd, x, sz);
168 if (r < 0) {
169 if (errno == EINTR) {
170 continue;
171 }
172 goto fail;
173 }
174 sz -= r;
175 x += r;
176 }
177 close(fd);
178 return data;
179
180 fail:
181 if (data) {
182 free(data);
183 }
184 close(fd);
185 return NULL;
186 }
187
bootimage_add_file(bootimage * img,unsigned type,const char * fn)188 bootentry_file *bootimage_add_file(bootimage *img, unsigned type, const char *fn) {
189 unsigned char *data;
190 size_t len;
191
192 if ((data = load_file(fn, &len)) == NULL) {
193 fprintf(stderr, "error: cannot load '%s'\n", fn);
194 return NULL;
195 }
196
197 /* if fpga image, trim everything before ffffffaa995566 and wordwise endian swap */
198 if (type == TYPE_FPGA_IMAGE) {
199 static const unsigned char pat[] = { 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 };
200
201 size_t i;
202 if (len < sizeof(pat)) {
203 free(data);
204 fprintf(stderr, "error: fpga image too short\n");
205 return NULL;
206 }
207
208 for (i = 0; i < len - sizeof(pat); i++) {
209 if (!memcmp(data + i, pat, sizeof(pat))) {
210 /* we've found the pattern, trim everything before it */
211 memmove(data, data + i, len - i);
212 len -= i;
213 }
214 }
215
216 /* wordwise endian swap */
217 #define SWAP_32(x) \
218 (((uint32_t)(x) << 24) | (((uint32_t)(x) & 0xff00) << 8) |(((uint32_t)(x) & 0x00ff0000) >> 8) | ((uint32_t)(x) >> 24))
219 uint32_t *w = (uint32_t *)data;
220 for (i = 0; i < len / 4; i++) {
221 *w = SWAP_32(*w);
222 w++;
223 }
224 #undef SWAP_32
225 }
226
227 return bootimage_add_filedata(img, type, data, len);
228 }
229
230