blob: bb1929bffd1ab5144e9ffa194583fc5433e86aa7 [file] [log] [blame]
Cástor Muñoz346423c2016-02-04 23:05:17 +01001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2015 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdint.h>
24#include <stdbool.h>
25
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <string.h>
31
32#include "mks5lboot.h"
33
34/* Header for ARM code binaries */
35#include "dualboot.h"
36
37/* Win32 compatibility */
38#ifndef O_BINARY
39#define O_BINARY 0
40#endif
41
42/*
43 * This code is based on emCORE, adds a couple of improvements thanks to
44 * some extra features in Apple's ROM:
45 * - Generic Im3Info header valid for all payloads. It is done by moving
46 * the certificate to a fixed position (before data), and using a 'magic'
47 * value (0x300) for signature offset.
48 * - Some integer overflows in ROM make it possible to use the free space
49 * available in Im3Hdr, resulting a maximum payload size of:
50 * 128 KiB - 0x50 bytes (IM3INFO_SZ) - 700 bytes (CERT_SIZE).
51 */
52
53const struct ipod_models ipod_identity[] =
54{
55 [MODEL_IPOD6G] = {
56 "Classic 6G", "ipod6g", "ip6g", 71,
57 dualboot_install_ipod6g, sizeof(dualboot_install_ipod6g),
58 dualboot_uninstall_ipod6g, sizeof(dualboot_uninstall_ipod6g) },
59};
60
61struct Im3Info s5l8702hdr =
62{
63 .ident = IM3_IDENT,
64 .version = IM3_VERSION,
65 .enc_type = 3,
66 .u.enc34 = {
67 .sign_off = "\x00\x03\x00\x00",
68 .cert_off = "\x50\xF8\xFF\xFF", /* -0x800 + CERT_OFFSET */
69 .cert_sz = "\xBA\x02\x00\x00", /* CERT_SIZE */
70 },
71 .info_sign = "\xC2\x54\x51\x31\xDC\xC0\x84\xA4"
72 "\x7F\xD1\x45\x08\xE8\xFF\xE8\x1D",
73};
74
75unsigned char s5l8702pwnage[/*CERT_SIZE*/] =
76{
77 "\x30\x82\x00\x7A\x30\x66\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86"
78 "\xF7\x0D\x01\x01\x05\x05\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55"
79 "\x04\x03\x13\x00\x30\x1E\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00"
80 "\x00\x00\x00\x00\x00\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00"
81 "\x00\x00\x00\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55\x04\x03\x13"
82 "\x00\x30\x19\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"
83 "\x05\x00\x03\x08\x00\x30\x05\x02\x01\x00\x02\x00\x30\x0D\x06\x09"
84 "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x01\x00\x30\x82"
85 "\x00\x7A\x30\x66\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D"
86 "\x01\x01\x05\x05\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55\x04\x03"
87 "\x13\x00\x30\x1E\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
88 "\x00\x00\x00\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
89 "\x00\x00\x30\x0B\x31\x09\x30\x07\x06\x03\x55\x04\x03\x13\x00\x30"
90 "\x19\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00"
91 "\x03\x08\x00\x30\x05\x02\x01\x00\x02\x00\x30\x0D\x06\x09\x2A\x86"
92 "\x48\x86\xF7\x0D\x01\x01\x05\x05\x00\x03\x01\x00\x30\x82\x01\xBA"
93 "\x30\x50\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01"
94 "\x05\x05\x00\x30\x00\x30\x1E\x17\x0D\x00\x00\x00\x00\x00\x00\x00"
95 "\x00\x00\x00\x00\x00\x00\x17\x0D\x00\x00\x00\x00\x00\x00\x00\x00"
96 "\x00\x00\x00\x00\x00\x30\x00\x30\x19\x30\x0D\x06\x09\x2A\x86\x48"
97 "\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x08\x00\x30\x05\x02\x01\x00"
98 "\x02\x00\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05\x05"
99 "\x00\x03\x82\x01\x55"
100};
101
102static uint32_t get_uint32le(unsigned char* p)
103{
104 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
105}
106
107static uint32_t get_uint32be(unsigned char* p)
108{
109 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
110}
111
112static void put_uint32le(unsigned char* p, uint32_t x)
113{
114 p[0] = x & 0xff;
115 p[1] = (x >> 8) & 0xff;
116 p[2] = (x >> 16) & 0xff;
117 p[3] = (x >> 24) & 0xff;
118}
119
Cástor Muñozfbbba922017-05-04 10:52:03 +0200120#define _ERR(format, ...) \
Cástor Muñoz346423c2016-02-04 23:05:17 +0100121 do { \
122 snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
123 goto error; \
124 } while(0)
125
126static unsigned char *load_file(char *filename, int *bufsize,
127 const struct ipod_models** model,
128 char* errstr, int errstrsize)
129{
130 int fd, i;
131 struct stat s;
132 unsigned char header[8];
133 unsigned char *buf = NULL;
134 bool is_rbbl = (model);
135
136 fd = open(filename, O_RDONLY|O_BINARY);
137 if (fd < 0)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200138 _ERR("Could not open %s for reading", filename);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100139
140 if (fstat(fd, &s) < 0)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200141 _ERR("Checking filesize of input file %s", filename);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100142 *bufsize = s.st_size;
143
144 if (is_rbbl) {
145 /* Read Rockbox header */
146 if (read(fd, header, sizeof(header)) != sizeof(header))
Cástor Muñozfbbba922017-05-04 10:52:03 +0200147 _ERR("Could not read file %s", filename);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100148 *bufsize -= sizeof(header);
149
150 for (i = 0; i < NUM_MODELS; i++)
151 if (memcmp(ipod_identity[i].rb_model_name, header + 4, 4) == 0)
152 break;
153
154 if (i == NUM_MODELS)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200155 _ERR("Model name \"%4.4s\" unknown. "
Cástor Muñoz346423c2016-02-04 23:05:17 +0100156 "Is this really a rockbox bootloader?", header + 4);
157
158 *model = &ipod_identity[i];
159 }
160
161 buf = malloc(*bufsize);
162 if (buf == NULL)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200163 _ERR("Could not allocate memory for %s", filename);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100164
165 if (read(fd, buf, *bufsize) != *bufsize)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200166 _ERR("Could not read file %s", filename);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100167
168 if (is_rbbl) {
169 /* Check checksum */
170 uint32_t sum = (*model)->rb_model_num;
171 for (i = 0; i < *bufsize; i++) {
172 /* add 8 unsigned bits but keep a 32 bit sum */
173 sum += buf[i];
174 }
175 if (sum != get_uint32be(header))
Cástor Muñozfbbba922017-05-04 10:52:03 +0200176 _ERR("Checksum mismatch in %s", filename);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100177 }
178
179 close(fd);
180 return buf;
181
182error:
183 if (fd >= 0)
184 close(fd);
185 if (buf)
186 free(buf);
187 return NULL;
188}
189
190unsigned char *mkdfu(int dfu_type, char *dfu_arg, int* dfu_size,
191 char* errstr, int errstrsize)
192{
193 const struct ipod_models *model = NULL;
194 unsigned char *dfu_buf = NULL;
195 unsigned char *f_buf;
196 int f_size;
197 uint32_t padded_bl_size;
198 uint32_t cert_off, cert_sz;
199 off_t cur_off;
200 char *dfu_desc;
201 int i;
202
203 switch (dfu_type)
204 {
205 case DFU_INST:
206 case DFU_INST_SINGLE:
207 f_buf = load_file(dfu_arg, &f_size, &model, errstr, errstrsize);
208 if (f_buf == NULL)
209 goto error;
210 /* IM3 data size should be padded to 16 */
211 padded_bl_size = ((f_size + 0xf) & ~0xf);
212 *dfu_size = BIN_OFFSET + (model->dualboot_install_size +
213 (IM3HDR_SZ - (int)IM3INFO_SZ) + (int)padded_bl_size);
214 dfu_desc = (dfu_type == DFU_INST_SINGLE) ? "BL installer (single)"
215 : "BL installer";
216 break;
217
218 case DFU_UNINST:
219 for (i = 0; i < NUM_MODELS; i++) {
220 if (!strcmp(ipod_identity[i].platform_name, dfu_arg)) {
221 model = &ipod_identity[i];
222 break;
223 }
224 }
225 if (!model)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200226 _ERR("Platform name \"%s\" unknown", dfu_arg);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100227
228 *dfu_size = BIN_OFFSET + model->dualboot_uninstall_size;
229 dfu_desc = "BL uninstaller";
230 break;
231
232 case DFU_RAW:
233 default:
234 f_buf = load_file(dfu_arg, &f_size, NULL, errstr, errstrsize);
235 if (f_buf == NULL)
236 goto error;
237 /* IM3 data size should be padded to 16 */
238 *dfu_size = BIN_OFFSET + ((f_size + 0xf) & ~0xf);
239 dfu_desc = "raw binary";
240 break;
241 }
242
243 printf("[INFO] Building DFU:\n");
244 printf("[INFO] type: %s\n", dfu_desc);
245 if ((dfu_type == DFU_INST) || (dfu_type == DFU_INST_SINGLE))
246 printf("[INFO] BL size: %d\n", f_size);
247 if (dfu_type == DFU_RAW)
248 printf("[INFO] BIN size: %d\n", f_size);
249 printf("[INFO] DFU size: %d\n", *dfu_size);
250 if (model) {
251 printf("[INFO] model name: %s\n", model->model_name);
252 printf("[INFO] platform: %s\n", model->platform_name);
253 printf("[INFO] RB name: %s\n", model->rb_model_name);
254 printf("[INFO] RB num: %d\n", model->rb_model_num);
255 }
256
257 if (*dfu_size > DFU_MAXSIZE)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200258 _ERR("DFU image (%d bytes) too big", *dfu_size);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100259
260 dfu_buf = calloc(*dfu_size, 1);
261 if (!dfu_buf)
Cástor Muñozfbbba922017-05-04 10:52:03 +0200262 _ERR("Could not allocate %d bytes for DFU image", *dfu_size);
Cástor Muñoz346423c2016-02-04 23:05:17 +0100263
264 cert_off = get_uint32le(s5l8702hdr.u.enc34.cert_off);
265 cert_sz = get_uint32le(s5l8702hdr.u.enc34.cert_sz);
266
267 memcpy(dfu_buf, &s5l8702hdr, sizeof(s5l8702hdr));
268
269 cur_off = IM3HDR_SZ + cert_off;
270
271 memcpy(dfu_buf + cur_off, s5l8702pwnage, sizeof(s5l8702pwnage));
272
273 /* set entry point */
274 cur_off += cert_sz - 4;
275 put_uint32le(dfu_buf + cur_off, DFU_LOADADDR + BIN_OFFSET);
276
277 cur_off = BIN_OFFSET;
278
279 switch (dfu_type)
280 {
281 case DFU_INST:
282 case DFU_INST_SINGLE:
283 /* copy the dualboot installer binary */
284 memcpy(dfu_buf + cur_off, model->dualboot_install,
285 model->dualboot_install_size);
286 /* point to the start of the included IM3 header info */
287 cur_off += model->dualboot_install_size - IM3INFO_SZ;
288 /* set bootloader data size */
289 struct Im3Info *bl_info = (struct Im3Info*)(dfu_buf + cur_off);
290 put_uint32le(bl_info->data_sz, padded_bl_size);
291 /* use info_sign to pass params to the dualboot installer */
292 if (dfu_type == DFU_INST_SINGLE)
293 bl_info->info_sign[0] = 0x1;
294 /* add bootloader binary */
295 cur_off += IM3HDR_SZ;
296 memcpy(dfu_buf + cur_off, f_buf, f_size);
297 break;
298
299 case DFU_UNINST:
300 /* copy the dualboot uninstaller binary */
301 memcpy(dfu_buf + cur_off, model->dualboot_uninstall,
302 model->dualboot_uninstall_size);
303 break;
304
305 case DFU_RAW:
306 default:
307 /* add raw binary */
308 memcpy(dfu_buf + cur_off, f_buf, f_size);
309 break;
310 }
311
312 return dfu_buf;
313
314error:
315 if (dfu_buf)
316 free(dfu_buf);
317 return NULL;
318}