diff options
-rw-r--r-- | apps/plugins/iriver_flash.c | 1123 | ||||
-rw-r--r-- | firmware/export/config/iriverh100.h | 1 | ||||
-rw-r--r-- | firmware/export/config/iriverh120.h | 1 | ||||
-rw-r--r-- | firmware/export/config/iriverh300.h | 1 | ||||
-rw-r--r-- | firmware/export/system.h | 4 |
5 files changed, 617 insertions, 513 deletions
diff --git a/apps/plugins/iriver_flash.c b/apps/plugins/iriver_flash.c index 9d1c3456a6..e5da55c7ed 100644 --- a/apps/plugins/iriver_flash.c +++ b/apps/plugins/iriver_flash.c | |||
@@ -9,7 +9,8 @@ | |||
9 | * | 9 | * |
10 | * !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!! | 10 | * !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!! |
11 | * | 11 | * |
12 | * Copyright (C) 2006 by Miika Pekkarinen | 12 | * Copyright (C) 2020 by James Buren (refactor + H300 support) |
13 | * Copyright (C) 2006 by Miika Pekkarinen (original + H100/H120 support) | ||
13 | * | 14 | * |
14 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
15 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
@@ -22,93 +23,185 @@ | |||
22 | ****************************************************************************/ | 23 | ****************************************************************************/ |
23 | #include "plugin.h" | 24 | #include "plugin.h" |
24 | 25 | ||
25 | /* cfi_program_word() relies on writing to address 0, which normally is illegal. | 26 | /* |
26 | So we need this to ensure we don't helpfully optimize it away into a TRAP | 27 | * Flash commands may rely on null pointer dereferences to work correctly. |
27 | when compiled with -fdelete-null-pointer-checks, which is enabled by default | 28 | * Disable this feature of GCC that may interfere with proper code generation. |
28 | at -Os with our current gcc 4.9.x toolchain. | 29 | */ |
29 | */ | ||
30 | #pragma GCC optimize "no-delete-null-pointer-checks" | 30 | #pragma GCC optimize "no-delete-null-pointer-checks" |
31 | 31 | ||
32 | /* All CFI flash routines are copied and ported from firmware_flash.c */ | 32 | enum firmware |
33 | { | ||
34 | FIRMWARE_ROCKBOX, /* all .iriver firmwares */ | ||
35 | FIRMWARE_ROMDUMP, /* a debug romdump */ | ||
36 | FIRMWARE_ORIGINAL, /* an unscrambled original firmware */ | ||
37 | }; | ||
38 | |||
39 | #define WORD_SIZE 2 | ||
40 | #define BOOT_VECTOR_SIZE 8 | ||
41 | #define BOOT_SECTOR_OFFSET 0 | ||
42 | #define SECTOR_SIZE 4096 | ||
43 | #define BOOTLOADER_MAX_SIZE 65536 | ||
44 | #define BOOTLOADER_SECTORS (BOOTLOADER_MAX_SIZE / SECTOR_SIZE) | ||
45 | #define RAM_IMAGE_RAW_SIZE (FLASH_ROMIMAGE_ENTRY - FLASH_RAMIMAGE_ENTRY) | ||
46 | #define RAM_IMAGE_MAX_SIZE (RAM_IMAGE_RAW_SIZE - sizeof(struct flash_header)) | ||
47 | #define RAM_IMAGE_SECTORS (RAM_IMAGE_RAW_SIZE / SECTOR_SIZE) | ||
48 | #define ROM_IMAGE_RAW_SIZE (BOOTLOADER_ENTRYPOINT - FLASH_ROMIMAGE_ENTRY) | ||
49 | #define ROM_IMAGE_MAX_SIZE (ROM_IMAGE_RAW_SIZE - sizeof(struct flash_header)) | ||
50 | #define ROM_IMAGE_SECTORS (ROM_IMAGE_RAW_SIZE / SECTOR_SIZE) | ||
51 | #define ROM_IMAGE_RELOCATION (FLASH_ROMIMAGE_ENTRY + sizeof(struct flash_header)) | ||
52 | #define WHOLE_FIRMWARE_SECTORS (BOOTLOADER_ENTRYPOINT / SECTOR_SIZE) | ||
53 | #define FIRMWARE_OFFSET 544 | ||
54 | |||
55 | #if BOOTLOADER_ENTRYPOINT + BOOTLOADER_MAX_SIZE != FLASH_SIZE | ||
56 | #error "Bootloader is not located at the end of flash." | ||
57 | #endif | ||
33 | 58 | ||
34 | uint8_t* audiobuf; | 59 | #if FLASH_ROMIMAGE_ENTRY < FLASH_RAMIMAGE_ENTRY |
35 | ssize_t audiobuf_size; | 60 | #error "RAM image must be located before the ROM image." |
61 | #endif | ||
62 | |||
63 | #if BOOTLOADER_ENTRYPOINT < FLASH_ROMIMAGE_ENTRY | ||
64 | #error "ROM image must be located before the bootloader." | ||
65 | #endif | ||
36 | 66 | ||
37 | #if !defined(IRIVER_H100_SERIES) && !defined(IRIVER_H300_SERIES) | 67 | #if FLASH_SIZE == 2048 * 1024 |
38 | #error this platform is not (yet) flashable | 68 | #define ROMDUMP "/internal_rom_000000-1FFFFF.bin" |
69 | #elif FLASH_SIZE == 4096 * 1024 | ||
70 | #define ROMDUMP "/internal_rom_000000-3FFFFF.bin" | ||
39 | #endif | 71 | #endif |
40 | 72 | ||
41 | #if CONFIG_KEYPAD == IRIVER_H100_PAD | 73 | #ifdef IRIVER_H100 |
42 | #define KEY1 BUTTON_OFF | 74 | #define MODEL (const uint8_t[]) { 'h', '1', '0', '0' } |
43 | #define KEY2 BUTTON_ON | 75 | #define ORIGINAL "/ihp_100.bin" |
44 | #define KEY3 BUTTON_SELECT | 76 | #elif defined(IRIVER_H120) |
45 | #define KEYNAME1 "[Stop]" | 77 | #define MODEL (const uint8_t[]) { 'h', '1', '2', '0' } |
46 | #define KEYNAME2 "[On]" | 78 | #define ORIGINAL "/ihp_120.bin" |
47 | #define KEYNAME3 "[Select]" | 79 | #elif defined(IRIVER_H300) |
80 | #define MODEL (const uint8_t[]) { 'h', '3', '0', '0' } | ||
81 | #define ORIGINAL "/H300.bin" | ||
82 | #else | ||
83 | #error "Unsupported target." | ||
48 | #endif | 84 | #endif |
49 | 85 | ||
50 | struct flash_info | 86 | struct flash_info |
51 | { | 87 | { |
52 | uint16_t manufacturer; | 88 | uint16_t vendor; |
53 | uint16_t id; | 89 | uint16_t product; |
54 | uint32_t size; | 90 | uint32_t size; |
55 | char name[32]; | 91 | char name[16]; |
56 | }; | 92 | }; |
57 | 93 | ||
58 | #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) | 94 | /* checks if the region has a valid bootloader */ |
59 | #define SEC_SIZE 4096 | 95 | static bool detect_valid_bootloader(const void* ptr, uint32_t size) |
60 | #define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE) | 96 | { |
61 | enum sections { | 97 | static const struct |
62 | SECT_RAMIMAGE = 1, | 98 | { |
63 | SECT_ROMIMAGE = 2, | 99 | uint32_t size; |
64 | }; | 100 | uint32_t crc32; |
65 | 101 | } | |
66 | static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */ | 102 | bootloaders[] = |
103 | { | ||
104 | #ifdef IRIVER_H100 | ||
105 | { 48760, 0x2efc3323 }, /* 7-pre4 */ | ||
106 | { 56896, 0x0cd8dad4 }, /* 7-pre5 */ | ||
107 | #elif defined(IRIVER_H120) | ||
108 | { 63788, 0x08ff01a9 }, /* 7-pre3, improved failsafe functions */ | ||
109 | { 48764, 0xc674323e }, /* 7-pre4. Fixed audio thump & remote bootup */ | ||
110 | { 56896, 0x167f5d25 }, /* 7-pre5, various ATA fixes */ | ||
111 | #elif defined(IRIVER_H300) | ||
67 | #endif | 112 | #endif |
113 | {0} | ||
114 | }; | ||
68 | 115 | ||
69 | #ifdef IRIVER_H100 /* iRiver H110/H115 */ | 116 | for (size_t i = 0; bootloaders[i].size != 0; i++) |
70 | #define MODEL "h100" | 117 | { |
71 | #elif defined(IRIVER_H120) /* iRiver H120/H140 */ | 118 | uint32_t crc32; |
72 | #define MODEL "h120" | 119 | |
73 | #elif defined(IRIVER_H300) /* iRiver H320/H340 */ | 120 | if (size != 0 && size != bootloaders[i].size) |
74 | #define MODEL "h300" | 121 | continue; |
75 | #endif | 122 | |
123 | crc32 = rb->crc_32(ptr, bootloaders[i].size, 0xFFFFFFFF); | ||
124 | if (crc32 == bootloaders[i].crc32) | ||
125 | return true; | ||
126 | } | ||
127 | |||
128 | return false; | ||
129 | } | ||
130 | |||
131 | /* get read-only access to flash at the given offset */ | ||
132 | static const void* flash(uint32_t offset) | ||
133 | { | ||
134 | const uint16_t* FB = (uint16_t*) FLASH_BASE; | ||
135 | return &FB[offset / WORD_SIZE]; | ||
136 | } | ||
76 | 137 | ||
77 | /* read the manufacturer and device ID */ | 138 | /* queries the rom for information and returns it if it is known */ |
78 | static void cfi_read_id(struct flash_info* pInfo) | 139 | static bool flash_get_info(const struct flash_info** out_info) |
79 | { | 140 | { |
80 | FB[0x5555] = 0xAA; /* enter command mode */ | 141 | static const struct flash_info roms[] = |
142 | { | ||
143 | { 0x00BF, 0x2782, 2048 * 1024, "SST39VF160" }, | ||
144 | { 0x00BF, 0x235B, 4096 * 1024, "SST39VF3201" }, | ||
145 | {0} | ||
146 | }; | ||
147 | static struct flash_info unknown_rom = {0}; | ||
148 | volatile uint16_t* FB = (uint16_t*) FLASH_BASE; | ||
149 | uint16_t vendor; | ||
150 | uint16_t product; | ||
151 | |||
152 | /* execute the software ID entry command */ | ||
153 | FB[0x5555] = 0xAA; | ||
81 | FB[0x2AAA] = 0x55; | 154 | FB[0x2AAA] = 0x55; |
82 | FB[0x5555] = 0x90; /* enter ID mode */ | 155 | FB[0x5555] = 0x90; |
83 | rb->sleep(HZ/100); /* we only need to sleep 150ns but 10ms is the minimum */ | 156 | rb->sleep(HZ / 100); |
84 | 157 | ||
85 | pInfo->manufacturer = FB[0]; | 158 | /* copy the IDs from the previous command */ |
86 | pInfo->id = FB[1]; | 159 | vendor = FB[0]; |
160 | product = FB[1]; | ||
87 | 161 | ||
88 | FB[0x5555] = 0xAA; /* enter command mode */ | 162 | /* execute the software ID exit command */ |
163 | FB[0x5555] = 0xAA; | ||
89 | FB[0x2AAA] = 0x55; | 164 | FB[0x2AAA] = 0x55; |
90 | FB[0x5555] = 0xF0; /* exit ID mode */ | 165 | FB[0x5555] = 0xF0; |
91 | rb->sleep(HZ/100); /* we only need to sleep 150ns but 10ms is the minimum */ | 166 | rb->sleep(HZ / 100); |
167 | |||
168 | /* search for a known match */ | ||
169 | for (size_t i = 0; roms[i].size != 0; i++) | ||
170 | { | ||
171 | if (roms[i].vendor == vendor && roms[i].product == product) | ||
172 | { | ||
173 | *out_info = &roms[i]; | ||
174 | return true; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | /* return only the vendor / product ids if unknown */ | ||
179 | unknown_rom.vendor = vendor; | ||
180 | unknown_rom.product = product; | ||
181 | *out_info = &unknown_rom; | ||
182 | return false; | ||
92 | } | 183 | } |
93 | 184 | ||
94 | /* wait until the rom signals completion of an operation */ | 185 | /* wait until the rom signals completion of an operation */ |
95 | static bool cfi_wait_for_rom(volatile uint16_t* pAddr) | 186 | static bool flash_wait_for_rom(uint32_t offset) |
96 | { | 187 | { |
97 | const unsigned MAX_TIMEOUT = 0xffffff; /* should be sufficient for most targets */ | 188 | const size_t MAX_TIMEOUT = 0xFFFFFF; /* should be sufficient for most targets */ |
98 | const unsigned RECOVERY_TIME = 64; /* based on 140MHz MCF 5249 */ | 189 | const size_t RECOVERY_TIME = 64; /* based on 140MHz MCF 5249 */ |
99 | uint16_t old_data = *pAddr & 0x0040; /* we only want DQ6 */ | 190 | volatile uint16_t* FB = (uint16_t*) FLASH_BASE; |
100 | volatile unsigned i; /* disables certain optimizations */ | 191 | uint16_t old_data = FB[offset / WORD_SIZE] & 0x0040; /* we only want DQ6 */ |
192 | volatile size_t i; /* disables certain optimizations */ | ||
193 | bool result; | ||
101 | 194 | ||
102 | /* repeat up to MAX_TIMEOUT times or until DQ6 stops flipping */ | 195 | /* repeat up to MAX_TIMEOUT times or until DQ6 stops flipping */ |
103 | for (i = 0; i < MAX_TIMEOUT; i++) | 196 | for (i = 0; i < MAX_TIMEOUT; i++) |
104 | { | 197 | { |
105 | uint16_t new_data = *pAddr & 0x0040; /* we only want DQ6 */ | 198 | uint16_t new_data = FB[offset / WORD_SIZE] & 0x0040; /* we only want DQ6 */ |
106 | if(old_data == new_data) | 199 | if (old_data == new_data) |
107 | break; | 200 | break; |
108 | old_data = new_data; | 201 | old_data = new_data; |
109 | } | 202 | } |
110 | 203 | ||
111 | bool result = i != MAX_TIMEOUT; | 204 | result = i != MAX_TIMEOUT; |
112 | 205 | ||
113 | /* delay at least 1us to give the bus time to recover */ | 206 | /* delay at least 1us to give the bus time to recover */ |
114 | for (i = 0; i < RECOVERY_TIME; i++); | 207 | for (i = 0; i < RECOVERY_TIME; i++); |
@@ -116,646 +209,654 @@ static bool cfi_wait_for_rom(volatile uint16_t* pAddr) | |||
116 | return result; | 209 | return result; |
117 | } | 210 | } |
118 | 211 | ||
119 | /* erase the sector which contains the given address */ | 212 | /* erase the sector at the given offset */ |
120 | static bool cfi_erase_sector(volatile uint16_t* pAddr) | 213 | static bool flash_erase_sector(uint32_t offset) |
121 | { | 214 | { |
122 | FB[0x5555] = 0xAA; /* enter command mode */ | 215 | volatile uint16_t* FB = (uint16_t*) FLASH_BASE; |
216 | |||
217 | /* execute the sector erase command */ | ||
218 | FB[0x5555] = 0xAA; | ||
123 | FB[0x2AAA] = 0x55; | 219 | FB[0x2AAA] = 0x55; |
124 | FB[0x5555] = 0x80; /* erase command */ | 220 | FB[0x5555] = 0x80; |
125 | FB[0x5555] = 0xAA; /* enter command mode */ | 221 | FB[0x5555] = 0xAA; |
126 | FB[0x2AAA] = 0x55; | 222 | FB[0x2AAA] = 0x55; |
127 | *pAddr = 0x30; /* erase the sector */ | 223 | FB[offset / WORD_SIZE] = 0x30; |
128 | 224 | ||
129 | return cfi_wait_for_rom(pAddr); | 225 | return flash_wait_for_rom(offset); |
130 | } | 226 | } |
131 | 227 | ||
132 | /* address must be in an erased location */ | 228 | /* program a word at the given offset */ |
133 | static bool cfi_program_word(volatile uint16_t* pAddr, uint16_t data) | 229 | static bool flash_program_word(uint32_t offset, uint16_t word) |
134 | { | 230 | { |
135 | FB[0x5555] = 0xAA; /* enter command mode */ | 231 | volatile uint16_t* FB = (uint16_t*) FLASH_BASE; |
232 | |||
233 | /* execute the word program command */ | ||
234 | FB[0x5555] = 0xAA; | ||
136 | FB[0x2AAA] = 0x55; | 235 | FB[0x2AAA] = 0x55; |
137 | FB[0x5555] = 0xA0; /* byte program command */ | 236 | FB[0x5555] = 0xA0; |
138 | *pAddr = data; /* write the word data */ | 237 | FB[offset / WORD_SIZE] = word; |
139 | 238 | ||
140 | return cfi_wait_for_rom(pAddr); | 239 | return flash_wait_for_rom(offset); |
141 | } | 240 | } |
142 | 241 | ||
143 | /* fills in the struct with data about the flash rom */ | 242 | /* bulk erase of adjacent sectors */ |
144 | static void cfi_get_flash_info(struct flash_info* pInfo) | 243 | static void flash_erase_sectors(uint32_t offset, uint32_t sectors, |
244 | bool progress) | ||
145 | { | 245 | { |
146 | uint32_t size = 0; | 246 | for (uint32_t i = 0; i < sectors; i++) |
147 | const char* name = ""; | 247 | { |
148 | 248 | flash_erase_sector(offset + i * SECTOR_SIZE); | |
149 | cfi_read_id(pInfo); | ||
150 | |||
151 | switch (pInfo->manufacturer) | ||
152 | { | ||
153 | /* SST */ | ||
154 | case 0x00BF: | ||
155 | switch (pInfo->id) | ||
156 | { | ||
157 | case 0x2782: | ||
158 | size = 2048 * 1024; /* 2 MiB */ | ||
159 | name = "SST39VF160"; | ||
160 | break; | ||
161 | case 0x235B: | ||
162 | size = 4096 * 1024; /* 4 MiB */ | ||
163 | name = "SST39VF3201"; | ||
164 | break; | ||
165 | } | ||
166 | break; | ||
167 | } | ||
168 | 249 | ||
169 | pInfo->size = size; | 250 | /* display a progress report if requested */ |
170 | rb->strcpy(pInfo->name, name); | 251 | if (progress) |
252 | { | ||
253 | rb->lcd_putsf(0, 3, "Erasing... %u%%", (i + 1) * 100 / sectors); | ||
254 | rb->lcd_update(); | ||
255 | } | ||
256 | } | ||
171 | } | 257 | } |
172 | 258 | ||
173 | /***************** User Interface Functions *****************/ | 259 | /* bulk program of bytes */ |
174 | static int wait_for_button(void) | 260 | static void flash_program_bytes(uint32_t offset, const void* ptr, |
261 | uint32_t len, bool progress) | ||
175 | { | 262 | { |
176 | int button; | 263 | const uint8_t* data = ptr; |
177 | 264 | ||
178 | do | 265 | for (uint32_t i = 0; i < len; i += WORD_SIZE) |
179 | { | 266 | { |
180 | button = rb->button_get(true); | 267 | uint32_t j = i + 1; |
181 | } while (IS_SYSEVENT(button) || (button & BUTTON_REL)); | 268 | uint32_t k = ((j < len) ? j : i) + 1; |
269 | uint16_t word = (data[i] << 8) | (j < len ? data[j] : 0xFF); | ||
270 | |||
271 | flash_program_word(offset + i, word); | ||
182 | 272 | ||
183 | return button; | 273 | /* display a progress report if requested */ |
274 | if (progress && ((i % SECTOR_SIZE) == 0 || k == len)) | ||
275 | { | ||
276 | rb->lcd_putsf(0, 4, "Programming... %u%%", k * 100 / len); | ||
277 | rb->lcd_update(); | ||
278 | } | ||
279 | } | ||
184 | } | 280 | } |
185 | 281 | ||
186 | /* helper for DoUserDialog() */ | 282 | /* bulk verify of programmed bytes */ |
187 | static void ShowFlashInfo(const struct flash_info* pInfo) | 283 | static bool flash_verify_bytes(uint32_t offset, const void* ptr, |
284 | uint32_t len, bool progress) | ||
188 | { | 285 | { |
189 | if (!pInfo->manufacturer) | 286 | const uint8_t* FB = flash(offset); |
190 | { | 287 | const uint8_t* data = ptr; |
191 | rb->lcd_puts(0, 0, "Flash: M=???? D=????"); | 288 | |
192 | rb->lcd_puts(0, 1, "Impossible to program"); | 289 | /* don't use memcmp so we can provide progress updates */ |
193 | } | 290 | for (uint32_t i = 0; i < len; i++) |
194 | else | ||
195 | { | 291 | { |
196 | rb->lcd_putsf(0, 0, "Flash: M=%04x D=%04x", | 292 | uint32_t j = i + 1; |
197 | pInfo->manufacturer, pInfo->id); | ||
198 | 293 | ||
199 | if (pInfo->size) | 294 | if (FB[i] != data[i]) |
200 | { | 295 | return false; |
201 | rb->lcd_puts(0, 1, pInfo->name); | 296 | |
202 | rb->lcd_putsf(0, 2, "Size: %u KB", pInfo->size / 1024); | 297 | /* display a progress report if requested */ |
203 | } | 298 | if (progress && ((i % SECTOR_SIZE) == 0 || j == len)) |
204 | else | ||
205 | { | 299 | { |
206 | rb->lcd_puts(0, 1, "Unsupported chip"); | 300 | rb->lcd_putsf(0, 5, "Verifying... %u%%", j * 100 / len); |
301 | rb->lcd_update(); | ||
207 | } | 302 | } |
208 | } | 303 | } |
209 | 304 | ||
210 | rb->lcd_update(); | 305 | return true; |
211 | } | 306 | } |
212 | 307 | ||
308 | /* print information about the flash chip */ | ||
213 | static bool show_info(void) | 309 | static bool show_info(void) |
214 | { | 310 | { |
215 | struct flash_info fi; | 311 | static const struct flash_info* fi = NULL; |
216 | 312 | ||
217 | rb->lcd_clear_display(); | 313 | rb->lcd_clear_display(); |
218 | cfi_get_flash_info(&fi); | 314 | |
219 | ShowFlashInfo(&fi); | 315 | if (fi == NULL) |
220 | if (fi.size == 0) /* no valid chip */ | 316 | flash_get_info(&fi); |
317 | |||
318 | rb->lcd_putsf(0, 0, "Flash: V=%04x P=%04x", fi->vendor, fi->product); | ||
319 | |||
320 | if (fi->size != 0) | ||
321 | { | ||
322 | rb->lcd_puts(0, 1, fi->name); | ||
323 | rb->lcd_putsf(0, 2, "Size: %u KB", fi->size / 1024); | ||
324 | } | ||
325 | else | ||
221 | { | 326 | { |
222 | rb->splash(HZ*3, "Sorry!"); | 327 | rb->lcd_puts(0, 1, "Unknown chip"); |
223 | return false; /* exit */ | 328 | } |
329 | |||
330 | rb->lcd_update(); | ||
331 | |||
332 | if (fi->size == 0) | ||
333 | { | ||
334 | rb->splash(HZ * 3, "Sorry!"); | ||
335 | return false; | ||
224 | } | 336 | } |
225 | 337 | ||
226 | return true; | 338 | return true; |
227 | } | 339 | } |
228 | 340 | ||
229 | static bool confirm(const char* msg) | 341 | /* confirm a user's choice */ |
342 | static bool confirm_choice(const char* msg) | ||
230 | { | 343 | { |
344 | long button; | ||
231 | rb->splashf(0, "%s ([PLAY] to CONFIRM)", msg); | 345 | rb->splashf(0, "%s ([PLAY] to CONFIRM)", msg); |
232 | bool ret = (wait_for_button() == BUTTON_ON); | 346 | do |
347 | button = rb->button_get(true); | ||
348 | while (IS_SYSEVENT(button) || (button & BUTTON_REL)); | ||
233 | show_info(); | 349 | show_info(); |
234 | return ret; | 350 | return (button == BUTTON_ON); |
235 | } | 351 | } |
236 | 352 | ||
237 | static off_t load_firmware_file(const char* filename, uint32_t* out_checksum) | 353 | /* all-in-one firmware loader */ |
354 | static bool load_firmware(const char* filename, enum firmware firmware, | ||
355 | const void** data, size_t* data_len) | ||
238 | { | 356 | { |
239 | int fd; | 357 | bool result = false; |
240 | off_t len; | 358 | const char* msg = NULL; |
241 | uint32_t checksum; | 359 | int fd = -1; |
242 | char model[4]; | 360 | off_t fd_len; |
243 | uint32_t sum; | 361 | uint8_t* buffer; |
362 | size_t buffer_len; | ||
244 | 363 | ||
245 | fd = rb->open(filename, O_RDONLY); | 364 | fd = rb->open(filename, O_RDONLY); |
246 | if (fd < 0) | 365 | if (fd < 0) |
247 | return -1; | ||
248 | |||
249 | len = rb->filesize(fd); | ||
250 | if (audiobuf_size < len) | ||
251 | { | ||
252 | rb->splash(HZ*3, "Aborting: Out of memory!"); | ||
253 | rb->close(fd); | ||
254 | return -2; | ||
255 | } | ||
256 | |||
257 | if (rb->read(fd, &checksum, sizeof(checksum)) != sizeof(checksum)) | ||
258 | { | 366 | { |
259 | rb->splash(HZ*3, "Aborting: Read failure"); | 367 | msg = "Aborting: open failure"; |
260 | rb->close(fd); | 368 | goto bail; |
261 | return -3; | ||
262 | } | 369 | } |
263 | 370 | ||
264 | if (rb->read(fd, model, sizeof(model)) != sizeof(model)) | 371 | /* get file and buffer lengths and acquire the buffer */ |
265 | { | 372 | fd_len = rb->filesize(fd); |
266 | rb->splash(HZ*3, "Aborting: Read failure"); | 373 | buffer = rb->plugin_get_audio_buffer(&buffer_len); |
267 | rb->close(fd); | ||
268 | return -4; | ||
269 | } | ||
270 | 374 | ||
271 | len -= FIRMWARE_OFFSET_FILE_DATA; | 375 | /* ensure there's enough space in the buffer */ |
272 | 376 | if ((size_t) fd_len > buffer_len) | |
273 | if (rb->read(fd, audiobuf, len) != len) | ||
274 | { | 377 | { |
275 | rb->splash(HZ*3, "Aborting: Read failure"); | 378 | msg = "Aborting: out of memory"; |
276 | rb->close(fd); | 379 | goto bail; |
277 | return -5; | ||
278 | } | 380 | } |
279 | 381 | ||
280 | rb->close(fd); | 382 | /* all known firmwares are less than or equal to FLASH_SIZE */ |
281 | 383 | if (fd_len > FLASH_SIZE) | |
282 | /* Verify the checksum */ | ||
283 | sum = MODEL_NUMBER; | ||
284 | for (off_t i = 0; i < len; i++) | ||
285 | sum += audiobuf[i]; | ||
286 | |||
287 | if (sum != checksum) | ||
288 | { | ||
289 | rb->splash(HZ*3, "Aborting: Checksums mismatch!"); | ||
290 | return -6; | ||
291 | } | ||
292 | |||
293 | /* Verify the model */ | ||
294 | if (rb->memcmp(model, MODEL, sizeof(model)) != 0) | ||
295 | { | 384 | { |
296 | rb->splash(HZ*3, "Aborting: Models mismatch!"); | 385 | msg = "Aborting: firmware too big"; |
297 | return -7; | 386 | goto bail; |
298 | } | 387 | } |
299 | 388 | ||
300 | if (out_checksum != NULL) | 389 | /* rockbox firmware specific code */ |
301 | *out_checksum = checksum; | 390 | if (firmware == FIRMWARE_ROCKBOX) |
302 | |||
303 | return len; | ||
304 | } | ||
305 | |||
306 | static const uint32_t valid_bootloaders[][2] = { | ||
307 | /* Size-8, CRC32 */ | ||
308 | #ifdef IRIVER_H100 /* iRiver H110/H115 */ | ||
309 | { 48760, 0x2efc3323 }, /* 7-pre4 */ | ||
310 | { 56896, 0x0cd8dad4 }, /* 7-pre5 */ | ||
311 | #elif defined(IRIVER_H120) /* iRiver H120/H140 */ | ||
312 | { 63788, 0x08ff01a9 }, /* 7-pre3, improved failsafe functions */ | ||
313 | { 48764, 0xc674323e }, /* 7-pre4. Fixed audio thump & remote bootup */ | ||
314 | { 56896, 0x167f5d25 }, /* 7-pre5, various ATA fixes */ | ||
315 | #elif defined(IRIVER_H300) /* iRiver H320/H340 */ | ||
316 | #endif | ||
317 | {} | ||
318 | }; | ||
319 | |||
320 | /* check if the bootloader is a known good one */ | ||
321 | static bool detect_valid_bootloader(const uint8_t* pAddr, uint32_t len) | ||
322 | { | ||
323 | for (size_t i = 0; valid_bootloaders[i][0]; i++) | ||
324 | { | 391 | { |
325 | if (len != valid_bootloaders[i][0]) | 392 | uint32_t checksum; |
326 | continue; | 393 | uint8_t model[4]; |
394 | uint32_t sum; | ||
327 | 395 | ||
328 | uint32_t crc32 = rb->crc_32(pAddr, valid_bootloaders[i][0], 0xffffffff); | 396 | /* subtract the header length */ |
329 | if (crc32 == valid_bootloaders[i][1]) | 397 | fd_len -= sizeof(checksum) + sizeof(model); |
330 | return true; | ||
331 | } | ||
332 | 398 | ||
333 | return false; | 399 | /* sanity check the length */ |
334 | } | 400 | if (fd_len < WORD_SIZE) |
401 | { | ||
402 | msg = "Aborting: firmware too small"; | ||
403 | goto bail; | ||
404 | } | ||
335 | 405 | ||
336 | static int get_section_address(int section) | 406 | /* read the various parts */ |
337 | { | 407 | if ( |
338 | if (section == SECT_RAMIMAGE) | 408 | rb->read(fd, &checksum, sizeof(checksum)) != sizeof(checksum) || |
339 | return FLASH_RAMIMAGE_ENTRY; | 409 | rb->read(fd, model, sizeof(model)) != sizeof(model) || |
340 | else if (section == SECT_ROMIMAGE) | 410 | rb->read(fd, buffer, fd_len) != fd_len |
341 | return FLASH_ROMIMAGE_ENTRY; | 411 | ) |
342 | else | 412 | { |
343 | return -1; | 413 | msg = "Aborting: read failure"; |
344 | } | 414 | goto bail; |
415 | } | ||
345 | 416 | ||
346 | int flash_rockbox(const char *filename, int section) | 417 | /* calculate the checksum */ |
347 | { | 418 | sum = MODEL_NUMBER; |
348 | struct flash_header hdr; | 419 | for (off_t i = 0; i < fd_len; i++) |
349 | int pos, i, len/*, rc */; | 420 | sum += buffer[i]; |
350 | unsigned long checksum, sum; | ||
351 | unsigned char *p8; | ||
352 | uint16_t *p16; | ||
353 | 421 | ||
354 | if (get_section_address(section) < 0) | 422 | /* verify the checksum */ |
355 | return -1; | 423 | if (sum != checksum) |
424 | { | ||
425 | msg = "Aborting: checksum mismatch"; | ||
426 | goto bail; | ||
427 | } | ||
356 | 428 | ||
357 | p8 = (char *)BOOTLOADER_ENTRYPOINT; | 429 | /* verify the model */ |
358 | if (!detect_valid_bootloader(p8, 0)) | 430 | if (rb->memcmp(model, MODEL, sizeof(model)) != 0) |
359 | { | 431 | { |
360 | rb->splash(HZ*3, "Incompatible bootloader"); | 432 | msg = "Aborting: model mismatch"; |
361 | return -1; | 433 | goto bail; |
434 | } | ||
362 | } | 435 | } |
363 | 436 | ||
364 | if (!rb->detect_original_firmware()) | 437 | /* romdump specific code */ |
365 | { | 438 | if (firmware == FIRMWARE_ROMDUMP) |
366 | if (!confirm("Update Rockbox flash image?")) | ||
367 | return -2; | ||
368 | } | ||
369 | else | ||
370 | { | 439 | { |
371 | if (!confirm("Erase original firmware?")) | 440 | /* the romdump should be exactly the same size as the flash */ |
372 | return -3; | 441 | if (fd_len != FLASH_SIZE) |
373 | } | 442 | { |
374 | 443 | msg = "Aborting: firmware size incorrect"; | |
375 | len = load_firmware_file(filename, &checksum); | 444 | goto bail; |
376 | if (len <= 0) | 445 | } |
377 | return len * 10; | ||
378 | |||
379 | pos = get_section_address(section); | ||
380 | 446 | ||
381 | /* Check if image relocation seems to be sane. */ | 447 | /* exclude boot vector and boot loader regions */ |
382 | if (section == SECT_ROMIMAGE) | 448 | fd_len = BOOTLOADER_ENTRYPOINT - BOOT_VECTOR_SIZE; |
383 | { | ||
384 | uint32_t *p32 = (uint32_t *)audiobuf; | ||
385 | 449 | ||
386 | if (pos+sizeof(struct flash_header) != *p32) | 450 | /* skip the boot vector */ |
451 | if (rb->lseek(fd, BOOT_VECTOR_SIZE, SEEK_SET) != BOOT_VECTOR_SIZE) | ||
387 | { | 452 | { |
388 | rb->splashf(HZ*10, "Incorrect relocation: 0x%08lx/0x%08lx", | 453 | msg = "Aborting: lseek failure"; |
389 | *p32, pos+sizeof(struct flash_header)); | 454 | goto bail; |
390 | return -1; | ||
391 | } | 455 | } |
392 | 456 | ||
457 | /* read everything up to the boot loader */ | ||
458 | if (rb->read(fd, buffer, fd_len) != fd_len) | ||
459 | { | ||
460 | msg = "Aborting: read failure"; | ||
461 | goto bail; | ||
462 | } | ||
393 | } | 463 | } |
394 | 464 | ||
395 | /* Erase the program flash. */ | 465 | /* original firmware specific code */ |
396 | for (i = 0; i + pos < BOOTLOADER_ENTRYPOINT && i < len + 32; i += SEC_SIZE) | 466 | if (firmware == FIRMWARE_ORIGINAL) |
397 | { | 467 | { |
398 | /* Additional safety check. */ | 468 | uint32_t boot_vector[2]; |
399 | if (i + pos < SEC_SIZE) | ||
400 | return -1; | ||
401 | |||
402 | rb->lcd_putsf(0, 3, "Erasing... %d%%", (i+SEC_SIZE)*100/len); | ||
403 | rb->lcd_update(); | ||
404 | 469 | ||
405 | /*rc = */cfi_erase_sector(FB + (i + pos)/2); | 470 | /* subtract the offset and the size of the boot vector */ |
406 | } | 471 | fd_len -= FIRMWARE_OFFSET + sizeof(boot_vector); |
407 | |||
408 | /* Write the magic and size. */ | ||
409 | rb->memset(&hdr, 0, sizeof(struct flash_header)); | ||
410 | hdr.magic = FLASH_MAGIC; | ||
411 | hdr.length = len; | ||
412 | // rb->strncpy(hdr.version, rb->rbversion , sizeof(hdr.version)-1); | ||
413 | p16 = (uint16_t *)&hdr; | ||
414 | 472 | ||
415 | rb->lcd_puts(0, 4, "Programming..."); | 473 | /* sanity check the length */ |
416 | rb->lcd_update(); | 474 | if (fd_len < WORD_SIZE) |
475 | { | ||
476 | msg = "Aborting: firmware too small"; | ||
477 | goto bail; | ||
478 | } | ||
417 | 479 | ||
418 | pos = get_section_address(section)/2; | 480 | /* skip the leading bytes, whatever they are */ |
419 | for (i = 0; i < (long)sizeof(struct flash_header)/2; i++) | 481 | if (rb->lseek(fd, FIRMWARE_OFFSET, SEEK_SET) != FIRMWARE_OFFSET) |
420 | { | 482 | { |
421 | cfi_program_word(FB + pos, p16[i]); | 483 | msg = "Aborting: lseek failure"; |
422 | pos++; | 484 | goto bail; |
423 | } | 485 | } |
424 | 486 | ||
425 | p16 = (uint16_t *)audiobuf; | 487 | /* read the various parts */ |
426 | for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++) | 488 | if ( |
427 | { | 489 | rb->read(fd, boot_vector, sizeof(boot_vector)) != sizeof(boot_vector) || |
428 | if (i % SEC_SIZE == 0) | 490 | rb->read(fd, buffer, fd_len) != fd_len |
491 | ) | ||
429 | { | 492 | { |
430 | rb->lcd_putsf(0, 4, "Programming... %d%%", (i+1)*100/(len/2)); | 493 | msg = "Aborting: read failure"; |
431 | rb->lcd_update(); | 494 | goto bail; |
432 | } | 495 | } |
433 | 496 | ||
434 | cfi_program_word(FB + pos + i, p16[i]); | 497 | /* verify the boot vector */ |
498 | if (boot_vector[0] != 0x10017ff0 || boot_vector[1] != 0x00000008) | ||
499 | { | ||
500 | msg = "Aborting: not an original firmware"; | ||
501 | goto bail; | ||
502 | } | ||
435 | } | 503 | } |
436 | 504 | ||
437 | /* Verify */ | 505 | /* write the resulting buffer and length in the output parameters */ |
438 | rb->lcd_puts(0, 5, "Verifying"); | 506 | *data = buffer; |
439 | rb->lcd_update(); | 507 | *data_len = fd_len; |
440 | |||
441 | p8 = (char *)get_section_address(section); | ||
442 | p8 += sizeof(struct flash_header); | ||
443 | sum = MODEL_NUMBER; | ||
444 | for (i = 0; i < len; i++) | ||
445 | sum += p8[i]; | ||
446 | |||
447 | if (sum != checksum) | ||
448 | { | ||
449 | rb->splash(HZ*3, "Verify failed!"); | ||
450 | /* Erase the magic sector so bootloader does not try to load | ||
451 | * rockbox from flash and crash. */ | ||
452 | if (section == SECT_RAMIMAGE) | ||
453 | cfi_erase_sector(FB + FLASH_RAMIMAGE_ENTRY/2); | ||
454 | else | ||
455 | cfi_erase_sector(FB + FLASH_ROMIMAGE_ENTRY/2); | ||
456 | return -5; | ||
457 | } | ||
458 | 508 | ||
459 | rb->splash(HZ*2, "Success"); | 509 | /* mark success */ |
510 | result = true; | ||
460 | 511 | ||
461 | return 0; | 512 | bail: /* common exit code */ |
513 | if (fd >= 0) | ||
514 | rb->close(fd); | ||
515 | if (msg != NULL) | ||
516 | rb->splash(HZ * 3, msg); | ||
517 | return result; | ||
462 | } | 518 | } |
463 | 519 | ||
520 | /* prints fatal error if a critical failure occurs */ | ||
464 | static void show_fatal_error(void) | 521 | static void show_fatal_error(void) |
465 | { | 522 | { |
466 | rb->splash(HZ*30, "Disable idle poweroff, connect AC power and DON'T TURN PLAYER OFF!!"); | 523 | rb->splash(HZ * 30, "Disable idle poweroff, connect AC power and DON'T TURN PLAYER OFF!"); |
467 | rb->splash(HZ*30, "Contact Rockbox developers as soon as possible!"); | 524 | rb->splash(HZ * 30, "Contact Rockbox developers as soon as possible!"); |
468 | rb->splash(HZ*30, "Your device won't be bricked unless you turn off the power"); | 525 | rb->splash(HZ * 30, "Your device won't be bricked unless you turn off the power!"); |
469 | rb->splash(HZ*30, "Don't use the device before further instructions from Rockbox developers"); | 526 | rb->splash(HZ * 30, "Don't use the device before further instructions from Rockbox developers!"); |
470 | } | 527 | } |
471 | 528 | ||
472 | int flash_bootloader(const char *filename) | 529 | /* flash a bootloader */ |
530 | static bool flash_bootloader(const char* filename) | ||
473 | { | 531 | { |
474 | char *bootsector; | 532 | bool result = false; |
475 | int pos, i, len/*, rc*/; | 533 | const char* msg = NULL; |
476 | unsigned long checksum, sum; | 534 | bool show_fatal = false; |
477 | unsigned char *p8; | 535 | const void* data; |
478 | uint16_t *p16; | 536 | size_t data_len; |
537 | static uint8_t boot_sector[SECTOR_SIZE]; | ||
479 | 538 | ||
480 | bootsector = audiobuf; | 539 | /* load the firmware */ |
481 | audiobuf += SEC_SIZE; | 540 | if (!load_firmware(filename, FIRMWARE_ROCKBOX, &data, &data_len)) |
482 | audiobuf_size -= SEC_SIZE; | 541 | goto bail; |
483 | 542 | ||
484 | if (!confirm("Update bootloader?")) | 543 | /* the bootloader can only be so big */ |
485 | return -2; | 544 | if (data_len > BOOTLOADER_MAX_SIZE) |
486 | |||
487 | len = load_firmware_file(filename, &checksum); | ||
488 | if (len <= 0) | ||
489 | return len * 10; | ||
490 | |||
491 | if (len > 0xFFFF) | ||
492 | { | 545 | { |
493 | rb->splash(HZ*3, "Too big bootloader"); | 546 | msg = "Aborting: bootloader too large"; |
494 | return -1; | 547 | goto bail; |
495 | } | 548 | } |
496 | 549 | ||
497 | /* Verify the crc32 checksum also. */ | 550 | /* only support known bootloaders */ |
498 | if (!detect_valid_bootloader(audiobuf, len)) | 551 | if (!detect_valid_bootloader(data, data_len)) |
499 | { | 552 | { |
500 | rb->splash(HZ*3, "Incompatible/Untested bootloader"); | 553 | msg = "Aborting: bootloader is invalid"; |
501 | return -1; | 554 | goto bail; |
502 | } | 555 | } |
503 | 556 | ||
504 | rb->lcd_puts(0, 3, "Flashing..."); | 557 | /* ask before doing anything dangerous */ |
505 | rb->lcd_update(); | 558 | if (!confirm_choice("Update bootloader?")) |
559 | goto bail; | ||
506 | 560 | ||
507 | /* Backup the bootloader sector first. */ | 561 | /* copy the original boot sector */ |
508 | p8 = (char *)FB; | 562 | rb->memcpy(boot_sector, flash(BOOT_SECTOR_OFFSET), SECTOR_SIZE); |
509 | rb->memcpy(bootsector, p8, SEC_SIZE); | ||
510 | 563 | ||
511 | /* Erase the boot sector and write a proper reset vector. */ | 564 | /* update the boot vector */ |
512 | cfi_erase_sector(FB); | 565 | rb->memcpy(boot_sector, data, BOOT_VECTOR_SIZE); |
513 | p16 = (uint16_t *)audiobuf; | ||
514 | for (i = 0; i < 8/2; i++) | ||
515 | cfi_program_word(FB + i, p16[i]); | ||
516 | 566 | ||
517 | /* And restore original content for original FW to function. */ | 567 | /* erase the boot sector */ |
518 | p16 = (uint16_t *)bootsector; | 568 | flash_erase_sector(BOOT_SECTOR_OFFSET); |
519 | for (i = 8/2; i < SEC_SIZE/2; i++) | ||
520 | cfi_program_word(FB + i, p16[i]); | ||
521 | 569 | ||
522 | /* Erase the bootloader flash section. */ | 570 | /* erase the bootloader sectors */ |
523 | for (i = BOOTLOADER_ERASEGUARD; i < BOOTLOADER_ERASEGUARD+16; i++) | 571 | flash_erase_sectors(BOOTLOADER_ENTRYPOINT, BOOTLOADER_SECTORS, false); |
524 | /*rc =*/ cfi_erase_sector(FB + (SEC_SIZE/2) * i); | ||
525 | 572 | ||
526 | pos = BOOTLOADER_ENTRYPOINT/2; | 573 | /* program the new boot sector */ |
527 | p16 = (uint16_t *)audiobuf; | 574 | flash_program_bytes(BOOT_SECTOR_OFFSET, boot_sector, SECTOR_SIZE, false); |
528 | for (i = 0; i < len/2; i++) | ||
529 | cfi_program_word(FB + pos + i, p16[i]); | ||
530 | 575 | ||
531 | /* Verify */ | 576 | /* program the new bootloader */ |
532 | p8 = (char *)BOOTLOADER_ENTRYPOINT; | 577 | flash_program_bytes(BOOTLOADER_ENTRYPOINT, data, data_len, false); |
533 | sum = MODEL_NUMBER; | ||
534 | for (i = 0; i < len; i++) | ||
535 | sum += p8[i]; | ||
536 | 578 | ||
537 | if (sum != checksum) | 579 | /* verify the new boot sector */ |
580 | if (!flash_verify_bytes(BOOT_SECTOR_OFFSET, boot_sector, SECTOR_SIZE, false)) | ||
538 | { | 581 | { |
539 | rb->splash(HZ*3, "Verify failed!"); | 582 | msg = "Boot sector corrupt!"; |
540 | show_fatal_error(); | 583 | show_fatal = true; |
541 | return -5; | 584 | goto bail; |
542 | } | 585 | } |
543 | 586 | ||
544 | p8 = (char *)FB; | 587 | /* verify the new bootloader */ |
545 | for (i = 0; i < 8; i++) | 588 | if (!flash_verify_bytes(BOOTLOADER_ENTRYPOINT, data, data_len, false)) |
546 | { | 589 | { |
547 | if (p8[i] != audiobuf[i]) | 590 | msg = "Verify failed!"; |
548 | { | 591 | show_fatal = true; |
549 | rb->splash(HZ*3, "Bootvector corrupt!"); | 592 | goto bail; |
550 | show_fatal_error(); | ||
551 | return -6; | ||
552 | } | ||
553 | } | 593 | } |
554 | 594 | ||
555 | rb->splash(HZ*2, "Success"); | 595 | /* report success */ |
596 | rb->splash(HZ * 3, "Success!"); | ||
556 | 597 | ||
557 | return 0; | 598 | /* mark success */ |
599 | result = true; | ||
600 | |||
601 | bail: /* common exit code */ | ||
602 | if (msg != NULL) | ||
603 | rb->splash(HZ * 3, msg); | ||
604 | if (show_fatal) | ||
605 | show_fatal_error(); | ||
606 | return result; | ||
558 | } | 607 | } |
559 | 608 | ||
560 | int flash_original_fw(int len) | 609 | /* flash a rockbox ram / rom image */ |
610 | static bool flash_rockbox(const char* filename, uint32_t offset) | ||
561 | { | 611 | { |
562 | unsigned char reset_vector[8]; | 612 | bool result = false; |
563 | int pos, i, rc; | 613 | const char* msg = NULL; |
564 | unsigned char *p8; | 614 | const void* data; |
565 | uint16_t *p16; | 615 | size_t data_len; |
616 | struct flash_header header; | ||
566 | 617 | ||
567 | rb->lcd_puts(0, 3, "Critical section..."); | 618 | /* load the firmware */ |
568 | rb->lcd_update(); | 619 | if (!load_firmware(filename, FIRMWARE_ROCKBOX, &data, &data_len)) |
569 | 620 | goto bail; | |
570 | p8 = (char *)FB; | ||
571 | rb->memcpy(reset_vector, p8, sizeof reset_vector); | ||
572 | 621 | ||
573 | /* Erase the boot sector and write back the reset vector. */ | 622 | /* sanity check that the offset was set correctly */ |
574 | cfi_erase_sector(FB); | 623 | if (offset != FLASH_RAMIMAGE_ENTRY && offset != FLASH_ROMIMAGE_ENTRY) |
575 | p16 = (uint16_t *)reset_vector; | ||
576 | for (i = 0; i < (long)sizeof(reset_vector)/2; i++) | ||
577 | cfi_program_word(FB + i, p16[i]); | ||
578 | |||
579 | rb->lcd_puts(0, 4, "Flashing orig. FW"); | ||
580 | rb->lcd_update(); | ||
581 | |||
582 | /* Erase the program flash. */ | ||
583 | for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len; i++) | ||
584 | { | 624 | { |
585 | rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i); | 625 | msg = "Aborting: invalid image offset"; |
586 | rb->lcd_putsf(0, 5, "Erase: 0x%03x (%d)", i, rc); | 626 | goto bail; |
587 | rb->lcd_update(); | ||
588 | } | 627 | } |
589 | 628 | ||
590 | rb->lcd_puts(0, 6, "Programming"); | 629 | /* ensure there's enough room for the ram / rom image */ |
591 | rb->lcd_update(); | 630 | if ( |
592 | 631 | (offset == FLASH_RAMIMAGE_ENTRY && data_len > RAM_IMAGE_MAX_SIZE) || | |
593 | pos = 0x00000008/2; | 632 | (offset == FLASH_ROMIMAGE_ENTRY && data_len > ROM_IMAGE_MAX_SIZE) |
594 | p16 = (uint16_t *)audiobuf; | 633 | ) |
595 | for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++) | 634 | { |
596 | cfi_program_word(FB + pos + i, p16[i]); | 635 | msg = "Aborting: ram / rom image too large"; |
636 | goto bail; | ||
637 | } | ||
597 | 638 | ||
598 | rb->lcd_puts(0, 7, "Verifying"); | 639 | /* check for bootloader that can load rockbox from ram / rom */ |
599 | rb->lcd_update(); | 640 | if (!detect_valid_bootloader(flash(BOOTLOADER_ENTRYPOINT), 0)) |
641 | { | ||
642 | msg = "Aborting: incompatible bootloader"; | ||
643 | goto bail; | ||
644 | } | ||
600 | 645 | ||
601 | /* Verify reset vectors. */ | 646 | /* rom image specific checks */ |
602 | p8 = (char *)FB; | 647 | if (offset == FLASH_ROMIMAGE_ENTRY) |
603 | for (i = 0; i < 8; i++) | ||
604 | { | 648 | { |
605 | if (p8[i] != reset_vector[i]) | 649 | uint32_t relocation = *((const uint32_t*) data); |
650 | |||
651 | /* sanity check of the image relocation */ | ||
652 | if (relocation != ROM_IMAGE_RELOCATION) | ||
606 | { | 653 | { |
607 | rb->splash(HZ*3, "Bootvector corrupt!"); | 654 | msg = "Aborting: invalid image relocation"; |
608 | show_fatal_error(); | 655 | goto bail; |
609 | break; | ||
610 | } | 656 | } |
611 | } | 657 | } |
612 | 658 | ||
613 | /* Verify */ | 659 | /* ask before doing anything dangerous */ |
614 | p8 = (char *)0x00000008; | 660 | if (!rb->detect_original_firmware()) |
615 | for (i = 0; i < len; i++) | ||
616 | { | 661 | { |
617 | if (p8[i] != audiobuf[i]) | 662 | if (!confirm_choice("Update Rockbox flash image?")) |
618 | { | 663 | goto bail; |
619 | rb->splash(HZ*3, "Verify failed!"); | 664 | } |
620 | rb->splashf(HZ*10, "at: 0x%08x", i); | 665 | else |
621 | return -5; | 666 | { |
622 | } | 667 | if (!confirm_choice("Erase original firmware?")) |
668 | goto bail; | ||
623 | } | 669 | } |
624 | 670 | ||
625 | rb->splash(HZ*2, "Success"); | 671 | /* erase all ram / rom image sectors */ |
672 | if (offset == FLASH_RAMIMAGE_ENTRY) | ||
673 | flash_erase_sectors(offset, RAM_IMAGE_SECTORS, true); | ||
674 | else if (offset == FLASH_ROMIMAGE_ENTRY) | ||
675 | flash_erase_sectors(offset, ROM_IMAGE_SECTORS, true); | ||
676 | |||
677 | /* prepare the header */ | ||
678 | header.magic = FLASH_MAGIC; | ||
679 | header.length = data_len; | ||
680 | rb->memset(&header.version, 0x00, sizeof(header.version)); | ||
681 | |||
682 | /* program the header */ | ||
683 | flash_program_bytes(offset, &header, sizeof(header), false); | ||
684 | |||
685 | /* program the ram / rom image */ | ||
686 | flash_program_bytes(offset + sizeof(header), data, data_len, true); | ||
687 | |||
688 | /* verify the header and ram / rom image */ | ||
689 | if ( | ||
690 | !flash_verify_bytes(offset, &header, sizeof(header), false) || | ||
691 | !flash_verify_bytes(offset + sizeof(header), data, data_len, true) | ||
692 | ) | ||
693 | { | ||
694 | msg = "Verify failed!"; | ||
695 | /* | ||
696 | * erase the ram / rom image header to prevent the bootloader | ||
697 | * from trying to boot from it | ||
698 | */ | ||
699 | flash_erase_sector(offset); | ||
700 | goto bail; | ||
701 | } | ||
626 | 702 | ||
627 | return 0; | 703 | /* report success */ |
704 | rb->splash(HZ * 3, "Success!"); | ||
705 | |||
706 | /* mark success */ | ||
707 | result = true; | ||
708 | |||
709 | bail: /* common exit code */ | ||
710 | if (msg != NULL) | ||
711 | rb->splash(HZ * 3, msg); | ||
712 | return result; | ||
628 | } | 713 | } |
629 | 714 | ||
630 | int load_original_bin(const char *filename) | 715 | /* flash whole firmware; common code for romdump / original */ |
716 | static bool flash_whole_firmware(const void* data, size_t data_len) | ||
631 | { | 717 | { |
632 | unsigned long magic[2]; | 718 | bool result = false; |
633 | int len, rc; | 719 | const char* msg = NULL; |
634 | int fd; | 720 | bool show_fatal = false; |
721 | uint8_t boot_vector[BOOT_VECTOR_SIZE]; | ||
635 | 722 | ||
636 | if (!confirm("Restore original firmware (bootloader will be kept)?")) | 723 | /* copy the original boot vector */ |
637 | return -2; | 724 | rb->memcpy(boot_vector, flash(BOOT_SECTOR_OFFSET), BOOT_VECTOR_SIZE); |
638 | 725 | ||
639 | fd = rb->open(filename, O_RDONLY); | 726 | /* erase everything except the bootloader */ |
640 | if (fd < 0) | 727 | flash_erase_sectors(BOOT_SECTOR_OFFSET, WHOLE_FIRMWARE_SECTORS, true); |
641 | return -1; | 728 | |
729 | /* program the original boot vector */ | ||
730 | flash_program_bytes(BOOT_SECTOR_OFFSET, boot_vector, BOOT_VECTOR_SIZE, false); | ||
731 | |||
732 | /* program the whole firmware */ | ||
733 | flash_program_bytes(BOOT_SECTOR_OFFSET + BOOT_VECTOR_SIZE, data, data_len, true); | ||
642 | 734 | ||
643 | len = rb->filesize(fd) - 0x228; | 735 | /* verify the new boot vector */ |
644 | rb->lseek(fd, 0x220, SEEK_SET); | 736 | if (!flash_verify_bytes(BOOT_SECTOR_OFFSET, boot_vector, BOOT_VECTOR_SIZE, false)) |
645 | rb->read(fd, magic, 8); | ||
646 | if (magic[1] != 0x00000008 || len <= 0 || len > audiobuf_size) | ||
647 | { | 737 | { |
648 | rb->splash(HZ*2, "Not an original firmware file"); | 738 | msg = "Boot vector corrupt!"; |
649 | rb->close(fd); | 739 | show_fatal = true; |
650 | return -1; | 740 | goto bail; |
651 | } | 741 | } |
652 | 742 | ||
653 | rc = rb->read(fd, audiobuf, len); | 743 | /* verify the new firmware */ |
654 | rb->close(fd); | 744 | if (!flash_verify_bytes(BOOT_SECTOR_OFFSET + BOOT_VECTOR_SIZE, data, data_len, true)) |
655 | |||
656 | if (rc != len) | ||
657 | { | 745 | { |
658 | rb->splash(HZ*2, "Read error"); | 746 | msg = "Verify failed!"; |
659 | return -2; | 747 | goto bail; |
660 | } | 748 | } |
661 | 749 | ||
662 | if (len % 2) | 750 | /* report success */ |
663 | len++; | 751 | rb->splash(HZ * 3, "Success!"); |
752 | |||
753 | /* mark success */ | ||
754 | result = true; | ||
664 | 755 | ||
665 | return flash_original_fw(len); | 756 | bail: /* common exit code */ |
757 | if (msg != NULL) | ||
758 | rb->splash(HZ * 3, msg); | ||
759 | if (show_fatal) | ||
760 | show_fatal_error(); | ||
761 | return result; | ||
666 | } | 762 | } |
667 | 763 | ||
668 | int load_romdump(const char *filename) | 764 | /* flash rom dumps */ |
765 | static bool flash_romdump(const char* filename) | ||
669 | { | 766 | { |
670 | int len, rc; | 767 | const void* data; |
671 | int fd; | 768 | size_t data_len; |
672 | 769 | ||
673 | if (!confirm("Restore firmware section (bootloader will be kept)?")) | 770 | /* load the firmware */ |
674 | return -2; | 771 | if (!load_firmware(filename, FIRMWARE_ROMDUMP, &data, &data_len)) |
772 | return false; | ||
675 | 773 | ||
676 | fd = rb->open(filename, O_RDONLY); | 774 | /* ask before doing anything dangerous */ |
677 | if (fd < 0) | 775 | if (!confirm_choice("Restore firmware section (bootloader will be kept)?")) |
678 | return -1; | 776 | return false; |
679 | |||
680 | len = rb->filesize(fd) - 8; | ||
681 | if (len <= 0) | ||
682 | return -1; | ||
683 | 777 | ||
684 | rb->lseek(fd, 8, SEEK_SET); | 778 | return flash_whole_firmware(data, data_len); |
685 | rc = rb->read(fd, audiobuf, len); | 779 | } |
686 | rb->close(fd); | ||
687 | 780 | ||
688 | if (rc != len) | 781 | /* flash original firmware */ |
689 | { | 782 | static bool flash_original(const char* filename) |
690 | rb->splash(HZ*2, "Read error"); | 783 | { |
691 | return -2; | 784 | const void* data; |
692 | } | 785 | size_t data_len; |
693 | 786 | ||
694 | if (len % 2) | 787 | /* load the firmware */ |
695 | len++; | 788 | if (!load_firmware(filename, FIRMWARE_ORIGINAL, &data, &data_len)) |
789 | return false; | ||
696 | 790 | ||
697 | if (len > BOOTLOADER_ENTRYPOINT - 8) | 791 | /* ask before doing anything dangerous */ |
698 | len = BOOTLOADER_ENTRYPOINT - 8; | 792 | if (!confirm_choice("Restore original firmware (bootloader will be kept)?")) |
793 | return false; | ||
699 | 794 | ||
700 | return flash_original_fw(len); | 795 | return flash_whole_firmware(data, data_len); |
701 | } | 796 | } |
702 | 797 | ||
703 | /* Kind of our main function, defines the application flow. */ | 798 | /* main function of plugin */ |
704 | static void DoUserDialog(const char* filename) | 799 | static void iriver_flash(const char* filename) |
705 | { | 800 | { |
706 | /* check whether we're running from ROM */ | 801 | /* refuse to run from ROM */ |
707 | uint16_t* RB = (uint16_t*) rb; | 802 | const uint8_t* RB = (uint8_t*) rb; |
708 | if (RB >= FB && RB < FB + (FLASH_SIZE / sizeof(*FB))) | 803 | const uint8_t* FB = (uint8_t*) flash(0); |
804 | if (RB >= FB && RB < FB + FLASH_SIZE) | ||
709 | { | 805 | { |
710 | rb->splash(HZ*3, "Not from ROM"); | 806 | rb->splash(HZ * 3, "Refusing to run from ROM"); |
711 | return; /* exit */ | 807 | return; |
712 | } | 808 | } |
713 | 809 | ||
714 | /* refuse to work if the power may fail meanwhile */ | 810 | /* refuse to run with low battery */ |
715 | if (!rb->battery_level_safe()) | 811 | if (!rb->battery_level_safe()) |
716 | { | 812 | { |
717 | rb->splash(HZ*3, "Battery too low!"); | 813 | rb->splash(HZ * 3, "Refusing to run with low battery"); |
718 | return; /* exit */ | 814 | return; |
719 | } | 815 | } |
720 | 816 | ||
817 | /* print information about flash; exit if not supported */ | ||
721 | if (!show_info()) | 818 | if (!show_info()) |
722 | return; /* exit */ | 819 | return; |
723 | 820 | ||
821 | /* exit if no filename was provided */ | ||
724 | if (filename == NULL) | 822 | if (filename == NULL) |
725 | { | 823 | { |
726 | rb->splash(HZ*3, "Please use this plugin with \"Open with...\""); | 824 | rb->splash(HZ * 3, "Please use this plugin with \"Open with...\""); |
727 | return; /* exit */ | 825 | return; |
728 | } | 826 | } |
729 | 827 | ||
730 | audiobuf = rb->plugin_get_audio_buffer((size_t *)&audiobuf_size); | 828 | /* choose what to do with the file */ |
731 | 829 | if (rb->strcasestr(filename, "/bootloader.iriver") != NULL) | |
732 | if (rb->strcasestr(filename, "/rockbox.iriver")) | ||
733 | flash_rockbox(filename, SECT_RAMIMAGE); | ||
734 | else if (rb->strcasestr(filename, "/rombox.iriver")) | ||
735 | flash_rockbox(filename, SECT_ROMIMAGE); | ||
736 | else if (rb->strcasestr(filename, "/bootloader.iriver")) | ||
737 | flash_bootloader(filename); | 830 | flash_bootloader(filename); |
738 | else if (rb->strcasestr(filename, "/ihp_120.bin")) | 831 | else if (rb->strcasestr(filename, "/rockbox.iriver") != NULL) |
739 | load_original_bin(filename); | 832 | flash_rockbox(filename, FLASH_RAMIMAGE_ENTRY); |
740 | else if (rb->strcasestr(filename, "/internal_rom_000000-1FFFFF.bin")) | 833 | else if (rb->strcasestr(filename, "/rombox.iriver") != NULL) |
741 | load_romdump(filename); | 834 | flash_rockbox(filename, FLASH_ROMIMAGE_ENTRY); |
835 | else if (rb->strcasestr(filename, ROMDUMP) != NULL) | ||
836 | flash_romdump(filename); | ||
837 | else if (rb->strcasestr(filename, ORIGINAL) != NULL) | ||
838 | flash_original(filename); | ||
742 | else | 839 | else |
743 | rb->splash(HZ*3, "Unknown file type"); | 840 | rb->splash(HZ * 3, "Unknown file type"); |
744 | } | 841 | } |
745 | 842 | ||
746 | 843 | /* plugin entry point */ | |
747 | /***************** Plugin Entry Point *****************/ | ||
748 | |||
749 | enum plugin_status plugin_start(const void* parameter) | 844 | enum plugin_status plugin_start(const void* parameter) |
750 | { | 845 | { |
751 | int oldmode; | 846 | /* need to disable memguard to write to flash */ |
847 | int mode = rb->system_memory_guard(MEMGUARD_NONE); | ||
752 | 848 | ||
753 | /* now go ahead and have fun! */ | 849 | /* setup LCD font */ |
754 | oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */ | ||
755 | rb->lcd_setfont(FONT_SYSFIXED); | 850 | rb->lcd_setfont(FONT_SYSFIXED); |
756 | DoUserDialog(parameter); | 851 | |
852 | /* run the main entry function */ | ||
853 | iriver_flash(parameter); | ||
854 | |||
855 | /* restore LCD font */ | ||
757 | rb->lcd_setfont(FONT_UI); | 856 | rb->lcd_setfont(FONT_UI); |
758 | rb->system_memory_guard(oldmode); /* re-enable memory guard */ | 857 | |
858 | /* restore original memory guard setting */ | ||
859 | rb->system_memory_guard(mode); | ||
759 | 860 | ||
760 | return PLUGIN_OK; | 861 | return PLUGIN_OK; |
761 | } | 862 | } |
diff --git a/firmware/export/config/iriverh100.h b/firmware/export/config/iriverh100.h index bbfab01ba5..b7f1ca4b30 100644 --- a/firmware/export/config/iriverh100.h +++ b/firmware/export/config/iriverh100.h | |||
@@ -172,6 +172,7 @@ | |||
172 | #define BOOTFILE "rockbox." BOOTFILE_EXT | 172 | #define BOOTFILE "rockbox." BOOTFILE_EXT |
173 | #define BOOTDIR "/.rockbox" | 173 | #define BOOTDIR "/.rockbox" |
174 | 174 | ||
175 | #define FLASH_BASE 0x00000000 | ||
175 | #define BOOTLOADER_ENTRYPOINT 0x001F0000 | 176 | #define BOOTLOADER_ENTRYPOINT 0x001F0000 |
176 | #define FLASH_RAMIMAGE_ENTRY 0x00001000 | 177 | #define FLASH_RAMIMAGE_ENTRY 0x00001000 |
177 | #define FLASH_ROMIMAGE_ENTRY 0x00100000 | 178 | #define FLASH_ROMIMAGE_ENTRY 0x00100000 |
diff --git a/firmware/export/config/iriverh120.h b/firmware/export/config/iriverh120.h index 77ee1382be..4b658bcf49 100644 --- a/firmware/export/config/iriverh120.h +++ b/firmware/export/config/iriverh120.h | |||
@@ -178,6 +178,7 @@ | |||
178 | #define BOOTFILE "rockbox." BOOTFILE_EXT | 178 | #define BOOTFILE "rockbox." BOOTFILE_EXT |
179 | #define BOOTDIR "/.rockbox" | 179 | #define BOOTDIR "/.rockbox" |
180 | 180 | ||
181 | #define FLASH_BASE 0x00000000 | ||
181 | #define BOOTLOADER_ENTRYPOINT 0x001F0000 | 182 | #define BOOTLOADER_ENTRYPOINT 0x001F0000 |
182 | #define FLASH_RAMIMAGE_ENTRY 0x00001000 | 183 | #define FLASH_RAMIMAGE_ENTRY 0x00001000 |
183 | #define FLASH_ROMIMAGE_ENTRY 0x00100000 | 184 | #define FLASH_ROMIMAGE_ENTRY 0x00100000 |
diff --git a/firmware/export/config/iriverh300.h b/firmware/export/config/iriverh300.h index f901f160c6..e5805dd8f4 100644 --- a/firmware/export/config/iriverh300.h +++ b/firmware/export/config/iriverh300.h | |||
@@ -187,6 +187,7 @@ | |||
187 | #define BOOTFILE "rockbox." BOOTFILE_EXT | 187 | #define BOOTFILE "rockbox." BOOTFILE_EXT |
188 | #define BOOTDIR "/.rockbox" | 188 | #define BOOTDIR "/.rockbox" |
189 | 189 | ||
190 | #define FLASH_BASE 0x00000000 | ||
190 | #define BOOTLOADER_ENTRYPOINT 0x003F0000 | 191 | #define BOOTLOADER_ENTRYPOINT 0x003F0000 |
191 | #define FLASH_RAMIMAGE_ENTRY 0x00001000 | 192 | #define FLASH_RAMIMAGE_ENTRY 0x00001000 |
192 | #define FLASH_ROMIMAGE_ENTRY 0x00200000 | 193 | #define FLASH_ROMIMAGE_ENTRY 0x00200000 |
diff --git a/firmware/export/system.h b/firmware/export/system.h index 1885acfffd..68d7958870 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h | |||
@@ -36,8 +36,8 @@ extern void system_init(void); | |||
36 | extern long cpu_frequency; | 36 | extern long cpu_frequency; |
37 | 37 | ||
38 | struct flash_header { | 38 | struct flash_header { |
39 | unsigned long magic; | 39 | uint32_t magic; |
40 | unsigned long length; | 40 | uint32_t length; |
41 | char version[32]; | 41 | char version[32]; |
42 | }; | 42 | }; |
43 | 43 | ||