mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 20:55:17 -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
65
lib/x1000-installer/test_lib/core_alloc.c
Normal file
65
lib/x1000-installer/test_lib/core_alloc.c
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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "core_alloc.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N_POINTERS 100
|
||||
|
||||
static void* pointers[N_POINTERS];
|
||||
|
||||
int core_alloc(const char* name, size_t size)
|
||||
{
|
||||
(void)name;
|
||||
|
||||
void* mem = malloc(size);
|
||||
if(!mem)
|
||||
return -1;
|
||||
|
||||
for(int i = 0; i < N_POINTERS; ++i) {
|
||||
if(pointers[i])
|
||||
continue;
|
||||
|
||||
pointers[i] = mem;
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
free(mem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int core_free(int handle)
|
||||
{
|
||||
if(handle > 0) {
|
||||
free(pointers[handle-1]);
|
||||
pointers[handle-1] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* core_get_data(int handle)
|
||||
{
|
||||
if(handle > 0)
|
||||
return pointers[handle-1];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
33
lib/x1000-installer/test_lib/core_alloc.h
Normal file
33
lib/x1000-installer/test_lib/core_alloc.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* fake core_alloc implementation for testing */
|
||||
|
||||
#ifndef CORE_ALLOC_H
|
||||
#define CORE_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int core_alloc(const char* name, size_t size);
|
||||
int core_free(int handle);
|
||||
void* core_get_data(int handle);
|
||||
|
||||
#endif
|
||||
270
lib/x1000-installer/test_lib/fakenand.c
Normal file
270
lib/x1000-installer/test_lib/fakenand.c
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 "nand-x1000.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char* nand_backing_file = "fakeNAND.bin";
|
||||
const char* nand_meta_file = "fakeNAND_meta.bin";
|
||||
|
||||
struct nand_trace* nand_trace = NULL;
|
||||
size_t nand_trace_capacity = 0;
|
||||
size_t nand_trace_length = 0;
|
||||
|
||||
static struct nand_trace* nand_trace_cur = NULL;
|
||||
|
||||
static int injected_err = 0;
|
||||
|
||||
#define METAF_PROGRAMMED 1
|
||||
|
||||
static const nand_chip fake_chip = {
|
||||
/* ATO25D1GA */
|
||||
.log2_ppb = 6, /* 64 pages */
|
||||
.page_size = 2048,
|
||||
.oob_size = 64,
|
||||
.nr_blocks = 1024,
|
||||
};
|
||||
|
||||
void nand_trace_reset(size_t size)
|
||||
{
|
||||
nand_trace = realloc(nand_trace, size);
|
||||
nand_trace_capacity = size;
|
||||
nand_trace_length = 0;
|
||||
nand_trace_cur = nand_trace;
|
||||
}
|
||||
|
||||
void nand_inject_error(int rc)
|
||||
{
|
||||
injected_err = rc;
|
||||
}
|
||||
|
||||
nand_drv* nand_init(void)
|
||||
{
|
||||
static bool inited = false;
|
||||
static uint8_t scratch_buf[NAND_DRV_SCRATCHSIZE];
|
||||
static uint8_t page_buf[NAND_DRV_MAXPAGESIZE];
|
||||
static nand_drv d;
|
||||
|
||||
if(!inited) {
|
||||
d.scratch_buf = scratch_buf;
|
||||
d.page_buf = page_buf;
|
||||
d.chip = &fake_chip;
|
||||
inited = true;
|
||||
}
|
||||
|
||||
return &d;
|
||||
}
|
||||
|
||||
static void lock_assert(bool cond, const char* msg)
|
||||
{
|
||||
if(!cond) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void nand_lock(nand_drv* drv)
|
||||
{
|
||||
drv->lock_count++;
|
||||
}
|
||||
|
||||
void nand_unlock(nand_drv* drv)
|
||||
{
|
||||
lock_assert(drv->lock_count > 0, "nand_unlock() called when not locked");
|
||||
drv->lock_count--;
|
||||
}
|
||||
|
||||
#define CHECK_INJECTED_ERROR \
|
||||
do { int __err = injected_err; injected_err = 0; if(__err) return __err; } while(0)
|
||||
|
||||
int nand_open(nand_drv* drv)
|
||||
{
|
||||
lock_assert(drv->lock_count > 0, "nand_open(): lock not held");
|
||||
CHECK_INJECTED_ERROR;
|
||||
|
||||
if(drv->refcount > 0) {
|
||||
drv->refcount++;
|
||||
return NAND_SUCCESS;
|
||||
}
|
||||
|
||||
/* leaks an fd on error but this is only testing... */
|
||||
drv->fd = open(nand_backing_file, O_RDWR|O_CREAT, 0644);
|
||||
drv->metafd = open(nand_meta_file, O_RDWR|O_CREAT, 0644);
|
||||
if(drv->fd < 0 || drv->metafd < 0)
|
||||
goto err;
|
||||
|
||||
drv->ppb = 1 << drv->chip->log2_ppb;
|
||||
drv->fpage_size = drv->chip->page_size + drv->chip->oob_size;
|
||||
|
||||
/* make backing file the correct size */
|
||||
if(ftruncate(drv->fd, drv->chip->page_size * drv->ppb * drv->chip->nr_blocks) < 0)
|
||||
goto err;
|
||||
if(ftruncate(drv->metafd, drv->chip->nr_blocks * drv->ppb) < 0)
|
||||
goto err;
|
||||
|
||||
drv->refcount++;
|
||||
return NAND_SUCCESS;
|
||||
|
||||
err:
|
||||
if(drv->fd >= 0)
|
||||
close(drv->fd);
|
||||
if(drv->metafd >= 0)
|
||||
close(drv->metafd);
|
||||
return NAND_ERR_OTHER;
|
||||
}
|
||||
|
||||
void nand_close(nand_drv* drv)
|
||||
{
|
||||
lock_assert(drv->lock_count > 0, "nand_close(): lock not held");
|
||||
|
||||
if(--drv->refcount > 0)
|
||||
return;
|
||||
|
||||
close(drv->fd);
|
||||
close(drv->metafd);
|
||||
drv->fd = -1;
|
||||
drv->metafd = -1;
|
||||
}
|
||||
|
||||
static int read_meta(nand_drv* drv, nand_page_t page)
|
||||
{
|
||||
/* probably won't fail */
|
||||
if(lseek(drv->metafd, page, SEEK_SET) < 0)
|
||||
return NAND_ERR_OTHER;
|
||||
if(read(drv->metafd, drv->scratch_buf, 1) != 1)
|
||||
return NAND_ERR_OTHER;
|
||||
|
||||
return drv->scratch_buf[0];
|
||||
}
|
||||
|
||||
static int write_meta(nand_drv* drv, nand_page_t page, int val)
|
||||
{
|
||||
drv->scratch_buf[0] = val;
|
||||
|
||||
if(lseek(drv->metafd, page, SEEK_SET) < 0)
|
||||
return NAND_ERR_OTHER;
|
||||
if(write(drv->metafd, drv->scratch_buf, 1) != 1)
|
||||
return NAND_ERR_OTHER;
|
||||
|
||||
return NAND_SUCCESS;
|
||||
}
|
||||
|
||||
static int upd_meta(nand_drv* drv, nand_page_t page, uint8_t clr, uint8_t set)
|
||||
{
|
||||
int meta = read_meta(drv, page);
|
||||
if(meta < 0)
|
||||
return meta;
|
||||
|
||||
meta &= ~clr;
|
||||
meta |= set;
|
||||
|
||||
return write_meta(drv, page, meta);
|
||||
}
|
||||
|
||||
static int page_program(nand_drv* drv, nand_page_t page, const void* buffer,
|
||||
uint8_t clr, uint8_t set)
|
||||
{
|
||||
if(lseek(drv->fd, page * drv->chip->page_size, SEEK_SET) < 0)
|
||||
return NAND_ERR_OTHER;
|
||||
if(write(drv->fd, buffer, drv->chip->page_size) != (ssize_t)drv->chip->page_size)
|
||||
return NAND_ERR_PROGRAM_FAIL;
|
||||
|
||||
return upd_meta(drv, page, clr, set);
|
||||
}
|
||||
|
||||
static void trace(enum nand_trace_type ty, enum nand_trace_exception ex, nand_page_t addr)
|
||||
{
|
||||
if(nand_trace_length < nand_trace_capacity) {
|
||||
nand_trace_cur->type = ty;
|
||||
nand_trace_cur->exception = ex;
|
||||
nand_trace_cur->addr = addr;
|
||||
nand_trace_cur++;
|
||||
nand_trace_length++;
|
||||
}
|
||||
}
|
||||
|
||||
int nand_block_erase(nand_drv* drv, nand_block_t block)
|
||||
{
|
||||
lock_assert(drv->lock_count > 0, "nand_block_erase(): lock not held");
|
||||
CHECK_INJECTED_ERROR;
|
||||
|
||||
trace(NTT_ERASE, NTE_NONE, block);
|
||||
|
||||
memset(drv->page_buf, 0xff, drv->fpage_size);
|
||||
|
||||
for(unsigned i = 0; i < drv->ppb; ++i) {
|
||||
int rc = page_program(drv, block + i, drv->page_buf, METAF_PROGRAMMED, 0);
|
||||
if(rc < 0)
|
||||
return NAND_ERR_ERASE_FAIL;
|
||||
}
|
||||
|
||||
return NAND_SUCCESS;
|
||||
}
|
||||
|
||||
int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
|
||||
{
|
||||
lock_assert(drv->lock_count > 0, "nand_page_program(): lock not held");
|
||||
CHECK_INJECTED_ERROR;
|
||||
|
||||
int meta = read_meta(drv, page);
|
||||
if(meta < 0)
|
||||
return meta;
|
||||
|
||||
enum nand_trace_exception exception = NTE_NONE;
|
||||
if(meta & METAF_PROGRAMMED)
|
||||
exception = NTE_DOUBLE_PROGRAMMED;
|
||||
|
||||
trace(NTT_PROGRAM, exception, page);
|
||||
|
||||
return page_program(drv, page, buffer, 0, METAF_PROGRAMMED);
|
||||
}
|
||||
|
||||
int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer)
|
||||
{
|
||||
lock_assert(drv->lock_count > 0, "nand_page_read(): lock not held");
|
||||
CHECK_INJECTED_ERROR;
|
||||
|
||||
enum nand_trace_exception exception = NTE_NONE;
|
||||
|
||||
int meta = read_meta(drv, page);
|
||||
if(meta < 0)
|
||||
return meta;
|
||||
|
||||
if(meta & METAF_PROGRAMMED) {
|
||||
if(lseek(drv->fd, page * drv->chip->page_size, SEEK_SET) < 0)
|
||||
return NAND_ERR_OTHER;
|
||||
if(read(drv->fd, buffer, drv->chip->page_size) != (ssize_t)drv->chip->page_size)
|
||||
return NAND_ERR_OTHER;
|
||||
} else {
|
||||
memset(buffer, 0xff, drv->chip->page_size);
|
||||
exception = NTE_CLEARED;
|
||||
}
|
||||
|
||||
trace(NTT_READ, exception, page);
|
||||
|
||||
memset(buffer + drv->chip->page_size, 0xff, drv->chip->oob_size);
|
||||
return NAND_SUCCESS;
|
||||
}
|
||||
11
lib/x1000-installer/test_lib/file.c
Normal file
11
lib/x1000-installer/test_lib/file.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "file.h"
|
||||
|
||||
off_t filesize(int osfd)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (!fstat(osfd, &sb))
|
||||
return sb.st_size;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
18
lib/x1000-installer/test_lib/file.h
Normal file
18
lib/x1000-installer/test_lib/file.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef MAX_PATH
|
||||
# undef MAX_PATH
|
||||
#endif
|
||||
|
||||
#define MAX_PATH 260
|
||||
|
||||
off_t filesize(int fd);
|
||||
|
||||
#endif
|
||||
245
lib/x1000-installer/test_lib/md5.c
Normal file
245
lib/x1000-installer/test_lib/md5.c
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#define GET_UINT32(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32_t) (b)[(i) ] ) \
|
||||
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
|
||||
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
|
||||
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
|
||||
}
|
||||
|
||||
#define PUT_UINT32(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (uint8_t) ( (n) ); \
|
||||
(b)[(i) + 1] = (uint8_t) ( (n) >> 8 ); \
|
||||
(b)[(i) + 2] = (uint8_t) ( (n) >> 16 ); \
|
||||
(b)[(i) + 3] = (uint8_t) ( (n) >> 24 ); \
|
||||
}
|
||||
|
||||
void md5_starts( md5_context *ctx )
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
static void md5_process( md5_context *ctx, uint8_t data[64] )
|
||||
{
|
||||
uint32_t X[16], A, B, C, D;
|
||||
|
||||
GET_UINT32( X[0], data, 0 );
|
||||
GET_UINT32( X[1], data, 4 );
|
||||
GET_UINT32( X[2], data, 8 );
|
||||
GET_UINT32( X[3], data, 12 );
|
||||
GET_UINT32( X[4], data, 16 );
|
||||
GET_UINT32( X[5], data, 20 );
|
||||
GET_UINT32( X[6], data, 24 );
|
||||
GET_UINT32( X[7], data, 28 );
|
||||
GET_UINT32( X[8], data, 32 );
|
||||
GET_UINT32( X[9], data, 36 );
|
||||
GET_UINT32( X[10], data, 40 );
|
||||
GET_UINT32( X[11], data, 44 );
|
||||
GET_UINT32( X[12], data, 48 );
|
||||
GET_UINT32( X[13], data, 52 );
|
||||
GET_UINT32( X[14], data, 56 );
|
||||
GET_UINT32( X[15], data, 60 );
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P( A, B, C, D, 0, 7, 0xD76AA478 );
|
||||
P( D, A, B, C, 1, 12, 0xE8C7B756 );
|
||||
P( C, D, A, B, 2, 17, 0x242070DB );
|
||||
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
|
||||
P( A, B, C, D, 4, 7, 0xF57C0FAF );
|
||||
P( D, A, B, C, 5, 12, 0x4787C62A );
|
||||
P( C, D, A, B, 6, 17, 0xA8304613 );
|
||||
P( B, C, D, A, 7, 22, 0xFD469501 );
|
||||
P( A, B, C, D, 8, 7, 0x698098D8 );
|
||||
P( D, A, B, C, 9, 12, 0x8B44F7AF );
|
||||
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
|
||||
P( B, C, D, A, 11, 22, 0x895CD7BE );
|
||||
P( A, B, C, D, 12, 7, 0x6B901122 );
|
||||
P( D, A, B, C, 13, 12, 0xFD987193 );
|
||||
P( C, D, A, B, 14, 17, 0xA679438E );
|
||||
P( B, C, D, A, 15, 22, 0x49B40821 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P( A, B, C, D, 1, 5, 0xF61E2562 );
|
||||
P( D, A, B, C, 6, 9, 0xC040B340 );
|
||||
P( C, D, A, B, 11, 14, 0x265E5A51 );
|
||||
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
|
||||
P( A, B, C, D, 5, 5, 0xD62F105D );
|
||||
P( D, A, B, C, 10, 9, 0x02441453 );
|
||||
P( C, D, A, B, 15, 14, 0xD8A1E681 );
|
||||
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
|
||||
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
|
||||
P( D, A, B, C, 14, 9, 0xC33707D6 );
|
||||
P( C, D, A, B, 3, 14, 0xF4D50D87 );
|
||||
P( B, C, D, A, 8, 20, 0x455A14ED );
|
||||
P( A, B, C, D, 13, 5, 0xA9E3E905 );
|
||||
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
|
||||
P( C, D, A, B, 7, 14, 0x676F02D9 );
|
||||
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P( A, B, C, D, 5, 4, 0xFFFA3942 );
|
||||
P( D, A, B, C, 8, 11, 0x8771F681 );
|
||||
P( C, D, A, B, 11, 16, 0x6D9D6122 );
|
||||
P( B, C, D, A, 14, 23, 0xFDE5380C );
|
||||
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
|
||||
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
|
||||
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
|
||||
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
|
||||
P( A, B, C, D, 13, 4, 0x289B7EC6 );
|
||||
P( D, A, B, C, 0, 11, 0xEAA127FA );
|
||||
P( C, D, A, B, 3, 16, 0xD4EF3085 );
|
||||
P( B, C, D, A, 6, 23, 0x04881D05 );
|
||||
P( A, B, C, D, 9, 4, 0xD9D4D039 );
|
||||
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
|
||||
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
|
||||
P( B, C, D, A, 2, 23, 0xC4AC5665 );
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P( A, B, C, D, 0, 6, 0xF4292244 );
|
||||
P( D, A, B, C, 7, 10, 0x432AFF97 );
|
||||
P( C, D, A, B, 14, 15, 0xAB9423A7 );
|
||||
P( B, C, D, A, 5, 21, 0xFC93A039 );
|
||||
P( A, B, C, D, 12, 6, 0x655B59C3 );
|
||||
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
|
||||
P( C, D, A, B, 10, 15, 0xFFEFF47D );
|
||||
P( B, C, D, A, 1, 21, 0x85845DD1 );
|
||||
P( A, B, C, D, 8, 6, 0x6FA87E4F );
|
||||
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
|
||||
P( C, D, A, B, 6, 15, 0xA3014314 );
|
||||
P( B, C, D, A, 13, 21, 0x4E0811A1 );
|
||||
P( A, B, C, D, 4, 6, 0xF7537E82 );
|
||||
P( D, A, B, C, 11, 10, 0xBD3AF235 );
|
||||
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
|
||||
P( B, C, D, A, 9, 21, 0xEB86D391 );
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
}
|
||||
|
||||
void md5_update( md5_context *ctx, uint8_t *input, uint32_t length )
|
||||
{
|
||||
uint32_t left, fill;
|
||||
|
||||
if( ! length ) return;
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += length;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if( ctx->total[0] < length )
|
||||
ctx->total[1]++;
|
||||
|
||||
if( left && length >= fill )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, fill );
|
||||
md5_process( ctx, ctx->buffer );
|
||||
length -= fill;
|
||||
input += fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while( length >= 64 )
|
||||
{
|
||||
md5_process( ctx, input );
|
||||
length -= 64;
|
||||
input += 64;
|
||||
}
|
||||
|
||||
if( length )
|
||||
{
|
||||
memcpy( (void *) (ctx->buffer + left),
|
||||
(void *) input, length );
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t md5_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void md5_finish( md5_context *ctx, uint8_t digest[16] )
|
||||
{
|
||||
uint32_t last, padn;
|
||||
uint32_t high, low;
|
||||
uint8_t msglen[8];
|
||||
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT32( low, msglen, 0 );
|
||||
PUT_UINT32( high, msglen, 4 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
md5_update( ctx, md5_padding, padn );
|
||||
md5_update( ctx, msglen, 8 );
|
||||
|
||||
PUT_UINT32( ctx->state[0], digest, 0 );
|
||||
PUT_UINT32( ctx->state[1], digest, 4 );
|
||||
PUT_UINT32( ctx->state[2], digest, 8 );
|
||||
PUT_UINT32( ctx->state[3], digest, 12 );
|
||||
}
|
||||
18
lib/x1000-installer/test_lib/md5.h
Normal file
18
lib/x1000-installer/test_lib/md5.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _MD5_H
|
||||
#define _MD5_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total[2];
|
||||
uint32_t state[4];
|
||||
uint8_t buffer[64];
|
||||
}
|
||||
md5_context;
|
||||
|
||||
void md5_starts( md5_context *ctx );
|
||||
void md5_update( md5_context *ctx, uint8_t *input, uint32_t length );
|
||||
void md5_finish( md5_context *ctx, uint8_t digest[16] );
|
||||
|
||||
#endif /* md5.h */
|
||||
112
lib/x1000-installer/test_lib/nand-x1000.h
Normal file
112
lib/x1000-installer/test_lib/nand-x1000.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Stripped down fake version of X1000 NAND API for testing purposes,
|
||||
* uses a normal file to store the data */
|
||||
|
||||
#ifndef __NAND_X1000_H__
|
||||
#define __NAND_X1000_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define NAND_SUCCESS 0
|
||||
#define NAND_ERR_UNKNOWN_CHIP (-1)
|
||||
#define NAND_ERR_PROGRAM_FAIL (-2)
|
||||
#define NAND_ERR_ERASE_FAIL (-3)
|
||||
#define NAND_ERR_UNALIGNED (-4)
|
||||
#define NAND_ERR_OTHER (-5)
|
||||
#define NAND_ERR_INJECTED (-6)
|
||||
|
||||
/* keep max page size in sync with the NAND chip table in the .c file */
|
||||
#define NAND_DRV_SCRATCHSIZE 32
|
||||
#define NAND_DRV_MAXPAGESIZE 2112
|
||||
|
||||
typedef uint32_t nand_block_t;
|
||||
typedef uint32_t nand_page_t;
|
||||
|
||||
enum nand_trace_type {
|
||||
NTT_READ,
|
||||
NTT_PROGRAM,
|
||||
NTT_ERASE,
|
||||
};
|
||||
|
||||
enum nand_trace_exception {
|
||||
NTE_NONE,
|
||||
NTE_DOUBLE_PROGRAMMED,
|
||||
NTE_CLEARED,
|
||||
};
|
||||
|
||||
struct nand_trace {
|
||||
enum nand_trace_type type;
|
||||
enum nand_trace_exception exception;
|
||||
nand_page_t addr;
|
||||
};
|
||||
|
||||
typedef struct nand_chip {
|
||||
/* Base2 logarithm of the number of pages per block */
|
||||
unsigned log2_ppb;
|
||||
|
||||
/* Size of a page's main / oob areas, in bytes. */
|
||||
unsigned page_size;
|
||||
unsigned oob_size;
|
||||
|
||||
/* Total number of blocks in the chip */
|
||||
unsigned nr_blocks;
|
||||
} nand_chip;
|
||||
|
||||
typedef struct nand_drv {
|
||||
/* Backing file */
|
||||
int fd;
|
||||
int metafd;
|
||||
int lock_count;
|
||||
|
||||
unsigned refcount;
|
||||
uint8_t* scratch_buf;
|
||||
uint8_t* page_buf;
|
||||
const nand_chip* chip;
|
||||
unsigned ppb;
|
||||
unsigned fpage_size;
|
||||
} nand_drv;
|
||||
|
||||
extern const char* nand_backing_file;
|
||||
extern const char* nand_meta_file;
|
||||
|
||||
extern struct nand_trace* nand_trace;
|
||||
extern size_t nand_trace_capacity;
|
||||
extern size_t nand_trace_length;
|
||||
|
||||
extern void nand_trace_reset(size_t size);
|
||||
extern void nand_inject_error(int rc);
|
||||
|
||||
extern nand_drv* nand_init(void);
|
||||
|
||||
extern void nand_lock(nand_drv* drv);
|
||||
extern void nand_unlock(nand_drv* drv);
|
||||
|
||||
extern int nand_open(nand_drv* drv);
|
||||
extern void nand_close(nand_drv* drv);
|
||||
extern int nand_block_erase(nand_drv* drv, nand_block_t block);
|
||||
extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer);
|
||||
extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer);
|
||||
|
||||
#endif /* __NAND_X1000_H__ */
|
||||
130
lib/x1000-installer/test_lib/pathfuncs.c
Normal file
130
lib/x1000-installer/test_lib/pathfuncs.c
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2014 by Michael Sevakis
|
||||
*
|
||||
* 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 "pathfuncs.h"
|
||||
#include "strlcpy.h"
|
||||
#include "system.h"
|
||||
#include <string.h>
|
||||
|
||||
static const char* GOBBLE_PATH_SEPCH(const char* p)
|
||||
{
|
||||
int c;
|
||||
while((c = *p) == PATH_SEPCH)
|
||||
++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static const char* GOBBLE_PATH_COMP(const char* p)
|
||||
{
|
||||
int c;
|
||||
while((c = *p) && c != PATH_SEPCH)
|
||||
++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Strips the trailing component from the path
|
||||
* "" *nameptr->NUL, len=0: ""
|
||||
* "/" *nameptr->/, len=1: "/"
|
||||
* "//" *nameptr->2nd /, len=1: "/"
|
||||
* "/a" *nameptr->/, len=1: "/"
|
||||
* "a/" *nameptr->a, len=0: ""
|
||||
* "/a/bc" *nameptr->/, len=2: "/a"
|
||||
* "d" *nameptr->d, len=0: ""
|
||||
* "ef/gh" *nameptr->e, len=2: "ef"
|
||||
*
|
||||
* Notes: * Interpret len=0 as ".".
|
||||
* * In the same string, path_dirname() returns a pointer with the
|
||||
* same or lower address as path_basename().
|
||||
* * Pasting a separator between the returns of path_dirname() and
|
||||
* path_basename() will result in a path equivalent to the input.
|
||||
*
|
||||
*/
|
||||
size_t path_dirname(const char *name, const char **nameptr)
|
||||
{
|
||||
const char *p = GOBBLE_PATH_SEPCH(name);
|
||||
const char *q = name;
|
||||
const char *r = p;
|
||||
|
||||
while (*(p = GOBBLE_PATH_COMP(p)))
|
||||
{
|
||||
const char *s = p;
|
||||
|
||||
if (!*(p = GOBBLE_PATH_SEPCH(p)))
|
||||
break;
|
||||
|
||||
q = s;
|
||||
}
|
||||
|
||||
if (q == name && r > name)
|
||||
name = r, q = name--; /* root - return last slash */
|
||||
|
||||
*nameptr = name;
|
||||
return q - name;
|
||||
}
|
||||
|
||||
/* Appends one path to another, adding separators between components if needed.
|
||||
* Return value and behavior is otherwise as strlcpy so that truncation may be
|
||||
* detected.
|
||||
*
|
||||
* For basepath and component:
|
||||
* PA_SEP_HARD adds a separator even if the base path is empty
|
||||
* PA_SEP_SOFT adds a separator only if the base path is not empty
|
||||
*/
|
||||
size_t path_append(char *buf, const char *basepath,
|
||||
const char *component, size_t bufsize)
|
||||
{
|
||||
const char *base = basepath && basepath[0] ? basepath : buf;
|
||||
if (!base)
|
||||
return bufsize; /* won't work to get lengths from buf */
|
||||
|
||||
if (!buf)
|
||||
bufsize = 0;
|
||||
|
||||
if (path_is_absolute(component))
|
||||
{
|
||||
/* 'component' is absolute; replace all */
|
||||
basepath = component;
|
||||
component = "";
|
||||
}
|
||||
|
||||
/* if basepath is not null or empty, buffer contents are replaced,
|
||||
otherwise buf contains the base path */
|
||||
size_t len = base == buf ? strlen(buf) : my_strlcpy(buf, basepath, bufsize);
|
||||
|
||||
bool separate = false;
|
||||
|
||||
if (!basepath || !component)
|
||||
separate = !len || base[len-1] != PATH_SEPCH;
|
||||
else if (component[0])
|
||||
separate = len && base[len-1] != PATH_SEPCH;
|
||||
|
||||
/* caller might lie about size of buf yet use buf as the base */
|
||||
if (base == buf && bufsize && len >= bufsize)
|
||||
buf[bufsize - 1] = '\0';
|
||||
|
||||
buf += len;
|
||||
bufsize -= MIN(len, bufsize);
|
||||
|
||||
if (separate && (len++, bufsize > 0) && --bufsize > 0)
|
||||
*buf++ = PATH_SEPCH;
|
||||
|
||||
return len + my_strlcpy(buf, component ?: "", bufsize);
|
||||
}
|
||||
39
lib/x1000-installer/test_lib/pathfuncs.h
Normal file
39
lib/x1000-installer/test_lib/pathfuncs.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2014 by Michael Sevakis
|
||||
*
|
||||
* 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 _PATHFUNCS_H_
|
||||
#define _PATHFUNCS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PATH_SEPCH '/'
|
||||
|
||||
/* return true if path begins with a root '/' component and is not NULL */
|
||||
static inline bool path_is_absolute(const char *path)
|
||||
{
|
||||
return path && path[0] == PATH_SEPCH;
|
||||
}
|
||||
|
||||
size_t path_dirname(const char *name, const char **nameptr);
|
||||
size_t path_append(char *buf, const char *basepath,
|
||||
const char *component, size_t bufsize);
|
||||
|
||||
#endif
|
||||
50
lib/x1000-installer/test_lib/strlcpy.c
Normal file
50
lib/x1000-installer/test_lib/strlcpy.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
my_strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0) {
|
||||
while (--n != 0) {
|
||||
if ((*d++ = *s++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
4
lib/x1000-installer/test_lib/strlcpy.h
Normal file
4
lib/x1000-installer/test_lib/strlcpy.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef STRLCPY_H
|
||||
#define STRLCPY_H
|
||||
size_t my_strlcpy(char *dst, const char *src, size_t siz);
|
||||
#endif
|
||||
10
lib/x1000-installer/test_lib/system.h
Normal file
10
lib/x1000-installer/test_lib/system.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
#define CACHEALIGN_SIZE 1
|
||||
#define CACHEALIGN_BUFFER(x,y) do { } while(0)
|
||||
#define MIN(a, b) (((a)<(b))?(a):(b))
|
||||
#define ALIGN_BUFFER(ptr, size, align) do { } while(0)
|
||||
#define ALIGN_UP_P2(x, p) (((x) + ((1 << (p)) - 1)) & ~((1 << (p)) - 1))
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue