summaryrefslogtreecommitdiff
path: root/utils/hwstub/tools/hwstub_load.cpp
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-06-13 02:02:53 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-06-13 02:25:15 +0200
commitc5357940ab0108b4102442d07825c44d5be0d22f (patch)
treeddfdd9744b1f0ac037fed1c802329cb4542f376b /utils/hwstub/tools/hwstub_load.cpp
parent934e1e15af6f2b7bcfdd9dbe8a3a6393ffe5a4a1 (diff)
downloadrockbox-c5357940ab0108b4102442d07825c44d5be0d22f.tar.gz
rockbox-c5357940ab0108b4102442d07825c44d5be0d22f.zip
hwstub: major improvement in the stub and the tools
Fix the stub in many way to correctly detect the STMP family and act upon that. Drop some unused commands and bump version. Rewrite the tool to allows scripting in lua and load the register description from an XML file using the regtools. Introduce a new tool to load and run code using the hwstub (either binary format or Rockbox additive scramble format). Also switch to an optimise version of the memcpy/move/set functions to correctly handle alignement issue (like writing a full word/half-word when possible for registers which is crucial) Change-Id: Id1d5cfe0b1b47e8b43900d32c5cd6eafae6414f6
Diffstat (limited to 'utils/hwstub/tools/hwstub_load.cpp')
-rw-r--r--utils/hwstub/tools/hwstub_load.cpp316
1 files changed, 316 insertions, 0 deletions
diff --git a/utils/hwstub/tools/hwstub_load.cpp b/utils/hwstub/tools/hwstub_load.cpp
new file mode 100644
index 0000000000..d58eb83396
--- /dev/null
+++ b/utils/hwstub/tools/hwstub_load.cpp
@@ -0,0 +1,316 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 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 "hwstub.h"
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <getopt.h>
26#include <stdbool.h>
27#include <ctype.h>
28
29struct player_info_t
30{
31 const char *name;
32 const char *username;
33 int modelnum;
34};
35
36enum image_type_t
37{
38 IT_RAW,
39 IT_ROCKBOX,
40 IT_DETECT,
41 /* positive values reserved for rockbox-specific models */
42};
43
44struct player_info_t players[] =
45{
46 { "zenv", "Zen V", 85 },
47 { "zmoz", "Zen Mozaic", 87 },
48 { "zen", "Zen", 88 },
49 { "zxfi", "Zen X-Fi", 86 },
50 { NULL, 0 },
51};
52
53enum image_type_t detect_type(unsigned char *buffer, size_t size)
54{
55 if(size < 8)
56 return IT_RAW;
57 int player;
58 for(player = 0; players[player].name; player++)
59 if(memcmp(buffer + 4, players[player].name, 4) == 0)
60 break;
61 if(players[player].name == NULL)
62 return IT_RAW;
63 unsigned long checksum = players[player].modelnum;
64 for(size_t i = 8; i < size; i++)
65 checksum += buffer[i];
66 unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
67 if(checksum != expected)
68 return IT_RAW;
69 return IT_ROCKBOX;
70}
71
72const char *get_player_name(unsigned char *buffer)
73{
74 for(int player = 0; players[player].name; player++)
75 if(memcmp(buffer, players[player].name, 4) == 0)
76 return players[player].username;
77 return NULL;
78}
79
80bool could_be_rockbox(unsigned char *buffer, size_t size)
81{
82 /* usually target use 3 or 4 digits */
83 if(size >= 8 && isprint(buffer[4]) && isprint(buffer[5]) && isprint(buffer[6]) &&
84 (isprint(buffer[7]) || buffer[7] == 0))
85 {
86 unsigned long checksum = 0;
87 for(size_t i = 8; i < size; i++)
88 checksum += buffer[i];
89 unsigned long expected = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
90 unsigned long expected_modelnm = expected - checksum;
91 if(expected_modelnm < 150)
92 fprintf(stderr, "This file looks like a valid rockbox image but I don't know this player: %.4s (modelnum=%ld)\n",
93 buffer + 4, expected_modelnm);
94 else
95 fprintf(stderr, "This file could be a valid rockbox image but I don't know this player and the checksum is strange: %.4s\n",
96 buffer + 4);
97 return true;
98 }
99 else
100 return false;
101}
102
103void usage(void)
104{
105 printf("usage: hwstub_load [options] <addr> <file>\n");
106 printf("options:\n");
107 printf(" --help/-? Display this help\n");
108 printf(" --quiet/-q Quiet output\n");
109 printf(" --type/-t <t> Override file type\n");
110 printf("file types:\n");
111 printf(" raw Load a raw binary blob\n");
112 printf(" rockbox Load a rockbox image produced by scramble\n");
113 printf(" detect Try to guess the format\n");
114 printf("known players:");
115 for(int i = 0; players[i].name; i++)
116 printf(" %s", players[i].name);
117 printf("\n");
118 exit(1);
119}
120
121int main(int argc, char **argv)
122{
123 bool quiet = false;
124 struct hwstub_device_t hwdev;
125 enum image_type_t type = IT_DETECT;
126
127 // parse command line
128 while(1)
129 {
130 static struct option long_options[] =
131 {
132 {"help", no_argument, 0, '?'},
133 {"quiet", no_argument, 0, 'q'},
134 {"type", required_argument, 0, 't'},
135 {0, 0, 0, 0}
136 };
137
138 int c = getopt_long(argc, argv, "?qt:", long_options, NULL);
139 if(c == -1)
140 break;
141 switch(c)
142 {
143 case -1:
144 break;
145 case 'q':
146 quiet = true;
147 break;
148 case '?':
149 usage();
150 break;
151 case 't':
152 if(strcmp(optarg, "raw") == 0)
153 type = IT_RAW;
154 else if(strcmp(optarg, "rockbox") == 0)
155 type = IT_ROCKBOX;
156 else if(strcmp(optarg, "detect") == 0)
157 type = IT_DETECT;
158 else
159 {
160 fprintf(stderr, "Unknown file type '%s'\n", optarg);
161 return 1;
162 }
163 break;
164 default:
165 abort();
166 }
167 }
168
169 if(optind + 2 != argc)
170 usage();
171
172 char *end;
173 unsigned long addr = strtoul(argv[optind], &end, 0);
174 if(*end)
175 {
176 fprintf(stderr, "Invalid load address\n");
177 return 2;
178 }
179
180 FILE *f = fopen(argv[optind + 1], "rb");
181 if(f == NULL)
182 {
183 fprintf(stderr, "Cannot open file for reading: %m\n");
184 return 3;
185 }
186 fseek(f, 0, SEEK_END);
187 size_t size = ftell(f);
188 fseek(f, 0, SEEK_SET);
189 unsigned char *buffer = (unsigned char*)malloc(size);
190 fread(buffer, size, 1, f);
191 fclose(f);
192
193 if(type == IT_ROCKBOX || type == IT_DETECT)
194 {
195 enum image_type_t det = detect_type(buffer, size);
196 if(type == IT_ROCKBOX && det != IT_ROCKBOX)
197 {
198 if(!could_be_rockbox(buffer, size))
199 fprintf(stderr, "This file does not appear to be valid rockbox image.\n");
200 return 4;
201 }
202 if(type == IT_DETECT && det == IT_RAW)
203 could_be_rockbox(buffer, size);
204 type = det;
205 if(type == IT_ROCKBOX)
206 {
207 if(!quiet)
208 printf("Rockox image is for player %s (%.4s)\n", get_player_name(buffer + 4), buffer + 4);
209 memmove(buffer, buffer + 8, size - 8);
210 size -= 8;
211 }
212 }
213
214 if(!quiet)
215 {
216 if(type == IT_RAW)
217 printf("Loading raw image at %#lx\n", addr);
218 else
219 printf("Loading rockbox image at %#lx\n", addr);
220 }
221
222 // create usb context
223 libusb_context *ctx;
224 libusb_init(&ctx);
225 libusb_set_debug(ctx, 3);
226
227 // look for device
228 if(!quiet)
229 printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID);
230
231 libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx,
232 HWSTUB_USB_VID, HWSTUB_USB_PID);
233 if(handle == NULL)
234 {
235 fprintf(stderr, "No device found\n");
236 return 1;
237 }
238
239 // admin stuff
240 libusb_device *mydev = libusb_get_device(handle);
241 if(!quiet)
242 {
243 printf("device found at %d:%d\n",
244 libusb_get_bus_number(mydev),
245 libusb_get_device_address(mydev));
246 }
247 hwdev.handle = handle;
248 if(hwstub_probe(&hwdev))
249 {
250 fprintf(stderr, "Cannot probe device!\n");
251 return 1;
252 }
253
254 // get hwstub information
255 struct usb_resp_info_version_t hwdev_ver;
256 int ret = hwstub_get_info(&hwdev, HWSTUB_INFO_VERSION, &hwdev_ver, sizeof(hwdev_ver));
257 if(ret != sizeof(hwdev_ver))
258 {
259 fprintf(stderr, "Cannot get version!\n");
260 goto Lerr;
261 }
262 if(hwdev_ver.major != HWSTUB_VERSION_MAJOR || hwdev_ver.minor < HWSTUB_VERSION_MINOR)
263 {
264 printf("Warning: this tool is possibly incompatible with your device:\n");
265 printf("Device version: %d.%d.%d\n", hwdev_ver.major, hwdev_ver.minor, hwdev_ver.revision);
266 printf("Host version: %d.%d.%d\n", HWSTUB_VERSION_MAJOR, HWSTUB_VERSION_MINOR, HWSTUB_VERSION_REV);
267 }
268
269 // get features
270 struct usb_resp_info_features_t hwdev_features;
271 ret = hwstub_get_info(&hwdev, HWSTUB_INFO_FEATURES, &hwdev_features, sizeof(hwdev_features));
272 if(ret != sizeof(hwdev_features))
273 {
274 fprintf(stderr, "Cannot get features: %d\n", ret);
275 goto Lerr;
276 }
277 if(!(hwdev_features.feature_mask & HWSTUB_RW_MEM))
278 {
279 fprintf(stderr, "Device doesn't support R/W commands\n");
280 goto Lerr;
281 }
282 if(!(hwdev_features.feature_mask & HWSTUB_JUMP))
283 {
284 fprintf(stderr, "Device doesn't support jump commands\n");
285 goto Lerr;
286 }
287 ret = hwstub_rw_mem(&hwdev, 0, addr, buffer, size);
288 if(ret != (int)size)
289 {
290 fprintf(stderr, "Image write failed\n");
291 goto Lerr;
292 }
293 hwstub_jump(&hwdev, addr);
294
295 hwstub_release(&hwdev);
296 return 0;
297
298 Lerr:
299 // display log if handled
300 if(hwdev_features.feature_mask & HWSTUB_FEATURE_LOG)
301 {
302 fprintf(stderr, "Device log:\n");
303 do
304 {
305 char buffer[128];
306 int length = hwstub_get_log(&hwdev, buffer, sizeof(buffer) - 1);
307 if(length <= 0)
308 break;
309 buffer[length] = 0;
310 fprintf(stderr, "%s", buffer);
311 }while(1);
312 }
313 hwstub_release(&hwdev);
314 return 1;
315}
316