diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/rk27utils/README | 15 | ||||
-rw-r--r-- | utils/rk27utils/rkwtool/Makefile | 7 | ||||
-rw-r--r-- | utils/rk27utils/rkwtool/main.c | 129 | ||||
-rw-r--r-- | utils/rk27utils/rkwtool/rkw.c | 538 | ||||
-rw-r--r-- | utils/rk27utils/rkwtool/rkw.h | 123 |
5 files changed, 812 insertions, 0 deletions
diff --git a/utils/rk27utils/README b/utils/rk27utils/README index d0343580b8..802f5a559b 100644 --- a/utils/rk27utils/README +++ b/utils/rk27utils/README | |||
@@ -36,6 +36,21 @@ rockchip player. | |||
36 | 36 | ||
37 | You need libusb-1.0 + header files in order to compile this utility. | 37 | You need libusb-1.0 + header files in order to compile this utility. |
38 | 38 | ||
39 | |||
40 | rkwtool | ||
41 | This directory contains tool to inspect and extract content of | ||
42 | 'full' update RKW file. | ||
43 | |||
44 | The RKW file contains specific section which instruct update | ||
45 | routine of the DAP what to do, custom archive with firmware files, | ||
46 | images of stage1 and stage2 nand bootloader and Rock27Boot.bin file | ||
47 | image. Nand bootloader images are stored in scrambled form but | ||
48 | the tool deciphers it to plain binary during extraction. | ||
49 | |||
50 | More complete descritpion of file format can be found on wiki: | ||
51 | http://www.rockbox.org/wiki/RKWFileFormat | ||
52 | |||
53 | |||
39 | nandextract | 54 | nandextract |
40 | This directory contains quick and dirty tool which allows to extract | 55 | This directory contains quick and dirty tool which allows to extract |
41 | nand bootloader from raw dump of the first nand block. The main reason | 56 | nand bootloader from raw dump of the first nand block. The main reason |
diff --git a/utils/rk27utils/rkwtool/Makefile b/utils/rk27utils/rkwtool/Makefile new file mode 100644 index 0000000000..239733cb87 --- /dev/null +++ b/utils/rk27utils/rkwtool/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | all: rkwtool | ||
2 | |||
3 | rkwtool: rkw.c main.c | ||
4 | gcc -g -std=c99 -o $@ -W -Wall $^ | ||
5 | |||
6 | clean: | ||
7 | rm -fr rkwtool | ||
diff --git a/utils/rk27utils/rkwtool/main.c b/utils/rk27utils/rkwtool/main.c new file mode 100644 index 0000000000..dacfd9ffab --- /dev/null +++ b/utils/rk27utils/rkwtool/main.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include <getopt.h> | ||
22 | #include <stdbool.h> | ||
23 | #include <stddef.h> | ||
24 | #include <stdio.h> | ||
25 | #include "rkw.h" | ||
26 | |||
27 | #define VERSION "v0.1" | ||
28 | |||
29 | static void banner(void) | ||
30 | { | ||
31 | printf("RKWtool " VERSION " (C) Marcin Bukat 2014\n"); | ||
32 | printf("This is free software; see the source for copying conditions. There is NO\n"); | ||
33 | printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | ||
34 | } | ||
35 | |||
36 | static void usage(char *name) | ||
37 | { | ||
38 | banner(); | ||
39 | |||
40 | printf("Usage: %s [-i] [-b] [-e] [-a] [-o prefix] file.rkw\n", name); | ||
41 | printf("-i\t\tprint info about RKW file\n"); | ||
42 | printf("-b\t\textract nand bootloader images (s1.bin and s2.bin)\n"); | ||
43 | printf("-e\t\textract firmware files stored in RKST section\n"); | ||
44 | printf("-o prefix\twhen extracting firmware files put it there\n"); | ||
45 | printf("-a\t\textract additional file(s) (usually Rock27Boot.bin)\n"); | ||
46 | printf("-A\t\textract all data\n"); | ||
47 | printf("file.rkw\tRKW file to be processed\n"); | ||
48 | } | ||
49 | |||
50 | int main(int argc, char **argv) | ||
51 | { | ||
52 | int opt; | ||
53 | struct rkw_info_t *rkw_info = NULL; | ||
54 | char *prefix = NULL; | ||
55 | bool info = false; | ||
56 | bool extract = false; | ||
57 | bool bootloader = false; | ||
58 | bool addfile = false; | ||
59 | |||
60 | while ((opt = getopt(argc, argv, "iebo:aA")) != -1) | ||
61 | { | ||
62 | switch (opt) | ||
63 | { | ||
64 | case 'i': | ||
65 | info = true; | ||
66 | break; | ||
67 | |||
68 | case 'e': | ||
69 | extract = true; | ||
70 | break; | ||
71 | |||
72 | case 'b': | ||
73 | bootloader = true; | ||
74 | break; | ||
75 | |||
76 | case 'o': | ||
77 | prefix = optarg; | ||
78 | break; | ||
79 | |||
80 | case 'a': | ||
81 | addfile = true; | ||
82 | break; | ||
83 | |||
84 | case 'A': | ||
85 | extract = true; | ||
86 | bootloader = true; | ||
87 | addfile = true; | ||
88 | break; | ||
89 | |||
90 | default: | ||
91 | usage(argv[0]); | ||
92 | break; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if ((argc - optind) != 1 || | ||
97 | (!info && !extract && ! bootloader && !addfile)) | ||
98 | { | ||
99 | usage(argv[0]); | ||
100 | return -1; | ||
101 | } | ||
102 | |||
103 | banner(); | ||
104 | |||
105 | rkw_info = rkw_slurp(argv[optind]); | ||
106 | |||
107 | if (rkw_info) | ||
108 | { | ||
109 | if (info) | ||
110 | { | ||
111 | rkrs_list_named_items(rkw_info); | ||
112 | rkst_list_named_items(rkw_info); | ||
113 | } | ||
114 | |||
115 | if (extract) | ||
116 | unpack_rkst(rkw_info, prefix); | ||
117 | |||
118 | if (bootloader) | ||
119 | unpack_bootloader(rkw_info, prefix); | ||
120 | |||
121 | if (addfile) | ||
122 | unpack_addfile(rkw_info, prefix); | ||
123 | |||
124 | rkw_free(rkw_info); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | return -1; | ||
129 | } | ||
diff --git a/utils/rk27utils/rkwtool/rkw.c b/utils/rk27utils/rkwtool/rkw.c new file mode 100644 index 0000000000..eacef87b8e --- /dev/null +++ b/utils/rk27utils/rkwtool/rkw.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include <stdio.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdbool.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <string.h> | ||
26 | #include <errno.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <sys/types.h> | ||
29 | |||
30 | #include "rkw.h" | ||
31 | |||
32 | const char *section_name[] = { | ||
33 | "RKLD", | ||
34 | "RKRS", | ||
35 | "RKST" | ||
36 | }; | ||
37 | |||
38 | const uint32_t section_magic[] = { | ||
39 | RKLD_MAGIC, | ||
40 | RKRS_MAGIC, | ||
41 | RKST_MAGIC | ||
42 | }; | ||
43 | |||
44 | const char *rkrs_action_name[] = { | ||
45 | [act_null] = "null", | ||
46 | [act_mkdir] = "mkdir", | ||
47 | [act_fcopy] = "fcopy", | ||
48 | [act_fsoper] = "fsoper", | ||
49 | [act_format] = "format", | ||
50 | [act_loader] = "loader", | ||
51 | [act_dispbmp] = "dispbmp", | ||
52 | [act_dispstr] = "dispstr", | ||
53 | [act_setfont] = "setfont", | ||
54 | [act_delay] = "delay", | ||
55 | [act_system] = "system", | ||
56 | [act_readme] = "readme", | ||
57 | [act_copyright] = "copyright", | ||
58 | [act_select] = "select", | ||
59 | [act_restart] = "restart", | ||
60 | [act_regkey] = "regkey", | ||
61 | [act_version] = "version", | ||
62 | [act_freplace] = "freplace", | ||
63 | [act_fpreplace] = "fpreplace", | ||
64 | [act_fsdel] = "fsdel", | ||
65 | [act_space] = "space", | ||
66 | [act_addfile] = "addfile", | ||
67 | [act_setmem] = "setmem", | ||
68 | [act_getmem] = "getmem" | ||
69 | }; | ||
70 | |||
71 | /* scrambling/descrambling reverse engineered by AleMaxx */ | ||
72 | static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size) | ||
73 | { | ||
74 | |||
75 | uint8_t key[] = { | ||
76 | 0x7C, 0x4E, 0x03, 0x04, | ||
77 | 0x55, 0x05, 0x09, 0x07, | ||
78 | 0x2D, 0x2C, 0x7B, 0x38, | ||
79 | 0x17, 0x0D, 0x17, 0x11 | ||
80 | }; | ||
81 | int i, i3, x, val, idx; | ||
82 | |||
83 | uint8_t key1[0x100]; | ||
84 | uint8_t key2[0x100]; | ||
85 | |||
86 | for (i=0; i<0x100; i++) { | ||
87 | key1[i] = i; | ||
88 | key2[i] = key[i&0xf]; | ||
89 | } | ||
90 | |||
91 | i3 = 0; | ||
92 | for (i=0; i<0x100; i++) { | ||
93 | x = key1[i]; | ||
94 | i3 = key1[i] + i3; | ||
95 | i3 += key2[i]; | ||
96 | i3 &= 0xff; | ||
97 | key1[i] = key1[i3]; | ||
98 | key1[i3] = x; | ||
99 | } | ||
100 | |||
101 | idx = 0; | ||
102 | for (i=0; i<size; i++) { | ||
103 | x = key1[(i+1) & 0xff]; | ||
104 | val = x; | ||
105 | idx = (x + idx) & 0xff; | ||
106 | key1[(i+1) & 0xff] = key1[idx]; | ||
107 | key1[idx] = (x & 0xff); | ||
108 | val = (key1[(i+1)&0xff] + x) & 0xff; | ||
109 | val = key1[val]; | ||
110 | outpg[i] = val ^ inpg[i]; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | /* take path as stored in RKST and convert it to unix path | ||
115 | * with optional prefix | ||
116 | */ | ||
117 | static char *unixpath(char *path, char *prefix) | ||
118 | { | ||
119 | char *parsed, *ptr; | ||
120 | size_t size = 0; | ||
121 | |||
122 | if (NULL == path) | ||
123 | return NULL; | ||
124 | |||
125 | size = strlen(path) + 1; | ||
126 | |||
127 | /* full windows path i.e C:\something */ | ||
128 | if (strlen(path) > 2 && ':' == path[1]) | ||
129 | path += 3; | ||
130 | |||
131 | if (prefix) | ||
132 | { | ||
133 | /* account for '/' after prefix */ | ||
134 | size += strlen(prefix) + 1; | ||
135 | } | ||
136 | |||
137 | /* allocate buffer */ | ||
138 | parsed = malloc(size); | ||
139 | ptr = parsed; | ||
140 | |||
141 | /* malloc failed */ | ||
142 | if (NULL == ptr) | ||
143 | return NULL; | ||
144 | |||
145 | /* copy prefix */ | ||
146 | if (prefix) | ||
147 | { | ||
148 | strcpy(ptr, prefix); | ||
149 | ptr += strlen(prefix); | ||
150 | *ptr++ = '/'; | ||
151 | } | ||
152 | |||
153 | do | ||
154 | { | ||
155 | if (*path == '\\') | ||
156 | *ptr = '/'; | ||
157 | else | ||
158 | *ptr = *path; | ||
159 | |||
160 | ptr++; | ||
161 | } while ('\0' != *(path++)); | ||
162 | |||
163 | return parsed; | ||
164 | } | ||
165 | |||
166 | /* returns pointer to the rkrs header in rkw file */ | ||
167 | static char *find_section(struct rkw_info_t *rkw_info, enum section_type_t type) | ||
168 | { | ||
169 | char *ptr; | ||
170 | struct section_header_t *h; | ||
171 | |||
172 | switch(type) | ||
173 | { | ||
174 | case ST_RKRS: | ||
175 | case ST_RKST: | ||
176 | for (ptr=(char *)rkw_info->rkw; ptr<(char *)rkw_info->rkw+rkw_info->size; ptr++) | ||
177 | { | ||
178 | h = (struct section_header_t *)ptr; | ||
179 | if (h->magic == section_magic[type] && | ||
180 | h->size == sizeof(struct section_header_t) && | ||
181 | h->number_of_named_entries != 0) | ||
182 | { | ||
183 | fprintf(stderr, "[info]: %s found at 0x%0x\n", | ||
184 | section_name[type], (int)(ptr - rkw_info->rkw)); | ||
185 | |||
186 | return ptr; | ||
187 | } | ||
188 | } | ||
189 | break; | ||
190 | |||
191 | default: | ||
192 | fprintf(stderr, "[error]: Not supported section type %d\n", type); | ||
193 | return NULL; | ||
194 | } | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | /* load rkw file into memory and setup pointers to various sections */ | ||
199 | struct rkw_info_t *rkw_slurp(char *filename) | ||
200 | { | ||
201 | FILE *fp; | ||
202 | struct rkw_info_t *rkw_info; | ||
203 | |||
204 | rkw_info = (struct rkw_info_t *)malloc(sizeof(struct rkw_info_t)); | ||
205 | |||
206 | if (NULL == rkw_info) | ||
207 | { | ||
208 | fprintf(stderr, "[error]: Can't allocate %ld bytes of memory\n", | ||
209 | sizeof(struct rkw_info_t)); | ||
210 | |||
211 | return NULL; | ||
212 | } | ||
213 | |||
214 | fp = fopen(filename, "rb"); | ||
215 | |||
216 | if (NULL == fp) | ||
217 | { | ||
218 | fprintf(stderr, "[error]: Can't open %s\n", filename); | ||
219 | free(rkw_info); | ||
220 | return NULL; | ||
221 | } | ||
222 | |||
223 | fseek(fp, 0, SEEK_END); | ||
224 | rkw_info->size = ftell(fp); | ||
225 | fseek(fp, 0, SEEK_SET); | ||
226 | |||
227 | rkw_info->rkw = (char *)malloc(rkw_info->size); | ||
228 | |||
229 | if (NULL == rkw_info->rkw) | ||
230 | { | ||
231 | fprintf(stderr, "[error]: Can't allocate %ld bytes of memory\n", | ||
232 | rkw_info->size); | ||
233 | |||
234 | free(rkw_info); | ||
235 | fclose(fp); | ||
236 | return NULL; | ||
237 | } | ||
238 | |||
239 | if (fread(rkw_info->rkw, rkw_info->size, 1, fp) != 1) | ||
240 | { | ||
241 | fprintf(stderr, "[error]: Can't read %s\n", filename); | ||
242 | free(rkw_info); | ||
243 | fclose(fp); | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | rkw_info->rkrs_info.header = find_section(rkw_info, ST_RKRS); | ||
248 | rkw_info->rkrs_info.items = rkw_info->rkrs_info.header + | ||
249 | ((struct section_header_t *) | ||
250 | (rkw_info->rkrs_info.header))->offset_of_named_entries; | ||
251 | |||
252 | rkw_info->rkst_info.header = find_section(rkw_info, ST_RKST); | ||
253 | rkw_info->rkst_info.items = rkw_info->rkst_info.header + | ||
254 | ((struct section_header_t *) | ||
255 | (rkw_info->rkst_info.header))->offset_of_named_entries; | ||
256 | |||
257 | fclose(fp); | ||
258 | return rkw_info; | ||
259 | } | ||
260 | |||
261 | void rkw_free(struct rkw_info_t *rkw_info) | ||
262 | { | ||
263 | free(rkw_info->rkw); | ||
264 | free(rkw_info); | ||
265 | } | ||
266 | |||
267 | static void rkrs_named_item_info(struct rkrs_named_t *item) | ||
268 | { | ||
269 | fprintf(stderr, "[info]: size=0x%0x (%d)\n", item->size, item->size); | ||
270 | fprintf(stderr, "[info]: type=0x%0x (%d) %s\n", item->type, item->type, rkrs_action_name[item->type]); | ||
271 | fprintf(stderr, "[info]: data_offset=0x%0x (%d)\n", item->data_offset, item->data_offset); | ||
272 | fprintf(stderr, "[info]: data_size=0x%0x (%d)\n", item->data_size, item->data_size); | ||
273 | fprintf(stderr, "[info]: param[0]=0x%0x (%d)\n", item->param[0], item->param[0]); | ||
274 | fprintf(stderr, "[info]: param[1]=0x%0x (%d)\n", item->param[1], item->param[1]); | ||
275 | fprintf(stderr, "[info]: param[2]=0x%0x (%d)\n", item->param[2], item->param[2]); | ||
276 | fprintf(stderr, "[info]: param[3]=0x%0x (%d)\n", item->param[3], item->param[3]); | ||
277 | } | ||
278 | |||
279 | static void rkst_named_item_info(struct rkst_named_t *item) | ||
280 | { | ||
281 | fprintf(stderr, "[info]: size=0x%0x (%d)\n", item->size, item->size); | ||
282 | fprintf(stderr, "[info]: action=0x%0x (%d) %s\n", item->action, item->action, rkrs_action_name[item->action]); | ||
283 | fprintf(stderr, "[info]: data_offset=0x%0x (%d)\n", item->data_offset, item->data_offset); | ||
284 | fprintf(stderr, "[info]: data_size=0x%0x (%d)\n", item->data_size, item->data_size); | ||
285 | fprintf(stderr, "[info]: name=\"%s\"\n", &item->name); | ||
286 | } | ||
287 | |||
288 | static struct rkrs_named_t *find_item(struct rkw_info_t *rkw_info, enum rkst_action_t type, bool search_start) | ||
289 | { | ||
290 | static struct rkrs_named_t *item; | ||
291 | |||
292 | if (search_start) | ||
293 | { | ||
294 | item = (struct rkrs_named_t *)rkw_info->rkrs_info.items; | ||
295 | } | ||
296 | else | ||
297 | { | ||
298 | if (item) | ||
299 | item++; | ||
300 | else | ||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | while (item->size > 0) | ||
305 | { | ||
306 | if (item->type == type) | ||
307 | { | ||
308 | fprintf(stderr, "[info]: Item type=%d found at 0x%x\n", type, | ||
309 | (int)((char *)item - rkw_info->rkw)); | ||
310 | return item; | ||
311 | } | ||
312 | item++; | ||
313 | } | ||
314 | |||
315 | return NULL; | ||
316 | } | ||
317 | |||
318 | void rkrs_list_named_items(struct rkw_info_t *rkw_info) | ||
319 | { | ||
320 | struct rkrs_named_t *item = (struct rkrs_named_t *)rkw_info->rkrs_info.items; | ||
321 | struct section_header_t *rkrs_header = (struct section_header_t *)(rkw_info->rkrs_info.header); | ||
322 | int i; | ||
323 | |||
324 | for (i=0; i<rkrs_header->number_of_named_entries; i++) | ||
325 | { | ||
326 | fprintf(stderr, "[info]: rkrs named entry %d\n", i); | ||
327 | rkrs_named_item_info(item++); | ||
328 | fprintf(stderr, "\n"); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | void rkst_list_named_items(struct rkw_info_t *rkw_info) | ||
333 | { | ||
334 | struct rkst_named_t *item = (struct rkst_named_t *)rkw_info->rkst_info.items; | ||
335 | struct section_header_t *rkst_header = (struct section_header_t *)(rkw_info->rkst_info.header); | ||
336 | int i; | ||
337 | |||
338 | for (i=0; i<rkst_header->number_of_named_entries; i++) | ||
339 | { | ||
340 | fprintf(stderr, "[info]: rkst named entry %d\n", i); | ||
341 | rkst_named_item_info(item); | ||
342 | item = (struct rkst_named_t *)((char *)item + item->size); | ||
343 | fprintf(stderr, "\n"); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | void unpack_bootloader(struct rkw_info_t *rkw_info, char *prefix) | ||
348 | { | ||
349 | FILE *fp; | ||
350 | char *ptr; | ||
351 | size_t size; | ||
352 | int len; | ||
353 | char *buf; | ||
354 | struct rkrs_named_t *item = find_item(rkw_info, act_loader, true); | ||
355 | |||
356 | if (NULL == item) | ||
357 | { | ||
358 | fprintf(stderr, "[error]: Can't find nand bootloader\n"); | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | ptr = (char *)(rkw_info->rkrs_info.header) + item->data_offset; | ||
363 | size = item->param[0]; | ||
364 | buf = malloc(size); | ||
365 | |||
366 | if (NULL == buf) | ||
367 | { | ||
368 | fprintf(stderr, "[error]: Can't allocate %ld bytes of memory\n", | ||
369 | size); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | /* make a copy for decryption */ | ||
374 | memcpy(buf, ptr, size); | ||
375 | encode_page((uint8_t *)buf, (uint8_t *)buf, size); | ||
376 | fp = fopen(unixpath("s1.bin", prefix), "w"); | ||
377 | |||
378 | if (NULL == fp) | ||
379 | { | ||
380 | fprintf(stderr, "[error]: Can't open s1.bin for writing\n"); | ||
381 | free(buf); | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | if (fwrite(buf, size, 1, fp) != 1) | ||
386 | { | ||
387 | fprintf(stderr, "[error]: Can't write s1.bin file\n"); | ||
388 | free(buf); | ||
389 | fclose(fp); | ||
390 | return; | ||
391 | } | ||
392 | |||
393 | fclose(fp); | ||
394 | |||
395 | ptr = (char *)(rkw_info->rkrs_info.header) + item->param[1]; | ||
396 | size = item->param[2]; | ||
397 | len = size; | ||
398 | buf = realloc(buf, size); | ||
399 | |||
400 | if (NULL == buf) | ||
401 | { | ||
402 | fprintf(stderr, "[error]: Can't allocate %ld bytes of memory\n", | ||
403 | size); | ||
404 | |||
405 | free(buf); | ||
406 | return; | ||
407 | } | ||
408 | |||
409 | memcpy(buf, ptr, size); | ||
410 | ptr = buf; | ||
411 | |||
412 | while (len >= 0x200) | ||
413 | { | ||
414 | encode_page((uint8_t *)ptr, (uint8_t *)ptr, 0x200); | ||
415 | ptr += 0x200; | ||
416 | len -= 0x200; | ||
417 | } | ||
418 | encode_page((uint8_t *)ptr, (uint8_t *)ptr, len); | ||
419 | |||
420 | fp = fopen(unixpath("s2.bin", prefix), "w"); | ||
421 | |||
422 | if (NULL == fp) | ||
423 | { | ||
424 | fprintf(stderr, "[error]: Can't open s2.bin for writing\n"); | ||
425 | free(buf); | ||
426 | return; | ||
427 | } | ||
428 | |||
429 | if (fwrite(buf, size, 1, fp) != 1) | ||
430 | { | ||
431 | fprintf(stderr, "[error]: Can't write s2.bin file\n"); | ||
432 | free(buf); | ||
433 | fclose(fp); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | fclose(fp); | ||
438 | free(buf); | ||
439 | fprintf(stderr, "[info]: Extracted bootloader version: %x.%x\n", | ||
440 | (item->param[3] >> 8) & 0xff, item->param[3] & 0xff); | ||
441 | } | ||
442 | |||
443 | void unpack_addfile(struct rkw_info_t *rkw_info, char *prefix) | ||
444 | { | ||
445 | FILE *fp; | ||
446 | char *name; | ||
447 | int name_len; | ||
448 | |||
449 | struct rkrs_named_t *item = find_item(rkw_info, act_addfile, true); | ||
450 | |||
451 | do | ||
452 | { | ||
453 | name = unixpath(rkw_info->rkrs_info.header + item->data_offset, prefix); | ||
454 | name_len = item->param[0]; | ||
455 | |||
456 | fprintf(stderr, "[info]: unpacking addfile %s\n", name); | ||
457 | |||
458 | fp = fopen(name, "w"); | ||
459 | |||
460 | if (NULL == fp) | ||
461 | { | ||
462 | fprintf(stderr, "[error]: Can't open %s for writing\n", name); | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | if (fwrite(rkw_info->rkrs_info.header + item->data_offset + name_len, | ||
467 | item->data_size - name_len, 1, fp) != 1) | ||
468 | { | ||
469 | fprintf(stderr, "[error]: Can't write %s file\n", name); | ||
470 | fclose(fp); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | fclose(fp); | ||
475 | } while (NULL != (item = find_item(rkw_info, act_addfile, false))); | ||
476 | } | ||
477 | |||
478 | /* unpack content of RKST section | ||
479 | * this mimics what is done when processing 'fsoper' field of RKRS | ||
480 | */ | ||
481 | void unpack_rkst(struct rkw_info_t *rkw_info, char *prefix) | ||
482 | { | ||
483 | FILE *fp; | ||
484 | struct rkst_named_t *item = (struct rkst_named_t *)rkw_info->rkst_info.items; | ||
485 | struct section_header_t *rkst_header = (struct section_header_t *)(rkw_info->rkst_info.header); | ||
486 | char *name; | ||
487 | int i; | ||
488 | |||
489 | if (prefix) | ||
490 | { | ||
491 | if (0 != mkdir(prefix, 0755)) | ||
492 | { | ||
493 | fprintf(stderr, "[error]: Can't create %s directory (%s)\n", | ||
494 | prefix, strerror(errno)); | ||
495 | return; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | fprintf(stderr, "[info]: Unpacking content of RKST section\n"); | ||
500 | |||
501 | for (i=0; i<rkst_header->number_of_named_entries; i++) | ||
502 | { | ||
503 | name = unixpath((char *)&(item->name), prefix); | ||
504 | |||
505 | switch (item->action) | ||
506 | { | ||
507 | case act_mkdir: | ||
508 | if (0 != mkdir(name, 0755)) | ||
509 | { | ||
510 | fprintf(stderr, "[error]: Can't create %s directory (%s)\n", | ||
511 | name, strerror(errno)); | ||
512 | return; | ||
513 | } | ||
514 | fprintf(stderr, "[info]: mkdir %s\n", name); | ||
515 | break; | ||
516 | |||
517 | case act_fcopy: | ||
518 | fp = fopen(name, "w"); | ||
519 | if (NULL == fp) | ||
520 | { | ||
521 | fprintf(stderr, "[error]: Can't open %s for writing (%s)\n", | ||
522 | name, strerror(errno)); | ||
523 | return; | ||
524 | } | ||
525 | |||
526 | fwrite((char *)rkst_header + item->data_offset, item->data_size, 1, fp); | ||
527 | fprintf(stderr, "[info]: unpack %s\n", name); | ||
528 | fclose(fp); | ||
529 | break; | ||
530 | |||
531 | default: | ||
532 | break; | ||
533 | } | ||
534 | |||
535 | if (name) free(name); | ||
536 | item = (struct rkst_named_t *)((char *)item + item->size); | ||
537 | } | ||
538 | } | ||
diff --git a/utils/rk27utils/rkwtool/rkw.h b/utils/rk27utils/rkwtool/rkw.h new file mode 100644 index 0000000000..eba673c974 --- /dev/null +++ b/utils/rk27utils/rkwtool/rkw.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2014 by Marcin Bukat | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include <stdint.h> | ||
22 | |||
23 | #define RKLD_MAGIC 0x4C44524B | ||
24 | #define RKRS_MAGIC 0x53524B52 | ||
25 | #define RKST_MAGIC 0X53544B52 | ||
26 | |||
27 | enum section_type_t { | ||
28 | ST_RKLD, | ||
29 | ST_RKRS, | ||
30 | ST_RKST | ||
31 | }; | ||
32 | |||
33 | enum rkst_action_t { | ||
34 | act_null = 0, | ||
35 | act_mkdir = 1, | ||
36 | act_fcopy = 2, | ||
37 | act_fsoper = 3, | ||
38 | act_format = 4, | ||
39 | act_loader = 5, | ||
40 | |||
41 | act_dispbmp = 10, | ||
42 | act_dispstr = 11, | ||
43 | act_setfont = 12, | ||
44 | |||
45 | act_delay = 20, | ||
46 | |||
47 | act_system = 100, | ||
48 | act_uilogo = 100, | ||
49 | act_readme = 101, | ||
50 | act_copyright = 102, | ||
51 | act_select = 103, | ||
52 | act_restart = 104, | ||
53 | |||
54 | act_regkey = 120, | ||
55 | act_version = 121, | ||
56 | |||
57 | act_freplace = 130, | ||
58 | act_fpreplace = 131, | ||
59 | act_fsdel = 132, | ||
60 | |||
61 | act_space = 200, | ||
62 | |||
63 | act_addfile = 300, | ||
64 | |||
65 | act_setmem = 1000, | ||
66 | act_getmem = 1001, | ||
67 | }; | ||
68 | |||
69 | struct section_header_t { | ||
70 | uint32_t size; | ||
71 | uint32_t magic; | ||
72 | uint32_t property; | ||
73 | uint32_t timestamp; | ||
74 | uint32_t allign; | ||
75 | uint32_t file_size; | ||
76 | uint16_t size_of_name_dir; | ||
77 | uint16_t size_of_id_dir; | ||
78 | uint16_t number_of_named_entries; | ||
79 | uint16_t number_of_id_entries; | ||
80 | uint32_t offset_of_named_entries; | ||
81 | uint32_t offset_of_id_entries; | ||
82 | } __attribute__((__packed__)); | ||
83 | |||
84 | struct rkrs_named_t { | ||
85 | uint32_t size; | ||
86 | uint32_t type; | ||
87 | uint32_t data_offset; | ||
88 | uint32_t data_size; | ||
89 | uint32_t param[4]; | ||
90 | } __attribute__((__packed__)); | ||
91 | |||
92 | struct rkst_named_t { | ||
93 | uint32_t size; | ||
94 | uint32_t action; | ||
95 | uint32_t data_offset; | ||
96 | uint32_t data_size; | ||
97 | uint8_t name; | ||
98 | }; | ||
99 | |||
100 | struct section_info_t { | ||
101 | char *header; | ||
102 | char *items; | ||
103 | }; | ||
104 | |||
105 | struct rkw_info_t { | ||
106 | char *rkw; | ||
107 | long size; | ||
108 | struct section_info_t rkrs_info; | ||
109 | struct section_info_t rkst_info; | ||
110 | }; | ||
111 | |||
112 | /* general functions */ | ||
113 | struct rkw_info_t *rkw_slurp(char *filename); | ||
114 | void rkw_free(struct rkw_info_t *rkw_info); | ||
115 | |||
116 | /* info functions */ | ||
117 | void rkrs_list_named_items(struct rkw_info_t *rkw_info); | ||
118 | void rkst_list_named_items(struct rkw_info_t *rkw_info); | ||
119 | |||
120 | /* extract functions */ | ||
121 | void unpack_bootloader(struct rkw_info_t *rkw_info, char *prefix); | ||
122 | void unpack_rkst(struct rkw_info_t *rkw_info, char *prefix); | ||
123 | void unpack_addfile(struct rkw_info_t *rkw_info, char *prefix); | ||