summaryrefslogtreecommitdiff
path: root/tools/fwpatcher/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/fwpatcher/main.c')
-rw-r--r--tools/fwpatcher/main.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/tools/fwpatcher/main.c b/tools/fwpatcher/main.c
new file mode 100644
index 0000000000..c8fa11ea95
--- /dev/null
+++ b/tools/fwpatcher/main.c
@@ -0,0 +1,367 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Thom Johansen
11 *
12 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
13 * KIND, either express or implied.
14 *
15 ****************************************************************************/
16
17/* TODO: integrate the iriver.c and mkboot stuff better, they're pretty much
18 * intended to be called from a command line tool, and i haven't changed that.
19 */
20
21#include <stdio.h>
22#include <string.h>
23#include <tchar.h>
24#include <windows.h>
25#include "iriver.h"
26#include "md5.h"
27#include "resource.h"
28
29#define WINDOW_WIDTH 280
30#define WINDOW_HEIGHT 130
31
32#define IDM_RESTORE 1000
33#define IDM_EXIT 1010
34
35#define LABEL_FILENAME 0
36#define EDIT_FILENAME 1
37#define BUTTON_BROWSE 2
38#define BUTTON_PATCH 3
39
40#define CTL_NUM 4
41
42/* include precalculated checksums */
43static char *checksums[] = {
44#include "checksums.h"
45};
46
47HICON rbicon;
48HFONT deffont;
49HWND controls[CTL_NUM];
50
51/* begin mkboot.c excerpt */
52
53char image[0x200000 + 0x220 + 0x200000/0x200];
54
55int mkboot(TCHAR *infile, TCHAR *outfile, unsigned char *bldata, int bllen)
56{
57 FILE *f;
58 int i;
59 int len;
60 int actual_length, total_length, binary_length, num_chksums;
61
62 memset(image, 0xff, sizeof(image));
63
64 /* First, read the iriver original firmware into the image */
65 f = _tfopen(infile, TEXT("rb"));
66 if(!f) {
67 perror(infile);
68 return 0;
69 }
70
71 i = fread(image, 1, 16, f);
72 if(i < 16) {
73 perror(infile);
74 return 0;
75 }
76
77 /* This is the length of the binary image without the scrambling
78 overhead (but including the ESTFBINR header) */
79 binary_length = image[4] + (image[5] << 8) +
80 (image[6] << 16) + (image[7] << 24);
81
82 /* Read the rest of the binary data, but not the checksum block */
83 len = binary_length+0x200-16;
84 i = fread(image+16, 1, len, f);
85 if(i < len) {
86 perror(infile);
87 return 0;
88 }
89
90 fclose(f);
91
92 memcpy(image + 0x220 + 0x1f0000, bldata, bllen);
93
94 f = _tfopen(outfile, TEXT("wb"));
95 if(!f) {
96 perror(outfile);
97 return 0;
98 }
99
100 /* Patch the reset vector to start the boot loader */
101 image[0x220 + 4] = image[0x1f0000 + 0x220 + 4];
102 image[0x220 + 5] = image[0x1f0000 + 0x220 + 5];
103 image[0x220 + 6] = image[0x1f0000 + 0x220 + 6];
104 image[0x220 + 7] = image[0x1f0000 + 0x220 + 7];
105
106 /* This is the actual length of the binary, excluding all headers */
107 actual_length = 0x1f0000 + bllen;
108
109 /* Patch the ESTFBINR header */
110 image[0x20c] = (actual_length >> 24) & 0xff;
111 image[0x20d] = (actual_length >> 16) & 0xff;
112 image[0x20e] = (actual_length >> 8) & 0xff;
113 image[0x20f] = actual_length & 0xff;
114
115 image[0x21c] = (actual_length >> 24) & 0xff;
116 image[0x21d] = (actual_length >> 16) & 0xff;
117 image[0x21e] = (actual_length >> 8) & 0xff;
118 image[0x21f] = actual_length & 0xff;
119
120 /* This is the length of the binary, including the ESTFBINR header and
121 rounded up to the nearest 0x200 boundary */
122 binary_length = (actual_length + 0x20 + 0x1ff) & 0xfffffe00;
123
124 /* The number of checksums, i.e number of 0x200 byte blocks */
125 num_chksums = binary_length / 0x200;
126
127 /* The total file length, including all headers and checksums */
128 total_length = binary_length + num_chksums + 0x200;
129
130 /* Patch the scrambler header with the new length info */
131 image[0] = total_length & 0xff;
132 image[1] = (total_length >> 8) & 0xff;
133 image[2] = (total_length >> 16) & 0xff;
134 image[3] = (total_length >> 24) & 0xff;
135
136 image[4] = binary_length & 0xff;
137 image[5] = (binary_length >> 8) & 0xff;
138 image[6] = (binary_length >> 16) & 0xff;
139 image[7] = (binary_length >> 24) & 0xff;
140
141 image[8] = num_chksums & 0xff;
142 image[9] = (num_chksums >> 8) & 0xff;
143 image[10] = (num_chksums >> 16) & 0xff;
144 image[11] = (num_chksums >> 24) & 0xff;
145
146 i = fwrite(image, 1, total_length, f);
147 if(i < total_length) {
148 perror(outfile);
149 return 0;
150 }
151
152 fclose(f);
153
154 return 1;
155}
156
157/* end mkboot.c excerpt */
158
159int FileMD5(TCHAR *name, char *md5)
160{
161 int i, read;
162 md5_context ctx;
163 unsigned char md5sum[16];
164 unsigned char block[32768];
165 FILE *file;
166
167 file = _tfopen(name, TEXT("rb"));
168 if (!file) {
169 MessageBox(NULL,
170 TEXT("Could not open patched firmware for checksum check"),
171 TEXT("Error"), MB_ICONERROR);
172 return 0;
173 }
174 md5_starts(&ctx);
175 while ((read = fread(block, 1, sizeof(block), file)) > 0) {
176 md5_update(&ctx, block, read);
177 }
178 fclose(file);
179 md5_finish(&ctx, md5sum);
180 for (i = 0; i < 16; ++i)
181 sprintf(md5 + 2*i, "%02x", md5sum[i]);
182 return 1;
183}
184
185int PatchFirmware()
186{
187 TCHAR fn[MAX_PATH];
188 TCHAR name1[MAX_PATH], name2[MAX_PATH], name3[MAX_PATH];
189 HRSRC res;
190 HGLOBAL resload;
191 unsigned char *bootloader;
192 unsigned char md5sum_str[256];
193 DWORD blsize;
194 int i;
195
196 /* get pointer to bootloader.bin */
197 res = FindResource(NULL, MAKEINTRESOURCE(IDI_BOOTLOADER), TEXT("BIN"));
198 resload = LoadResource(NULL, res);
199 bootloader = (unsigned char *)LockResource(resload);
200 blsize = SizeofResource(NULL, res);
201
202 /* get filename from edit box */
203 GetWindowText(controls[EDIT_FILENAME], fn, MAX_PATH);
204 /* store temp files in temp directory */
205 GetTempPath(MAX_PATH, name1);
206 GetTempPath(MAX_PATH, name2);
207 GetTempPath(MAX_PATH, name3);
208 _tcscat(name1, TEXT("firmware.bin")); /* descrambled file */
209 _tcscat(name2, TEXT("new.bin")); /* patched file */
210 _tcscat(name3, TEXT("new.hex")); /* patched and scrambled file */
211 if (iriver_decode(fn, name1, FALSE, STRIP_NONE) == -1) {
212 MessageBox(NULL, TEXT("Error in descramble"),
213 TEXT("Error"), MB_ICONERROR);
214 goto error;
215 }
216 if (!mkboot(name1, name2, bootloader, blsize)) {
217 MessageBox(NULL, TEXT("Error in patching"),
218 TEXT("Error"), MB_ICONERROR);
219 goto error;
220 }
221 if (iriver_encode(name2, name3, FALSE) == -1) {
222 MessageBox(NULL, TEXT("Error in scramble"),
223 TEXT("Error"), MB_ICONERROR);
224 goto error;
225 }
226 /* now md5sum it */
227 if (!FileMD5(name3, md5sum_str)) goto error;
228 for (i = 0; i < sizeof(checksums)/sizeof(char *); ++i) {
229 if (strncmp(checksums[i], md5sum_str, 32) != 0) {
230 MessageBox(NULL,
231 TEXT("Checksum doesn't match known good patched firmware.\n")
232 TEXT("Download another firmware image, then try again."),
233 TEXT("Error"), MB_ICONERROR);
234 goto error;
235 }
236 }
237 /* all is fine, rename the patched file to original name of the firmware */
238 MoveFileEx(name3, fn, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
239 /* delete temp files */
240 DeleteFile(name1);
241 DeleteFile(name2);
242 return 1;
243error:
244 /* delete all temp files, don't care if some aren't created yet */
245 DeleteFile(name1);
246 DeleteFile(name2);
247 DeleteFile(name3);
248 return 0;
249}
250
251int FileDialog(TCHAR *fn)
252{
253 OPENFILENAME ofn;
254 TCHAR filename[MAX_PATH];
255
256 ZeroMemory(&ofn, sizeof(ofn));
257 ofn.lStructSize = sizeof(ofn);
258 ofn.lpstrFile = filename;
259 ofn.lpstrFile[0] = '\0'; // no default filename
260 ofn.nMaxFile = sizeof(filename);
261 ofn.lpstrFilter = TEXT("Firmware\0*.HEX\0");
262 ofn.nFilterIndex = 1;
263 ofn.lpstrFileTitle = NULL;
264 ofn.nMaxFileTitle = 0;
265 ofn.lpstrInitialDir = NULL;
266 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
267
268 if (GetOpenFileName(&ofn) == TRUE) {
269 _tcscpy(fn, filename);
270 return 1;
271 }
272 return 0;
273}
274
275LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
276{
277 int i;
278 switch (msg) {
279 case WM_CREATE:
280 /* text label */
281 controls[LABEL_FILENAME] =
282 CreateWindowEx(0, TEXT("STATIC"), TEXT("Firmware file name:"),
283 WS_CHILD | WS_VISIBLE, 10, 14,
284 100, 32, hwnd, 0, 0, 0);
285 /* text field for inputing file name */
286 controls[EDIT_FILENAME] =
287 CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT(""),
288 WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL,
289 10, 35, 180, 20, hwnd, 0, 0, 0);
290 /* browse button */
291 controls[BUTTON_BROWSE] =
292 CreateWindowEx(0, TEXT("BUTTON"), TEXT("Browse"),
293 WS_CHILD | WS_TABSTOP | WS_VISIBLE, 200, 32, 70, 25,
294 hwnd, 0, 0, 0);
295 /* patch button */
296 controls[BUTTON_PATCH] =
297 CreateWindowEx(0, TEXT("BUTTON"), TEXT("Patch"),
298 WS_CHILD | WS_TABSTOP | WS_VISIBLE, 90, 70, 90, 25,
299 hwnd, 0, 0, 0);
300 /* set default font on all controls, will be ugly if we don't do this */
301 deffont = GetStockObject(DEFAULT_GUI_FONT);
302 for (i = 0; i < CTL_NUM; ++i)
303 SendMessage(controls[i], WM_SETFONT, (WPARAM)deffont,
304 MAKELPARAM(FALSE, 0));
305 break;
306 case WM_CLOSE:
307 DestroyWindow(hwnd);
308 break;
309 case WM_DESTROY:
310 PostQuitMessage(0);
311 break;
312 case WM_SIZE:
313 break;
314 case WM_COMMAND:
315 /* user pressed browse button */
316 if (((HWND)lParam == controls[BUTTON_BROWSE])) {
317 TCHAR buf[MAX_PATH];
318 if (FileDialog(buf))
319 SetWindowText(controls[EDIT_FILENAME], buf);
320 }
321 /* user pressed patch button */
322 if (((HWND)lParam == controls[BUTTON_PATCH])) {
323 if (PatchFirmware())
324 MessageBox(NULL, TEXT("Firmware patched successfully"),
325 TEXT("Success"), MB_OK);
326 }
327 break;
328 default:
329 return DefWindowProc(hwnd, msg, wParam, lParam);
330 }
331 return 0;
332}
333
334int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance,
335 LPSTR command_line, int command_show)
336{
337 HWND window;
338 WNDCLASSEX wc;
339 MSG msg;
340
341 rbicon = LoadIcon(instance, MAKEINTRESOURCE(IDI_RBICON));
342 ZeroMemory(&wc, sizeof(wc));
343 wc.cbSize = sizeof(wc);
344 wc.lpfnWndProc = WndProc;
345 wc.hInstance = instance;
346 wc.hIcon = rbicon;
347 wc.hCursor = LoadCursor(0, IDC_ARROW);
348 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
349 wc.lpszClassName = TEXT("patcher");
350 RegisterClassEx(&wc);
351
352 window = CreateWindowEx(0, TEXT("patcher"), TEXT("Rockbox firmware patcher"),
353 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
354 WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
355 WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, instance, NULL);
356 if (!window) return 0;
357
358 ShowWindow(window, command_show);
359 while (GetMessage(&msg, 0, 0, 0) > 0) {
360 if (!IsDialogMessage(window, &msg)) {
361 TranslateMessage(&msg);
362 DispatchMessage(&msg);
363 }
364 }
365 return 0;
366}
367