mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
x1000-installer: Initial commit of new framework
This is a new flash installer framework for the X1000 targets. A bunch of this code is *UNTESTED* but there is an external test harness which allows the library to be built and tested on a PC. Once tests are written and the bugs are ironed out this framework will replace the existing installer code. New features: - Update tarballs are MD5-checksummed to guarantee integrity. - The flash map is no longer fixed -- updates are self describing and carry a map file which specifies the areas to update. - Can take full or partial backups with checksums computed on the fly. - Supports an additional verification mode which reads back data after writing to ensure the flash contents were not silently corrupted. Change-Id: I29a89190c7ff566019f6a844ad0571f01fb7192f
This commit is contained in:
parent
98f1271aec
commit
06423cab58
30 changed files with 2894 additions and 0 deletions
43
lib/x1000-installer/include/xf_error.h
Normal file
43
lib/x1000-installer/include/xf_error.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 _XF_ERROR_H_
|
||||
#define _XF_ERROR_H_
|
||||
|
||||
enum {
|
||||
XF_E_SUCCESS = 0,
|
||||
XF_E_IO = -1,
|
||||
XF_E_LINE_TOO_LONG = -2,
|
||||
XF_E_FILENAME_TOO_LONG = -3,
|
||||
XF_E_INT_OVERFLOW = -4,
|
||||
XF_E_BUF_OVERFLOW = -5,
|
||||
XF_E_SYNTAX_ERROR = -6,
|
||||
XF_E_INVALID_PARAMETER = -7,
|
||||
XF_E_NAND = -8,
|
||||
XF_E_OUT_OF_MEMORY = -9,
|
||||
XF_E_OUT_OF_RANGE = -10,
|
||||
XF_E_VERIFY_FAILED = -11,
|
||||
XF_E_CANNOT_OPEN_FILE = -12,
|
||||
};
|
||||
|
||||
const char* xf_strerror(int err);
|
||||
|
||||
#endif /* _XF_ERROR_H_ */
|
||||
91
lib/x1000-installer/include/xf_flashmap.h
Normal file
91
lib/x1000-installer/include/xf_flashmap.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 _XF_FLASHMAP_H_
|
||||
#define _XF_FLASHMAP_H_
|
||||
|
||||
#include "xf_stream.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define XF_MAP_NAMELEN 63
|
||||
|
||||
enum {
|
||||
XF_MAP_HAS_MD5 = 0x01, /* 'md5' field is valid */
|
||||
XF_MAP_HAS_FILE_LENGTH = 0x02, /* 'file_length' field is valid */
|
||||
};
|
||||
|
||||
struct xf_map {
|
||||
char name[XF_MAP_NAMELEN+1]; /* file name */
|
||||
uint8_t md5[16]; /* MD5 sum of file */
|
||||
uint32_t file_length; /* length of file in bytes */
|
||||
uint32_t offset; /* offset in flash */
|
||||
uint32_t length; /* region length in flash, in bytes */
|
||||
int flags;
|
||||
};
|
||||
|
||||
/* Parse a line with space- or tab-delimited fields of the form
|
||||
* <name> <md5> <file_length> <offset> <length>
|
||||
* <name> '-' <offset> <length>
|
||||
*
|
||||
* - name can be up to XF_FMAP_NAMELEN characters long
|
||||
* - md5 is 32 hexadecimal characters (case insensitive)
|
||||
* - file_length, offset, and length are 32-bit unsigned integers
|
||||
* and can be given in decimal or (with '0x' prefix) hexadecimal
|
||||
*
|
||||
* Parsed data is written to *map. Returns zero on success and
|
||||
* nonzero on error.
|
||||
*/
|
||||
int xf_map_parseline(const char* line, struct xf_map* map);
|
||||
|
||||
/* Parse a file calling xf_map_parseline() on each line to populate
|
||||
* a map of up to 'maxnum' regions. Blank and comment lines are
|
||||
* ignored (comments start with '#').
|
||||
*
|
||||
* Returns the number of regions in the resulting map if the file was
|
||||
* parsed successfully, or a negative value on error.
|
||||
*/
|
||||
int xf_map_parse(struct xf_stream* s, struct xf_map* map, int maxnum);
|
||||
|
||||
/* Sort the map so its members are in ascending order with the lowest
|
||||
* flash offset region first. After sorting, xf_map_validate() is used
|
||||
* to check for overlapping regions.
|
||||
*
|
||||
* The return value is that of xf_map_validate().
|
||||
*/
|
||||
int xf_map_sort(struct xf_map* map, int num);
|
||||
|
||||
/* Check if the input map is sorted and contains no overlap.
|
||||
*
|
||||
* Returns 0 if the map is sorted and contains no overlapping regions,
|
||||
* -1 if the map isn't sorted, or if an overlapping region is detected,
|
||||
* the index of the first overlapping region. (A returned index i is
|
||||
* always positive: the two overlapped entries are map[i] and map[i-1].)
|
||||
*/
|
||||
int xf_map_validate(const struct xf_map* map, int num);
|
||||
|
||||
/* Write the map to a stream. This does not check that the map is valid.
|
||||
* Returns the number of bytes written to the stream or a negative value
|
||||
* on error. The stream may be NULL, in which case the number of bytes
|
||||
* that would be written are returned (similar to snprintf).
|
||||
*/
|
||||
int xf_map_write(struct xf_map* map, int num, struct xf_stream* s);
|
||||
|
||||
#endif /* _XF_FLASHMAP_H_ */
|
||||
130
lib/x1000-installer/include/xf_nandio.h
Normal file
130
lib/x1000-installer/include/xf_nandio.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 _XF_NANDIO_H_
|
||||
#define _XF_NANDIO_H_
|
||||
|
||||
#include "nand-x1000.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum xf_nandio_mode {
|
||||
XF_NANDIO_READ = 0,
|
||||
XF_NANDIO_PROGRAM,
|
||||
XF_NANDIO_VERIFY,
|
||||
};
|
||||
|
||||
struct xf_nandio {
|
||||
nand_drv* ndrv;
|
||||
int nand_err; /* copy of the last NAND error code */
|
||||
int alloc_handle;
|
||||
enum xf_nandio_mode mode;
|
||||
|
||||
size_t block_size; /* size of a block, in bytes */
|
||||
size_t page_size; /* size of a page, in bytes */
|
||||
|
||||
uint8_t* old_buf; /* contains the 'old' block data already on chip */
|
||||
uint8_t* new_buf; /* contains the possibly modified 'new' block data */
|
||||
|
||||
nand_block_t cur_block; /* address of the current block */
|
||||
size_t offset_in_block; /* byte offset in the current block */
|
||||
unsigned block_valid: 1; /* 1 if buffered block data is valid */
|
||||
};
|
||||
|
||||
int xf_nandio_init(struct xf_nandio* nio);
|
||||
void xf_nandio_destroy(struct xf_nandio* nio);
|
||||
|
||||
/** Sets the operational mode, which determines read/write/flush semantics.
|
||||
*
|
||||
* - XF_NANDIO_READ: Accesses the chip in read-only mode. Writes are allowed,
|
||||
* but should not be used. (Writes will modify a temporary buffer but this
|
||||
* will not alter the flash contents.)
|
||||
*
|
||||
* - XF_NANDIO_PROGRAM: Writes are allowed to modify the flash contents.
|
||||
* Writes within a block are accumulated in a temporary buffer. When
|
||||
* crossing a block boundary, either by writing past the end the current
|
||||
* block or by seeking to a new one, the data written to the temporary
|
||||
* buffer is compared against the current flash contents. If the block
|
||||
* has been modified, it is erased and any non-blank pages are programmed
|
||||
* with the new data.
|
||||
*
|
||||
* - XF_NANDIO_VERIFY: This mode allows callers to easily check whether the
|
||||
* flash contents match some expected contents. Callers "write" the expected
|
||||
* contents as if programming it with XF_NANDIO_PROGRAM. When a block is
|
||||
* flushed, if the written data doesn't match the block contents, an
|
||||
* XF_E_VERIFY_FAILED error is returned. The flash contents will not be
|
||||
* altered in this mode.
|
||||
*
|
||||
* \returns XF_E_SUCCESS or a negative error code on failure.
|
||||
*/
|
||||
int xf_nandio_set_mode(struct xf_nandio* nio, enum xf_nandio_mode mode);
|
||||
|
||||
/** Seek to a given byte offset in the NAND flash.
|
||||
*
|
||||
* If the new offset is outside the current block, the current block will
|
||||
* be automatically flushed. Note this can result in verification or program
|
||||
* failures as with any other flush.
|
||||
*
|
||||
* \returns XF_E_SUCCESS or a negative error code on failure.
|
||||
*/
|
||||
int xf_nandio_seek(struct xf_nandio* nio, size_t offset);
|
||||
|
||||
/** Read or write a contiguous sequence of bytes from flash.
|
||||
*
|
||||
* The read or write starts at the current position and continues for `count`
|
||||
* bytes. Both reads and writes may cross block boundaries. Modified blocks
|
||||
* will be flushed automatically if the operation crosses a block boundary.
|
||||
*
|
||||
* After a successful read or write, the current position is advanced by
|
||||
* exactly `count` bytes. After a failure, the position is indeterminate.
|
||||
*
|
||||
* \returns XF_E_SUCCESS or a negative error code on failure.
|
||||
*/
|
||||
int xf_nandio_read(struct xf_nandio* nio, void* buf, size_t count);
|
||||
int xf_nandio_write(struct xf_nandio* nio, const void* buf, size_t count);
|
||||
|
||||
/** Get a pointer to the block buffer for direct read/write access.
|
||||
*
|
||||
* These functions can be used to read or write data without intermediate
|
||||
* buffers. The caller passes in the amount of data to be transferred in
|
||||
* `*count`. A pointer to part of the block buffer is returned in `*buf`
|
||||
* and the number of bytes available in `*buf` is returned in `*count`.
|
||||
*
|
||||
* Data at the current position can be read from the returned buffer and
|
||||
* it may be modified by writing to the buffer. The buffer is only valid
|
||||
* until the next call to an `xf_nandio` function.
|
||||
*
|
||||
* The read/write position is advanced by the returned `*count` on success,
|
||||
* and is unchanged on failure.
|
||||
*
|
||||
* \returns XF_E_SUCCESS or a negative error code on failure.
|
||||
*/
|
||||
int xf_nandio_get_buffer(struct xf_nandio* nio, void** buf, size_t* count);
|
||||
|
||||
/** Flush the buffered block to ensure all outstanding program or verification
|
||||
* operations have been performed. This should only be called to ensure the
|
||||
* final modified block is flushed after you have finished writing all data.
|
||||
*
|
||||
* \returns XF_E_SUCCESS or a negative error code on failure.
|
||||
*/
|
||||
int xf_nandio_flush(struct xf_nandio* nio);
|
||||
|
||||
#endif /* _XF_NANDIO_H_ */
|
||||
65
lib/x1000-installer/include/xf_package.h
Normal file
65
lib/x1000-installer/include/xf_package.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 _XF_PACKAGE_H_
|
||||
#define _XF_PACKAGE_H_
|
||||
|
||||
/* package format
|
||||
*
|
||||
* - bootloader-info.txt (contains a version label and optional metadata)
|
||||
* - flashmap.txt (describes the flash update map)
|
||||
* - [package must contain any other files referenced by the flash map]
|
||||
* - [other files may be present, but are ignored]
|
||||
*/
|
||||
|
||||
#include "xf_flashmap.h"
|
||||
#include "xf_stream.h"
|
||||
#include "microtar.h"
|
||||
|
||||
struct xf_package {
|
||||
int alloc_handle;
|
||||
mtar_t* tar;
|
||||
struct xf_map* map;
|
||||
int map_size;
|
||||
char* metadata;
|
||||
size_t metadata_len;
|
||||
};
|
||||
|
||||
/** Open an update package
|
||||
*
|
||||
* \param pkg Uninitialized package structure
|
||||
* \param file Name of the package file
|
||||
* \param dflt_map Default flash map for loading old format packages
|
||||
* \param dflt_map_size Size of the default flash map
|
||||
* \returns XF_E_SUCCESS or a negative error code
|
||||
*/
|
||||
int xf_package_open_ex(struct xf_package* pkg, const char* file,
|
||||
const struct xf_map* dflt_map, int dflt_map_size);
|
||||
|
||||
/** Close a package which was previously opened successfully */
|
||||
void xf_package_close(struct xf_package* pkg);
|
||||
|
||||
static inline int xf_package_open(struct xf_package* pkg, const char* file)
|
||||
{
|
||||
return xf_package_open_ex(pkg, file, NULL, 0);
|
||||
}
|
||||
|
||||
#endif /* _XF_PACKAGE_H_ */
|
||||
64
lib/x1000-installer/include/xf_stream.h
Normal file
64
lib/x1000-installer/include/xf_stream.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 _XF_STREAM_H_
|
||||
#define _XF_STREAM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h> /* ssize_t */
|
||||
#include "microtar.h"
|
||||
|
||||
struct xf_stream;
|
||||
|
||||
struct xf_stream_ops {
|
||||
off_t(*xget_size)(struct xf_stream* s);
|
||||
ssize_t(*xread)(struct xf_stream* s, void* buf, size_t len);
|
||||
ssize_t(*xwrite)(struct xf_stream* s, const void* buf, size_t len);
|
||||
int(*xclose)(struct xf_stream* s);
|
||||
};
|
||||
|
||||
struct xf_stream {
|
||||
intptr_t data;
|
||||
const struct xf_stream_ops* ops;
|
||||
};
|
||||
|
||||
inline size_t xf_stream_get_size(struct xf_stream* s)
|
||||
{ return s->ops->xget_size(s); }
|
||||
|
||||
inline ssize_t xf_stream_read(struct xf_stream* s, void* buf, size_t len)
|
||||
{ return s->ops->xread(s, buf, len); }
|
||||
|
||||
inline ssize_t xf_stream_write(struct xf_stream* s, const void* buf, size_t len)
|
||||
{ return s->ops->xwrite(s, buf, len); }
|
||||
|
||||
inline int xf_stream_close(struct xf_stream* s)
|
||||
{ return s->ops->xclose(s); }
|
||||
|
||||
int xf_open_file(const char* file, int flags, struct xf_stream* s);
|
||||
int xf_open_tar(mtar_t* mtar, const char* file, struct xf_stream* s);
|
||||
int xf_create_tar(mtar_t* mtar, const char* file, size_t size, struct xf_stream* s);
|
||||
|
||||
/* Utility function needed for a few things */
|
||||
int xf_stream_read_lines(struct xf_stream* s, char* buf, size_t bufsz,
|
||||
int(*callback)(int n, char* buf, void* arg), void* arg);
|
||||
|
||||
#endif /* _XF_STREAM_H_ */
|
||||
53
lib/x1000-installer/include/xf_update.h
Normal file
53
lib/x1000-installer/include/xf_update.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 _XF_UPDATE_H_
|
||||
#define _XF_UPDATE_H_
|
||||
|
||||
#include "xf_package.h"
|
||||
#include "xf_nandio.h"
|
||||
#include "xf_flashmap.h"
|
||||
|
||||
typedef int(*xf_update_open_stream_cb)(void* arg, const char* file,
|
||||
struct xf_stream* stream);
|
||||
|
||||
enum xf_update_mode {
|
||||
XF_UPDATE,
|
||||
XF_BACKUP,
|
||||
XF_VERIFY,
|
||||
};
|
||||
|
||||
/** The main updater entry point
|
||||
*
|
||||
* \param mode Operational mode
|
||||
* \param nio Initialized NAND I/O object.
|
||||
* \param map Flash map describing what regions to update.
|
||||
* \param map_size Number of entries in the map.
|
||||
* \param open_stream Callback used to open a stream for each map entry.
|
||||
* \param arg Argument passed to the `open_stream` callback.
|
||||
*
|
||||
* \returns XF_E_SUCCESS on success or a negative error code on failure.
|
||||
*/
|
||||
int xf_updater_run(enum xf_update_mode mode, struct xf_nandio* nio,
|
||||
struct xf_map* map, int map_size,
|
||||
xf_update_open_stream_cb open_stream, void* arg);
|
||||
|
||||
#endif /* _XF_UPDATE_H_ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue