summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-07-11 02:32:05 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-07-11 15:39:50 +0100
commit84362141a0d1e33b29d12162caba7537dd5684b8 (patch)
treed966b33e6049cc54abe04d9b66ef0db794ebe948
parente9d228832ccbee7e486c45a51680c6f94ce1ab92 (diff)
downloadrockbox-84362141a0d1e33b29d12162caba7537dd5684b8.tar.gz
rockbox-84362141a0d1e33b29d12162caba7537dd5684b8.zip
x1000: Unified flash bootloader installer
Change-Id: Ib1d41d4e7d663ff8a21eb08108c13568f7408533
-rw-r--r--bootloader/x1000.c23
-rw-r--r--firmware/SOURCES6
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c253
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h51
-rw-r--r--firmware/target/mips/ingenic_x1000/installer-x1000.c326
-rw-r--r--firmware/target/mips/ingenic_x1000/installer-x1000.h55
6 files changed, 390 insertions, 324 deletions
diff --git a/bootloader/x1000.c b/bootloader/x1000.c
index 0b28b7449d..2c61773b11 100644
--- a/bootloader/x1000.c
+++ b/bootloader/x1000.c
@@ -48,16 +48,13 @@
48#include "loader_strerror.h" 48#include "loader_strerror.h"
49#include "version.h" 49#include "version.h"
50#include "boot-x1000.h" 50#include "boot-x1000.h"
51#include "installer-x1000.h"
51#include <stddef.h> 52#include <stddef.h>
52#include <stdbool.h> 53#include <stdbool.h>
53#include <string.h> 54#include <string.h>
54#include <stdio.h> 55#include <stdio.h>
55#include <stdarg.h> 56#include <stdarg.h>
56 57
57#ifdef FIIO_M3K
58# include "installer-fiiom3k.h"
59#endif
60
61#if defined(FIIO_M3K) 58#if defined(FIIO_M3K)
62# define BL_RECOVERY BUTTON_VOL_UP 59# define BL_RECOVERY BUTTON_VOL_UP
63# define BL_UP BUTTON_VOL_UP 60# define BL_UP BUTTON_VOL_UP
@@ -68,6 +65,7 @@
68# define BL_DOWN_NAME "VOL-" 65# define BL_DOWN_NAME "VOL-"
69# define BL_SELECT_NAME "PLAY" 66# define BL_SELECT_NAME "PLAY"
70# define BL_QUIT_NAME "POWER" 67# define BL_QUIT_NAME "POWER"
68# define BOOTBACKUP_FILE "/fiiom3k-boot.bin"
71#else 69#else
72# error "Missing keymap!" 70# error "Missing keymap!"
73#endif 71#endif
@@ -387,14 +385,12 @@ void reboot(void)
387 while(1); 385 while(1);
388} 386}
389 387
390/* TODO: clean this up, make the installer generic as well */
391enum { 388enum {
392 INSTALL, 389 INSTALL,
393 BACKUP, 390 BACKUP,
394 RESTORE, 391 RESTORE,
395}; 392};
396 393
397#ifdef FIIO_M3K
398void bootloader_action(int which) 394void bootloader_action(int which)
399{ 395{
400 if(init_disk() != 0) { 396 if(init_disk() != 0) {
@@ -414,14 +410,14 @@ void bootloader_action(int which)
414 410
415 int rc; 411 int rc;
416 switch(which) { 412 switch(which) {
417 case INSTALL: rc = install_boot("/bootloader.m3k"); break; 413 case INSTALL: rc = install_bootloader("/bootloader." BOOTFILE_EXT); break;
418 case BACKUP: rc = backup_boot("/fiiom3k-boot.bin"); break; 414 case BACKUP: rc = backup_bootloader(BOOTBACKUP_FILE); break;
419 case RESTORE: rc = restore_boot("/fiiom3k-boot.bin"); break; 415 case RESTORE: rc = restore_bootloader(BOOTBACKUP_FILE); break;
420 default: return; 416 default: return;
421 } 417 }
422 418
423 static char buf[64]; 419 static char buf[64];
424 snprintf(buf, sizeof(buf), "Failed! Error: %d", rc); 420 snprintf(buf, sizeof(buf), "%s (%d)", installer_strerror(rc), rc);
425 const char* msg1 = rc == 0 ? "Success" : buf; 421 const char* msg1 = rc == 0 ? "Success" : buf;
426 const char* msg2 = "Press " BL_QUIT_NAME " to continue"; 422 const char* msg2 = "Press " BL_QUIT_NAME " to continue";
427 splash2(0, msg1, msg2); 423 splash2(0, msg1, msg2);
@@ -429,13 +425,6 @@ void bootloader_action(int which)
429 button_clear_queue(); 425 button_clear_queue();
430 while(button_get(true) != BL_QUIT); 426 while(button_get(true) != BL_QUIT);
431} 427}
432#else
433void bootloader_action(int which)
434{
435 (void)which;
436 splash(5*HZ, "Not implemented!");
437}
438#endif
439 428
440void bootloader_install(void) 429void bootloader_install(void)
441{ 430{
diff --git a/firmware/SOURCES b/firmware/SOURCES
index b1024d97da..2414682bb4 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1676,9 +1676,12 @@ target/mips/ingenic_x1000/msc-x1000.c
1676#if (CONFIG_STORAGE & STORAGE_SD) 1676#if (CONFIG_STORAGE & STORAGE_SD)
1677target/mips/ingenic_x1000/sd-x1000.c 1677target/mips/ingenic_x1000/sd-x1000.c
1678#endif 1678#endif
1679#ifdef BOOTLOADER
1680target/mips/ingenic_x1000/installer-x1000.c
1679target/mips/ingenic_x1000/spl-start.S 1681target/mips/ingenic_x1000/spl-start.S
1680target/mips/ingenic_x1000/spl-x1000.c 1682target/mips/ingenic_x1000/spl-x1000.c
1681common/ucl_decompress.c 1683common/ucl_decompress.c
1684#endif
1682#endif /* CONFIG_CPU == X1000 */ 1685#endif /* CONFIG_CPU == X1000 */
1683 1686
1684#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) 1687#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
@@ -1711,9 +1714,6 @@ target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
1711target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c 1714target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
1712target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c 1715target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
1713target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c 1716target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
1714#ifdef BOOTLOADER
1715target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
1716#endif
1717#endif /* FIIO_M3K */ 1717#endif /* FIIO_M3K */
1718 1718
1719#if defined(LYRE_PROTO1) 1719#if defined(LYRE_PROTO1)
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
deleted file mode 100644
index 8ce73bf09e..0000000000
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
+++ /dev/null
@@ -1,253 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "installer-fiiom3k.h"
23#include "nand-x1000.h"
24#include "system.h"
25#include "core_alloc.h"
26#include "file.h"
27#include "microtar.h"
28#include <stdint.h>
29#include <string.h>
30#include <stdio.h>
31
32#define IMAGE_SIZE (128 * 1024)
33#define TAR_SIZE (256 * 1024)
34
35static int flash_img_read(uint8_t* buffer)
36{
37 nand_drv* drv = nand_init();
38 nand_lock(drv);
39
40 int rc = nand_open(drv);
41 if(rc < 0)
42 goto error;
43
44 rc = nand_read_bytes(drv, 0, IMAGE_SIZE, buffer);
45 if(rc < 0) {
46 rc = INSTALL_ERR_FLASH(NAND_READ, rc);
47 goto error;
48 }
49
50 error:
51 nand_close(drv);
52 nand_unlock(drv);
53 return rc;
54}
55
56static int flash_img_write(const uint8_t* buffer)
57{
58 nand_drv* drv = nand_init();
59 nand_lock(drv);
60
61 int rc = nand_open(drv);
62 if(rc < 0)
63 goto error;
64
65 rc = nand_write_bytes(drv, 0, IMAGE_SIZE, buffer);
66 if(rc < 0) {
67 rc = INSTALL_ERR_FLASH(NAND_WRITE, rc);
68 goto error;
69 }
70
71 error:
72 nand_close(drv);
73 nand_unlock(drv);
74 return rc;
75}
76
77static int patch_img(mtar_t* tar, uint8_t* buffer, const char* filename,
78 size_t patch_offset, size_t patch_size)
79{
80 /* Seek to file */
81 mtar_header_t h;
82 int rc = mtar_find(tar, filename, &h);
83 if(rc != MTAR_ESUCCESS) {
84 rc = INSTALL_ERR_MTAR(TAR_FIND, rc);
85 return rc;
86 }
87
88 /* We need a normal file */
89 if(h.type != 0 && h.type != MTAR_TREG)
90 return INSTALL_ERR_BAD_FORMAT;
91
92 /* Check size does not exceed patch area */
93 if(h.size > patch_size)
94 return INSTALL_ERR_BAD_FORMAT;
95
96 /* Read data directly into patch area, fill unused bytes with 0xff */
97 memset(&buffer[patch_offset], 0xff, patch_size);
98 rc = mtar_read_data(tar, &buffer[patch_offset], h.size);
99 if(rc != MTAR_ESUCCESS) {
100 rc = INSTALL_ERR_MTAR(TAR_READ, rc);
101 return rc;
102 }
103
104 return INSTALL_SUCCESS;
105}
106
107int install_boot(const char* srcfile)
108{
109 int rc;
110 mtar_t* tar = NULL;
111 int handle = -1;
112
113 /* Allocate enough memory for image and tar state */
114 size_t bufsize = IMAGE_SIZE + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
115 handle = core_alloc("boot_image", bufsize);
116 if(handle < 0) {
117 rc = INSTALL_ERR_OUT_OF_MEMORY;
118 goto error;
119 }
120
121 uint8_t* buffer = core_get_data(handle);
122
123 /* Tar state alloc */
124 CACHEALIGN_BUFFER(buffer, bufsize);
125 tar = (mtar_t*)buffer;
126 memset(tar, 0, sizeof(tar));
127
128 /* Image buffer alloc */
129 buffer += sizeof(mtar_t);
130 CACHEALIGN_BUFFER(buffer, bufsize);
131
132 /* Read the flash -- we need an existing image to patch */
133 rc = flash_img_read(buffer);
134 if(rc < 0)
135 goto error;
136
137 /* Open the tarball */
138 rc = mtar_open(tar, srcfile, "r");
139 if(rc != MTAR_ESUCCESS) {
140 rc = INSTALL_ERR_MTAR(TAR_OPEN, rc);
141 goto error;
142 }
143
144 /* Extract the needed files & patch 'em in */
145 rc = patch_img(tar, buffer, "spl.m3k", 0, 12 * 1024);
146 if(rc < 0)
147 goto error;
148
149 rc = patch_img(tar, buffer, "bootloader.ucl", 0x6800, 102 * 1024);
150 if(rc < 0)
151 goto error;
152
153 /* Flash the new image */
154 rc = flash_img_write(buffer);
155 if(rc < 0)
156 goto error;
157
158 rc = INSTALL_SUCCESS;
159
160 error:
161 if(tar && tar->close)
162 mtar_close(tar);
163 if(handle >= 0)
164 core_free(handle);
165 return rc;
166}
167
168int backup_boot(const char* destfile)
169{
170 int rc;
171 int handle = -1;
172 int fd = -1;
173 size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
174 handle = core_alloc("boot_image", bufsize);
175 if(handle < 0) {
176 rc = INSTALL_ERR_OUT_OF_MEMORY;
177 goto error;
178 }
179
180 uint8_t* buffer = core_get_data(handle);
181 CACHEALIGN_BUFFER(buffer, bufsize);
182
183 rc = flash_img_read(buffer);
184 if(rc < 0)
185 goto error;
186
187 fd = open(destfile, O_CREAT|O_TRUNC|O_WRONLY);
188 if(fd < 0) {
189 rc = INSTALL_ERR_FILE_IO;
190 goto error;
191 }
192
193 ssize_t cnt = write(fd, buffer, IMAGE_SIZE);
194 if(cnt != IMAGE_SIZE) {
195 rc = INSTALL_ERR_FILE_IO;
196 goto error;
197 }
198
199 error:
200 if(fd >= 0)
201 close(fd);
202 if(handle >= 0)
203 core_free(handle);
204 return rc;
205}
206
207int restore_boot(const char* srcfile)
208{
209 int rc;
210 int handle = -1;
211 int fd = -1;
212 size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
213 handle = core_alloc("boot_image", bufsize);
214 if(handle < 0) {
215 rc = INSTALL_ERR_OUT_OF_MEMORY;
216 goto error;
217 }
218
219 uint8_t* buffer = core_get_data(handle);
220 CACHEALIGN_BUFFER(buffer, bufsize);
221
222 fd = open(srcfile, O_RDONLY);
223 if(fd < 0) {
224 rc = INSTALL_ERR_FILE_NOT_FOUND;
225 goto error;
226 }
227
228 off_t fsize = filesize(fd);
229 if(fsize != IMAGE_SIZE) {
230 rc = INSTALL_ERR_BAD_FORMAT;
231 goto error;
232 }
233
234 ssize_t cnt = read(fd, buffer, IMAGE_SIZE);
235 if(cnt != IMAGE_SIZE) {
236 rc = INSTALL_ERR_FILE_IO;
237 goto error;
238 }
239
240 close(fd);
241 fd = -1;
242
243 rc = flash_img_write(buffer);
244 if(rc < 0)
245 goto error;
246
247 error:
248 if(fd >= 0)
249 close(fd);
250 if(handle >= 0)
251 core_free(handle);
252 return rc;
253}
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h
deleted file mode 100644
index eb700e6689..0000000000
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h
+++ /dev/null
@@ -1,51 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __INSTALLER_FIIOM3K_H__
23#define __INSTALLER_FIIOM3K_H__
24
25#include <stddef.h>
26
27#define INSTALL_SUCCESS 0
28#define INSTALL_ERR_OUT_OF_MEMORY (-1)
29#define INSTALL_ERR_FILE_NOT_FOUND (-2)
30#define INSTALL_ERR_FILE_IO (-3)
31#define INSTALL_ERR_BAD_FORMAT (-4)
32#define INSTALL_ERR_NAND_OPEN (-5)
33#define INSTALL_ERR_NAND_IDENTIFY (-6)
34#define INSTALL_ERR_NAND_READ (-7)
35#define INSTALL_ERR_NAND_ENABLE_WRITES (-8)
36#define INSTALL_ERR_NAND_ERASE (-9)
37#define INSTALL_ERR_NAND_WRITE (-10)
38#define INSTALL_ERR_TAR_OPEN (-11)
39#define INSTALL_ERR_TAR_FIND (-12)
40#define INSTALL_ERR_TAR_READ (-13)
41#define INSTALL_ERR_MTAR(x,y) ((INSTALL_ERR_##x)*100 + (y))
42#define INSTALL_ERR_FLASH(x,y) ((INSTALL_ERR_##x)*100 + (y))
43
44/* Install the Rockbox bootloader from a bootloader.m3k image */
45extern int install_boot(const char* srcfile);
46
47/* Backup or restore the bootloader from a raw NAND image */
48extern int backup_boot(const char* destfile);
49extern int restore_boot(const char* srcfile);
50
51#endif /* __INSTALLER_FIIOM3K_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.c b/firmware/target/mips/ingenic_x1000/installer-x1000.c
new file mode 100644
index 0000000000..617e6645b7
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/installer-x1000.c
@@ -0,0 +1,326 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "installer-x1000.h"
23#include "nand-x1000.h"
24#include "core_alloc.h"
25#include "file.h"
26#include "microtar.h"
27#include <stddef.h>
28
29struct update_part {
30 const char* filename;
31 size_t offset;
32 size_t length;
33};
34
35/* Parts of the flash to update. The offset and length are given in bytes,
36 * offset relative to start of flash. The region's new contents are given
37 * by the named file inside the update archive. If any file is missing, the
38 * update will fail. (gracefully! nothing is written unless the package has
39 * all its components)
40 *
41 * If the update file is smaller than the region size, unused space at the
42 * end of the region is padded with 0xff.
43 *
44 * NOTE: The current code assumes all parts are contiguous. The current
45 * update map fits in one eraseblock, but if it ever needs extending beyond
46 * that, better implement a bitmap to indicate which blocks need updating
47 * and which can be skipped. We don't want to erase and reprogram blocks
48 * for no good reason, it's bad for the flash lifespan.
49 */
50static const struct update_part updates[] = {
51 {
52 .filename = "spl." BOOTFILE_EXT,
53 .offset = 0,
54 .length = 12 * 1024,
55 },
56 {
57 .filename = "bootloader.ucl",
58 .offset = 0x6800,
59 .length = 102 * 1024,
60 },
61};
62
63static const int num_updates = sizeof(updates) / sizeof(struct update_part);
64
65/* calculate the offset and length of the update image; this is constant
66 * for a given target, based on the update parts and the NAND chip geometry.
67 */
68static void get_image_loc(nand_drv* ndrv, size_t* offptr, size_t* lenptr)
69{
70 size_t blk_size = ndrv->chip->page_size << ndrv->chip->log2_ppb;
71 size_t img_off = 0;
72 size_t img_len = 0;
73
74 /* calculate minimal image needed to contain all update blocks */
75 for(int i = 0; i < num_updates; ++i) {
76 img_len = MAX(img_len, updates[i].offset + updates[i].length);
77 img_off = MIN(img_off, updates[i].offset);
78 }
79
80 /* round everything to a multiple of the block size */
81 size_t r_off = blk_size * (img_off / blk_size);
82 size_t r_len = blk_size * ((img_len + img_off - r_off + blk_size - 1) / blk_size);
83
84 *offptr = r_off;
85 *lenptr = r_len;
86}
87
88/* Read in a single part of the update from the tarball, and patch it
89 * into the image */
90static int patch_part(mtar_t* tar, const struct update_part* part,
91 uint8_t* img_buf, size_t img_off)
92{
93 mtar_header_t h;
94 int rc = mtar_find(tar, part->filename, &h);
95 if(rc != MTAR_ESUCCESS)
96 return IERR_BAD_FORMAT;
97
98 if(h.type != 0 && h.type != MTAR_TREG)
99 return IERR_BAD_FORMAT;
100
101 if(h.size > part->length)
102 return IERR_BAD_FORMAT;
103
104 /* wipe the patched area, and read in the new data */
105 memset(&img_buf[part->offset - img_off], 0xff, part->length);
106 rc = mtar_read_data(tar, &img_buf[part->offset - img_off], h.size);
107 if(rc != MTAR_ESUCCESS)
108 return IERR_FILE_IO;
109
110 return IERR_SUCCESS;
111}
112
113struct updater {
114 int buf_hnd; /* core_alloc handle for our memory buffer */
115 size_t buf_len; /* sizeof the buffer */
116
117 uint8_t* img_buf;
118 size_t img_off; /* image address in flash */
119 size_t img_len; /* image length in flash = size of the buffer */
120
121 mtar_t* tar;
122 nand_drv* ndrv;
123};
124
125static int updater_init(struct updater* u)
126{
127 int rc;
128
129 /* initialize stuff correctly */
130 u->buf_hnd = -1;
131 u->buf_len = 0;
132 u->img_buf = NULL;
133 u->img_off = 0;
134 u->img_len = 0;
135 u->tar = NULL;
136 u->ndrv = NULL;
137
138 /* open NAND */
139 u->ndrv = nand_init();
140 nand_lock(u->ndrv);
141 rc = nand_open(u->ndrv);
142 if(rc != NAND_SUCCESS) {
143 rc = IERR_NAND_OPEN;
144 goto error;
145 }
146
147 get_image_loc(u->ndrv, &u->img_off, &u->img_len);
148
149 /* buf_len is a bit oversized here, but it's not really important */
150 u->buf_len = u->img_len + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
151 u->buf_hnd = core_alloc("boot_image", u->buf_len);
152 if(u->buf_hnd < 0) {
153 rc = IERR_OUT_OF_MEMORY;
154 goto error;
155 }
156
157 /* allocate from the buffer */
158 uint8_t* buffer = (uint8_t*)core_get_data(u->buf_hnd);
159 size_t buf_len = u->buf_len;
160
161 CACHEALIGN_BUFFER(buffer, buf_len);
162 u->img_buf = buffer;
163 buffer += u->img_len;
164 buf_len -= u->img_len;
165
166 CACHEALIGN_BUFFER(buffer, buf_len);
167 u->tar = (mtar_t*)buffer;
168 memset(u->tar, 0, sizeof(struct mtar_t));
169
170 rc = IERR_SUCCESS;
171
172 error:
173 return rc;
174}
175
176static void updater_cleanup(struct updater* u)
177{
178 if(u->tar && u->tar->close)
179 mtar_close(u->tar);
180
181 if(u->buf_hnd >= 0)
182 core_free(u->buf_hnd);
183
184 if(u->ndrv) {
185 nand_close(u->ndrv);
186 nand_unlock(u->ndrv);
187 }
188}
189
190int install_bootloader(const char* filename)
191{
192 struct updater u;
193 int rc = updater_init(&u);
194 if(rc != IERR_SUCCESS)
195 goto error;
196
197 /* get the image */
198 rc = nand_read_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
199 if(rc != NAND_SUCCESS) {
200 rc = IERR_NAND_READ;
201 goto error;
202 }
203
204 /* get the tarball */
205 rc = mtar_open(u.tar, filename, "r");
206 if(rc != MTAR_ESUCCESS) {
207 if(rc == MTAR_EOPENFAIL)
208 rc = IERR_FILE_NOT_FOUND;
209 else if(rc == MTAR_EREADFAIL)
210 rc = IERR_FILE_IO;
211 else
212 rc = IERR_BAD_FORMAT;
213 goto error;
214 }
215
216 /* patch stuff */
217 for(int i = 0; i < num_updates; ++i) {
218 rc = patch_part(u.tar, &updates[i], u.img_buf, u.img_off);
219 if(rc != IERR_SUCCESS)
220 goto error;
221 }
222
223 /* write back the patched image */
224 rc = nand_write_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
225 if(rc != NAND_SUCCESS) {
226 rc = IERR_NAND_WRITE;
227 goto error;
228 }
229
230 rc = IERR_SUCCESS;
231
232 error:
233 updater_cleanup(&u);
234 return rc;
235}
236
237int backup_bootloader(const char* filename)
238{
239 int rc, fd = 0;
240 struct updater u;
241
242 rc = updater_init(&u);
243 if(rc != IERR_SUCCESS)
244 goto error;
245
246 /* read image */
247 rc = nand_read_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
248 if(rc != NAND_SUCCESS) {
249 rc = IERR_NAND_READ;
250 goto error;
251 }
252
253 /* write to file */
254 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY);
255 if(fd < 0) {
256 rc = IERR_FILE_IO;
257 goto error;
258 }
259
260 ssize_t cnt = write(fd, u.img_buf, u.img_len);
261 if(cnt < 0 || (size_t)cnt != u.img_len) {
262 rc = IERR_FILE_IO;
263 goto error;
264 }
265
266 rc = IERR_SUCCESS;
267
268 error:
269 if(fd >= 0)
270 close(fd);
271 updater_cleanup(&u);
272 return rc;
273}
274
275int restore_bootloader(const char* filename)
276{
277 int rc, fd = 0;
278 struct updater u;
279
280 rc = updater_init(&u);
281 if(rc != IERR_SUCCESS)
282 goto error;
283
284 /* read from file */
285 fd = open(filename, O_RDONLY);
286 if(fd < 0) {
287 rc = IERR_FILE_NOT_FOUND;
288 goto error;
289 }
290
291 ssize_t cnt = read(fd, u.img_buf, u.img_len);
292 if(cnt < 0 || (size_t)cnt != u.img_len) {
293 rc = IERR_FILE_IO;
294 goto error;
295 }
296
297 /* write image */
298 rc = nand_write_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
299 if(rc != NAND_SUCCESS) {
300 rc = IERR_NAND_WRITE;
301 goto error;
302 }
303
304 rc = IERR_SUCCESS;
305
306 error:
307 if(fd >= 0)
308 close(fd);
309 updater_cleanup(&u);
310 return rc;
311}
312
313const char* installer_strerror(int rc)
314{
315 switch(rc) {
316 case IERR_SUCCESS: return "Success";
317 case IERR_OUT_OF_MEMORY: return "Out of memory";
318 case IERR_FILE_NOT_FOUND: return "File not found";
319 case IERR_FILE_IO: return "Disk I/O error";
320 case IERR_BAD_FORMAT: return "Bad archive";
321 case IERR_NAND_OPEN: return "NAND open error";
322 case IERR_NAND_READ: return "NAND read error";
323 case IERR_NAND_WRITE: return "NAND write error";
324 default: return "Unknown error!?";
325 }
326}
diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.h b/firmware/target/mips/ingenic_x1000/installer-x1000.h
new file mode 100644
index 0000000000..b71839a907
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/installer-x1000.h
@@ -0,0 +1,55 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __INSTALLER_X1000_H__
23#define __INSTALLER_X1000_H__
24
25/* This API is for the bootloader recovery menu and Rockbox utility to handle
26 * bootloader installation, backup, and restore.
27 *
28 * Currently the installer can only handle NAND flash, although the X1000 can
29 * boot from NOR flash or SD/MMC. Support for other storage media can be added
30 * when there is a target that needs it.
31 *
32 * Bootloader updates are tarballs, and they can "monkey patch" the flash in
33 * a customizable way (but fixed at compile time).
34 *
35 * Backup and restore simply takes the range of eraseblocks touched by the
36 * monkey patch and copies them to or from a regular file.
37 */
38
39enum {
40 IERR_SUCCESS = 0,
41 IERR_OUT_OF_MEMORY,
42 IERR_FILE_NOT_FOUND,
43 IERR_FILE_IO,
44 IERR_BAD_FORMAT,
45 IERR_NAND_OPEN,
46 IERR_NAND_READ,
47 IERR_NAND_WRITE,
48};
49
50extern int install_bootloader(const char* filename);
51extern int backup_bootloader(const char* filename);
52extern int restore_bootloader(const char* filename);
53extern const char* installer_strerror(int rc);
54
55#endif /* __INSTALLER_X1000_H__ */