x1000: Unified flash bootloader installer
Change-Id: Ib1d41d4e7d663ff8a21eb08108c13568f7408533
This commit is contained in:
parent
e9d228832c
commit
84362141a0
6 changed files with 390 additions and 324 deletions
|
@ -48,16 +48,13 @@
|
||||||
#include "loader_strerror.h"
|
#include "loader_strerror.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "boot-x1000.h"
|
#include "boot-x1000.h"
|
||||||
|
#include "installer-x1000.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#ifdef FIIO_M3K
|
|
||||||
# include "installer-fiiom3k.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(FIIO_M3K)
|
#if defined(FIIO_M3K)
|
||||||
# define BL_RECOVERY BUTTON_VOL_UP
|
# define BL_RECOVERY BUTTON_VOL_UP
|
||||||
# define BL_UP BUTTON_VOL_UP
|
# define BL_UP BUTTON_VOL_UP
|
||||||
|
@ -68,6 +65,7 @@
|
||||||
# define BL_DOWN_NAME "VOL-"
|
# define BL_DOWN_NAME "VOL-"
|
||||||
# define BL_SELECT_NAME "PLAY"
|
# define BL_SELECT_NAME "PLAY"
|
||||||
# define BL_QUIT_NAME "POWER"
|
# define BL_QUIT_NAME "POWER"
|
||||||
|
# define BOOTBACKUP_FILE "/fiiom3k-boot.bin"
|
||||||
#else
|
#else
|
||||||
# error "Missing keymap!"
|
# error "Missing keymap!"
|
||||||
#endif
|
#endif
|
||||||
|
@ -387,14 +385,12 @@ void reboot(void)
|
||||||
while(1);
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: clean this up, make the installer generic as well */
|
|
||||||
enum {
|
enum {
|
||||||
INSTALL,
|
INSTALL,
|
||||||
BACKUP,
|
BACKUP,
|
||||||
RESTORE,
|
RESTORE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef FIIO_M3K
|
|
||||||
void bootloader_action(int which)
|
void bootloader_action(int which)
|
||||||
{
|
{
|
||||||
if(init_disk() != 0) {
|
if(init_disk() != 0) {
|
||||||
|
@ -414,14 +410,14 @@ void bootloader_action(int which)
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
switch(which) {
|
switch(which) {
|
||||||
case INSTALL: rc = install_boot("/bootloader.m3k"); break;
|
case INSTALL: rc = install_bootloader("/bootloader." BOOTFILE_EXT); break;
|
||||||
case BACKUP: rc = backup_boot("/fiiom3k-boot.bin"); break;
|
case BACKUP: rc = backup_bootloader(BOOTBACKUP_FILE); break;
|
||||||
case RESTORE: rc = restore_boot("/fiiom3k-boot.bin"); break;
|
case RESTORE: rc = restore_bootloader(BOOTBACKUP_FILE); break;
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char buf[64];
|
static char buf[64];
|
||||||
snprintf(buf, sizeof(buf), "Failed! Error: %d", rc);
|
snprintf(buf, sizeof(buf), "%s (%d)", installer_strerror(rc), rc);
|
||||||
const char* msg1 = rc == 0 ? "Success" : buf;
|
const char* msg1 = rc == 0 ? "Success" : buf;
|
||||||
const char* msg2 = "Press " BL_QUIT_NAME " to continue";
|
const char* msg2 = "Press " BL_QUIT_NAME " to continue";
|
||||||
splash2(0, msg1, msg2);
|
splash2(0, msg1, msg2);
|
||||||
|
@ -429,13 +425,6 @@ void bootloader_action(int which)
|
||||||
button_clear_queue();
|
button_clear_queue();
|
||||||
while(button_get(true) != BL_QUIT);
|
while(button_get(true) != BL_QUIT);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void bootloader_action(int which)
|
|
||||||
{
|
|
||||||
(void)which;
|
|
||||||
splash(5*HZ, "Not implemented!");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void bootloader_install(void)
|
void bootloader_install(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1676,9 +1676,12 @@ target/mips/ingenic_x1000/msc-x1000.c
|
||||||
#if (CONFIG_STORAGE & STORAGE_SD)
|
#if (CONFIG_STORAGE & STORAGE_SD)
|
||||||
target/mips/ingenic_x1000/sd-x1000.c
|
target/mips/ingenic_x1000/sd-x1000.c
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef BOOTLOADER
|
||||||
|
target/mips/ingenic_x1000/installer-x1000.c
|
||||||
target/mips/ingenic_x1000/spl-start.S
|
target/mips/ingenic_x1000/spl-start.S
|
||||||
target/mips/ingenic_x1000/spl-x1000.c
|
target/mips/ingenic_x1000/spl-x1000.c
|
||||||
common/ucl_decompress.c
|
common/ucl_decompress.c
|
||||||
|
#endif
|
||||||
#endif /* CONFIG_CPU == X1000 */
|
#endif /* CONFIG_CPU == X1000 */
|
||||||
|
|
||||||
#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
|
#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
|
||||||
|
@ -1711,9 +1714,6 @@ target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
|
||||||
target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
|
target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
|
||||||
target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
|
target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
|
||||||
target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
|
target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
|
||||||
#ifdef BOOTLOADER
|
|
||||||
target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
|
|
||||||
#endif
|
|
||||||
#endif /* FIIO_M3K */
|
#endif /* FIIO_M3K */
|
||||||
|
|
||||||
#if defined(LYRE_PROTO1)
|
#if defined(LYRE_PROTO1)
|
||||||
|
|
|
@ -1,253 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* __________ __ ___.
|
|
||||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
||||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
||||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
||||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
||||||
* \/ \/ \/ \/ \/
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Aidan MacDonald
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
||||||
* KIND, either express or implied.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "installer-fiiom3k.h"
|
|
||||||
#include "nand-x1000.h"
|
|
||||||
#include "system.h"
|
|
||||||
#include "core_alloc.h"
|
|
||||||
#include "file.h"
|
|
||||||
#include "microtar.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define IMAGE_SIZE (128 * 1024)
|
|
||||||
#define TAR_SIZE (256 * 1024)
|
|
||||||
|
|
||||||
static int flash_img_read(uint8_t* buffer)
|
|
||||||
{
|
|
||||||
nand_drv* drv = nand_init();
|
|
||||||
nand_lock(drv);
|
|
||||||
|
|
||||||
int rc = nand_open(drv);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
rc = nand_read_bytes(drv, 0, IMAGE_SIZE, buffer);
|
|
||||||
if(rc < 0) {
|
|
||||||
rc = INSTALL_ERR_FLASH(NAND_READ, rc);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
nand_close(drv);
|
|
||||||
nand_unlock(drv);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int flash_img_write(const uint8_t* buffer)
|
|
||||||
{
|
|
||||||
nand_drv* drv = nand_init();
|
|
||||||
nand_lock(drv);
|
|
||||||
|
|
||||||
int rc = nand_open(drv);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
rc = nand_write_bytes(drv, 0, IMAGE_SIZE, buffer);
|
|
||||||
if(rc < 0) {
|
|
||||||
rc = INSTALL_ERR_FLASH(NAND_WRITE, rc);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
nand_close(drv);
|
|
||||||
nand_unlock(drv);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int patch_img(mtar_t* tar, uint8_t* buffer, const char* filename,
|
|
||||||
size_t patch_offset, size_t patch_size)
|
|
||||||
{
|
|
||||||
/* Seek to file */
|
|
||||||
mtar_header_t h;
|
|
||||||
int rc = mtar_find(tar, filename, &h);
|
|
||||||
if(rc != MTAR_ESUCCESS) {
|
|
||||||
rc = INSTALL_ERR_MTAR(TAR_FIND, rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We need a normal file */
|
|
||||||
if(h.type != 0 && h.type != MTAR_TREG)
|
|
||||||
return INSTALL_ERR_BAD_FORMAT;
|
|
||||||
|
|
||||||
/* Check size does not exceed patch area */
|
|
||||||
if(h.size > patch_size)
|
|
||||||
return INSTALL_ERR_BAD_FORMAT;
|
|
||||||
|
|
||||||
/* Read data directly into patch area, fill unused bytes with 0xff */
|
|
||||||
memset(&buffer[patch_offset], 0xff, patch_size);
|
|
||||||
rc = mtar_read_data(tar, &buffer[patch_offset], h.size);
|
|
||||||
if(rc != MTAR_ESUCCESS) {
|
|
||||||
rc = INSTALL_ERR_MTAR(TAR_READ, rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return INSTALL_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int install_boot(const char* srcfile)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
mtar_t* tar = NULL;
|
|
||||||
int handle = -1;
|
|
||||||
|
|
||||||
/* Allocate enough memory for image and tar state */
|
|
||||||
size_t bufsize = IMAGE_SIZE + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
|
|
||||||
handle = core_alloc("boot_image", bufsize);
|
|
||||||
if(handle < 0) {
|
|
||||||
rc = INSTALL_ERR_OUT_OF_MEMORY;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* buffer = core_get_data(handle);
|
|
||||||
|
|
||||||
/* Tar state alloc */
|
|
||||||
CACHEALIGN_BUFFER(buffer, bufsize);
|
|
||||||
tar = (mtar_t*)buffer;
|
|
||||||
memset(tar, 0, sizeof(tar));
|
|
||||||
|
|
||||||
/* Image buffer alloc */
|
|
||||||
buffer += sizeof(mtar_t);
|
|
||||||
CACHEALIGN_BUFFER(buffer, bufsize);
|
|
||||||
|
|
||||||
/* Read the flash -- we need an existing image to patch */
|
|
||||||
rc = flash_img_read(buffer);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Open the tarball */
|
|
||||||
rc = mtar_open(tar, srcfile, "r");
|
|
||||||
if(rc != MTAR_ESUCCESS) {
|
|
||||||
rc = INSTALL_ERR_MTAR(TAR_OPEN, rc);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract the needed files & patch 'em in */
|
|
||||||
rc = patch_img(tar, buffer, "spl.m3k", 0, 12 * 1024);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
rc = patch_img(tar, buffer, "bootloader.ucl", 0x6800, 102 * 1024);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Flash the new image */
|
|
||||||
rc = flash_img_write(buffer);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
rc = INSTALL_SUCCESS;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if(tar && tar->close)
|
|
||||||
mtar_close(tar);
|
|
||||||
if(handle >= 0)
|
|
||||||
core_free(handle);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int backup_boot(const char* destfile)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
int handle = -1;
|
|
||||||
int fd = -1;
|
|
||||||
size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
|
|
||||||
handle = core_alloc("boot_image", bufsize);
|
|
||||||
if(handle < 0) {
|
|
||||||
rc = INSTALL_ERR_OUT_OF_MEMORY;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* buffer = core_get_data(handle);
|
|
||||||
CACHEALIGN_BUFFER(buffer, bufsize);
|
|
||||||
|
|
||||||
rc = flash_img_read(buffer);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
fd = open(destfile, O_CREAT|O_TRUNC|O_WRONLY);
|
|
||||||
if(fd < 0) {
|
|
||||||
rc = INSTALL_ERR_FILE_IO;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t cnt = write(fd, buffer, IMAGE_SIZE);
|
|
||||||
if(cnt != IMAGE_SIZE) {
|
|
||||||
rc = INSTALL_ERR_FILE_IO;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
if(fd >= 0)
|
|
||||||
close(fd);
|
|
||||||
if(handle >= 0)
|
|
||||||
core_free(handle);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int restore_boot(const char* srcfile)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
int handle = -1;
|
|
||||||
int fd = -1;
|
|
||||||
size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
|
|
||||||
handle = core_alloc("boot_image", bufsize);
|
|
||||||
if(handle < 0) {
|
|
||||||
rc = INSTALL_ERR_OUT_OF_MEMORY;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* buffer = core_get_data(handle);
|
|
||||||
CACHEALIGN_BUFFER(buffer, bufsize);
|
|
||||||
|
|
||||||
fd = open(srcfile, O_RDONLY);
|
|
||||||
if(fd < 0) {
|
|
||||||
rc = INSTALL_ERR_FILE_NOT_FOUND;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t fsize = filesize(fd);
|
|
||||||
if(fsize != IMAGE_SIZE) {
|
|
||||||
rc = INSTALL_ERR_BAD_FORMAT;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t cnt = read(fd, buffer, IMAGE_SIZE);
|
|
||||||
if(cnt != IMAGE_SIZE) {
|
|
||||||
rc = INSTALL_ERR_FILE_IO;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
|
|
||||||
rc = flash_img_write(buffer);
|
|
||||||
if(rc < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if(fd >= 0)
|
|
||||||
close(fd);
|
|
||||||
if(handle >= 0)
|
|
||||||
core_free(handle);
|
|
||||||
return rc;
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* __________ __ ___.
|
|
||||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
||||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
||||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
||||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
||||||
* \/ \/ \/ \/ \/
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Aidan MacDonald
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
||||||
* KIND, either express or implied.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef __INSTALLER_FIIOM3K_H__
|
|
||||||
#define __INSTALLER_FIIOM3K_H__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define INSTALL_SUCCESS 0
|
|
||||||
#define INSTALL_ERR_OUT_OF_MEMORY (-1)
|
|
||||||
#define INSTALL_ERR_FILE_NOT_FOUND (-2)
|
|
||||||
#define INSTALL_ERR_FILE_IO (-3)
|
|
||||||
#define INSTALL_ERR_BAD_FORMAT (-4)
|
|
||||||
#define INSTALL_ERR_NAND_OPEN (-5)
|
|
||||||
#define INSTALL_ERR_NAND_IDENTIFY (-6)
|
|
||||||
#define INSTALL_ERR_NAND_READ (-7)
|
|
||||||
#define INSTALL_ERR_NAND_ENABLE_WRITES (-8)
|
|
||||||
#define INSTALL_ERR_NAND_ERASE (-9)
|
|
||||||
#define INSTALL_ERR_NAND_WRITE (-10)
|
|
||||||
#define INSTALL_ERR_TAR_OPEN (-11)
|
|
||||||
#define INSTALL_ERR_TAR_FIND (-12)
|
|
||||||
#define INSTALL_ERR_TAR_READ (-13)
|
|
||||||
#define INSTALL_ERR_MTAR(x,y) ((INSTALL_ERR_##x)*100 + (y))
|
|
||||||
#define INSTALL_ERR_FLASH(x,y) ((INSTALL_ERR_##x)*100 + (y))
|
|
||||||
|
|
||||||
/* Install the Rockbox bootloader from a bootloader.m3k image */
|
|
||||||
extern int install_boot(const char* srcfile);
|
|
||||||
|
|
||||||
/* Backup or restore the bootloader from a raw NAND image */
|
|
||||||
extern int backup_boot(const char* destfile);
|
|
||||||
extern int restore_boot(const char* srcfile);
|
|
||||||
|
|
||||||
#endif /* __INSTALLER_FIIOM3K_H__ */
|
|
326
firmware/target/mips/ingenic_x1000/installer-x1000.c
Normal file
326
firmware/target/mips/ingenic_x1000/installer-x1000.c
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Aidan MacDonald
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "installer-x1000.h"
|
||||||
|
#include "nand-x1000.h"
|
||||||
|
#include "core_alloc.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "microtar.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct update_part {
|
||||||
|
const char* filename;
|
||||||
|
size_t offset;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Parts of the flash to update. The offset and length are given in bytes,
|
||||||
|
* offset relative to start of flash. The region's new contents are given
|
||||||
|
* by the named file inside the update archive. If any file is missing, the
|
||||||
|
* update will fail. (gracefully! nothing is written unless the package has
|
||||||
|
* all its components)
|
||||||
|
*
|
||||||
|
* If the update file is smaller than the region size, unused space at the
|
||||||
|
* end of the region is padded with 0xff.
|
||||||
|
*
|
||||||
|
* NOTE: The current code assumes all parts are contiguous. The current
|
||||||
|
* update map fits in one eraseblock, but if it ever needs extending beyond
|
||||||
|
* that, better implement a bitmap to indicate which blocks need updating
|
||||||
|
* and which can be skipped. We don't want to erase and reprogram blocks
|
||||||
|
* for no good reason, it's bad for the flash lifespan.
|
||||||
|
*/
|
||||||
|
static const struct update_part updates[] = {
|
||||||
|
{
|
||||||
|
.filename = "spl." BOOTFILE_EXT,
|
||||||
|
.offset = 0,
|
||||||
|
.length = 12 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.filename = "bootloader.ucl",
|
||||||
|
.offset = 0x6800,
|
||||||
|
.length = 102 * 1024,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int num_updates = sizeof(updates) / sizeof(struct update_part);
|
||||||
|
|
||||||
|
/* calculate the offset and length of the update image; this is constant
|
||||||
|
* for a given target, based on the update parts and the NAND chip geometry.
|
||||||
|
*/
|
||||||
|
static void get_image_loc(nand_drv* ndrv, size_t* offptr, size_t* lenptr)
|
||||||
|
{
|
||||||
|
size_t blk_size = ndrv->chip->page_size << ndrv->chip->log2_ppb;
|
||||||
|
size_t img_off = 0;
|
||||||
|
size_t img_len = 0;
|
||||||
|
|
||||||
|
/* calculate minimal image needed to contain all update blocks */
|
||||||
|
for(int i = 0; i < num_updates; ++i) {
|
||||||
|
img_len = MAX(img_len, updates[i].offset + updates[i].length);
|
||||||
|
img_off = MIN(img_off, updates[i].offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* round everything to a multiple of the block size */
|
||||||
|
size_t r_off = blk_size * (img_off / blk_size);
|
||||||
|
size_t r_len = blk_size * ((img_len + img_off - r_off + blk_size - 1) / blk_size);
|
||||||
|
|
||||||
|
*offptr = r_off;
|
||||||
|
*lenptr = r_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in a single part of the update from the tarball, and patch it
|
||||||
|
* into the image */
|
||||||
|
static int patch_part(mtar_t* tar, const struct update_part* part,
|
||||||
|
uint8_t* img_buf, size_t img_off)
|
||||||
|
{
|
||||||
|
mtar_header_t h;
|
||||||
|
int rc = mtar_find(tar, part->filename, &h);
|
||||||
|
if(rc != MTAR_ESUCCESS)
|
||||||
|
return IERR_BAD_FORMAT;
|
||||||
|
|
||||||
|
if(h.type != 0 && h.type != MTAR_TREG)
|
||||||
|
return IERR_BAD_FORMAT;
|
||||||
|
|
||||||
|
if(h.size > part->length)
|
||||||
|
return IERR_BAD_FORMAT;
|
||||||
|
|
||||||
|
/* wipe the patched area, and read in the new data */
|
||||||
|
memset(&img_buf[part->offset - img_off], 0xff, part->length);
|
||||||
|
rc = mtar_read_data(tar, &img_buf[part->offset - img_off], h.size);
|
||||||
|
if(rc != MTAR_ESUCCESS)
|
||||||
|
return IERR_FILE_IO;
|
||||||
|
|
||||||
|
return IERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct updater {
|
||||||
|
int buf_hnd; /* core_alloc handle for our memory buffer */
|
||||||
|
size_t buf_len; /* sizeof the buffer */
|
||||||
|
|
||||||
|
uint8_t* img_buf;
|
||||||
|
size_t img_off; /* image address in flash */
|
||||||
|
size_t img_len; /* image length in flash = size of the buffer */
|
||||||
|
|
||||||
|
mtar_t* tar;
|
||||||
|
nand_drv* ndrv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int updater_init(struct updater* u)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* initialize stuff correctly */
|
||||||
|
u->buf_hnd = -1;
|
||||||
|
u->buf_len = 0;
|
||||||
|
u->img_buf = NULL;
|
||||||
|
u->img_off = 0;
|
||||||
|
u->img_len = 0;
|
||||||
|
u->tar = NULL;
|
||||||
|
u->ndrv = NULL;
|
||||||
|
|
||||||
|
/* open NAND */
|
||||||
|
u->ndrv = nand_init();
|
||||||
|
nand_lock(u->ndrv);
|
||||||
|
rc = nand_open(u->ndrv);
|
||||||
|
if(rc != NAND_SUCCESS) {
|
||||||
|
rc = IERR_NAND_OPEN;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_image_loc(u->ndrv, &u->img_off, &u->img_len);
|
||||||
|
|
||||||
|
/* buf_len is a bit oversized here, but it's not really important */
|
||||||
|
u->buf_len = u->img_len + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
|
||||||
|
u->buf_hnd = core_alloc("boot_image", u->buf_len);
|
||||||
|
if(u->buf_hnd < 0) {
|
||||||
|
rc = IERR_OUT_OF_MEMORY;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate from the buffer */
|
||||||
|
uint8_t* buffer = (uint8_t*)core_get_data(u->buf_hnd);
|
||||||
|
size_t buf_len = u->buf_len;
|
||||||
|
|
||||||
|
CACHEALIGN_BUFFER(buffer, buf_len);
|
||||||
|
u->img_buf = buffer;
|
||||||
|
buffer += u->img_len;
|
||||||
|
buf_len -= u->img_len;
|
||||||
|
|
||||||
|
CACHEALIGN_BUFFER(buffer, buf_len);
|
||||||
|
u->tar = (mtar_t*)buffer;
|
||||||
|
memset(u->tar, 0, sizeof(struct mtar_t));
|
||||||
|
|
||||||
|
rc = IERR_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updater_cleanup(struct updater* u)
|
||||||
|
{
|
||||||
|
if(u->tar && u->tar->close)
|
||||||
|
mtar_close(u->tar);
|
||||||
|
|
||||||
|
if(u->buf_hnd >= 0)
|
||||||
|
core_free(u->buf_hnd);
|
||||||
|
|
||||||
|
if(u->ndrv) {
|
||||||
|
nand_close(u->ndrv);
|
||||||
|
nand_unlock(u->ndrv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int install_bootloader(const char* filename)
|
||||||
|
{
|
||||||
|
struct updater u;
|
||||||
|
int rc = updater_init(&u);
|
||||||
|
if(rc != IERR_SUCCESS)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* get the image */
|
||||||
|
rc = nand_read_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
|
||||||
|
if(rc != NAND_SUCCESS) {
|
||||||
|
rc = IERR_NAND_READ;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the tarball */
|
||||||
|
rc = mtar_open(u.tar, filename, "r");
|
||||||
|
if(rc != MTAR_ESUCCESS) {
|
||||||
|
if(rc == MTAR_EOPENFAIL)
|
||||||
|
rc = IERR_FILE_NOT_FOUND;
|
||||||
|
else if(rc == MTAR_EREADFAIL)
|
||||||
|
rc = IERR_FILE_IO;
|
||||||
|
else
|
||||||
|
rc = IERR_BAD_FORMAT;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* patch stuff */
|
||||||
|
for(int i = 0; i < num_updates; ++i) {
|
||||||
|
rc = patch_part(u.tar, &updates[i], u.img_buf, u.img_off);
|
||||||
|
if(rc != IERR_SUCCESS)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write back the patched image */
|
||||||
|
rc = nand_write_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
|
||||||
|
if(rc != NAND_SUCCESS) {
|
||||||
|
rc = IERR_NAND_WRITE;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = IERR_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
updater_cleanup(&u);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int backup_bootloader(const char* filename)
|
||||||
|
{
|
||||||
|
int rc, fd = 0;
|
||||||
|
struct updater u;
|
||||||
|
|
||||||
|
rc = updater_init(&u);
|
||||||
|
if(rc != IERR_SUCCESS)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* read image */
|
||||||
|
rc = nand_read_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
|
||||||
|
if(rc != NAND_SUCCESS) {
|
||||||
|
rc = IERR_NAND_READ;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write to file */
|
||||||
|
fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY);
|
||||||
|
if(fd < 0) {
|
||||||
|
rc = IERR_FILE_IO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t cnt = write(fd, u.img_buf, u.img_len);
|
||||||
|
if(cnt < 0 || (size_t)cnt != u.img_len) {
|
||||||
|
rc = IERR_FILE_IO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = IERR_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if(fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
updater_cleanup(&u);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_bootloader(const char* filename)
|
||||||
|
{
|
||||||
|
int rc, fd = 0;
|
||||||
|
struct updater u;
|
||||||
|
|
||||||
|
rc = updater_init(&u);
|
||||||
|
if(rc != IERR_SUCCESS)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* read from file */
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
if(fd < 0) {
|
||||||
|
rc = IERR_FILE_NOT_FOUND;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t cnt = read(fd, u.img_buf, u.img_len);
|
||||||
|
if(cnt < 0 || (size_t)cnt != u.img_len) {
|
||||||
|
rc = IERR_FILE_IO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write image */
|
||||||
|
rc = nand_write_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf);
|
||||||
|
if(rc != NAND_SUCCESS) {
|
||||||
|
rc = IERR_NAND_WRITE;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = IERR_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if(fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
updater_cleanup(&u);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* installer_strerror(int rc)
|
||||||
|
{
|
||||||
|
switch(rc) {
|
||||||
|
case IERR_SUCCESS: return "Success";
|
||||||
|
case IERR_OUT_OF_MEMORY: return "Out of memory";
|
||||||
|
case IERR_FILE_NOT_FOUND: return "File not found";
|
||||||
|
case IERR_FILE_IO: return "Disk I/O error";
|
||||||
|
case IERR_BAD_FORMAT: return "Bad archive";
|
||||||
|
case IERR_NAND_OPEN: return "NAND open error";
|
||||||
|
case IERR_NAND_READ: return "NAND read error";
|
||||||
|
case IERR_NAND_WRITE: return "NAND write error";
|
||||||
|
default: return "Unknown error!?";
|
||||||
|
}
|
||||||
|
}
|
55
firmware/target/mips/ingenic_x1000/installer-x1000.h
Normal file
55
firmware/target/mips/ingenic_x1000/installer-x1000.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Aidan MacDonald
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __INSTALLER_X1000_H__
|
||||||
|
#define __INSTALLER_X1000_H__
|
||||||
|
|
||||||
|
/* This API is for the bootloader recovery menu and Rockbox utility to handle
|
||||||
|
* bootloader installation, backup, and restore.
|
||||||
|
*
|
||||||
|
* Currently the installer can only handle NAND flash, although the X1000 can
|
||||||
|
* boot from NOR flash or SD/MMC. Support for other storage media can be added
|
||||||
|
* when there is a target that needs it.
|
||||||
|
*
|
||||||
|
* Bootloader updates are tarballs, and they can "monkey patch" the flash in
|
||||||
|
* a customizable way (but fixed at compile time).
|
||||||
|
*
|
||||||
|
* Backup and restore simply takes the range of eraseblocks touched by the
|
||||||
|
* monkey patch and copies them to or from a regular file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IERR_SUCCESS = 0,
|
||||||
|
IERR_OUT_OF_MEMORY,
|
||||||
|
IERR_FILE_NOT_FOUND,
|
||||||
|
IERR_FILE_IO,
|
||||||
|
IERR_BAD_FORMAT,
|
||||||
|
IERR_NAND_OPEN,
|
||||||
|
IERR_NAND_READ,
|
||||||
|
IERR_NAND_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int install_bootloader(const char* filename);
|
||||||
|
extern int backup_bootloader(const char* filename);
|
||||||
|
extern int restore_bootloader(const char* filename);
|
||||||
|
extern const char* installer_strerror(int rc);
|
||||||
|
|
||||||
|
#endif /* __INSTALLER_X1000_H__ */
|
Loading…
Reference in a new issue