summaryrefslogtreecommitdiff
path: root/utils/mknwzboot/mknwzboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mknwzboot/mknwzboot.c')
-rw-r--r--utils/mknwzboot/mknwzboot.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/utils/mknwzboot/mknwzboot.c b/utils/mknwzboot/mknwzboot.c
new file mode 100644
index 0000000000..22885674d8
--- /dev/null
+++ b/utils/mknwzboot/mknwzboot.c
@@ -0,0 +1,294 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Amaury Pouly
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 <stdarg.h>
24#include <string.h>
25#include <ctype.h>
26#include "mknwzboot.h"
27#include "upg.h"
28
29#include "install_script.h"
30#include "uninstall_script.h"
31
32struct nwz_model_desc_t
33{
34 /* Descriptive name of this model */
35 const char *model_name;
36 /* Model name used in the Rockbox header in ".sansa" files - these match the
37 -add parameter to the "scramble" tool */
38 const char *rb_model_name;
39 /* Model number used to initialise the checksum in the Rockbox header in
40 ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
41 const int rb_model_num;
42 /* Codename used in upgtool */
43 const char *codename;
44};
45
46static const struct nwz_model_desc_t nwz_models[] =
47{
48 { "Sony NWZ-E350 Series", "e350", 109, "nwz-e350" },
49 { "Sony NWZ-E450 Series", "e450", 100, "nwz-e450" },
50 { "Sony NWZ-E460 Series", "e460", 101, "nwz-e460" },
51 { "Sony NWZ-E470 Series", "e470", 103, "nwz-e470" },
52 { "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" },
53 { "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" },
54 { "Sony NW-A20 Series", "a20", 106, "nw-a20" },
55 { "Sony NWZ-A860 Series", "a860", 107, "nwz-a860" },
56 { "Sony NWZ-S750 Series", "s750", 108, "nwz-s750" },
57};
58
59#define NR_NWZ_MODELS (sizeof(nwz_models) / sizeof(nwz_models[0]))
60
61void dump_nwz_dev_info(const char *prefix)
62{
63 printf("%smknwzboot models:\n", prefix);
64 for(int i = 0; i < NR_NWZ_MODELS; i++)
65 {
66 printf("%s %s: rb_model=%s rb_num=%d codename=%s\n", prefix,
67 nwz_models[i].model_name, nwz_models[i].rb_model_name,
68 nwz_models[i].rb_model_num, nwz_models[i].codename);
69 }
70}
71
72/* read a file to a buffer */
73static void *read_file(const char *file, size_t *size)
74{
75 FILE *f = fopen(file, "rb");
76 if(f == NULL)
77 {
78 printf("[ERR] Cannot open file '%s' for reading: %m\n", file);
79 return NULL;
80 }
81 fseek(f, 0, SEEK_END);
82 *size = ftell(f);
83 fseek(f, 0, SEEK_SET);
84 void *buffer = malloc(*size);
85 if(fread(buffer, *size, 1, f) != 1)
86 {
87 free(buffer);
88 fclose(f);
89 printf("[ERR] Cannot read file '%s': %m\n", file);
90 return NULL;
91 }
92 fclose(f);
93 return buffer;
94}
95
96/* write a file from a buffer */
97static bool write_file(const char *file, void *buffer, size_t size)
98{
99 FILE *f = fopen(file, "wb");
100 if(f == NULL)
101 {
102 printf("[ERR] Cannot open file '%s' for writing: %m\n", file);
103 return false;
104 }
105 if(fwrite(buffer, size, 1, f) != 1)
106 {
107 fclose(f);
108 printf("[ERR] Cannot write file '%s': %m\n", file);
109 return false;
110 }
111 fclose(f);
112 return true;
113}
114
115static unsigned int be2int(unsigned char* buf)
116{
117 return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
118}
119
120static int find_model(uint8_t *boot, size_t boot_size)
121{
122 if(boot_size < 8)
123 {
124 printf("[ERR] Boot file is too small to be valid\n");
125 return -1;
126 }
127 /* find model by comparing magic scramble value */
128 int model = 0;
129 for(; model < NR_NWZ_MODELS; model++)
130 if(memcmp(boot + 4, nwz_models[model].rb_model_name, 4) == 0)
131 break;
132 if(model == NR_NWZ_MODELS)
133 {
134 printf("[ERR] This player is not supported: %.4s\n", boot + 4);
135 return -1;
136 }
137 printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
138 /* verify checksum */
139 uint32_t sum = nwz_models[model].rb_model_num;
140 for(int i = 8; i < boot_size; i++)
141 sum += boot[i];
142 if(sum != be2int(boot))
143 {
144 printf("[ERR] Checksum mismatch\n");
145 return -1;
146 }
147 return model;
148}
149
150static int find_model2(const char *model_str)
151{
152 /* since it can be confusing for the user, we accept both rbmodel and codename */
153 /* find model by comparing magic scramble value */
154 int model = 0;
155 for(; model < NR_NWZ_MODELS; model++)
156 if(strcmp(nwz_models[model].rb_model_name, model_str) == 0 ||
157 strcmp(nwz_models[model].codename, model_str) == 0)
158 break;
159 if(model == NR_NWZ_MODELS)
160 {
161 printf("[ERR] Unknown model: %s\n", model_str);
162 return -1;
163 }
164 printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
165 return model;
166}
167
168static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE])
169{
170 const char *codename = nwz_models[model].codename;
171 for(int i = 0; g_model_list[i].model; i++)
172 if(strcmp(g_model_list[i].model, codename) == 0)
173 {
174 if(decrypt_keysig(g_model_list[i].kas, key, sig) == 0)
175 return true;
176 printf("[ERR] Cannot decrypt kas '%s'\n", g_model_list[i].kas);
177 return false;
178 }
179 printf("[ERR] Codename '%s' matches to entry in upg database\n", codename);
180 return false;
181}
182
183void nwz_printf(void *u, bool err, color_t c, const char *f, ...)
184{
185 (void)err;
186 (void)c;
187 bool *debug = u;
188 va_list args;
189 va_start(args, f);
190 if(err || *debug)
191 vprintf(f, args);
192 va_end(args);
193}
194
195static void *memdup(void *data, size_t size)
196{
197 void *buf = malloc(size);
198 memcpy(buf, data, size);
199 return buf;
200}
201
202int mknwzboot(const char *bootfile, const char *outfile, bool debug)
203{
204 size_t boot_size;
205 uint8_t *boot = read_file(bootfile, &boot_size);
206 if(boot == NULL)
207 {
208 printf("[ERR] Cannot open boot file\n");
209 return 1;
210 }
211 /* check that it is a valid scrambled file */
212 int model = find_model(boot, boot_size);
213 if(model < 0)
214 {
215 free(boot);
216 printf("[ERR] Invalid boot file\n");
217 return 2;
218 }
219 /* find keys */
220 char key[NWZ_KEY_SIZE];
221 char sig[NWZ_SIG_SIZE];
222 if(!get_model_keysig(model, key, sig))
223 {
224 printf("[ERR][INTERNAL] Cannot get keys for model\n");
225 return 3;
226 }
227 /* create the upg file */
228 struct upg_file_t *upg = upg_new();
229 /* first file is the install script: we have to copy data because upg_free()
230 * will free it */
231 upg_append(upg, memdup(install_script, LEN_install_script), LEN_install_script);
232 /* second file is the bootloader content (expected to be a tar file): we have
233 * to copy data because upg_free() will free it */
234 upg_append(upg, memdup(boot + 8, boot_size - 8), boot_size - 8);
235 free(boot);
236 /* write file to buffer */
237 size_t upg_size;
238 void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
239 upg_free(upg);
240 if(upg_buf == NULL)
241 {
242 printf("[ERR] Cannot create UPG file\n");
243 return 4;
244 }
245 if(!write_file(outfile, upg_buf, upg_size))
246 {
247 free(upg_buf);
248 printf("[ERR] Cannpt write UPG file\n");
249 return 5;
250 }
251 free(upg_buf);
252 return 0;
253}
254
255int mknwzboot_uninst(const char *model_string, const char *outfile, bool debug)
256{
257 /* check that it is a valid scrambled file */
258 int model = find_model2(model_string);
259 if(model < 0)
260 {
261 printf("[ERR] Invalid model\n");
262 return 2;
263 }
264 /* find keys */
265 char key[NWZ_KEY_SIZE];
266 char sig[NWZ_SIG_SIZE];
267 if(!get_model_keysig(model, key, sig))
268 {
269 printf("[ERR][INTERNAL] Cannot get keys for model\n");
270 return 3;
271 }
272 /* create the upg file */
273 struct upg_file_t *upg = upg_new();
274 /* first file is the uninstall script: we have to copy data because upg_free()
275 * will free it */
276 upg_append(upg, memdup(uninstall_script, LEN_uninstall_script), LEN_uninstall_script);
277 /* write file to buffer */
278 size_t upg_size;
279 void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
280 upg_free(upg);
281 if(upg_buf == NULL)
282 {
283 printf("[ERR] Cannot create UPG file\n");
284 return 4;
285 }
286 if(!write_file(outfile, upg_buf, upg_size))
287 {
288 free(upg_buf);
289 printf("[ERR] Cannpt write UPG file\n");
290 return 5;
291 }
292 free(upg_buf);
293 return 0;
294}