diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-05-11 13:28:43 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-05-12 10:35:20 +0000 |
commit | 3f26fcf34001197ed267fa1ad549095aae49c88e (patch) | |
tree | c81ab3298a349d1156e905d467492b603236f74d /bootloader/fiiom3k.c | |
parent | cc22df198d0ccb64dfdfe0c2f247f7d86b7fd750 (diff) | |
download | rockbox-3f26fcf34001197ed267fa1ad549095aae49c88e.tar.gz rockbox-3f26fcf34001197ed267fa1ad549095aae49c88e.zip |
FiiO M3K: New bootloaderbootloader_fiiom3k_v1
SPL and UCL-compressed bootloader are now packed into one output,
bootloader.m3k, eliminating the separate SPL build phase.
The Rockbox bootloader now has a recovery menu, accessible by
holding VOL+ when booting, that lets you back up, restore, and
update the bootloader from the device.
Change-Id: I642c6e5fb83587a013ab2fbfd1adab439561ced2
Diffstat (limited to 'bootloader/fiiom3k.c')
-rw-r--r-- | bootloader/fiiom3k.c | 264 |
1 files changed, 233 insertions, 31 deletions
diff --git a/bootloader/fiiom3k.c b/bootloader/fiiom3k.c index 9f169755ae..3d42ba7314 100644 --- a/bootloader/fiiom3k.c +++ b/bootloader/fiiom3k.c | |||
@@ -20,6 +20,7 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "core_alloc.h" | ||
23 | #include "kernel/kernel-internal.h" | 24 | #include "kernel/kernel-internal.h" |
24 | #include "i2c.h" | 25 | #include "i2c.h" |
25 | #include "power.h" | 26 | #include "power.h" |
@@ -35,6 +36,9 @@ | |||
35 | #include "rb-loader.h" | 36 | #include "rb-loader.h" |
36 | #include "loader_strerror.h" | 37 | #include "loader_strerror.h" |
37 | #include "version.h" | 38 | #include "version.h" |
39 | #include "installer-fiiom3k.h" | ||
40 | #include "spl-x1000.h" | ||
41 | #include "x1000/cpm.h" | ||
38 | 42 | ||
39 | /* Load address where the binary needs to be placed */ | 43 | /* Load address where the binary needs to be placed */ |
40 | extern unsigned char loadaddress[]; | 44 | extern unsigned char loadaddress[]; |
@@ -59,6 +63,7 @@ void exec(void* dst, const void* src, int bytes) | |||
59 | 63 | ||
60 | static bool lcd_inited = false; | 64 | static bool lcd_inited = false; |
61 | static bool usb_inited = false; | 65 | static bool usb_inited = false; |
66 | static bool disk_inited = false; | ||
62 | 67 | ||
63 | static void init_lcd(void) | 68 | static void init_lcd(void) |
64 | { | 69 | { |
@@ -79,6 +84,12 @@ static void init_lcd(void) | |||
79 | lcd_inited = true; | 84 | lcd_inited = true; |
80 | } | 85 | } |
81 | 86 | ||
87 | static void put_version(void) | ||
88 | { | ||
89 | lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2, | ||
90 | (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion); | ||
91 | } | ||
92 | |||
82 | static void do_splash2(int delay, const char* msg, const char* msg2) | 93 | static void do_splash2(int delay, const char* msg, const char* msg2) |
83 | { | 94 | { |
84 | init_lcd(); | 95 | init_lcd(); |
@@ -90,8 +101,7 @@ static void do_splash2(int delay, const char* msg, const char* msg2) | |||
90 | (LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2); | 101 | (LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2); |
91 | } | 102 | } |
92 | 103 | ||
93 | lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2, | 104 | put_version(); |
94 | (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion); | ||
95 | lcd_update(); | 105 | lcd_update(); |
96 | sleep(delay); | 106 | sleep(delay); |
97 | } | 107 | } |
@@ -109,20 +119,232 @@ static void do_usb(void) | |||
109 | usb_inited = true; | 119 | usb_inited = true; |
110 | } | 120 | } |
111 | 121 | ||
112 | do_splash(0, "Waiting for USB"); | 122 | do_splash2(0, "Waiting for USB", "Press POWER to go back"); |
113 | 123 | ||
114 | while(button_get(true) != SYS_USB_CONNECTED); | 124 | int btn; |
115 | do_splash(0, "USB mode"); | 125 | while(1) { |
126 | btn = button_get(true); | ||
127 | if(btn == SYS_USB_CONNECTED) | ||
128 | break; | ||
129 | else if(btn == BUTTON_POWER) | ||
130 | return; | ||
131 | } | ||
116 | 132 | ||
133 | do_splash(0, "USB mode"); | ||
117 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 134 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
118 | while(button_get(true) != SYS_USB_DISCONNECTED); | 135 | while(button_get(true) != SYS_USB_DISCONNECTED); |
119 | 136 | ||
120 | do_splash(3*HZ, "USB disconnected"); | 137 | do_splash(3*HZ, "USB disconnected"); |
121 | } | 138 | } |
122 | 139 | ||
140 | static int init_disk(void) | ||
141 | { | ||
142 | if(disk_inited) | ||
143 | return 0; | ||
144 | |||
145 | while(!storage_present(0)) { | ||
146 | do_splash2(0, "Insert SD card", "Press POWER for recovery"); | ||
147 | int btn = button_get_w_tmo(HZ); | ||
148 | if(btn == BUTTON_POWER) | ||
149 | return 1; | ||
150 | } | ||
151 | |||
152 | if(disk_mount_all() <= 0) { | ||
153 | do_splash(5*HZ, "Cannot mount filesystem"); | ||
154 | return 1; | ||
155 | } | ||
156 | |||
157 | disk_inited = true; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void do_boot(void) | ||
162 | { | ||
163 | if(init_disk() != 0) | ||
164 | return; | ||
165 | |||
166 | int loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE); | ||
167 | if(loadsize <= 0) { | ||
168 | do_splash2(5*HZ, "Error loading Rockbox", | ||
169 | loader_strerror(loadsize)); | ||
170 | do_usb(); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | if(lcd_inited) | ||
175 | backlight_hw_off(); | ||
176 | |||
177 | disable_irq(); | ||
178 | exec(loadaddress, loadbuffer, loadsize); | ||
179 | } | ||
180 | |||
181 | #define INSTALL 0 | ||
182 | #define BACKUP 1 | ||
183 | #define RESTORE 2 | ||
184 | |||
185 | static void do_install(int which) | ||
186 | { | ||
187 | int rc = init_disk(); | ||
188 | if(rc != 0) { | ||
189 | do_splash2(5*HZ, "Install aborted", "No SD card present"); | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | const char* msg; | ||
194 | if(rc == INSTALL) | ||
195 | msg = "Installing"; | ||
196 | else if(rc == BACKUP) | ||
197 | msg = "Backing up"; | ||
198 | else | ||
199 | msg = "Restoring backup"; | ||
200 | |||
201 | do_splash(0, msg); | ||
202 | |||
203 | if(which == INSTALL) | ||
204 | rc = install_boot("/bootloader.m3k"); | ||
205 | else if(which == BACKUP) | ||
206 | rc = backup_boot("/fiiom3k-boot.bin"); | ||
207 | else | ||
208 | rc = restore_boot("/fiiom3k-boot.bin"); | ||
209 | |||
210 | char buf[32]; | ||
211 | snprintf(buf, sizeof(buf), "Failed! Error: %d", rc); | ||
212 | const char* msg1 = rc == 0 ? "Success" : buf; | ||
213 | const char* msg2 = "Press POWER to continue"; | ||
214 | do_splash2(0, msg1, msg2); | ||
215 | |||
216 | button_clear_queue(); | ||
217 | while(button_get(true) != BUTTON_POWER); | ||
218 | } | ||
219 | |||
220 | static void recovery_menu(void) | ||
221 | { | ||
222 | static const char* items[] = { | ||
223 | "--- Rockbox recovery menu ---", | ||
224 | "[System]", | ||
225 | " Start Rockbox", | ||
226 | " USB mode", | ||
227 | " Shutdown", | ||
228 | " Reboot", | ||
229 | "[Bootloader]", | ||
230 | " Install or update", | ||
231 | " Backup", | ||
232 | " Restore", | ||
233 | "", | ||
234 | "", | ||
235 | "", | ||
236 | "", | ||
237 | "", | ||
238 | "VOL+/VOL- move cursor", | ||
239 | "PLAY select item", | ||
240 | "POWER power off", | ||
241 | }; | ||
242 | |||
243 | static const int nitems = sizeof(items) / sizeof(char*); | ||
244 | |||
245 | init_lcd(); | ||
246 | |||
247 | int selection = 2; | ||
248 | do { | ||
249 | /* Draw menu */ | ||
250 | lcd_clear_display(); | ||
251 | |||
252 | for(int i = 0; i < nitems; ++i) | ||
253 | lcd_puts(0, i, items[i]); | ||
254 | |||
255 | if(items[selection][0] == ' ') | ||
256 | lcd_puts(0, selection, "=>"); | ||
257 | |||
258 | put_version(); | ||
259 | lcd_update(); | ||
260 | |||
261 | /* Clear queue to avoid accidental input */ | ||
262 | button_clear_queue(); | ||
263 | |||
264 | /* Get the button */ | ||
265 | int btn = button_get(true); | ||
266 | |||
267 | /* Process user input */ | ||
268 | if(btn == BUTTON_VOL_UP) { | ||
269 | for(int i = selection-1; i >= 0; --i) { | ||
270 | if(items[i][0] == ' ') { | ||
271 | selection = i; | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | continue; | ||
277 | } else if(btn == BUTTON_VOL_DOWN) { | ||
278 | for(int i = selection+1; i < nitems; ++i) { | ||
279 | if(items[i][0] == ' ') { | ||
280 | selection = i; | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | continue; | ||
286 | } else if(btn == BUTTON_POWER) { | ||
287 | selection = 4; /* Shutdown */ | ||
288 | } else if(btn != BUTTON_PLAY) { | ||
289 | continue; | ||
290 | } | ||
291 | |||
292 | /* User pressed PLAY so decide what action to take */ | ||
293 | switch(selection) { | ||
294 | case 2: /* Start rockbox */ | ||
295 | do_boot(); | ||
296 | break; | ||
297 | |||
298 | case 3: /* USB mode */ | ||
299 | do_usb(); | ||
300 | break; | ||
301 | |||
302 | case 4: /* Shutdown */ | ||
303 | do_splash(HZ, "Shutting down"); | ||
304 | power_off(); | ||
305 | break; | ||
306 | |||
307 | case 5: /* Reboot */ | ||
308 | do_splash(HZ, "Rebooting"); | ||
309 | system_reboot(); | ||
310 | break; | ||
311 | |||
312 | case 7: /* Install bootloader */ | ||
313 | do_install(INSTALL); | ||
314 | break; | ||
315 | |||
316 | case 8: /* Backup bootloader */ | ||
317 | do_install(BACKUP); | ||
318 | break; | ||
319 | |||
320 | case 9: /* Restore bootloader */ | ||
321 | do_install(RESTORE); | ||
322 | break; | ||
323 | |||
324 | default: | ||
325 | break; | ||
326 | } | ||
327 | } while(1); | ||
328 | } | ||
329 | |||
123 | void main(void) | 330 | void main(void) |
124 | { | 331 | { |
332 | bool recovery_mode = false; | ||
333 | |||
334 | /* This hack is needed because when USB booting, we cannot initialize | ||
335 | * clocks in the SPL -- it may break the mask ROM's USB code. So if the | ||
336 | * SPL has not already initialized the clocks, we need to do that now. | ||
337 | * | ||
338 | * Also use this as a sign that we should enter the recovery menu since | ||
339 | * this is probably the expected result if the user is USB booting... | ||
340 | */ | ||
341 | if(jz_readf(CPM_MPCR, ENABLE)) { | ||
342 | spl_handle_pre_boot(0); | ||
343 | recovery_mode = true; | ||
344 | } | ||
345 | |||
125 | system_init(); | 346 | system_init(); |
347 | core_allocator_init(); | ||
126 | kernel_init(); | 348 | kernel_init(); |
127 | i2c_init(); | 349 | i2c_init(); |
128 | power_init(); | 350 | power_init(); |
@@ -136,32 +358,12 @@ void main(void) | |||
136 | 358 | ||
137 | filesystem_init(); | 359 | filesystem_init(); |
138 | 360 | ||
139 | int loadsize = 0; | 361 | if(button_read_device() & BUTTON_VOL_UP) |
140 | do { | 362 | recovery_mode = true; |
141 | if(!storage_present(0)) { | ||
142 | do_splash(HZ, "Insert SD card"); | ||
143 | continue; | ||
144 | } | ||
145 | |||
146 | if(disk_mount_all() <= 0) { | ||
147 | do_splash(5*HZ, "Cannot mount filesystem"); | ||
148 | do_usb(); | ||
149 | continue; | ||
150 | } | ||
151 | |||
152 | loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE); | ||
153 | if(loadsize <= 0) { | ||
154 | do_splash2(5*HZ, "Error loading Rockbox", | ||
155 | loader_strerror(loadsize)); | ||
156 | do_usb(); | ||
157 | continue; | ||
158 | } | ||
159 | } while(loadsize <= 0); | ||
160 | 363 | ||
161 | if(lcd_inited) | 364 | if(!recovery_mode) |
162 | backlight_hw_off(); | 365 | do_boot(); |
163 | 366 | ||
164 | disable_irq(); | 367 | /* If boot fails or user holds Vol+, go to recovery menu */ |
165 | 368 | recovery_menu(); | |
166 | exec(loadaddress, loadbuffer, loadsize); | ||
167 | } | 369 | } |