summaryrefslogtreecommitdiff
path: root/utils/mkmpioboot/mkmpioboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mkmpioboot/mkmpioboot.c')
-rw-r--r--utils/mkmpioboot/mkmpioboot.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/utils/mkmpioboot/mkmpioboot.c b/utils/mkmpioboot/mkmpioboot.c
new file mode 100644
index 0000000000..ea619ed2f2
--- /dev/null
+++ b/utils/mkmpioboot/mkmpioboot.c
@@ -0,0 +1,243 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:$
9 *
10 * Copyright (C) 2010 by Marcin Bukat
11 *
12 * code taken mostly from mkboot.c
13 * Copyright (C) 2005 by Linus Nielsen Feltzing
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include "mkmpioboot.h"
28
29#define OF_FIRMWARE_LEN 0x100000 /* size of the OF file */
30#define MPIO_STRING_OFFSET 0xfffe0 /* offset of the version string in OF */
31#define BOOTLOADER_MAX_SIZE 0x1f800 /* free space size */
32
33struct mpio_model {
34 /* Descriptive name of this model */
35 const char* model_name;
36 /* Model name used in the Rockbox header in ".mpio" 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 ".mpio" files - these are the same as MODEL_NUMBER in config-target.h */
41 const int rb_model_num;
42 /* Strings which indentifies OF version */
43 const char* of_model_string;
44};
45
46static const struct mpio_model mpio_models[] = {
47 [MODEL_HD200] =
48 { "MPIO HD200", "hd20", 69, "HD200 HDD Audio Ver113005" },
49 [MODEL_HD300] =
50 { "MPIO HD300", "hd30", 70, "HD300 HDD Audio Ver113006" },
51};
52
53
54/* MPIO HD200 and HD300 firmware is plain binary image
55 * 4 bytes of initial SP (loaded on reset)
56 * 4 bytes of initial PC (loaded on reset)
57 * binary image with entry point 0x00000008
58 *
59 * We put our bootloader code at 0x000e0000
60 * and patch reset vector to jump directly
61 * into our code on reset
62 */
63
64static unsigned char image[OF_FIRMWARE_LEN];
65
66static unsigned int get_uint32be(unsigned char* p)
67{
68 return ((p[0] << 24) | (p[1] << 16) | (p[2]<<8) | p[3]);
69}
70
71static long checksum(unsigned char* buf, int model, unsigned long length)
72{
73 unsigned long chksum = model;
74 unsigned long i;
75
76 if(buf == NULL)
77 return -1;
78
79 for (i = 0; i < length; i++)
80 {
81 chksum += *buf++;
82 }
83
84return chksum;
85}
86
87int mkmpioboot(const char* infile, const char* bootfile, const char* outfile, int origin)
88{
89 FILE *f;
90 int i;
91 int len;
92 int model_index;
93 unsigned long file_checksum;
94 unsigned char header[8];
95
96 memset(image, 0xff, sizeof(image));
97
98 /* First, read the mpio original firmware into the image */
99 f = fopen(infile, "rb");
100 if(!f)
101 {
102 fprintf(stderr, "[ERR] Can not open %s file for reading\n", infile);
103 return -1;
104 }
105
106 i = fread(image, 1, OF_FIRMWARE_LEN, f);
107 if(i < OF_FIRMWARE_LEN)
108 {
109 fprintf(stderr, "[ERR] %s file read error\n", infile);
110 fclose(f);
111 return -2;
112 }
113
114 fclose(f);
115
116 /* Now check if we have OF file loaded based on presence
117 * of the version string in firmware
118 */
119
120 for(model_index = 0; model_index < NUM_MODELS; model_index++)
121 if (strcmp(mpio_models[model_index].of_model_string,
122 (char*)(image + MPIO_STRING_OFFSET)) == 0)
123 break;
124
125 if(model_index == NUM_MODELS)
126 {
127 fprintf(stderr, "[ERR] Unknown MPIO original firmware version\n");
128 return -3;
129 }
130
131 fprintf(stderr, "[INFO] Loading original firmware file for %s\n",
132 mpio_models[model_index].model_name);
133
134 /* Now, read the boot loader into the image */
135 f = fopen(bootfile, "rb");
136 if(!f)
137 {
138 fprintf(stderr, "[ERR] Can not open %s file for reading\n", bootfile);
139 return -4;
140 }
141
142 fprintf(stderr, "[INFO] Loading Rockbox bootloader file\n");
143
144 /* get bootloader size
145 * excluding header
146 */
147 fseek(f, 0, SEEK_END);
148 len = ftell(f) - 8;
149
150 if (len > BOOTLOADER_MAX_SIZE)
151 {
152 fprintf(stderr, "[ERR] Bootloader doesn't fit in firmware file.\n");
153 fprintf(stderr, "[ERR] This bootloader is %d bytes long\n", len);
154 fprintf(stderr, "[ERR] and maximum allowed size is %d bytes\n",
155 BOOTLOADER_MAX_SIZE);
156 return -5;
157 }
158
159 /* Now check if the place we want to put
160 * our bootloader is free
161 */
162 for(i=0;i<len;i++)
163 {
164 if (image[origin+i] != 0)
165 {
166 fprintf(stderr, "[ERR] Place for bootloader in OF file not empty\n");
167 return -6;
168 }
169 }
170
171 fseek(f, 0, SEEK_SET);
172
173 /* get bootloader header*/
174 fread(header,1,8,f);
175
176 if ( memcmp(header + 4, mpio_models[model_index].rb_model_name, 4) != 0 )
177 {
178 fprintf(stderr, "[ERR] Original firmware and rockbox bootloader mismatch!\n");
179 fprintf(stderr, "[ERR] Double check that you have bootloader for %s\n",
180 mpio_models[model_index].model_name);
181 return -7;
182 }
183
184 /* omit header */
185 fseek(f, 8, SEEK_SET);
186
187 i = fread(image + origin, 1, len, f);
188 if(i < len)
189 {
190 fprintf(stderr, "[ERR] %s file read error\n", bootfile);
191 fclose(f);
192 return -8;
193 }
194
195 fclose(f);
196
197 /* calculate checksum and compare with data
198 * from header
199 */
200 file_checksum = checksum(image + origin, mpio_models[model_index].rb_model_num, len);
201
202 if ( file_checksum != get_uint32be(header) )
203 {
204 fprintf(stderr,"[ERR] Bootloader checksum error\n");
205 return -9;
206 }
207
208 f = fopen(outfile, "wb");
209 if(!f)
210 {
211 fprintf(stderr, "[ERR] Can not open %s file for writing\n" ,outfile);
212 return -10;
213 }
214
215 fprintf(stderr, "[INFO] Patching reset vector\n");
216
217 /* Patch the stack pointer address */
218 image[0] = image[origin + 0];
219 image[1] = image[origin + 1];
220 image[2] = image[origin + 2];
221 image[3] = image[origin + 3];
222
223 /* Patch the reset vector to start the boot loader */
224 image[4] = image[origin + 4];
225 image[5] = image[origin + 5];
226 image[6] = image[origin + 6];
227 image[7] = image[origin + 7];
228
229 i = fwrite(image, 1, OF_FIRMWARE_LEN, f);
230 if(i < OF_FIRMWARE_LEN)
231 {
232 fprintf(stderr,"[ERR] %s file write error\n", outfile);
233 fclose(f);
234 return -11;
235 }
236
237 fprintf(stderr,"[INFO] Wrote 0x%x bytes in %s\n", OF_FIRMWARE_LEN, outfile);
238 fprintf(stderr,"[INFO] Patching succeeded!\n");
239
240 fclose(f);
241
242 return 0;
243}