1 /*
2  * Copyright (c) 2014 Brian Swetland
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 
32 #include <lib/mincrypt/sha256.h>
33 
34 #include "bootimage.h"
35 
36 struct bootimage {
37     bootentry entry[64];
38     void *data[64];
39     uint32_t offset[64];
40     uint32_t length[64];
41     unsigned count;
42     uint32_t next_offset;
43 };
44 
bootimage_init(void)45 bootimage *bootimage_init(void)
46 {
47     bootimage *img;
48 
49     if ((img = malloc(sizeof(bootimage))) == NULL) {
50         return NULL;
51     }
52     memset(img, 0, sizeof(bootimage));
53     img->count = 2;
54     img->next_offset = 4096;
55     memset(img->entry, 0, 4096);
56     img->entry[0].file.kind = KIND_FILE;
57     img->entry[0].file.type = TYPE_BOOT_IMAGE;
58     img->entry[0].file.offset = 0;
59     img->entry[0].file.length = 4096;
60     img->entry[1].info.kind = KIND_BOOT_INFO;
61     img->entry[1].info.version = BOOT_VERSION;
62     memcpy(img->entry[0].file.name, BOOT_MAGIC, BOOT_MAGIC_LENGTH);
63     return img;
64 }
65 
bootimage_add_string(bootimage * img,unsigned kind,const char * s)66 bootentry_data *bootimage_add_string(bootimage *img, unsigned kind, const char *s)
67 {
68     unsigned n = img->count;
69     int len = strlen(s);
70     if (img->count == 64) return NULL;
71     if (len > 59) return NULL;
72     img->count++;
73 
74     img->entry[n].data.kind = kind;
75     strcpy((char *) img->entry[n].data.u.b, s);
76     return &(img->entry[n].data);
77 }
78 
bootimage_add_filedata(bootimage * img,unsigned type,void * data,unsigned len)79 bootentry_file *bootimage_add_filedata(bootimage *img, unsigned type, void *data, unsigned len)
80 {
81     unsigned n = img->count;
82     if (img->count == 64) return NULL;
83     img->count++;
84 
85     // align to page boundary
86     img->next_offset = (img->next_offset + 4095) & (~4095);
87 
88     img->entry[n].file.kind = KIND_FILE;
89     img->entry[n].file.type = type;
90     img->entry[n].file.offset = img->next_offset;
91     img->entry[n].file.length = len;
92     SHA256_hash(data, len, img->entry[n].file.sha256);
93 
94     img->data[n] = data;
95     img->offset[n] = img->next_offset;
96     img->length[n] = len;
97 
98     img->next_offset += len;
99 
100     return &(img->entry[n].file);
101 }
102 
bootimage_done(bootimage * img)103 void bootimage_done(bootimage *img)
104 {
105     unsigned sz = img->next_offset;
106     if (sz & 4095) {
107         sz += (4096 - (sz & 4095));
108     }
109     img->entry[1].info.image_size = sz;
110     img->entry[1].info.entry_count = img->count;
111     SHA256_hash((void *) &(img->entry[1]), 4096 - 64, img->entry[0].file.sha256);
112 }
113 
writex(int fd,void * data,size_t len)114 static int writex(int fd, void *data, size_t len)
115 {
116     int r;
117     char *x = data;
118     while (len > 0) {
119         r = write(fd, x, len);
120         if (r < 0) {
121             if (errno == EINTR) {
122                 continue;
123             }
124             return -1;
125         }
126         len -= r;
127         x += r;
128     }
129     return 0;
130 }
131 
132 static uint8_t filler[4096] = { 0, };
133 
bootimage_write(bootimage * img,int fd)134 int bootimage_write(bootimage *img, int fd)
135 {
136     unsigned off = 4096;
137     unsigned n, s;
138     if (writex(fd, img->entry, 4096)) {
139         return -1;
140     }
141     for (n = 1; n < 64; n++) {
142         if (img->offset[n] == 0) continue;
143         if (img->offset[n] < off) return -1;
144         s = img->offset[n] - off;
145         if (s > 4095) return -1;
146         if (writex(fd, filler, s)) {
147             return -1;
148         }
149         off += s;
150         if (writex(fd, img->data[n], img->length[n])) {
151             return -1;
152         }
153         off += img->length[n];
154     }
155     if (off & 4095) {
156         if (writex(fd, filler, 4096 - (off & 4095))) return -1;
157     }
158     return 0;
159 }
160 
load_file(const char * fn,size_t * len)161 static void *load_file(const char *fn, size_t *len)
162 {
163     off_t sz;
164     void *data = NULL;
165     char *x;
166     int fd, r;
167 
168     if ((fd = open(fn, O_RDONLY)) < 0) {
169         return NULL;
170     }
171 
172     if ((sz = lseek(fd, 0, SEEK_END)) < 0) {
173         goto fail;
174     }
175     if (lseek(fd, 0, SEEK_SET) != 0) {
176         goto fail;
177     }
178 
179     if ((data = malloc(sz)) == NULL) {
180         goto fail;
181     }
182     x = data;
183     if (len) {
184         *len = sz;
185     }
186     while (sz > 0) {
187         r = read(fd, x, sz);
188         if (r < 0) {
189             if (errno == EINTR) {
190                 continue;
191             }
192             goto fail;
193         }
194         sz -= r;
195         x += r;
196     }
197     close(fd);
198     return data;
199 
200 fail:
201     if (data) {
202         free(data);
203     }
204     close(fd);
205     return NULL;
206 }
207 
bootimage_add_file(bootimage * img,unsigned type,const char * fn)208 bootentry_file *bootimage_add_file(bootimage *img, unsigned type, const char *fn)
209 {
210     unsigned char *data;
211     size_t len;
212 
213     if ((data = load_file(fn, &len)) == NULL) {
214         fprintf(stderr, "error: cannot load '%s'\n", fn);
215         return NULL;
216     }
217 
218     /* if fpga image, trim everything before ffffffaa995566 and wordwise endian swap */
219     if (type == TYPE_FPGA_IMAGE) {
220         static const unsigned char pat[] = { 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 };
221 
222         size_t i;
223         if (len < sizeof(pat)) {
224             free(data);
225             fprintf(stderr, "error: fpga image too short\n");
226             return NULL;
227         }
228 
229         for (i = 0; i < len - sizeof(pat); i++) {
230             if (!memcmp(data + i, pat, sizeof(pat))) {
231                 /* we've found the pattern, trim everything before it */
232                 memmove(data, data + i, len - i);
233                 len -= i;
234             }
235         }
236 
237         /* wordwise endian swap */
238 #define SWAP_32(x) \
239     (((uint32_t)(x) << 24) | (((uint32_t)(x) & 0xff00) << 8) |(((uint32_t)(x) & 0x00ff0000) >> 8) | ((uint32_t)(x) >> 24))
240         uint32_t *w = (uint32_t *)data;
241         for (i = 0; i < len / 4; i++) {
242             *w = SWAP_32(*w);
243             w++;
244         }
245 #undef SWAP_32
246     }
247 
248     return bootimage_add_filedata(img, type, data, len);
249 }
250 
251