summaryrefslogtreecommitdiff
path: root/rbutil/jztool/src/fiiom3k.c
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/jztool/src/fiiom3k.c')
-rw-r--r--rbutil/jztool/src/fiiom3k.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/rbutil/jztool/src/fiiom3k.c b/rbutil/jztool/src/fiiom3k.c
new file mode 100644
index 0000000000..a43863c2f7
--- /dev/null
+++ b/rbutil/jztool/src/fiiom3k.c
@@ -0,0 +1,283 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
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
22#include "jztool.h"
23#include <string.h>
24
25#define IMAGE_ADDR 0
26#define IMAGE_SIZE (128 * 1024)
27#define SPL_OFFSET 0
28#define SPL_SIZE (12 * 1024)
29#define BOOT_OFFSET (26 * 1024)
30#define BOOT_SIZE (102 * 1024)
31
32int jz_fiiom3k_readboot(jz_usbdev* dev, jz_buffer** bufptr)
33{
34 jz_buffer* buf = jz_buffer_alloc(IMAGE_SIZE, NULL);
35 if(!buf)
36 return JZ_ERR_OUT_OF_MEMORY;
37
38 int rc = jz_x1000_read_flash(dev, IMAGE_ADDR, buf->size, buf->data);
39 if(rc < 0) {
40 jz_buffer_free(buf);
41 return rc;
42 }
43
44 *bufptr = buf;
45 return JZ_SUCCESS;
46}
47
48int jz_fiiom3k_writeboot(jz_usbdev* dev, size_t image_size, const void* image_buf)
49{
50 int rc = jz_identify_fiiom3k_bootimage(image_buf, image_size);
51 if(rc < 0 || image_size != IMAGE_SIZE)
52 return JZ_ERR_BAD_FILE_FORMAT;
53
54 rc = jz_x1000_write_flash(dev, IMAGE_ADDR, image_size, image_buf);
55 if(rc < 0)
56 return rc;
57
58 return JZ_SUCCESS;
59}
60
61int jz_fiiom3k_patchboot(jz_context* jz, void* image_buf, size_t image_size,
62 const void* spl_buf, size_t spl_size,
63 const void* boot_buf, size_t boot_size)
64{
65 int rc = jz_identify_fiiom3k_bootimage(image_buf, image_size);
66 if(rc < 0) {
67 jz_log(jz, JZ_LOG_ERROR, "Boot image is invalid: %d", rc);
68 return JZ_ERR_BAD_FILE_FORMAT;
69 }
70
71 rc = jz_identify_x1000_spl(spl_buf, spl_size);
72 if(rc < 0) {
73 jz_log(jz, JZ_LOG_ERROR, "SPL image is invalid: %d", rc);
74 return JZ_ERR_BAD_FILE_FORMAT;
75 }
76
77 if(spl_size > SPL_SIZE) {
78 jz_log(jz, JZ_LOG_ERROR, "SPL is too big");
79 return JZ_ERR_BAD_FILE_FORMAT;
80 }
81
82 rc = jz_identify_scramble_image(boot_buf, boot_size);
83 if(rc < 0) {
84 jz_log(jz, JZ_LOG_ERROR, "Bootloader image is invalid: %d", rc);
85 return JZ_ERR_BAD_FILE_FORMAT;
86 }
87
88 if(boot_size > BOOT_SIZE) {
89 jz_log(jz, JZ_LOG_ERROR, "Bootloader is too big");
90 return JZ_ERR_BAD_FILE_FORMAT;
91 }
92
93 uint8_t* imgdat = (uint8_t*)image_buf;
94 memset(&imgdat[SPL_OFFSET], 0xff, SPL_SIZE);
95 memcpy(&imgdat[SPL_OFFSET], spl_buf, spl_size);
96 memset(&imgdat[BOOT_OFFSET], 0xff, BOOT_SIZE);
97 memcpy(&imgdat[BOOT_OFFSET], boot_buf, boot_size);
98 return JZ_SUCCESS;
99}
100
101#define IMGBUF 0
102#define SPLBUF 1
103#define BOOTBUF 2
104#define NUMBUFS 3
105#define IMGBUF_NAME "image"
106#define SPLBUF_NAME "spl"
107#define BOOTBUF_NAME "bootloader"
108#define FIIOM3K_INIT_WORKSTATE {0}
109
110struct fiiom3k_workstate {
111 jz_usbdev* dev;
112 jz_buffer* bufs[NUMBUFS];
113};
114
115static void fiiom3k_action_cleanup(struct fiiom3k_workstate* state)
116{
117 for(int i = 0; i < NUMBUFS; ++i)
118 if(state->bufs[i])
119 jz_buffer_free(state->bufs[i]);
120
121 if(state->dev)
122 jz_usb_close(state->dev);
123}
124
125static int fiiom3k_action_loadbuf(jz_context* jz, jz_paramlist* pl,
126 struct fiiom3k_workstate* state, int idx)
127{
128 const char* const paramnames[] = {IMGBUF_NAME, SPLBUF_NAME, BOOTBUF_NAME};
129
130 if(state->bufs[idx])
131 return JZ_SUCCESS;
132
133 const char* filename = jz_paramlist_get(pl, paramnames[idx]);
134 if(!filename) {
135 jz_log(jz, JZ_LOG_ERROR, "Missing required parameter '%s'", paramnames[idx]);
136 return JZ_ERR_OTHER;
137 }
138
139 int rc = jz_buffer_load(&state->bufs[idx], filename);
140 if(rc < 0) {
141 jz_log(jz, JZ_LOG_ERROR, "Error reading '%s' file (%d): %s", paramnames[idx], rc, filename);
142 return rc;
143 }
144
145 return JZ_SUCCESS;
146}
147
148static int fiiom3k_action_setup(jz_context* jz, jz_paramlist* pl,
149 struct fiiom3k_workstate* state)
150{
151 const jz_device_info* info = jz_get_device_info(JZ_DEVICE_FIIOM3K);
152 if(!info)
153 return JZ_ERR_OTHER;
154
155 int rc = fiiom3k_action_loadbuf(jz, pl, state, SPLBUF);
156 if(rc < 0)
157 return rc;
158
159 jz_log(jz, JZ_LOG_DETAIL, "Open USB device %04x:%04x",
160 (unsigned int)info->vendor_id, (unsigned int)info->product_id);
161 rc = jz_usb_open(jz, &state->dev, info->vendor_id, info->product_id);
162 if(rc < 0)
163 return rc;
164
165 jz_log(jz, JZ_LOG_DETAIL, "Setup device for flash access");
166 jz_buffer* splbuf = state->bufs[SPLBUF];
167 return jz_x1000_setup(state->dev, splbuf->size, splbuf->data);
168}
169
170int jz_fiiom3k_install(jz_context* jz, jz_paramlist* pl)
171{
172 struct fiiom3k_workstate state = FIIOM3K_INIT_WORKSTATE;
173 int rc;
174
175 rc = fiiom3k_action_loadbuf(jz, pl, &state, BOOTBUF);
176 if(rc < 0)
177 goto error;
178
179 rc = fiiom3k_action_setup(jz, pl, &state);
180 if(rc < 0)
181 goto error;
182
183 jz_log(jz, JZ_LOG_DETAIL, "Reading boot image from device");
184 rc = jz_fiiom3k_readboot(state.dev, &state.bufs[IMGBUF]);
185 if(rc < 0)
186 goto error;
187
188 jz_buffer* img_buf = state.bufs[IMGBUF];
189 const char* backupfile = jz_paramlist_get(pl, "backup");
190 const char* without_backup = jz_paramlist_get(pl, "without-backup");
191 if(backupfile) {
192 jz_log(jz, JZ_LOG_DETAIL, "Backup original boot image to file: %s", backupfile);
193 rc = jz_buffer_save(img_buf, backupfile);
194 if(rc < 0) {
195 jz_log(jz, JZ_LOG_ERROR, "Error saving backup image file (%d): %s", rc, backupfile);
196 goto error;
197 }
198 } else if(!without_backup || strcmp(without_backup, "yes")) {
199 jz_log(jz, JZ_LOG_ERROR, "No --backup option given and --without-backup yes not specified");
200 jz_log(jz, JZ_LOG_ERROR, "Refusing to flash a new bootloader without taking a backup");
201 goto error;
202 }
203
204 jz_log(jz, JZ_LOG_DETAIL, "Patching image with new SPL/bootloader");
205 jz_buffer* boot_buf = state.bufs[BOOTBUF];
206 jz_buffer* spl_buf = state.bufs[SPLBUF];
207 rc = jz_fiiom3k_patchboot(jz, img_buf->data, img_buf->size,
208 spl_buf->data, spl_buf->size,
209 boot_buf->data, boot_buf->size);
210 if(rc < 0) {
211 jz_log(jz, JZ_LOG_ERROR, "Error patching image: %d", rc);
212 goto error;
213 }
214
215 jz_log(jz, JZ_LOG_DETAIL, "Writing patched image to device");
216 rc = jz_fiiom3k_writeboot(state.dev, img_buf->size, img_buf->data);
217 if(rc < 0)
218 goto error;
219
220 rc = JZ_SUCCESS;
221
222 error:
223 fiiom3k_action_cleanup(&state);
224 return rc;
225}
226
227int jz_fiiom3k_backup(jz_context* jz, jz_paramlist* pl)
228{
229 struct fiiom3k_workstate state = FIIOM3K_INIT_WORKSTATE;
230 int rc;
231
232 const char* outfile_path = jz_paramlist_get(pl, IMGBUF_NAME);
233 if(!outfile_path) {
234 jz_log(jz, JZ_LOG_ERROR, "Missing required parameter '%s'", IMGBUF_NAME);
235 rc = JZ_ERR_OTHER;
236 goto error;
237 }
238
239 rc = fiiom3k_action_setup(jz, pl, &state);
240 if(rc < 0)
241 goto error;
242
243 rc = jz_fiiom3k_readboot(state.dev, &state.bufs[IMGBUF]);
244 if(rc < 0)
245 goto error;
246
247 rc = jz_buffer_save(state.bufs[IMGBUF], outfile_path);
248 if(rc < 0) {
249 jz_log(jz, JZ_LOG_ERROR, "Error writing '%s' file (%d): %s", IMGBUF_NAME, rc, outfile_path);
250 goto error;
251 }
252
253 rc = JZ_SUCCESS;
254
255 error:
256 fiiom3k_action_cleanup(&state);
257 return rc;
258}
259
260int jz_fiiom3k_restore(jz_context* jz, jz_paramlist* pl)
261{
262 struct fiiom3k_workstate state = FIIOM3K_INIT_WORKSTATE;
263 int rc;
264
265 rc = fiiom3k_action_loadbuf(jz, pl, &state, IMGBUF);
266 if(rc < 0)
267 goto error;
268
269 rc = fiiom3k_action_setup(jz, pl, &state);
270 if(rc < 0)
271 goto error;
272
273 jz_buffer* img_buf = state.bufs[IMGBUF];
274 rc = jz_fiiom3k_writeboot(state.dev, img_buf->size, img_buf->data);
275 if(rc < 0)
276 goto error;
277
278 rc = JZ_SUCCESS;
279
280 error:
281 fiiom3k_action_cleanup(&state);
282 return rc;
283}