blob: 1b0e607cacd8eee68ccad682c897689390249725 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
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
36struct 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
45bootimage *bootimage_init(void) {
46 bootimage *img;
47
48 if ((img = malloc(sizeof(bootimage))) == NULL) {
49 return NULL;
50 }
51 memset(img, 0, sizeof(bootimage));
52 img->count = 2;
53 img->next_offset = 4096;
54 memset(img->entry, 0, 4096);
55 img->entry[0].file.kind = KIND_FILE;
56 img->entry[0].file.type = TYPE_BOOT_IMAGE;
57 img->entry[0].file.offset = 0;
58 img->entry[0].file.length = 4096;
59 img->entry[1].info.kind = KIND_BOOT_INFO;
60 img->entry[1].info.version = BOOT_VERSION;
61 memcpy(img->entry[0].file.name, BOOT_MAGIC, BOOT_MAGIC_LENGTH);
62 return img;
63}
64
65bootentry_data *bootimage_add_string(bootimage *img, unsigned kind, const char *s) {
66 unsigned n = img->count;
67 int len = strlen(s);
68 if (img->count == 64) return NULL;
69 if (len > 59) return NULL;
70 img->count++;
71
72 img->entry[n].data.kind = kind;
73 strcpy((char*) img->entry[n].data.u.b, s);
74 return &(img->entry[n].data);
75}
76
77bootentry_file *bootimage_add_filedata(bootimage *img, unsigned type, void *data, unsigned len) {
78 unsigned n = img->count;
79 if (img->count == 64) return NULL;
80 img->count++;
81
82 // align to page boundary
83 img->next_offset = (img->next_offset + 4095) & (~4095);
84
85 img->entry[n].file.kind = KIND_FILE;
86 img->entry[n].file.type = type;
87 img->entry[n].file.offset = img->next_offset;
88 img->entry[n].file.length = len;
89 SHA256_hash(data, len, img->entry[n].file.sha256);
90
91 img->data[n] = data;
92 img->offset[n] = img->next_offset;
93 img->length[n] = len;
94
95 img->next_offset += len;
96
97 return &(img->entry[n].file);
98}
99
100void bootimage_done(bootimage *img) {
101 unsigned sz = img->next_offset;
102 if (sz & 4095) {
103 sz += (4096 - (sz & 4095));
104 }
105 img->entry[1].info.image_size = sz;
106 img->entry[1].info.entry_count = img->count;
107 SHA256_hash((void*) &(img->entry[1]), 4096 - 64, img->entry[0].file.sha256);
108}
109
110static int writex(int fd, void *data, size_t len) {
111 int r;
112 char *x = data;
113 while (len > 0) {
114 r = write(fd, x, len);
115 if (r < 0) {
116 if (errno == EINTR) {
117 continue;
118 }
119 return -1;
120 }
121 len -= r;
122 x += r;
123 }
124 return 0;
125}
126
127static uint8_t filler[4096] = { 0, };
128
129int bootimage_write(bootimage *img, int fd) {
130 unsigned off = 4096;
131 unsigned n, s;
132 if (writex(fd, img->entry, 4096)) {
133 return -1;
134 }
135 for (n = 1; n < 64; n++) {
136 if (img->offset[n] == 0) continue;
137 if (img->offset[n] < off) return -1;
138 s = img->offset[n] - off;
139 if (s > 4095) return -1;
140 if (writex(fd, filler, s)) {
141 return -1;
142 }
143 off += s;
144 if (writex(fd, img->data[n], img->length[n])) {
145 return -1;
146 }
147 off += img->length[n];
148 }
149 if (off & 4095) {
150 if (writex(fd, filler, 4096 - (off & 4095))) return -1;
151 }
152 return 0;
153}
154
155static void *load_file(const char *fn, size_t *len) {
156 off_t sz;
157 void *data = NULL;
158 char *x;
159 int fd, r;
160
161 if((fd = open(fn, O_RDONLY)) < 0) {
162 return NULL;
163 }
164
165 if ((sz = lseek(fd, 0, SEEK_END)) < 0) {
166 goto fail;
167 }
168 if (lseek(fd, 0, SEEK_SET) != 0) {
169 goto fail;
170 }
171
172 if ((data = malloc(sz)) == NULL) {
173 goto fail;
174 }
175 x = data;
176 if (len) {
177 *len = sz;
178 }
179 while (sz > 0) {
180 r = read(fd, x, sz);
181 if (r < 0) {
182 if (errno == EINTR) {
183 continue;
184 }
185 goto fail;
186 }
187 sz -= r;
188 x += r;
189 }
190 close(fd);
191 return data;
192
193fail:
194 if (data) {
195 free(data);
196 }
197 close(fd);
198 return NULL;
199}
200
201bootentry_file *bootimage_add_file(bootimage *img, unsigned type, const char *fn) {
202 unsigned char *data;
203 size_t len;
204
205 if ((data = load_file(fn, &len)) == NULL) {
206 fprintf(stderr, "error: cannot load '%s'\n", fn);
207 return NULL;
208 }
209
210 /* if fpga image, trim everything before ffffffaa995566 and wordwise endian swap */
211 if (type == TYPE_FPGA_IMAGE) {
212 static const unsigned char pat[] = { 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 };
213
214 size_t i;
215 if (len < sizeof(pat)) {
216 free(data);
217 fprintf(stderr, "error: fpga image too short\n");
218 return NULL;
219 }
220
221 for (i = 0; i < len - sizeof(pat); i++) {
222 if (!memcmp(data + i, pat, sizeof(pat))) {
223 /* we've found the pattern, trim everything before it */
224 memmove(data, data + i, len - i);
225 len -= i;
226 }
227 }
228
229 /* wordwise endian swap */
230#define SWAP_32(x) \
231 (((uint32_t)(x) << 24) | (((uint32_t)(x) & 0xff00) << 8) |(((uint32_t)(x) & 0x00ff0000) >> 8) | ((uint32_t)(x) >> 24))
232 uint32_t *w = (uint32_t *)data;
233 for (i = 0; i < len / 4; i++) {
234 *w = SWAP_32(*w);
235 w++;
236 }
237#undef SWAP_32
238 }
239
240 return bootimage_add_filedata(img, type, data, len);
241}
242