1
0
Fork 0
forked from len0rd/rockbox

rbutil: Merge rbutil with utils folder.

rbutil uses several components from the utils folder, and can be
considered part of utils too. Having it in a separate folder is an
arbitrary split that doesn't help anymore these days, so merge them.

This also allows other utils to easily use libtools.make without the
need to navigate to a different folder.

Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21
This commit is contained in:
Dominik Riebeling 2021-12-15 21:04:28 +01:00
parent 6c6f0757d7
commit c876d3bbef
494 changed files with 13 additions and 13 deletions

23
utils/bspatch/LICENSE Normal file
View file

@ -0,0 +1,23 @@
Copyright 2003-2005 Colin Percival
All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted providing that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

17
utils/bspatch/Makefile Normal file
View file

@ -0,0 +1,17 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
LIBSOURCES := bspatch.c
SOURCES := main.c
OUTPUT := bspatch
EXTRADEPS := libbz2.a
include ../libtools.make

218
utils/bspatch/bspatch.c Normal file
View file

@ -0,0 +1,218 @@
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#include <io.h>
#else
#include <stdarg.h>
#include <sys/types.h>
#endif
#include "../bzip2/bzlib.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#define errx err
void err(int exitcode, const char * fmt, ...)
{
va_list valist;
va_start(valist, fmt);
vprintf(fmt, valist);
va_end(valist);
exit(exitcode);
}
static long offtin(u_char *buf)
{
long y;
y = buf[7] & 0x7F;
y = y * 256;y += buf[6];
y = y * 256;y += buf[5];
y = y * 256;y += buf[4];
y = y * 256;y += buf[3];
y = y * 256;y += buf[2];
y = y * 256;y += buf[1];
y = y * 256;y += buf[0];
if (buf[7] & 0x80) y = -y;
return y;
}
int apply_bspatch(const char *infile, const char *outfile, const char *patchfile)
{
FILE * f, *cpf, *dpf, *epf;
BZFILE * cpfbz2, *dpfbz2, *epfbz2;
int cbz2err, dbz2err, ebz2err;
FILE * fs;
long oldsize, newsize;
long bzctrllen, bzdatalen;
u_char header[32], buf[8];
u_char *pold, *pnew;
long oldpos, newpos;
long ctrl[3];
long lenread;
long i;
/* Open patch file */
if ((f = fopen(patchfile, "r")) == NULL)
err(1, "fopen(%s)", patchfile);
/*
File format:
0 8 "BSDIFF40"
8 8 X
16 8 Y
24 8 sizeof(newfile)
32 X bzip2(control block)
32+X Y bzip2(diff block)
32+X+Y ??? bzip2(extra block)
with control block a set of triples (x,y,z) meaning "add x bytes
from oldfile to x bytes from the diff block; copy y bytes from the
extra block; seek forwards in oldfile by z bytes".
*/
/* Read header */
if (fread(header, 1, 32, f) < 32) {
if (feof(f))
errx(1, "Corrupt patch\n");
err(1, "fread(%s)", patchfile);
}
/* Check for appropriate magic */
if (memcmp(header, "BSDIFF40", 8) != 0)
errx(1, "Corrupt patch\n");
/* Read lengths from header */
bzctrllen = offtin(header + 8);
bzdatalen = offtin(header + 16);
newsize = offtin(header + 24);
if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
errx(1, "Corrupt patch\n");
/* Close patch file and re-open it via libbzip2 at the right places */
if (fclose(f))
err(1, "fclose(%s)", patchfile);
if ((cpf = fopen(patchfile, "rb")) == NULL)
err(1, "fopen(%s)", patchfile);
if (fseek(cpf, 32, SEEK_SET))
err(1, "fseeko(%s, %lld)", patchfile,
(long long)32);
if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
if ((dpf = fopen(patchfile, "rb")) == NULL)
err(1, "fopen(%s)", patchfile);
if (fseek(dpf, 32 + bzctrllen, SEEK_SET))
err(1, "fseeko(%s, %lld)", patchfile,
(long long)(32 + bzctrllen));
if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
if ((epf = fopen(patchfile, "rb")) == NULL)
err(1, "fopen(%s)", patchfile);
if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
err(1, "fseeko(%s, %lld)", patchfile,
(long long)(32 + bzctrllen + bzdatalen));
if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
fs = fopen(infile, "rb");
if (fs == NULL)err(1, "Open failed :%s", infile);
if (fseek(fs, 0, SEEK_END) != 0)err(1, "Seek failed :%s", infile);
oldsize = ftell(fs);
pold = (u_char *)malloc(oldsize + 1);
if (pold == NULL) err(1, "Malloc failed :%s", infile);
fseek(fs, 0, SEEK_SET);
if (fread(pold, 1, oldsize, fs) == -1) err(1, "Read failed :%s", infile);
if (fclose(fs) == -1) err(1, "Close failed :%s", infile);
pnew = malloc(newsize + 1);
if (pnew == NULL)err(1, NULL);
oldpos = 0;newpos = 0;
while (newpos < newsize) {
/* Read control data */
for (i = 0;i <= 2;i++) {
lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
if ((lenread < 8) || ((cbz2err != BZ_OK) &&
(cbz2err != BZ_STREAM_END)))
errx(1, "Corrupt patch\n");
ctrl[i] = offtin(buf);
};
/* Sanity-check */
if (newpos + ctrl[0] > newsize)
errx(1, "Corrupt patch\n");
/* Read diff string */
lenread = BZ2_bzRead(&dbz2err, dpfbz2, pnew + newpos, ctrl[0]);
if ((lenread < ctrl[0]) ||
((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
errx(1, "Corrupt patch\n");
/* Add pold data to diff string */
for (i = 0;i < ctrl[0];i++)
if ((oldpos + i >= 0) && (oldpos + i < oldsize))
pnew[newpos + i] += pold[oldpos + i];
/* Adjust pointers */
newpos += ctrl[0];
oldpos += ctrl[0];
/* Sanity-check */
if (newpos + ctrl[1] > newsize)
errx(1, "Corrupt patch\n");
/* Read extra string */
lenread = BZ2_bzRead(&ebz2err, epfbz2, pnew + newpos, ctrl[1]);
if ((lenread < ctrl[1]) ||
((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
errx(1, "Corrupt patch\n");
/* Adjust pointers */
newpos += ctrl[1];
oldpos += ctrl[2];
};
/* Clean up the bzip2 reads */
BZ2_bzReadClose(&cbz2err, cpfbz2);
BZ2_bzReadClose(&dbz2err, dpfbz2);
BZ2_bzReadClose(&ebz2err, epfbz2);
if (fclose(cpf) || fclose(dpf) || fclose(epf))
err(1, "fclose(%s)", patchfile);
/* Write the pnew file */
fs = fopen(outfile, "wb");
if (fs == NULL)err(1, "Create failed :%s", outfile);
if (fwrite(pnew, 1, newsize, fs) == -1)err(1, "Write failed :%s", outfile);
if (fclose(fs) == -1)err(1, "Close failed :%s", outfile);
free(pnew);
free(pold);
return 0;
}

19
utils/bspatch/bspatch.h Normal file
View file

@ -0,0 +1,19 @@
/*
* Simple wrapper for the bspatch entry point.
*/
#ifndef _BSPATCH_H
#define _BSPATCH_H
#ifdef __cplusplus
extern "C" {
#endif
int apply_bspatch(const char *infile, const char *outfile, const char *patchfile);
#ifdef __cplusplus
}
#endif
#endif /* _BSPATCH_H */

34
utils/bspatch/main.c Normal file
View file

@ -0,0 +1,34 @@
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "bspatch.c"
int main(int argc, char * argv[])
{
if (argc != 4) errx(1, "usage: %s oldfile newfile patchfile\n", argv[0]);
apply_bspatch(argv[1], argv[2], argv[3]);
}

42
utils/bzip2/LICENSE Normal file
View file

@ -0,0 +1,42 @@
--------------------------------------------------------------------------
This program, "bzip2", the associated library "libbzip2", and all
documentation, are copyright (C) 1996-2010 Julian R Seward. All
rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
3. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
4. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Julian Seward, jseward@bzip.org
bzip2/libbzip2 version 1.0.6 of 6 September 2010
--------------------------------------------------------------------------

15
utils/bzip2/Makefile Normal file
View file

@ -0,0 +1,15 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
LIBSOURCES := blocksort.c compress.c decompress.c randtable.c \
bzlib.c crctable.c huffman.c
OUTPUT := bz2
include ../libtools.make

1094
utils/bzip2/blocksort.c Normal file

File diff suppressed because it is too large Load diff

1572
utils/bzip2/bzlib.c Normal file

File diff suppressed because it is too large Load diff

282
utils/bzip2/bzlib.h Normal file
View file

@ -0,0 +1,282 @@
/*-------------------------------------------------------------*/
/*--- Public header file for the library. ---*/
/*--- bzlib.h ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#ifndef _BZLIB_H
#define _BZLIB_H
#ifdef __cplusplus
extern "C" {
#endif
#define BZ_RUN 0
#define BZ_FLUSH 1
#define BZ_FINISH 2
#define BZ_OK 0
#define BZ_RUN_OK 1
#define BZ_FLUSH_OK 2
#define BZ_FINISH_OK 3
#define BZ_STREAM_END 4
#define BZ_SEQUENCE_ERROR (-1)
#define BZ_PARAM_ERROR (-2)
#define BZ_MEM_ERROR (-3)
#define BZ_DATA_ERROR (-4)
#define BZ_DATA_ERROR_MAGIC (-5)
#define BZ_IO_ERROR (-6)
#define BZ_UNEXPECTED_EOF (-7)
#define BZ_OUTBUFF_FULL (-8)
#define BZ_CONFIG_ERROR (-9)
typedef
struct {
char *next_in;
unsigned int avail_in;
unsigned int total_in_lo32;
unsigned int total_in_hi32;
char *next_out;
unsigned int avail_out;
unsigned int total_out_lo32;
unsigned int total_out_hi32;
void *state;
void *(*bzalloc)(void *,int,int);
void (*bzfree)(void *,void *);
void *opaque;
}
bz_stream;
#ifndef BZ_IMPORT
#define BZ_EXPORT
#endif
#ifndef BZ_NO_STDIO
/* Need a definitition for FILE */
#include <stdio.h>
#endif
#ifdef _WIN32
# include <windows.h>
# ifdef small
/* windows.h define small to char */
# undef small
# endif
# ifdef BZ_EXPORT
# define BZ_API(func) WINAPI func
# define BZ_EXTERN extern
# else
/* import windows dll dynamically */
# define BZ_API(func) (WINAPI * func)
# define BZ_EXTERN
# endif
#else
# define BZ_API(func) func
# define BZ_EXTERN extern
#endif
/*-- Core (low-level) library functions --*/
BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
bz_stream* strm,
int blockSize100k,
int verbosity,
int workFactor
);
BZ_EXTERN int BZ_API(BZ2_bzCompress) (
bz_stream* strm,
int action
);
BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
bz_stream* strm
);
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
bz_stream *strm,
int verbosity,
int small
);
BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
bz_stream* strm
);
BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
bz_stream *strm
);
/*-- High(er) level library functions --*/
#ifndef BZ_NO_STDIO
#define BZ_MAX_UNUSED 5000
typedef void BZFILE;
BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
int* bzerror,
FILE* f,
int verbosity,
int small,
void* unused,
int nUnused
);
BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
int* bzerror,
BZFILE* b
);
BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
int* bzerror,
BZFILE* b,
void** unused,
int* nUnused
);
BZ_EXTERN int BZ_API(BZ2_bzRead) (
int* bzerror,
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
int* bzerror,
FILE* f,
int blockSize100k,
int verbosity,
int workFactor
);
BZ_EXTERN void BZ_API(BZ2_bzWrite) (
int* bzerror,
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
int* bzerror,
BZFILE* b,
int abandon,
unsigned int* nbytes_in,
unsigned int* nbytes_out
);
BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
int* bzerror,
BZFILE* b,
int abandon,
unsigned int* nbytes_in_lo32,
unsigned int* nbytes_in_hi32,
unsigned int* nbytes_out_lo32,
unsigned int* nbytes_out_hi32
);
#endif
/*-- Utility functions --*/
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
char* dest,
unsigned int* destLen,
char* source,
unsigned int sourceLen,
int blockSize100k,
int verbosity,
int workFactor
);
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
char* dest,
unsigned int* destLen,
char* source,
unsigned int sourceLen,
int small,
int verbosity
);
/*--
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
to support better zlib compatibility.
This code is not _officially_ part of libbzip2 (yet);
I haven't tested it, documented it, or considered the
threading-safeness of it.
If this code breaks, please contact both Yoshioka and me.
--*/
BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
void
);
#ifndef BZ_NO_STDIO
BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
const char *path,
const char *mode
);
BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
int fd,
const char *mode
);
BZ_EXTERN int BZ_API(BZ2_bzread) (
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN int BZ_API(BZ2_bzwrite) (
BZFILE* b,
void* buf,
int len
);
BZ_EXTERN int BZ_API(BZ2_bzflush) (
BZFILE* b
);
BZ_EXTERN void BZ_API(BZ2_bzclose) (
BZFILE* b
);
BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
BZFILE *b,
int *errnum
);
#endif
#ifdef __cplusplus
}
#endif
#endif
/*-------------------------------------------------------------*/
/*--- end bzlib.h ---*/
/*-------------------------------------------------------------*/

512
utils/bzip2/bzlib_private.h Normal file
View file

@ -0,0 +1,512 @@
/*-------------------------------------------------------------*/
/*--- Private header file for the library. ---*/
/*--- bzlib_private.h ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#ifndef _BZLIB_PRIVATE_H
#define _BZLIB_PRIVATE_H
#include <stdlib.h>
#ifndef BZ_NO_STDIO
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#endif
#include "bzlib.h"
/*-- General stuff. --*/
#define BZ_VERSION "1.0.6, 6-Sept-2010"
typedef char Char;
typedef unsigned char Bool;
typedef unsigned char UChar;
typedef int Int32;
typedef unsigned int UInt32;
typedef short Int16;
typedef unsigned short UInt16;
#define True ((Bool)1)
#define False ((Bool)0)
#ifndef __GNUC__
#define __inline__ /* */
#endif
#ifndef BZ_NO_STDIO
extern void BZ2_bz__AssertH__fail ( int errcode );
#define AssertH(cond,errcode) \
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
#if BZ_DEBUG
#define AssertD(cond,msg) \
{ if (!(cond)) { \
fprintf ( stderr, \
"\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
exit(1); \
}}
#else
#define AssertD(cond,msg) /* */
#endif
#define VPrintf0(zf) \
fprintf(stderr,zf)
#define VPrintf1(zf,za1) \
fprintf(stderr,zf,za1)
#define VPrintf2(zf,za1,za2) \
fprintf(stderr,zf,za1,za2)
#define VPrintf3(zf,za1,za2,za3) \
fprintf(stderr,zf,za1,za2,za3)
#define VPrintf4(zf,za1,za2,za3,za4) \
fprintf(stderr,zf,za1,za2,za3,za4)
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
fprintf(stderr,zf,za1,za2,za3,za4,za5)
#else
extern void bz_internal_error ( int errcode );
#define AssertH(cond,errcode) \
{ if (!(cond)) bz_internal_error ( errcode ); }
#define AssertD(cond,msg) do { } while (0)
#define VPrintf0(zf) do { } while (0)
#define VPrintf1(zf,za1) do { } while (0)
#define VPrintf2(zf,za1,za2) do { } while (0)
#define VPrintf3(zf,za1,za2,za3) do { } while (0)
#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
#endif
#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
/*-- Header bytes. --*/
#define BZ_HDR_B 0x42 /* 'B' */
#define BZ_HDR_Z 0x5a /* 'Z' */
#define BZ_HDR_h 0x68 /* 'h' */
#define BZ_HDR_0 0x30 /* '0' */
/*-- Constants for the back end. --*/
#define BZ_MAX_ALPHA_SIZE 258
#define BZ_MAX_CODE_LEN 23
#define BZ_RUNA 0
#define BZ_RUNB 1
#define BZ_N_GROUPS 6
#define BZ_G_SIZE 50
#define BZ_N_ITERS 4
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
/*-- Stuff for randomising repetitive blocks. --*/
extern Int32 BZ2_rNums[512];
#define BZ_RAND_DECLS \
Int32 rNToGo; \
Int32 rTPos \
#define BZ_RAND_INIT_MASK \
s->rNToGo = 0; \
s->rTPos = 0 \
#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
#define BZ_RAND_UPD_MASK \
if (s->rNToGo == 0) { \
s->rNToGo = BZ2_rNums[s->rTPos]; \
s->rTPos++; \
if (s->rTPos == 512) s->rTPos = 0; \
} \
s->rNToGo--;
/*-- Stuff for doing CRCs. --*/
extern UInt32 BZ2_crc32Table[256];
#define BZ_INITIALISE_CRC(crcVar) \
{ \
crcVar = 0xffffffffL; \
}
#define BZ_FINALISE_CRC(crcVar) \
{ \
crcVar = ~(crcVar); \
}
#define BZ_UPDATE_CRC(crcVar,cha) \
{ \
crcVar = (crcVar << 8) ^ \
BZ2_crc32Table[(crcVar >> 24) ^ \
((UChar)cha)]; \
}
/*-- States and modes for compression. --*/
#define BZ_M_IDLE 1
#define BZ_M_RUNNING 2
#define BZ_M_FLUSHING 3
#define BZ_M_FINISHING 4
#define BZ_S_OUTPUT 1
#define BZ_S_INPUT 2
#define BZ_N_RADIX 2
#define BZ_N_QSORT 12
#define BZ_N_SHELL 18
#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
/*-- Structure holding all the compression-side stuff. --*/
typedef
struct {
/* pointer back to the struct bz_stream */
bz_stream* strm;
/* mode this stream is in, and whether inputting */
/* or outputting data */
Int32 mode;
Int32 state;
/* remembers avail_in when flush/finish requested */
UInt32 avail_in_expect;
/* for doing the block sorting */
UInt32* arr1;
UInt32* arr2;
UInt32* ftab;
Int32 origPtr;
/* aliases for arr1 and arr2 */
UInt32* ptr;
UChar* block;
UInt16* mtfv;
UChar* zbits;
/* for deciding when to use the fallback sorting algorithm */
Int32 workFactor;
/* run-length-encoding of the input */
UInt32 state_in_ch;
Int32 state_in_len;
BZ_RAND_DECLS;
/* input and output limits and current posns */
Int32 nblock;
Int32 nblockMAX;
Int32 numZ;
Int32 state_out_pos;
/* map of bytes used in block */
Int32 nInUse;
Bool inUse[256];
UChar unseqToSeq[256];
/* the buffer for bit stream creation */
UInt32 bsBuff;
Int32 bsLive;
/* block and combined CRCs */
UInt32 blockCRC;
UInt32 combinedCRC;
/* misc administratium */
Int32 verbosity;
Int32 blockNo;
Int32 blockSize100k;
/* stuff for coding the MTF values */
Int32 nMTF;
Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
UChar selector [BZ_MAX_SELECTORS];
UChar selectorMtf[BZ_MAX_SELECTORS];
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
/* second dimension: only 3 needed; 4 makes index calculations faster */
UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
}
EState;
/*-- externs for compression. --*/
extern void
BZ2_blockSort ( EState* );
extern void
BZ2_compressBlock ( EState*, Bool );
extern void
BZ2_bsInitWrite ( EState* );
extern void
BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
extern void
BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
/*-- states for decompression. --*/
#define BZ_X_IDLE 1
#define BZ_X_OUTPUT 2
#define BZ_X_MAGIC_1 10
#define BZ_X_MAGIC_2 11
#define BZ_X_MAGIC_3 12
#define BZ_X_MAGIC_4 13
#define BZ_X_BLKHDR_1 14
#define BZ_X_BLKHDR_2 15
#define BZ_X_BLKHDR_3 16
#define BZ_X_BLKHDR_4 17
#define BZ_X_BLKHDR_5 18
#define BZ_X_BLKHDR_6 19
#define BZ_X_BCRC_1 20
#define BZ_X_BCRC_2 21
#define BZ_X_BCRC_3 22
#define BZ_X_BCRC_4 23
#define BZ_X_RANDBIT 24
#define BZ_X_ORIGPTR_1 25
#define BZ_X_ORIGPTR_2 26
#define BZ_X_ORIGPTR_3 27
#define BZ_X_MAPPING_1 28
#define BZ_X_MAPPING_2 29
#define BZ_X_SELECTOR_1 30
#define BZ_X_SELECTOR_2 31
#define BZ_X_SELECTOR_3 32
#define BZ_X_CODING_1 33
#define BZ_X_CODING_2 34
#define BZ_X_CODING_3 35
#define BZ_X_MTF_1 36
#define BZ_X_MTF_2 37
#define BZ_X_MTF_3 38
#define BZ_X_MTF_4 39
#define BZ_X_MTF_5 40
#define BZ_X_MTF_6 41
#define BZ_X_ENDHDR_2 42
#define BZ_X_ENDHDR_3 43
#define BZ_X_ENDHDR_4 44
#define BZ_X_ENDHDR_5 45
#define BZ_X_ENDHDR_6 46
#define BZ_X_CCRC_1 47
#define BZ_X_CCRC_2 48
#define BZ_X_CCRC_3 49
#define BZ_X_CCRC_4 50
/*-- Constants for the fast MTF decoder. --*/
#define MTFA_SIZE 4096
#define MTFL_SIZE 16
/*-- Structure holding all the decompression-side stuff. --*/
typedef
struct {
/* pointer back to the struct bz_stream */
bz_stream* strm;
/* state indicator for this stream */
Int32 state;
/* for doing the final run-length decoding */
UChar state_out_ch;
Int32 state_out_len;
Bool blockRandomised;
BZ_RAND_DECLS;
/* the buffer for bit stream reading */
UInt32 bsBuff;
Int32 bsLive;
/* misc administratium */
Int32 blockSize100k;
Bool smallDecompress;
Int32 currBlockNo;
Int32 verbosity;
/* for undoing the Burrows-Wheeler transform */
Int32 origPtr;
UInt32 tPos;
Int32 k0;
Int32 unzftab[256];
Int32 nblock_used;
Int32 cftab[257];
Int32 cftabCopy[257];
/* for undoing the Burrows-Wheeler transform (FAST) */
UInt32 *tt;
/* for undoing the Burrows-Wheeler transform (SMALL) */
UInt16 *ll16;
UChar *ll4;
/* stored and calculated CRCs */
UInt32 storedBlockCRC;
UInt32 storedCombinedCRC;
UInt32 calculatedBlockCRC;
UInt32 calculatedCombinedCRC;
/* map of bytes used in block */
Int32 nInUse;
Bool inUse[256];
Bool inUse16[16];
UChar seqToUnseq[256];
/* for decoding the MTF values */
UChar mtfa [MTFA_SIZE];
Int32 mtfbase[256 / MTFL_SIZE];
UChar selector [BZ_MAX_SELECTORS];
UChar selectorMtf[BZ_MAX_SELECTORS];
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 minLens[BZ_N_GROUPS];
/* save area for scalars in the main decompress code */
Int32 save_i;
Int32 save_j;
Int32 save_t;
Int32 save_alphaSize;
Int32 save_nGroups;
Int32 save_nSelectors;
Int32 save_EOB;
Int32 save_groupNo;
Int32 save_groupPos;
Int32 save_nextSym;
Int32 save_nblockMAX;
Int32 save_nblock;
Int32 save_es;
Int32 save_N;
Int32 save_curr;
Int32 save_zt;
Int32 save_zn;
Int32 save_zvec;
Int32 save_zj;
Int32 save_gSel;
Int32 save_gMinlen;
Int32* save_gLimit;
Int32* save_gBase;
Int32* save_gPerm;
}
DState;
/*-- Macros for decompression. --*/
#define BZ_GET_FAST(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
s->tPos = s->tt[s->tPos]; \
cccc = (UChar)(s->tPos & 0xff); \
s->tPos >>= 8;
#define BZ_GET_FAST_C(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
c_tPos = c_tt[c_tPos]; \
cccc = (UChar)(c_tPos & 0xff); \
c_tPos >>= 8;
#define SET_LL4(i,n) \
{ if (((i) & 0x1) == 0) \
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
}
#define GET_LL4(i) \
((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
#define SET_LL(i,n) \
{ s->ll16[i] = (UInt16)(n & 0x0000ffff); \
SET_LL4(i, n >> 16); \
}
#define GET_LL(i) \
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
#define BZ_GET_SMALL(cccc) \
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
s->tPos = GET_LL(s->tPos);
/*-- externs for decompression. --*/
extern Int32
BZ2_indexIntoF ( Int32, Int32* );
extern Int32
BZ2_decompress ( DState* );
extern void
BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
Int32, Int32, Int32 );
#endif
/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
#ifdef BZ_NO_STDIO
#ifndef NULL
#define NULL 0
#endif
#endif
#ifndef WIN32
#define _fdopen fdopen
#endif
/*-------------------------------------------------------------*/
/*--- end bzlib_private.h ---*/
/*-------------------------------------------------------------*/

672
utils/bzip2/compress.c Normal file
View file

@ -0,0 +1,672 @@
/*-------------------------------------------------------------*/
/*--- Compression machinery (not incl block sorting) ---*/
/*--- compress.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
/* CHANGES
0.9.0 -- original version.
0.9.0a/b -- no changes in this file.
0.9.0c -- changed setting of nGroups in sendMTFValues()
so as to do a bit better on small files
*/
#include "bzlib_private.h"
/*---------------------------------------------------*/
/*--- Bit stream I/O ---*/
/*---------------------------------------------------*/
/*---------------------------------------------------*/
void BZ2_bsInitWrite ( EState* s )
{
s->bsLive = 0;
s->bsBuff = 0;
}
/*---------------------------------------------------*/
static
void bsFinishWrite ( EState* s )
{
while (s->bsLive > 0) {
s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
s->numZ++;
s->bsBuff <<= 8;
s->bsLive -= 8;
}
}
/*---------------------------------------------------*/
#define bsNEEDW(nz) \
{ \
while (s->bsLive >= 8) { \
s->zbits[s->numZ] \
= (UChar)(s->bsBuff >> 24); \
s->numZ++; \
s->bsBuff <<= 8; \
s->bsLive -= 8; \
} \
}
/*---------------------------------------------------*/
static
__inline__
void bsW ( EState* s, Int32 n, UInt32 v )
{
bsNEEDW ( n );
s->bsBuff |= (v << (32 - s->bsLive - n));
s->bsLive += n;
}
/*---------------------------------------------------*/
static
void bsPutUInt32 ( EState* s, UInt32 u )
{
bsW ( s, 8, (u >> 24) & 0xffL );
bsW ( s, 8, (u >> 16) & 0xffL );
bsW ( s, 8, (u >> 8) & 0xffL );
bsW ( s, 8, u & 0xffL );
}
/*---------------------------------------------------*/
static
void bsPutUChar ( EState* s, UChar c )
{
bsW( s, 8, (UInt32)c );
}
/*---------------------------------------------------*/
/*--- The back end proper ---*/
/*---------------------------------------------------*/
/*---------------------------------------------------*/
static
void makeMaps_e ( EState* s )
{
Int32 i;
s->nInUse = 0;
for (i = 0; i < 256; i++)
if (s->inUse[i]) {
s->unseqToSeq[i] = s->nInUse;
s->nInUse++;
}
}
/*---------------------------------------------------*/
static
void generateMTFValues ( EState* s )
{
UChar yy[256];
Int32 i, j;
Int32 zPend;
Int32 wr;
Int32 EOB;
/*
After sorting (eg, here),
s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
and
((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
holds the original block data.
The first thing to do is generate the MTF values,
and put them in
((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
Because there are strictly fewer or equal MTF values
than block values, ptr values in this area are overwritten
with MTF values only when they are no longer needed.
The final compressed bitstream is generated into the
area starting at
(UChar*) (&((UChar*)s->arr2)[s->nblock])
These storage aliases are set up in bzCompressInit(),
except for the last one, which is arranged in
compressBlock().
*/
UInt32* ptr = s->ptr;
UChar* block = s->block;
UInt16* mtfv = s->mtfv;
makeMaps_e ( s );
EOB = s->nInUse+1;
for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
wr = 0;
zPend = 0;
for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
for (i = 0; i < s->nblock; i++) {
UChar ll_i;
AssertD ( wr <= i, "generateMTFValues(1)" );
j = ptr[i]-1; if (j < 0) j += s->nblock;
ll_i = s->unseqToSeq[block[j]];
AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
if (yy[0] == ll_i) {
zPend++;
} else {
if (zPend > 0) {
zPend--;
while (True) {
if (zPend & 1) {
mtfv[wr] = BZ_RUNB; wr++;
s->mtfFreq[BZ_RUNB]++;
} else {
mtfv[wr] = BZ_RUNA; wr++;
s->mtfFreq[BZ_RUNA]++;
}
if (zPend < 2) break;
zPend = (zPend - 2) / 2;
};
zPend = 0;
}
{
register UChar rtmp;
register UChar* ryy_j;
register UChar rll_i;
rtmp = yy[1];
yy[1] = yy[0];
ryy_j = &(yy[1]);
rll_i = ll_i;
while ( rll_i != rtmp ) {
register UChar rtmp2;
ryy_j++;
rtmp2 = rtmp;
rtmp = *ryy_j;
*ryy_j = rtmp2;
};
yy[0] = rtmp;
j = ryy_j - &(yy[0]);
mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
}
}
}
if (zPend > 0) {
zPend--;
while (True) {
if (zPend & 1) {
mtfv[wr] = BZ_RUNB; wr++;
s->mtfFreq[BZ_RUNB]++;
} else {
mtfv[wr] = BZ_RUNA; wr++;
s->mtfFreq[BZ_RUNA]++;
}
if (zPend < 2) break;
zPend = (zPend - 2) / 2;
};
zPend = 0;
}
mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
s->nMTF = wr;
}
/*---------------------------------------------------*/
#define BZ_LESSER_ICOST 0
#define BZ_GREATER_ICOST 15
static
void sendMTFValues ( EState* s )
{
Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
Int32 nGroups, nBytes;
/*--
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
is a global since the decoder also needs it.
Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
are also globals only used in this proc.
Made global to keep stack frame size small.
--*/
UInt16 cost[BZ_N_GROUPS];
Int32 fave[BZ_N_GROUPS];
UInt16* mtfv = s->mtfv;
if (s->verbosity >= 3)
VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
"%d+2 syms in use\n",
s->nblock, s->nMTF, s->nInUse );
alphaSize = s->nInUse+2;
for (t = 0; t < BZ_N_GROUPS; t++)
for (v = 0; v < alphaSize; v++)
s->len[t][v] = BZ_GREATER_ICOST;
/*--- Decide how many coding tables to use ---*/
AssertH ( s->nMTF > 0, 3001 );
if (s->nMTF < 200) nGroups = 2; else
if (s->nMTF < 600) nGroups = 3; else
if (s->nMTF < 1200) nGroups = 4; else
if (s->nMTF < 2400) nGroups = 5; else
nGroups = 6;
/*--- Generate an initial set of coding tables ---*/
{
Int32 nPart, remF, tFreq, aFreq;
nPart = nGroups;
remF = s->nMTF;
gs = 0;
while (nPart > 0) {
tFreq = remF / nPart;
ge = gs-1;
aFreq = 0;
while (aFreq < tFreq && ge < alphaSize-1) {
ge++;
aFreq += s->mtfFreq[ge];
}
if (ge > gs
&& nPart != nGroups && nPart != 1
&& ((nGroups-nPart) % 2 == 1)) {
aFreq -= s->mtfFreq[ge];
ge--;
}
if (s->verbosity >= 3)
VPrintf5( " initial group %d, [%d .. %d], "
"has %d syms (%4.1f%%)\n",
nPart, gs, ge, aFreq,
(100.0 * (float)aFreq) / (float)(s->nMTF) );
for (v = 0; v < alphaSize; v++)
if (v >= gs && v <= ge)
s->len[nPart-1][v] = BZ_LESSER_ICOST; else
s->len[nPart-1][v] = BZ_GREATER_ICOST;
nPart--;
gs = ge+1;
remF -= aFreq;
}
}
/*---
Iterate up to BZ_N_ITERS times to improve the tables.
---*/
for (iter = 0; iter < BZ_N_ITERS; iter++) {
for (t = 0; t < nGroups; t++) fave[t] = 0;
for (t = 0; t < nGroups; t++)
for (v = 0; v < alphaSize; v++)
s->rfreq[t][v] = 0;
/*---
Set up an auxiliary length table which is used to fast-track
the common case (nGroups == 6).
---*/
if (nGroups == 6) {
for (v = 0; v < alphaSize; v++) {
s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
}
}
nSelectors = 0;
totc = 0;
gs = 0;
while (True) {
/*--- Set group start & end marks. --*/
if (gs >= s->nMTF) break;
ge = gs + BZ_G_SIZE - 1;
if (ge >= s->nMTF) ge = s->nMTF-1;
/*--
Calculate the cost of this group as coded
by each of the coding tables.
--*/
for (t = 0; t < nGroups; t++) cost[t] = 0;
if (nGroups == 6 && 50 == ge-gs+1) {
/*--- fast track the common case ---*/
register UInt32 cost01, cost23, cost45;
register UInt16 icv;
cost01 = cost23 = cost45 = 0;
# define BZ_ITER(nn) \
icv = mtfv[gs+(nn)]; \
cost01 += s->len_pack[icv][0]; \
cost23 += s->len_pack[icv][1]; \
cost45 += s->len_pack[icv][2]; \
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
# undef BZ_ITER
cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
} else {
/*--- slow version which correctly handles all situations ---*/
for (i = gs; i <= ge; i++) {
UInt16 icv = mtfv[i];
for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
}
}
/*--
Find the coding table which is best for this group,
and record its identity in the selector table.
--*/
bc = 999999999; bt = -1;
for (t = 0; t < nGroups; t++)
if (cost[t] < bc) { bc = cost[t]; bt = t; };
totc += bc;
fave[bt]++;
s->selector[nSelectors] = bt;
nSelectors++;
/*--
Increment the symbol frequencies for the selected table.
--*/
if (nGroups == 6 && 50 == ge-gs+1) {
/*--- fast track the common case ---*/
# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
# undef BZ_ITUR
} else {
/*--- slow version which correctly handles all situations ---*/
for (i = gs; i <= ge; i++)
s->rfreq[bt][ mtfv[i] ]++;
}
gs = ge+1;
}
if (s->verbosity >= 3) {
VPrintf2 ( " pass %d: size is %d, grp uses are ",
iter+1, totc/8 );
for (t = 0; t < nGroups; t++)
VPrintf1 ( "%d ", fave[t] );
VPrintf0 ( "\n" );
}
/*--
Recompute the tables based on the accumulated frequencies.
--*/
/* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
comment in huffman.c for details. */
for (t = 0; t < nGroups; t++)
BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
alphaSize, 17 /*20*/ );
}
AssertH( nGroups < 8, 3002 );
AssertH( nSelectors < 32768 &&
nSelectors <= (2 + (900000 / BZ_G_SIZE)),
3003 );
/*--- Compute MTF values for the selectors. ---*/
{
UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
for (i = 0; i < nGroups; i++) pos[i] = i;
for (i = 0; i < nSelectors; i++) {
ll_i = s->selector[i];
j = 0;
tmp = pos[j];
while ( ll_i != tmp ) {
j++;
tmp2 = tmp;
tmp = pos[j];
pos[j] = tmp2;
};
pos[0] = tmp;
s->selectorMtf[i] = j;
}
};
/*--- Assign actual codes for the tables. --*/
for (t = 0; t < nGroups; t++) {
minLen = 32;
maxLen = 0;
for (i = 0; i < alphaSize; i++) {
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
if (s->len[t][i] < minLen) minLen = s->len[t][i];
}
AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
AssertH ( !(minLen < 1), 3005 );
BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
minLen, maxLen, alphaSize );
}
/*--- Transmit the mapping table. ---*/
{
Bool inUse16[16];
for (i = 0; i < 16; i++) {
inUse16[i] = False;
for (j = 0; j < 16; j++)
if (s->inUse[i * 16 + j]) inUse16[i] = True;
}
nBytes = s->numZ;
for (i = 0; i < 16; i++)
if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
for (i = 0; i < 16; i++)
if (inUse16[i])
for (j = 0; j < 16; j++) {
if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
}
if (s->verbosity >= 3)
VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
}
/*--- Now the selectors. ---*/
nBytes = s->numZ;
bsW ( s, 3, nGroups );
bsW ( s, 15, nSelectors );
for (i = 0; i < nSelectors; i++) {
for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
bsW(s,1,0);
}
if (s->verbosity >= 3)
VPrintf1( "selectors %d, ", s->numZ-nBytes );
/*--- Now the coding tables. ---*/
nBytes = s->numZ;
for (t = 0; t < nGroups; t++) {
Int32 curr = s->len[t][0];
bsW ( s, 5, curr );
for (i = 0; i < alphaSize; i++) {
while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
bsW ( s, 1, 0 );
}
}
if (s->verbosity >= 3)
VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
/*--- And finally, the block data proper ---*/
nBytes = s->numZ;
selCtr = 0;
gs = 0;
while (True) {
if (gs >= s->nMTF) break;
ge = gs + BZ_G_SIZE - 1;
if (ge >= s->nMTF) ge = s->nMTF-1;
AssertH ( s->selector[selCtr] < nGroups, 3006 );
if (nGroups == 6 && 50 == ge-gs+1) {
/*--- fast track the common case ---*/
UInt16 mtfv_i;
UChar* s_len_sel_selCtr
= &(s->len[s->selector[selCtr]][0]);
Int32* s_code_sel_selCtr
= &(s->code[s->selector[selCtr]][0]);
# define BZ_ITAH(nn) \
mtfv_i = mtfv[gs+(nn)]; \
bsW ( s, \
s_len_sel_selCtr[mtfv_i], \
s_code_sel_selCtr[mtfv_i] )
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
# undef BZ_ITAH
} else {
/*--- slow version which correctly handles all situations ---*/
for (i = gs; i <= ge; i++) {
bsW ( s,
s->len [s->selector[selCtr]] [mtfv[i]],
s->code [s->selector[selCtr]] [mtfv[i]] );
}
}
gs = ge+1;
selCtr++;
}
AssertH( selCtr == nSelectors, 3007 );
if (s->verbosity >= 3)
VPrintf1( "codes %d\n", s->numZ-nBytes );
}
/*---------------------------------------------------*/
void BZ2_compressBlock ( EState* s, Bool is_last_block )
{
if (s->nblock > 0) {
BZ_FINALISE_CRC ( s->blockCRC );
s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
s->combinedCRC ^= s->blockCRC;
if (s->blockNo > 1) s->numZ = 0;
if (s->verbosity >= 2)
VPrintf4( " block %d: crc = 0x%08x, "
"combined CRC = 0x%08x, size = %d\n",
s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
BZ2_blockSort ( s );
}
s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
/*-- If this is the first block, create the stream header. --*/
if (s->blockNo == 1) {
BZ2_bsInitWrite ( s );
bsPutUChar ( s, BZ_HDR_B );
bsPutUChar ( s, BZ_HDR_Z );
bsPutUChar ( s, BZ_HDR_h );
bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
}
if (s->nblock > 0) {
bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
/*-- Now the block's CRC, so it is in a known place. --*/
bsPutUInt32 ( s, s->blockCRC );
/*--
Now a single bit indicating (non-)randomisation.
As of version 0.9.5, we use a better sorting algorithm
which makes randomisation unnecessary. So always set
the randomised bit to 'no'. Of course, the decoder
still needs to be able to handle randomised blocks
so as to maintain backwards compatibility with
older versions of bzip2.
--*/
bsW(s,1,0);
bsW ( s, 24, s->origPtr );
generateMTFValues ( s );
sendMTFValues ( s );
}
/*-- If this is the last block, add the stream trailer. --*/
if (is_last_block) {
bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
bsPutUInt32 ( s, s->combinedCRC );
if (s->verbosity >= 2)
VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
bsFinishWrite ( s );
}
}
/*-------------------------------------------------------------*/
/*--- end compress.c ---*/
/*-------------------------------------------------------------*/

104
utils/bzip2/crctable.c Normal file
View file

@ -0,0 +1,104 @@
/*-------------------------------------------------------------*/
/*--- Table for doing CRCs ---*/
/*--- crctable.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*--
I think this is an implementation of the AUTODIN-II,
Ethernet & FDDI 32-bit CRC standard. Vaguely derived
from code by Rob Warnock, in Section 51 of the
comp.compression FAQ.
--*/
UInt32 BZ2_crc32Table[256] = {
/*-- Ugly, innit? --*/
0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
};
/*-------------------------------------------------------------*/
/*--- end crctable.c ---*/
/*-------------------------------------------------------------*/

646
utils/bzip2/decompress.c Normal file
View file

@ -0,0 +1,646 @@
/*-------------------------------------------------------------*/
/*--- Decompression machinery ---*/
/*--- decompress.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*---------------------------------------------------*/
static
void makeMaps_d ( DState* s )
{
Int32 i;
s->nInUse = 0;
for (i = 0; i < 256; i++)
if (s->inUse[i]) {
s->seqToUnseq[s->nInUse] = i;
s->nInUse++;
}
}
/*---------------------------------------------------*/
#define RETURN(rrr) \
{ retVal = rrr; goto save_state_and_return; };
#define GET_BITS(lll,vvv,nnn) \
case lll: s->state = lll; \
while (True) { \
if (s->bsLive >= nnn) { \
UInt32 v; \
v = (s->bsBuff >> \
(s->bsLive-nnn)) & ((1 << nnn)-1); \
s->bsLive -= nnn; \
vvv = v; \
break; \
} \
if (s->strm->avail_in == 0) RETURN(BZ_OK); \
s->bsBuff \
= (s->bsBuff << 8) | \
((UInt32) \
(*((UChar*)(s->strm->next_in)))); \
s->bsLive += 8; \
s->strm->next_in++; \
s->strm->avail_in--; \
s->strm->total_in_lo32++; \
if (s->strm->total_in_lo32 == 0) \
s->strm->total_in_hi32++; \
}
#define GET_UCHAR(lll,uuu) \
GET_BITS(lll,uuu,8)
#define GET_BIT(lll,uuu) \
GET_BITS(lll,uuu,1)
/*---------------------------------------------------*/
#define GET_MTF_VAL(label1,label2,lval) \
{ \
if (groupPos == 0) { \
groupNo++; \
if (groupNo >= nSelectors) \
RETURN(BZ_DATA_ERROR); \
groupPos = BZ_G_SIZE; \
gSel = s->selector[groupNo]; \
gMinlen = s->minLens[gSel]; \
gLimit = &(s->limit[gSel][0]); \
gPerm = &(s->perm[gSel][0]); \
gBase = &(s->base[gSel][0]); \
} \
groupPos--; \
zn = gMinlen; \
GET_BITS(label1, zvec, zn); \
while (1) { \
if (zn > 20 /* the longest code */) \
RETURN(BZ_DATA_ERROR); \
if (zvec <= gLimit[zn]) break; \
zn++; \
GET_BIT(label2, zj); \
zvec = (zvec << 1) | zj; \
}; \
if (zvec - gBase[zn] < 0 \
|| zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
RETURN(BZ_DATA_ERROR); \
lval = gPerm[zvec - gBase[zn]]; \
}
/*---------------------------------------------------*/
Int32 BZ2_decompress ( DState* s )
{
UChar uc;
Int32 retVal;
Int32 minLen, maxLen;
bz_stream* strm = s->strm;
/* stuff that needs to be saved/restored */
Int32 i;
Int32 j;
Int32 t;
Int32 alphaSize;
Int32 nGroups;
Int32 nSelectors;
Int32 EOB;
Int32 groupNo;
Int32 groupPos;
Int32 nextSym;
Int32 nblockMAX;
Int32 nblock;
Int32 es;
Int32 N;
Int32 curr;
Int32 zt;
Int32 zn;
Int32 zvec;
Int32 zj;
Int32 gSel;
Int32 gMinlen;
Int32* gLimit;
Int32* gBase;
Int32* gPerm;
if (s->state == BZ_X_MAGIC_1) {
/*initialise the save area*/
s->save_i = 0;
s->save_j = 0;
s->save_t = 0;
s->save_alphaSize = 0;
s->save_nGroups = 0;
s->save_nSelectors = 0;
s->save_EOB = 0;
s->save_groupNo = 0;
s->save_groupPos = 0;
s->save_nextSym = 0;
s->save_nblockMAX = 0;
s->save_nblock = 0;
s->save_es = 0;
s->save_N = 0;
s->save_curr = 0;
s->save_zt = 0;
s->save_zn = 0;
s->save_zvec = 0;
s->save_zj = 0;
s->save_gSel = 0;
s->save_gMinlen = 0;
s->save_gLimit = NULL;
s->save_gBase = NULL;
s->save_gPerm = NULL;
}
/*restore from the save area*/
i = s->save_i;
j = s->save_j;
t = s->save_t;
alphaSize = s->save_alphaSize;
nGroups = s->save_nGroups;
nSelectors = s->save_nSelectors;
EOB = s->save_EOB;
groupNo = s->save_groupNo;
groupPos = s->save_groupPos;
nextSym = s->save_nextSym;
nblockMAX = s->save_nblockMAX;
nblock = s->save_nblock;
es = s->save_es;
N = s->save_N;
curr = s->save_curr;
zt = s->save_zt;
zn = s->save_zn;
zvec = s->save_zvec;
zj = s->save_zj;
gSel = s->save_gSel;
gMinlen = s->save_gMinlen;
gLimit = s->save_gLimit;
gBase = s->save_gBase;
gPerm = s->save_gPerm;
retVal = BZ_OK;
switch (s->state) {
GET_UCHAR(BZ_X_MAGIC_1, uc);
if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
GET_UCHAR(BZ_X_MAGIC_2, uc);
if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
GET_UCHAR(BZ_X_MAGIC_3, uc)
if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
if (s->blockSize100k < (BZ_HDR_0 + 1) ||
s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
s->blockSize100k -= BZ_HDR_0;
if (s->smallDecompress) {
s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
s->ll4 = BZALLOC(
((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
);
if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
} else {
s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
}
GET_UCHAR(BZ_X_BLKHDR_1, uc);
if (uc == 0x17) goto endhdr_2;
if (uc != 0x31) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_2, uc);
if (uc != 0x41) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_3, uc);
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_4, uc);
if (uc != 0x26) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_5, uc);
if (uc != 0x53) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_6, uc);
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
s->currBlockNo++;
if (s->verbosity >= 2)
VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
s->storedBlockCRC = 0;
GET_UCHAR(BZ_X_BCRC_1, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_BCRC_2, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_BCRC_3, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_BCRC_4, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
s->origPtr = 0;
GET_UCHAR(BZ_X_ORIGPTR_1, uc);
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
GET_UCHAR(BZ_X_ORIGPTR_2, uc);
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
GET_UCHAR(BZ_X_ORIGPTR_3, uc);
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
if (s->origPtr < 0)
RETURN(BZ_DATA_ERROR);
if (s->origPtr > 10 + 100000*s->blockSize100k)
RETURN(BZ_DATA_ERROR);
/*--- Receive the mapping table ---*/
for (i = 0; i < 16; i++) {
GET_BIT(BZ_X_MAPPING_1, uc);
if (uc == 1)
s->inUse16[i] = True; else
s->inUse16[i] = False;
}
for (i = 0; i < 256; i++) s->inUse[i] = False;
for (i = 0; i < 16; i++)
if (s->inUse16[i])
for (j = 0; j < 16; j++) {
GET_BIT(BZ_X_MAPPING_2, uc);
if (uc == 1) s->inUse[i * 16 + j] = True;
}
makeMaps_d ( s );
if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
alphaSize = s->nInUse+2;
/*--- Now the selectors ---*/
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
for (i = 0; i < nSelectors; i++) {
j = 0;
while (True) {
GET_BIT(BZ_X_SELECTOR_3, uc);
if (uc == 0) break;
j++;
if (j >= nGroups) RETURN(BZ_DATA_ERROR);
}
s->selectorMtf[i] = j;
}
/*--- Undo the MTF values for the selectors. ---*/
{
UChar pos[BZ_N_GROUPS], tmp, v;
for (v = 0; v < nGroups; v++) pos[v] = v;
for (i = 0; i < nSelectors; i++) {
v = s->selectorMtf[i];
tmp = pos[v];
while (v > 0) { pos[v] = pos[v-1]; v--; }
pos[0] = tmp;
s->selector[i] = tmp;
}
}
/*--- Now the coding tables ---*/
for (t = 0; t < nGroups; t++) {
GET_BITS(BZ_X_CODING_1, curr, 5);
for (i = 0; i < alphaSize; i++) {
while (True) {
if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
GET_BIT(BZ_X_CODING_2, uc);
if (uc == 0) break;
GET_BIT(BZ_X_CODING_3, uc);
if (uc == 0) curr++; else curr--;
}
s->len[t][i] = curr;
}
}
/*--- Create the Huffman decoding tables ---*/
for (t = 0; t < nGroups; t++) {
minLen = 32;
maxLen = 0;
for (i = 0; i < alphaSize; i++) {
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
if (s->len[t][i] < minLen) minLen = s->len[t][i];
}
BZ2_hbCreateDecodeTables (
&(s->limit[t][0]),
&(s->base[t][0]),
&(s->perm[t][0]),
&(s->len[t][0]),
minLen, maxLen, alphaSize
);
s->minLens[t] = minLen;
}
/*--- Now the MTF values ---*/
EOB = s->nInUse+1;
nblockMAX = 100000 * s->blockSize100k;
groupNo = -1;
groupPos = 0;
for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
/*-- MTF init --*/
{
Int32 ii, jj, kk;
kk = MTFA_SIZE-1;
for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
kk--;
}
s->mtfbase[ii] = kk + 1;
}
}
/*-- end MTF init --*/
nblock = 0;
GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
while (True) {
if (nextSym == EOB) break;
if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
es = -1;
N = 1;
do {
/* Check that N doesn't get too big, so that es doesn't
go negative. The maximum value that can be
RUNA/RUNB encoded is equal to the block size (post
the initial RLE), viz, 900k, so bounding N at 2
million should guard against overflow without
rejecting any legitimate inputs. */
if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
if (nextSym == BZ_RUNB) es = es + (1+1) * N;
N = N * 2;
GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
}
while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
es++;
uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
s->unzftab[uc] += es;
if (s->smallDecompress)
while (es > 0) {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
s->ll16[nblock] = (UInt16)uc;
nblock++;
es--;
}
else
while (es > 0) {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
s->tt[nblock] = (UInt32)uc;
nblock++;
es--;
};
continue;
} else {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
/*-- uc = MTF ( nextSym-1 ) --*/
{
Int32 ii, jj, kk, pp, lno, off;
UInt32 nn;
nn = (UInt32)(nextSym - 1);
if (nn < MTFL_SIZE) {
/* avoid general-case expense */
pp = s->mtfbase[0];
uc = s->mtfa[pp+nn];
while (nn > 3) {
Int32 z = pp+nn;
s->mtfa[(z) ] = s->mtfa[(z)-1];
s->mtfa[(z)-1] = s->mtfa[(z)-2];
s->mtfa[(z)-2] = s->mtfa[(z)-3];
s->mtfa[(z)-3] = s->mtfa[(z)-4];
nn -= 4;
}
while (nn > 0) {
s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
};
s->mtfa[pp] = uc;
} else {
/* general case */
lno = nn / MTFL_SIZE;
off = nn % MTFL_SIZE;
pp = s->mtfbase[lno] + off;
uc = s->mtfa[pp];
while (pp > s->mtfbase[lno]) {
s->mtfa[pp] = s->mtfa[pp-1]; pp--;
};
s->mtfbase[lno]++;
while (lno > 0) {
s->mtfbase[lno]--;
s->mtfa[s->mtfbase[lno]]
= s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
lno--;
}
s->mtfbase[0]--;
s->mtfa[s->mtfbase[0]] = uc;
if (s->mtfbase[0] == 0) {
kk = MTFA_SIZE-1;
for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
kk--;
}
s->mtfbase[ii] = kk + 1;
}
}
}
}
/*-- end uc = MTF ( nextSym-1 ) --*/
s->unzftab[s->seqToUnseq[uc]]++;
if (s->smallDecompress)
s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
nblock++;
GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
continue;
}
}
/* Now we know what nblock is, we can do a better sanity
check on s->origPtr.
*/
if (s->origPtr < 0 || s->origPtr >= nblock)
RETURN(BZ_DATA_ERROR);
/*-- Set up cftab to facilitate generation of T^(-1) --*/
/* Check: unzftab entries in range. */
for (i = 0; i <= 255; i++) {
if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
RETURN(BZ_DATA_ERROR);
}
/* Actually generate cftab. */
s->cftab[0] = 0;
for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
/* Check: cftab entries in range. */
for (i = 0; i <= 256; i++) {
if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
/* s->cftab[i] can legitimately be == nblock */
RETURN(BZ_DATA_ERROR);
}
}
/* Check: cftab entries non-descending. */
for (i = 1; i <= 256; i++) {
if (s->cftab[i-1] > s->cftab[i]) {
RETURN(BZ_DATA_ERROR);
}
}
s->state_out_len = 0;
s->state_out_ch = 0;
BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
s->state = BZ_X_OUTPUT;
if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
if (s->smallDecompress) {
/*-- Make a copy of cftab, used in generation of T --*/
for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
/*-- compute the T vector --*/
for (i = 0; i < nblock; i++) {
uc = (UChar)(s->ll16[i]);
SET_LL(i, s->cftabCopy[uc]);
s->cftabCopy[uc]++;
}
/*-- Compute T^(-1) by pointer reversal on T --*/
i = s->origPtr;
j = GET_LL(i);
do {
Int32 tmp = GET_LL(j);
SET_LL(j, i);
i = j;
j = tmp;
}
while (i != s->origPtr);
s->tPos = s->origPtr;
s->nblock_used = 0;
if (s->blockRandomised) {
BZ_RAND_INIT_MASK;
BZ_GET_SMALL(s->k0); s->nblock_used++;
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
} else {
BZ_GET_SMALL(s->k0); s->nblock_used++;
}
} else {
/*-- compute the T^(-1) vector --*/
for (i = 0; i < nblock; i++) {
uc = (UChar)(s->tt[i] & 0xff);
s->tt[s->cftab[uc]] |= (i << 8);
s->cftab[uc]++;
}
s->tPos = s->tt[s->origPtr] >> 8;
s->nblock_used = 0;
if (s->blockRandomised) {
BZ_RAND_INIT_MASK;
BZ_GET_FAST(s->k0); s->nblock_used++;
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
} else {
BZ_GET_FAST(s->k0); s->nblock_used++;
}
}
RETURN(BZ_OK);
endhdr_2:
GET_UCHAR(BZ_X_ENDHDR_2, uc);
if (uc != 0x72) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_3, uc);
if (uc != 0x45) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_4, uc);
if (uc != 0x38) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_5, uc);
if (uc != 0x50) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_6, uc);
if (uc != 0x90) RETURN(BZ_DATA_ERROR);
s->storedCombinedCRC = 0;
GET_UCHAR(BZ_X_CCRC_1, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_CCRC_2, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_CCRC_3, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
GET_UCHAR(BZ_X_CCRC_4, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
s->state = BZ_X_IDLE;
RETURN(BZ_STREAM_END);
default: AssertH ( False, 4001 );
}
AssertH ( False, 4002 );
save_state_and_return:
s->save_i = i;
s->save_j = j;
s->save_t = t;
s->save_alphaSize = alphaSize;
s->save_nGroups = nGroups;
s->save_nSelectors = nSelectors;
s->save_EOB = EOB;
s->save_groupNo = groupNo;
s->save_groupPos = groupPos;
s->save_nextSym = nextSym;
s->save_nblockMAX = nblockMAX;
s->save_nblock = nblock;
s->save_es = es;
s->save_N = N;
s->save_curr = curr;
s->save_zt = zt;
s->save_zn = zn;
s->save_zvec = zvec;
s->save_zj = zj;
s->save_gSel = gSel;
s->save_gMinlen = gMinlen;
s->save_gLimit = gLimit;
s->save_gBase = gBase;
s->save_gPerm = gPerm;
return retVal;
}
/*-------------------------------------------------------------*/
/*--- end decompress.c ---*/
/*-------------------------------------------------------------*/

205
utils/bzip2/huffman.c Normal file
View file

@ -0,0 +1,205 @@
/*-------------------------------------------------------------*/
/*--- Huffman coding low-level stuff ---*/
/*--- huffman.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*---------------------------------------------------*/
#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
#define ADDWEIGHTS(zw1,zw2) \
(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
#define UPHEAP(z) \
{ \
Int32 zz, tmp; \
zz = z; tmp = heap[zz]; \
while (weight[tmp] < weight[heap[zz >> 1]]) { \
heap[zz] = heap[zz >> 1]; \
zz >>= 1; \
} \
heap[zz] = tmp; \
}
#define DOWNHEAP(z) \
{ \
Int32 zz, yy, tmp; \
zz = z; tmp = heap[zz]; \
while (True) { \
yy = zz << 1; \
if (yy > nHeap) break; \
if (yy < nHeap && \
weight[heap[yy+1]] < weight[heap[yy]]) \
yy++; \
if (weight[tmp] < weight[heap[yy]]) break; \
heap[zz] = heap[yy]; \
zz = yy; \
} \
heap[zz] = tmp; \
}
/*---------------------------------------------------*/
void BZ2_hbMakeCodeLengths ( UChar *len,
Int32 *freq,
Int32 alphaSize,
Int32 maxLen )
{
/*--
Nodes and heap entries run from 1. Entry 0
for both the heap and nodes is a sentinel.
--*/
Int32 nNodes, nHeap, n1, n2, i, j, k;
Bool tooLong;
Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
for (i = 0; i < alphaSize; i++)
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
while (True) {
nNodes = alphaSize;
nHeap = 0;
heap[0] = 0;
weight[0] = 0;
parent[0] = -2;
for (i = 1; i <= alphaSize; i++) {
parent[i] = -1;
nHeap++;
heap[nHeap] = i;
UPHEAP(nHeap);
}
AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
while (nHeap > 1) {
n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
nNodes++;
parent[n1] = parent[n2] = nNodes;
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
parent[nNodes] = -1;
nHeap++;
heap[nHeap] = nNodes;
UPHEAP(nHeap);
}
AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
tooLong = False;
for (i = 1; i <= alphaSize; i++) {
j = 0;
k = i;
while (parent[k] >= 0) { k = parent[k]; j++; }
len[i-1] = j;
if (j > maxLen) tooLong = True;
}
if (! tooLong) break;
/* 17 Oct 04: keep-going condition for the following loop used
to be 'i < alphaSize', which missed the last element,
theoretically leading to the possibility of the compressor
looping. However, this count-scaling step is only needed if
one of the generated Huffman code words is longer than
maxLen, which up to and including version 1.0.2 was 20 bits,
which is extremely unlikely. In version 1.0.3 maxLen was
changed to 17 bits, which has minimal effect on compression
ratio, but does mean this scaling step is used from time to
time, enough to verify that it works.
This means that bzip2-1.0.3 and later will only produce
Huffman codes with a maximum length of 17 bits. However, in
order to preserve backwards compatibility with bitstreams
produced by versions pre-1.0.3, the decompressor must still
handle lengths of up to 20. */
for (i = 1; i <= alphaSize; i++) {
j = weight[i] >> 8;
j = 1 + (j / 2);
weight[i] = j << 8;
}
}
}
/*---------------------------------------------------*/
void BZ2_hbAssignCodes ( Int32 *code,
UChar *length,
Int32 minLen,
Int32 maxLen,
Int32 alphaSize )
{
Int32 n, vec, i;
vec = 0;
for (n = minLen; n <= maxLen; n++) {
for (i = 0; i < alphaSize; i++)
if (length[i] == n) { code[i] = vec; vec++; };
vec <<= 1;
}
}
/*---------------------------------------------------*/
void BZ2_hbCreateDecodeTables ( Int32 *limit,
Int32 *base,
Int32 *perm,
UChar *length,
Int32 minLen,
Int32 maxLen,
Int32 alphaSize )
{
Int32 pp, i, j, vec;
pp = 0;
for (i = minLen; i <= maxLen; i++)
for (j = 0; j < alphaSize; j++)
if (length[j] == i) { perm[pp] = j; pp++; };
for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
vec = 0;
for (i = minLen; i <= maxLen; i++) {
vec += (base[i+1] - base[i]);
limit[i] = vec-1;
vec <<= 1;
}
for (i = minLen + 1; i <= maxLen; i++)
base[i] = ((limit[i-1] + 1) << 1) - base[i];
}
/*-------------------------------------------------------------*/
/*--- end huffman.c ---*/
/*-------------------------------------------------------------*/

84
utils/bzip2/randtable.c Normal file
View file

@ -0,0 +1,84 @@
/*-------------------------------------------------------------*/
/*--- Table for randomising repetitive blocks ---*/
/*--- randtable.c ---*/
/*-------------------------------------------------------------*/
/* ------------------------------------------------------------------
This file is part of bzip2/libbzip2, a program and library for
lossless, block-sorting data compression.
bzip2/libbzip2 version 1.0.6 of 6 September 2010
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
Please read the WARNING, DISCLAIMER and PATENTS sections in the
README file.
This program is released under the terms of the license contained
in the file LICENSE.
------------------------------------------------------------------ */
#include "bzlib_private.h"
/*---------------------------------------------*/
Int32 BZ2_rNums[512] = {
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
936, 638
};
/*-------------------------------------------------------------*/
/*--- end randtable.c ---*/
/*-------------------------------------------------------------*/

View file

@ -0,0 +1,17 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
CFLAGS += -g -Wall
OUTPUT = chinachippatcher
LIBSOURCES = chinachip.c
SOURCES = main.c
include ../libtools.make

View file

@ -0,0 +1,258 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 by Maurus Cuelenaere
*
* 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 <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "chinachip.h"
/* From http://www.rockbox.org/wiki/ChinaChip */
struct header
{
uint32_t signature; /* WADF */
uint32_t unk;
int8_t timestamp[12]; /* 200805081100 */
uint32_t size;
uint32_t checksum;
uint32_t unk2;
int8_t identifier[32]; /* Chinachip PMP firmware V1.0 */
} __attribute__ ((packed));
static inline void int2le(unsigned char* addr, unsigned int val)
{
addr[0] = val & 0xff;
addr[1] = (val >> 8) & 0xff;
addr[2] = (val >> 16) & 0xff;
addr[3] = (val >> 24) & 0xff;
}
static inline unsigned int le2int(unsigned char* buf)
{
return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
}
static long int filesize(FILE* fd)
{
long int len;
fseek(fd, 0, SEEK_END);
len = ftell(fd);
fseek(fd, 0, SEEK_SET);
return len;
}
#define FCLOSE(fd) fclose(fd); fd = NULL;
#define CCPMPBIN_HEADER_SIZE (sizeof(uint32_t)*2 + sizeof(uint8_t) + 9)
#define TOTAL_SIZE (fsize + CCPMPBIN_HEADER_SIZE + bsize)
enum cc_error chinachip_patch(const char* firmware, const char* bootloader,
const char* output, const char* ccpmp_backup)
{
char header_time[13];
time_t cur_time;
struct tm* time_info;
unsigned char* buf = NULL;
FILE *fd = NULL, *bd = NULL, *od = NULL;
unsigned int ccpmp_size = 0, i, fsize, bsize;
signed int checksum = 0, ccpmp_pos;
int result = E_OK;
fd = fopen(firmware, "rb");
if(!fd)
{
fprintf(stderr, "[ERR] Can't open file %s!\n", firmware);
result = E_OPEN_FIRMWARE;
goto err;
}
bd = fopen(bootloader, "rb");
if(!bd)
{
fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader);
result = E_OPEN_BOOTLOADER;
goto err;
}
bsize = filesize(bd);
fprintf(stderr, "[INFO] Bootloader size is %d bytes\n", bsize);
FCLOSE(bd);
fsize = filesize(fd);
fprintf(stderr, "[INFO] Firmware size is %d bytes\n", fsize);
buf = malloc(TOTAL_SIZE);
if(buf == NULL)
{
fprintf(stderr, "[ERR] Can't allocate %d bytes!\n", fsize);
result = E_MEMALLOC;
goto err;
}
memset(buf, 0, TOTAL_SIZE);
fprintf(stderr, "[INFO] Reading %s into memory...\n", firmware);
if(fread(buf, fsize, 1, fd) != 1)
{
fprintf(stderr, "[ERR] Can't read file %s to memory!\n", firmware);
result = E_LOAD_FIRMWARE;
goto err;
}
FCLOSE(fd);
if(memcmp(buf, "WADF", 4))
{
fprintf(stderr, "[ERR] File %s isn't a valid ChinaChip firmware!\n", firmware);
result = E_INVALID_FILE;
goto err;
}
ccpmp_pos = -1, i = 0x40;
do
{
int filenamesize = le2int(&buf[i]);
i += sizeof(uint32_t);
if(!strncmp((char*) &buf[i], "ccpmp.bin", 9))
{
ccpmp_pos = i;
ccpmp_size = le2int(&buf[i + sizeof(uint8_t) + filenamesize]);
}
else
i += filenamesize + le2int(&buf[i + sizeof(uint8_t) + filenamesize])
+ sizeof(uint32_t) + sizeof(uint8_t);
} while(ccpmp_pos < 0 && i < fsize);
if(i >= fsize)
{
fprintf(stderr, "[ERR] Couldn't find ccpmp.bin in %s!\n", firmware);
result = E_NO_CCPMP;
goto err;
}
fprintf(stderr, "[INFO] Found ccpmp.bin at %d bytes\n", ccpmp_pos);
if(ccpmp_backup)
{
int ccpmp_data_pos = ccpmp_pos + 9;
bd = fopen(ccpmp_backup, "wb");
if(!bd)
{
fprintf(stderr, "[ERR] Can't open file %s!\n", ccpmp_backup);
result = E_OPEN_BACKUP;
goto err;
}
fprintf(stderr, "[INFO] Writing %d bytes to %s...\n", ccpmp_size, ccpmp_backup);
if(fwrite(&buf[ccpmp_data_pos], ccpmp_size, 1, bd) != 1)
{
fprintf(stderr, "[ERR] Can't write to file %s!\n", ccpmp_backup);
result = E_WRITE_BACKUP;
goto err;
}
FCLOSE(bd);
}
fprintf(stderr, "[INFO] Renaming it to ccpmp.old...\n");
buf[ccpmp_pos + 6] = 'o';
buf[ccpmp_pos + 7] = 'l';
buf[ccpmp_pos + 8] = 'd';
bd = fopen(bootloader, "rb");
if(!bd)
{
fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader);
result = E_OPEN_BOOTLOADER;
goto err;
}
/* Also include path size */
ccpmp_pos -= sizeof(uint32_t);
fprintf(stderr, "[INFO] Making place for ccpmp.bin...\n");
memmove(&buf[ccpmp_pos + bsize + CCPMPBIN_HEADER_SIZE],
&buf[ccpmp_pos], fsize - ccpmp_pos);
fprintf(stderr, "[INFO] Reading %s into memory...\n", bootloader);
if(fread(&buf[ccpmp_pos + CCPMPBIN_HEADER_SIZE],
bsize, 1, bd) != 1)
{
fprintf(stderr, "[ERR] Can't read file %s to memory!\n", bootloader);
result = E_LOAD_BOOTLOADER;
goto err;
}
FCLOSE(bd);
fprintf(stderr, "[INFO] Adding header to %s...\n", bootloader);
int2le(&buf[ccpmp_pos ], 9); /* Pathname Size */
memcpy(&buf[ccpmp_pos + 4 ], "ccpmp.bin", 9); /* Pathname */
memset(&buf[ccpmp_pos + 4 + 9 ], 0x20, sizeof(uint8_t)); /* File Type */
int2le(&buf[ccpmp_pos + 4 + 9 + 1], bsize); /* File Size */
time(&cur_time);
time_info = localtime(&cur_time);
if(time_info == NULL)
{
fprintf(stderr, "[ERR] Can't obtain current time!\n");
result = E_GET_TIME;
goto err;
}
snprintf(header_time, 13, "%04d%02d%02d%02d%02d", time_info->tm_year + 1900,
time_info->tm_mon,
time_info->tm_mday,
time_info->tm_hour,
time_info->tm_min);
fprintf(stderr, "[INFO] Computing checksum...\n");
for(i = sizeof(struct header); i < TOTAL_SIZE; i+=4)
checksum += le2int(&buf[i]);
fprintf(stderr, "[INFO] Updating main header...\n");
memcpy(&buf[offsetof(struct header, timestamp)], header_time, 12);
int2le(&buf[offsetof(struct header, size) ], TOTAL_SIZE);
int2le(&buf[offsetof(struct header, checksum) ], checksum);
od = fopen(output, "wb");
if(!od)
{
fprintf(stderr, "[ERR] Can't open file %s!\n", output);
result = E_OPEN_OUTFILE;
goto err;
}
fprintf(stderr, "[INFO] Writing output to %s...\n", output);
if(fwrite(buf, TOTAL_SIZE, 1, od) != 1)
{
fprintf(stderr, "[ERR] Can't write to file %s!\n", output);
result = E_WRITE_OUTFILE;
goto err;
}
err:
if(buf)
free(buf);
if(fd)
fclose(fd);
if(bd)
fclose(bd);
if(od)
fclose(od);
return result;
}

View file

@ -0,0 +1,52 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 by Maurus Cuelenaere
*
* 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 __INCLUDE_CHINACHIP_H_
#define __INCLUDE_CHINACHIP_H_
#ifdef __cplusplus
extern "C" {
#endif
enum cc_error {
E_OK,
E_OPEN_FIRMWARE,
E_OPEN_BOOTLOADER,
E_MEMALLOC,
E_LOAD_FIRMWARE,
E_INVALID_FILE,
E_NO_CCPMP,
E_OPEN_BACKUP,
E_WRITE_BACKUP,
E_LOAD_BOOTLOADER,
E_GET_TIME,
E_OPEN_OUTFILE,
E_WRITE_OUTFILE,
};
enum cc_error chinachip_patch(const char* firmware, const char* bootloader,
const char* output, const char* ccpmp_backup);
#ifdef __cplusplus
}
#endif
#endif /* __INCLUDE_CHINACHIP_H_ */

View file

@ -0,0 +1,55 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 by Maurus Cuelenaere
*
* 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 <stdio.h>
#include <stdarg.h>
#include "chinachip.h"
#ifndef VERSION /* allow setting version from outside for svn builds */
#define VERSION "0.1"
#endif
#define PRINT(fmt, ...) fprintf(stderr, fmt"\n", ##__VA_ARGS__)
void usage(char* name)
{
PRINT("Usage:");
PRINT(" %s <firmware> <bootloader> <firmware_output> [backup]", name);
PRINT("\nExample:");
PRINT(" %s VX747.HXF bootloader.bin output.HXF ccpmp.bak", name);
PRINT(" This will copy ccpmp.bin in VX747.HXF as ccpmp.old and replace it\n"
" with bootloader.bin, the output will get written to output.HXF.\n"
" The old ccpmp.bin will get written to ccpmp.bak.\n");
}
int main(int argc, char* argv[])
{
PRINT("ChinaChipPatcher v" VERSION " - (C) Maurus Cuelenaere 2009");
PRINT("This is free software; see the source for copying conditions. There is NO");
PRINT("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
if(argc < 4)
{
usage(argv[0]);
return 1;
}
return chinachip_patch(argv[1], argv[2], argv[3], argc > 4 ? argv[4] : NULL);
}

View file

@ -0,0 +1,56 @@
CFLAGS=-Wall -W
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
OUTPUT=e200rpatcher.exe
CROSS=
CFLAGS+=-mno-cygwin
else
OUTPUT=e200rpatcher
CROSS=i586-mingw32msvc-
endif
LIBS = -lusb
WINLIBS = -I libusb-win32-device-bin-0.1.12.1/include libusb-win32-device-bin-0.1.12.1/lib/dynamic/libusb_dyn.c
NATIVECC = gcc
CC = $(CROSS)gcc
WINDRES = $(CROSS)windres
all: $(OUTPUT)
e200rpatcher: e200rpatcher.c bootimg.c
gcc $(CFLAGS) $(LIBS) -o e200rpatcher e200rpatcher.c bootimg.c
strip e200rpatcher
e200rpatcher.exe: e200rpatcher.c bootimg.c e200rpatcher-rc.o
$(CC) $(CFLAGS) $(WINLIBS) -o e200rpatcher.exe e200rpatcher.c bootimg.c e200rpatcher-rc.o
$(CROSS)strip e200rpatcher.exe
e200rpatcher-rc.o: e200rpatcher.rc e200rpatcher.manifest
$(WINDRES) -i e200rpatcher.rc -o e200rpatcher-rc.o
e200rpatcher-mac: e200rpatcher-i386 e200rpatcher-ppc
lipo -create e200rpatcher-ppc e200rpatcher-i386 -output e200rpatcher-mac
e200rpatcher.dmg: e200rpatcher-mac
mkdir -p e200rpatcher-dmg
cp -p e200rpatcher-mac e200rpatcher-dmg
hdiutil create -srcfolder e200rpatcher-dmg e200rpatcher.dmg
e200rpatcher-i386: e200rpatcher.c bootimg.c usb.h libusb-i386.a
gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch i386 $(CFLAGS) -o e200rpatcher-i386 e200rpatcher.c bootimg.c -I. libusb-i386.a
strip e200rpatcher-i386
e200rpatcher-ppc: e200rpatcher.c bootimg.c usb.h libusb-ppc.a
gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch ppc $(CFLAGS) -o e200rpatcher-ppc e200rpatcher.c bootimg.c -I. libusb-ppc.a
strip e200rpatcher-ppc
bin2c: ../tools/bin2c.c
$(NATIVECC) $(CFLAGS) -o bin2c ../tools/bin2c.c
bootimg.c: bootloader.bin bin2c
./bin2c bootloader.bin bootimg
clean:
rm -f e200rpatcher.exe e200rpatcher-mac e200rpatcher-i386 e200rpatcher-ppc e200rpatcher bin2c bootimg.c bootimg.h *~ e200rpatcher.dmg
rm -rf e200rpatcher-dmg

48
utils/e200rpatcher/README Normal file
View file

@ -0,0 +1,48 @@
INTRODUCTION
e200rpatcher is a tool for uploading and executing an application to
an E200R in manufacturing mode. It is intended to be used to upload
the patching application to allow Rockbox installs.
e200rpatcher requires libusb (v0.1.2 has been tested successfully) for
cross-platform USB access. No-one has yet successfully installed
e200rpatcher on Windows, but it works on Linux and Mac OS X (and
should be fine on other Unix-like systems that libusb supports).
GENERAL BUILD INSTRUCTIONS
A pre-requisite for compiling e200rpatcher is a file called
"bootloader.bin" - this is the output of running an "I" (installer)
build for the E200R target.
In the Rockbox source directory, do:
mkdir build-e200rbootbin
cd build-e200rbootbin
../tools/configure
[Select E200R, then I for installer]
make
This should give you a bootloader/bootloader/bin file which you should
copy to the e200rpatcher source directory.
BUILDING ON LINUX
The Makefile expects libusb (and the headers) to be installed on your
system and will link dynamically. Just type "make".
BUILDING ON A MAC
To build the mac version (target e200rpatcher-mac in the Makefile)
requires three files from libusb to be copied to the current
directory:
usb.h (copied from your libusb build directory)
libusb-i386.a (copied and renamed from .libs/libusb.a in an i386 build)
libusb-ppc.a (copied and renamed from .libs/libusb.a in a PPC build)
To build the required libusb.a files, just run ./configure && make for
libusb. If anyone knows how to cross-compile a static libusb.a please
make the information known - this is currently done by compiling
natively on the appropriate hardware.

View file

@ -0,0 +1,241 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 Dave Chapman
*
* USB code based on ifp-line - http://ifp-driver.sourceforge.net
*
* ifp-line is (C) Pavel Kriz, Jun Yamishiro and Joe Roback and
* licensed under the GPL (v2)
*
*
* 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 <stdio.h>
#include <inttypes.h>
#include <usb.h>
#include <string.h>
#include "stdbool.h"
#include "bootimg.h"
#define VERSION "0.2"
/* USB IDs for Manufacturing Mode */
#define E200R_VENDORID 0x0781
#define E200R_PRODUCTID 0x0720
#define E200R_BULK_TO 1
#define TOUT 5000
#define MAX_TRANSFER 64 /* Number of bytes to send in one write */
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
static void put_int32le(uint32_t x, char* p)
{
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
}
int upload_app(usb_dev_handle* dh)
{
char buf[4];
int err;
int tosend;
char* p = (char*)bootimg;
int bytesleft = LEN_bootimg;
/* Write the data length */
put_int32le(LEN_bootimg, buf);
err = usb_bulk_write(dh, E200R_BULK_TO, buf, 4, TOUT);
if (err < 0)
{
fprintf(stderr,"[ERR] Error writing data length\n");
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
return -1;
}
/* Now send the data, MAX_TRANSFER bytes at a time. */
while (bytesleft > 0)
{
tosend = MAX(MAX_TRANSFER, bytesleft);
err = usb_bulk_write(dh, E200R_BULK_TO, p, tosend, TOUT);
if (err < 0)
{
fprintf(stderr,"[ERR] Error writing data\n");
fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
return -1;
}
p += tosend;
bytesleft -= tosend;
}
return 0;
}
/* The main function */
void do_patching(void)
{
struct usb_bus *busses;
struct usb_bus *bus;
struct usb_device *tmp_dev;
struct usb_device *dev = NULL;
usb_dev_handle *dh;
int err;
fprintf(stderr,"[INFO] Searching for E200R\n");
usb_init();
if(usb_find_busses() < 0) {
fprintf(stderr, "[ERR] Could not find any USB busses.\n");
return;
}
if (usb_find_devices() < 0) {
fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
return;
}
/* C calling convention, it's not nice to use global stuff */
busses = usb_get_busses();
for (bus = busses; bus; bus = bus->next) {
for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) {
if (tmp_dev->descriptor.idVendor == E200R_VENDORID &&
tmp_dev->descriptor.idProduct == E200R_PRODUCTID ) {
dev = tmp_dev;
goto found;
}
}
}
if (dev == NULL) {
fprintf(stderr, "[ERR] E200R device not found.\n");
fprintf(stderr, "[ERR] Ensure your E200R is in manufacturing mode and run e200rpatcher again.\n");
return;
}
found:
if ( (dh = usb_open(dev)) == NULL) {
fprintf(stderr,"[ERR] Unable to open E200R device.\n");
return;
}
err = usb_set_configuration(dh, 1);
if (err < 0) {
fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err);
usb_close(dh);
return;
}
/* "must be called" written in the libusb documentation */
err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
if (err < 0) {
fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err);
usb_close(dh);
return;
}
fprintf(stderr,"[INFO] Found E200R, uploading patching application.\n");
/* Now we can transfer the application to the device. */
if (upload_app(dh) < 0)
{
fprintf(stderr,"[ERR] Upload of application failed.\n");
}
else
{
fprintf(stderr,"[INFO] Patching application uploaded successfully!\n");
}
/* release claimed interface */
usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
usb_close(dh);
}
void print_usage(void)
{
fprintf(stderr,"Usage: e200rpatcher [options]\n");
fprintf(stderr,"Options:\n");
fprintf(stderr," -s, --silent\t\tDont display instructions\n");
}
int main(int argc, char* argv[])
{
char input[4];
int silent = 0;
int i;
/* check args */
if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
print_usage();
return 1;
}
for (i=1;i<argc;i++)
{
if (!strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s"))
silent = 1;
}
printf("e200rpatcher v" VERSION " - (C) 2007 Jonathan Gordon & Dave Chapman\n");
printf("This is free software; see the source for copying conditions. There is NO\n");
printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
if (!silent)
{
printf("Attach your E200R in \"manufacturing mode\" as follows:\n");
printf(" 1) Power-off your E200R\n");
printf(" 2) Turn ON the lock/hold switch\n");
printf(" 3) Press and hold the SELECT button and whilst it is held down,\n");
printf(" attach your E200R to your computer via USB\n");
printf(" 4) After attaching to USB, keep the SELECT button held for 10 seconds.\n");
printf("\n");
printf("NOTE: If your E200R starts in the normal Sansa firmware, you have\n");
printf(" failed to enter manufacturing mode and should try again at step 1).\n\n");
printf("[INFO] Press Enter to continue:");
fgets(input, 4, stdin);
}
do_patching();
if (!silent)
{
printf("[INFO] Press ENTER to exit: ");
fgets(input, 4, stdin);
}
return 0;
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="e200rpatcher.exe" type="win32"/>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View file

@ -0,0 +1 @@
1 24 MOVEABLE PURE "e200rpatcher.manifest"

View file

@ -0,0 +1,14 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MangoPlayer
LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c
TARGET_ARCH=arm
TARGET_PLATFORM=android-14
TARGET_ARCH_ABI=armeabi
#LOCAL_CFLAGS := -DDEBUG
#LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

View file

@ -0,0 +1,771 @@
/***************************************************************************
* __________ __ ___
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
* Copyright (C) 2014 by Mario Basister: iBasso DX90 port
* Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
* Copyright (C) 2014 by Udo Schläpfer: Code clean up, additional features
*
* 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 <dirent.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/fb.h>
#include <linux/input.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/reboot.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include "qdbmp.h"
/*- Android logcat ------------------------------------------------------------------------------*/
#ifdef DEBUG
#include <android/log.h>
static const char log_tag[] = "Rockbox Boot";
void debugf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__android_log_vprint(ANDROID_LOG_DEBUG, log_tag, fmt, ap);
va_end(ap);
}
void ldebugf(const char* file, int line, const char *fmt, ...)
{
va_list ap;
/* 13: 5 literal chars and 8 chars for the line number. */
char buf[strlen(file) + strlen(fmt) + 13];
snprintf(buf, sizeof(buf), "%s (%d): %s", file, line, fmt);
va_start(ap, fmt);
__android_log_vprint(ANDROID_LOG_DEBUG, log_tag, buf, ap);
va_end(ap);
}
void debug_trace(const char* function)
{
static const char trace_tag[] = "TRACE: ";
char msg[strlen(trace_tag) + strlen(function) + 1];
snprintf(msg, sizeof(msg), "%s%s", trace_tag, function);
__android_log_write(ANDROID_LOG_DEBUG, log_tag, msg);
}
#define DEBUGF debugf
#define TRACE debug_trace(__func__)
#else
#define DEBUGF(...)
#define TRACE
#endif /* DEBUG */
/*- Vold monitor --------------------------------------------------------------------------------*/
/*
Without this socket iBasso Vold will not start.
iBasso Vold uses this to send status messages about storage devices.
*/
static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain";
static int _vold_monitor_socket_fd = -1;
static void vold_monitor_open_socket(void)
{
TRACE;
unlink(VOLD_MONITOR_SOCKET_NAME);
_vold_monitor_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if(_vold_monitor_socket_fd < 0)
{
_vold_monitor_socket_fd = -1;
return;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, VOLD_MONITOR_SOCKET_NAME, sizeof(addr.sun_path) - 1);
if(bind(_vold_monitor_socket_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
{
close(_vold_monitor_socket_fd);
unlink(VOLD_MONITOR_SOCKET_NAME);
_vold_monitor_socket_fd = -1;
return;
}
if(listen(_vold_monitor_socket_fd, 1) < 0)
{
close(_vold_monitor_socket_fd);
unlink(VOLD_MONITOR_SOCKET_NAME);
_vold_monitor_socket_fd = -1;
return;
}
}
/*
bionic does not have pthread_cancel.
0: Vold monitor thread stopped/ending.
1: Vold monitor thread started/running.
*/
static volatile sig_atomic_t _vold_monitor_active = 0;
/* true: sdcard not mounted. */
static bool _sdcard_not_mounted = true;
/* Mutex for sdcard mounted flag. */
static pthread_mutex_t _sdcard_mount_mtx = PTHREAD_MUTEX_INITIALIZER;
/* Signal condition for sdcard mounted flag. */
static pthread_cond_t _sdcard_mount_cond = PTHREAD_COND_INITIALIZER;
static void* vold_monitor_run(void* nothing)
{
_vold_monitor_active = 1;
(void) nothing;
DEBUGF("DEBUG %s: Thread start.", __func__);
vold_monitor_open_socket();
if(_vold_monitor_socket_fd < 0)
{
DEBUGF("ERROR %s: Thread end: No socket.", __func__);
_vold_monitor_active = 0;
return 0;
}
struct pollfd fds[1];
fds[0].fd = _vold_monitor_socket_fd;
fds[0].events = POLLIN;
while(_vold_monitor_active == 1)
{
poll(fds, 1, 10);
if(! (fds[0].revents & POLLIN))
{
continue;
}
int socket_fd = accept(_vold_monitor_socket_fd, NULL, NULL);
if(socket_fd < 0)
{
DEBUGF("ERROR %s: accept failed.", __func__);
continue;
}
while(true)
{
char msg[1024];
memset(msg, 0, sizeof(msg));
int length = read(socket_fd, msg, sizeof(msg));
if(length <= 0)
{
close(socket_fd);
break;
}
DEBUGF("DEBUG %s: msg: %s", __func__, msg);
if(strcmp(msg, "Volume flash /mnt/sdcard state changed from 3 (Checking) to 4 (Mounted)") == 0)
{
pthread_mutex_lock(&_sdcard_mount_mtx);
_sdcard_not_mounted = false;
pthread_cond_signal(&_sdcard_mount_cond);
pthread_mutex_unlock(&_sdcard_mount_mtx);
}
}
}
close(_vold_monitor_socket_fd);
unlink(VOLD_MONITOR_SOCKET_NAME);
_vold_monitor_socket_fd = -1;
DEBUGF("DEBUG %s: Thread end.", __func__);
_vold_monitor_active = 0;
return 0;
}
/* Vold monitor thread. */
static pthread_t _vold_monitor_thread;
static void vold_monitor_start(void)
{
TRACE;
if(_vold_monitor_active == 0)
{
pthread_create(&_vold_monitor_thread, NULL, vold_monitor_run, NULL);
}
}
static void vold_monitor_stop(void)
{
TRACE;
if(_vold_monitor_active == 1)
{
_vold_monitor_active = 0;
int ret = pthread_join(_vold_monitor_thread, NULL);
DEBUGF("DEBUG %s: Thread joined: ret: %d.", __func__, ret);
}
}
/*- Input handler -------------------------------------------------------------------------------*/
/* Input devices monitored with poll API. */
static struct pollfd* _fds = NULL;
/* Number of input devices monitored with poll API. */
static nfds_t _nfds = 0;
/* The names of the devices in _fds. */
static char** _device_names = NULL;
/* Open device device_name and add it to the list of polled devices. */
static void open_device(const char* device_name)
{
int fd = open(device_name, O_RDONLY);
if(fd == -1)
{
DEBUGF("ERROR %s: open failed on %s.", __func__, device_name);
exit(-1);
}
struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1));
if(new_fds == NULL)
{
DEBUGF("ERROR %s: realloc for _fds failed.", __func__);
exit(-1);
}
_fds = new_fds;
_fds[_nfds].fd = fd;
_fds[_nfds].events = POLLIN;
char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1));
if(new_device_names == NULL)
{
DEBUGF("ERROR %s: realloc for _device_names failed.", __func__);
exit(-1);
}
_device_names = new_device_names;
_device_names[_nfds] = strdup(device_name);
if(_device_names[_nfds] == NULL)
{
DEBUGF("ERROR %s: strdup failed.", __func__);
exit(-1);
}
++_nfds;
DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name);
}
static void button_init_device(void)
{
TRACE;
if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL))
{
DEBUGF("ERROR %s: Allready initialized.", __func__);
return;
}
/* The input device directory. */
static const char device_path[] = "/dev/input";
/* Path delimeter. */
static const char delimeter[] = "/";
/* Open all devices in device_path. */
DIR* dir = opendir(device_path);
if(dir == NULL)
{
DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno);
exit(errno);
}
char device_name[PATH_MAX];
strcpy(device_name, device_path);
strcat(device_name, delimeter);
char* device_name_idx = device_name + strlen(device_name);
struct dirent* dir_entry;
while((dir_entry = readdir(dir)))
{
if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0'))
|| ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0')))
{
continue;
}
strcpy(device_name_idx, dir_entry->d_name);
/* Open and add device to _fds. */
open_device(device_name);
}
closedir(dir);
/* Sanity check. */
if(_nfds < 2)
{
DEBUGF("ERROR %s: No input devices.", __func__);
exit(-1);
}
}
#define EVENT_TYPE_BUTTON 1
#define EVENT_CODE_BUTTON_PWR_LONG 117
#define EVENT_CODE_BUTTON_REV 160
#define EVENT_CODE_BUTTON_NEXT 162
#define EVENT_TYPE_TOUCHSCREEN 3
#define EVENT_CODE_TOUCHSCREEN_X 53
enum user_choice
{
CHOICE_NONE = -1,
CHOICE_MANGO,
CHOICE_ROCKBOX,
CHOICE_POWEROFF
};
static int get_user_choice(void)
{
TRACE;
button_init_device();
enum user_choice choice = CHOICE_NONE;
while(choice == CHOICE_NONE)
{
/* Poll all input devices. */
poll(_fds, _nfds, 0);
nfds_t fds_idx = 0;
for( ; fds_idx < _nfds; ++fds_idx)
{
if(! (_fds[fds_idx].revents & POLLIN))
{
continue;
}
struct input_event event;
if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event))
{
DEBUGF("ERROR %s: Read of input devices failed.", __func__);
continue;
}
DEBUGF("DEBUG %s: device: %s, event.type: %d, event.code: %d, event.value: %d", __func__, _device_names[fds_idx], event.type, event.code, event.value);
if(event.type == EVENT_TYPE_BUTTON)
{
switch(event.code)
{
case EVENT_CODE_BUTTON_REV:
{
choice = CHOICE_MANGO;
break;
}
case EVENT_CODE_BUTTON_NEXT:
{
choice = CHOICE_ROCKBOX;
break;
}
case EVENT_CODE_BUTTON_PWR_LONG:
{
choice = CHOICE_POWEROFF;
break;
}
}
}
else if((event.type == EVENT_TYPE_TOUCHSCREEN) && (event.code == EVENT_CODE_TOUCHSCREEN_X))
{
if(event.value < 160)
{
choice = CHOICE_MANGO;
}
else
{
choice = CHOICE_ROCKBOX;
}
}
}
}
if(_fds)
{
nfds_t fds_idx = 0;
for( ; fds_idx < _nfds; ++fds_idx)
{
close(_fds[fds_idx].fd);
}
free(_fds);
_fds = NULL;
}
if(_device_names)
{
nfds_t fds_idx = 0;
for( ; fds_idx < _nfds; ++fds_idx)
{
free(_device_names[fds_idx]);
}
free(_device_names);
_device_names = NULL;
}
_nfds = 0;
return choice;
}
/*
Changing bit, when hold switch is toggled.
Bit is off when hold switch is engaged.
*/
#define HOLD_SWITCH_BIT 16
static bool check_for_hold(void)
{
TRACE;
char hold_state;
FILE* f = fopen("/sys/class/axppower/holdkey", "r");
fscanf(f, "%c", &hold_state);
fclose(f);
return(! (hold_state & HOLD_SWITCH_BIT));
}
/*- Display -------------------------------------------------------------------------------------*/
static void draw(const char* file)
{
DEBUGF("DEBUG %s: file: %s.", __func__, file);
int dev_fd = open("/dev/graphics/fb0", O_RDWR);
if(dev_fd == -1)
{
DEBUGF("ERROR %s: open failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
exit(errno);
}
/* Get fixed screen information. */
struct fb_fix_screeninfo finfo;
if(ioctl(dev_fd, FBIOGET_FSCREENINFO, &finfo) < 0)
{
DEBUGF("ERROR %s: ioctl FBIOGET_FSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
exit(errno);
}
/* Get the changeable information. */
struct fb_var_screeninfo vinfo;
if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
{
DEBUGF("ERROR %s: ioctl FBIOGET_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
exit(errno);
}
DEBUGF("DEBUG %s: bits_per_pixel: %u, width: %u, height: %u.", __func__, vinfo.bits_per_pixel, vinfo.width, vinfo.height);
size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
/* ToDo: Is this needed? */
vinfo.xres = 320;
vinfo.xres_virtual = 320;
vinfo.width = 320;
vinfo.yres = 240;
vinfo.yres_virtual = 240;
vinfo.height = 240;
vinfo.xoffset = 0;
vinfo.yoffset = 0;
vinfo.sync = 0;
vinfo.vmode = 0;
vinfo.pixclock = 104377;
vinfo.left_margin = 20;
vinfo.right_margin = 50;
vinfo.upper_margin = 2;
vinfo.lower_margin = 4;
vinfo.hsync_len = 10;
vinfo.vsync_len = 2;
vinfo.red.offset = 11;
vinfo.red.length = 5;
vinfo.red.msb_right = 0;
vinfo.green.offset = 5;
vinfo.green.length = 6;
vinfo.green.msb_right = 0;
vinfo.blue.offset = 0;
vinfo.blue.length = 5;
vinfo.blue.msb_right = 0;
vinfo.transp.offset = 0;
vinfo.transp.length = 0;
vinfo.transp.msb_right = 0;
vinfo.nonstd = 4;
if(ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
{
DEBUGF("ERROR %s: ioctl FBIOPUT_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
exit(errno);
}
/* Map the device to memory. */
char* dev_fb = (char*) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
if(dev_fb == MAP_FAILED)
{
DEBUGF("ERROR %s: mmap failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
exit(errno);
}
BMP* bmp = BMP_ReadFile(file);
if(BMP_GetError() != BMP_OK )
{
DEBUGF("ERROR %s: BMP_ReadFile failed on %s: %d.", __func__, file, BMP_GetError());
exit(BMP_GetError());
}
int y = 0;
for( ; y < 240; ++y)
{
int x = 0;
for( ; x < 320; ++x)
{
long int position = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8 )
+ (y + vinfo.yoffset) * finfo.line_length;
UCHAR r, g, b;
BMP_GetPixelRGB(bmp, x, y, &r, &g, &b);
unsigned short int pixel = (r >> 3) << 11 | (g >> 2) << 5 | (b >> 3);
*((unsigned short int*)(dev_fb + position)) = pixel;
}
}
BMP_Free(bmp);
munmap(dev_fb, screensize);
close(dev_fd);
}
/*-----------------------------------------------------------------------------------------------*/
static const char ROCKBOX_BIN[] = "/mnt/sdcard/.rockbox/rockbox";
static const char OF_PLAYER_BIN[] = "/system/bin/MangoPlayer_original";
static const char PLAYER_FILE[] = "/data/chosen_player";
int main(int argc, char **argv)
{
TRACE;
/*
Create the iBasso Vold socket and monitor it.
Do this early to not block Vold.
*/
vold_monitor_start();
int last_chosen_player = CHOICE_NONE;
FILE* f = fopen(PLAYER_FILE, "r");
if(f != NULL)
{
fscanf(f, "%d", &last_chosen_player);
fclose(f);
}
DEBUGF("DEBUG %s: Current player choice: %d.", __func__, last_chosen_player);
if(check_for_hold() || (last_chosen_player == CHOICE_NONE))
{
draw("/system/chooser.bmp");
enum user_choice choice = get_user_choice();
if(choice == CHOICE_POWEROFF)
{
reboot(RB_POWER_OFF);
while(true)
{
sleep(1);
}
}
if(choice != last_chosen_player)
{
last_chosen_player = choice;
f = fopen(PLAYER_FILE, "w");
fprintf(f, "%d", last_chosen_player);
fclose(f);
}
DEBUGF("DEBUG %s: New player choice: %d.", __func__, last_chosen_player);
}
/* true, Rockbox was started at least once. */
bool rockboxStarted = false;
while(true)
{
/* Excecute OF MangoPlayer or Rockbox and restart it if it crashes. */
if(last_chosen_player == CHOICE_ROCKBOX)
{
if(rockboxStarted)
{
/*
At this point it is assumed, that Rockbox has exited due to a USB connection
triggering a remount of the internal storage for mass storage access.
Rockbox will eventually restart, when /mnt/sdcard becomes available again.
*/
draw("/system/usb.bmp");
}
pthread_mutex_lock(&_sdcard_mount_mtx);
while(_sdcard_not_mounted)
{
DEBUGF("DEBUG %s: Waiting on /mnt/sdcard/.", __func__);
pthread_cond_wait(&_sdcard_mount_cond, &_sdcard_mount_mtx);
DEBUGF("DEBUG %s: /mnt/sdcard/ available.", __func__);
}
pthread_mutex_unlock(&_sdcard_mount_mtx);
/* To be able to execute rockbox. */
system("mount -o remount,exec /mnt/sdcard");
/* This symlink is needed mainly to keep themes functional. */
system("ln -s /mnt/sdcard/.rockbox /.rockbox");
if(access(ROCKBOX_BIN, X_OK) != -1)
{
/* Start Rockbox. */
/* Rockbox has its own vold monitor. */
vold_monitor_stop();
DEBUGF("DEBUG %s: Excecuting %s.", __func__, ROCKBOX_BIN);
int ret_code = system(ROCKBOX_BIN);
rockboxStarted = true;
DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
if(WIFEXITED(ret_code) && (WEXITSTATUS(ret_code) == 42))
{
/*
Rockbox terminated to prevent a froced shutdown due to a USB connection
triggering a remount of the internal storage for mass storage access.
*/
_sdcard_not_mounted = true;
}
/* else Rockbox crashed ... */
vold_monitor_start();
}
else
{
/* Rockbox executable missing. Show info screen for 30 seconds. */
draw("/system/rbmissing.bmp");
sleep(30);
/* Do not block Vold, so stop after sleep. */
vold_monitor_stop();
#ifdef DEBUG
system("setprop persist.sys.usb.config adb");
system("setprop persist.usb.debug 1");
#endif
DEBUGF("DEBUG %s: Rockbox missing, excecuting %s.", __func__, OF_PLAYER_BIN);
/* Start OF MangoPlayer. */
int ret_code = system(OF_PLAYER_BIN);
DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
}
}
else /* if(last_chosen_player == CHOICE_MANGO) */
{
vold_monitor_stop();
DEBUGF("DEBUG %s: Excecuting %s.", __func__, OF_PLAYER_BIN);
int ret_code = system(OF_PLAYER_BIN);
DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
}
}
return 0;
}

View file

@ -0,0 +1,798 @@
#include "qdbmp.h"
#include <stdlib.h>
#include <string.h>
/* Bitmap header */
typedef struct _BMP_Header
{
USHORT Magic; /* Magic identifier: "BM" */
UINT FileSize; /* Size of the BMP file in bytes */
USHORT Reserved1; /* Reserved */
USHORT Reserved2; /* Reserved */
UINT DataOffset; /* Offset of image data relative to the file's start */
UINT HeaderSize; /* Size of the header in bytes */
UINT Width; /* Bitmap's width */
UINT Height; /* Bitmap's height */
USHORT Planes; /* Number of color planes in the bitmap */
USHORT BitsPerPixel; /* Number of bits per pixel */
UINT CompressionType; /* Compression type */
UINT ImageDataSize; /* Size of uncompressed image's data */
UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */
UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */
UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */
UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */
} BMP_Header;
/* Private data structure */
struct _BMP
{
BMP_Header Header;
UCHAR* Palette;
UCHAR* Data;
};
/* Holds the last error code */
static BMP_STATUS BMP_LAST_ERROR_CODE = 0;
/* Error description strings */
static const char* BMP_ERROR_STRING[] =
{
"",
"General error",
"Could not allocate enough memory to complete the operation",
"File input/output error",
"File not found",
"File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)",
"File is not a valid BMP image",
"An argument is invalid or out of range",
"The requested action is not compatible with the BMP's type"
};
/* Size of the palette data for 8 BPP bitmaps */
#define BMP_PALETTE_SIZE ( 256 * 4 )
/*********************************** Forward declarations **********************************/
int ReadHeader ( BMP* bmp, FILE* f );
int WriteHeader ( BMP* bmp, FILE* f );
int ReadUINT ( UINT* x, FILE* f );
int ReadUSHORT ( USHORT *x, FILE* f );
int WriteUINT ( UINT x, FILE* f );
int WriteUSHORT ( USHORT x, FILE* f );
/*********************************** Public methods **********************************/
/**************************************************************
Creates a blank BMP image with the specified dimensions
and bit depth.
**************************************************************/
BMP* BMP_Create( UINT width, UINT height, USHORT depth )
{
BMP* bmp;
int bytes_per_pixel = depth >> 3;
UINT bytes_per_row;
if ( height <= 0 || width <= 0 )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
return NULL;
}
if ( depth != 8 && depth != 24 && depth != 32 )
{
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
return NULL;
}
/* Allocate the bitmap data structure */
bmp = calloc( 1, sizeof( BMP ) );
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
return NULL;
}
/* Set header' default values */
bmp->Header.Magic = 0x4D42;
bmp->Header.Reserved1 = 0;
bmp->Header.Reserved2 = 0;
bmp->Header.HeaderSize = 40;
bmp->Header.Planes = 1;
bmp->Header.CompressionType = 0;
bmp->Header.HPixelsPerMeter = 0;
bmp->Header.VPixelsPerMeter = 0;
bmp->Header.ColorsUsed = 0;
bmp->Header.ColorsRequired = 0;
/* Calculate the number of bytes used to store a single image row. This is always
rounded up to the next multiple of 4. */
bytes_per_row = width * bytes_per_pixel;
bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 );
/* Set header's image specific values */
bmp->Header.Width = width;
bmp->Header.Height = height;
bmp->Header.BitsPerPixel = depth;
bmp->Header.ImageDataSize = bytes_per_row * height;
bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
/* Allocate palette */
if ( bmp->Header.BitsPerPixel == 8 )
{
bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) );
if ( bmp->Palette == NULL )
{
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
free( bmp );
return NULL;
}
}
else
{
bmp->Palette = NULL;
}
/* Allocate pixels */
bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) );
if ( bmp->Data == NULL )
{
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
free( bmp->Palette );
free( bmp );
return NULL;
}
BMP_LAST_ERROR_CODE = BMP_OK;
return bmp;
}
/**************************************************************
Frees all the memory used by the specified BMP image.
**************************************************************/
void BMP_Free( BMP* bmp )
{
if ( bmp == NULL )
{
return;
}
if ( bmp->Palette != NULL )
{
free( bmp->Palette );
}
if ( bmp->Data != NULL )
{
free( bmp->Data );
}
free( bmp );
BMP_LAST_ERROR_CODE = BMP_OK;
}
/**************************************************************
Reads the specified BMP image file.
**************************************************************/
BMP* BMP_ReadFile( const char* filename )
{
BMP* bmp;
FILE* f;
if ( filename == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
return NULL;
}
/* Allocate */
bmp = calloc( 1, sizeof( BMP ) );
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
return NULL;
}
/* Open file */
f = fopen( filename, "rb" );
if ( f == NULL )
{
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
free( bmp );
return NULL;
}
/* Read header */
if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 )
{
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
fclose( f );
free( bmp );
return NULL;
}
/* Verify that the bitmap variant is supported */
if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 )
|| bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 )
{
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
fclose( f );
free( bmp );
return NULL;
}
/* Allocate and read palette */
if ( bmp->Header.BitsPerPixel == 8 )
{
bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) );
if ( bmp->Palette == NULL )
{
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
fclose( f );
free( bmp );
return NULL;
}
if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
{
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
fclose( f );
free( bmp->Palette );
free( bmp );
return NULL;
}
}
else /* Not an indexed image */
{
bmp->Palette = NULL;
}
/* Allocate memory for image data */
bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize );
if ( bmp->Data == NULL )
{
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
fclose( f );
free( bmp->Palette );
free( bmp );
return NULL;
}
/* Read image data */
if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
{
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
fclose( f );
free( bmp->Data );
free( bmp->Palette );
free( bmp );
return NULL;
}
fclose( f );
BMP_LAST_ERROR_CODE = BMP_OK;
return bmp;
}
/**************************************************************
Writes the BMP image to the specified file.
**************************************************************/
void BMP_WriteFile( BMP* bmp, const char* filename )
{
FILE* f;
if ( filename == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
return;
}
/* Open file */
f = fopen( filename, "wb" );
if ( f == NULL )
{
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
return;
}
/* Write header */
if ( WriteHeader( bmp, f ) != BMP_OK )
{
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
fclose( f );
return;
}
/* Write palette */
if ( bmp->Palette )
{
if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
{
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
fclose( f );
return;
}
}
/* Write data */
if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
{
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
fclose( f );
return;
}
BMP_LAST_ERROR_CODE = BMP_OK;
fclose( f );
}
/**************************************************************
Returns the image's width.
**************************************************************/
UINT BMP_GetWidth( BMP* bmp )
{
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
return -1;
}
BMP_LAST_ERROR_CODE = BMP_OK;
return ( bmp->Header.Width );
}
/**************************************************************
Returns the image's height.
**************************************************************/
UINT BMP_GetHeight( BMP* bmp )
{
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
return -1;
}
BMP_LAST_ERROR_CODE = BMP_OK;
return ( bmp->Header.Height );
}
/**************************************************************
Returns the image's color depth (bits per pixel).
**************************************************************/
USHORT BMP_GetDepth( BMP* bmp )
{
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
return -1;
}
BMP_LAST_ERROR_CODE = BMP_OK;
return ( bmp->Header.BitsPerPixel );
}
/**************************************************************
Populates the arguments with the specified pixel's RGB
values.
**************************************************************/
void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b )
{
UCHAR* pixel;
UINT bytes_per_row;
UCHAR bytes_per_pixel;
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
}
else
{
BMP_LAST_ERROR_CODE = BMP_OK;
bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
/* Row's size is rounded up to the next multiple of 4 bytes */
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
/* Calculate the location of the relevant pixel (rows are flipped) */
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
/* In indexed color mode the pixel's value is an index within the palette */
if ( bmp->Header.BitsPerPixel == 8 )
{
pixel = bmp->Palette + *pixel * 4;
}
/* Note: colors are stored in BGR order */
if ( r ) *r = *( pixel + 2 );
if ( g ) *g = *( pixel + 1 );
if ( b ) *b = *( pixel + 0 );
}
}
/**************************************************************
Sets the specified pixel's RGB values.
**************************************************************/
void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b )
{
UCHAR* pixel;
UINT bytes_per_row;
UCHAR bytes_per_pixel;
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
}
else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 )
{
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
}
else
{
BMP_LAST_ERROR_CODE = BMP_OK;
bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
/* Row's size is rounded up to the next multiple of 4 bytes */
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
/* Calculate the location of the relevant pixel (rows are flipped) */
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
/* Note: colors are stored in BGR order */
*( pixel + 2 ) = r;
*( pixel + 1 ) = g;
*( pixel + 0 ) = b;
}
}
/**************************************************************
Gets the specified pixel's color index.
**************************************************************/
void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val )
{
UCHAR* pixel;
UINT bytes_per_row;
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
}
else if ( bmp->Header.BitsPerPixel != 8 )
{
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
}
else
{
BMP_LAST_ERROR_CODE = BMP_OK;
/* Row's size is rounded up to the next multiple of 4 bytes */
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
/* Calculate the location of the relevant pixel */
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
if ( val ) *val = *pixel;
}
}
/**************************************************************
Sets the specified pixel's color index.
**************************************************************/
void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val )
{
UCHAR* pixel;
UINT bytes_per_row;
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
}
else if ( bmp->Header.BitsPerPixel != 8 )
{
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
}
else
{
BMP_LAST_ERROR_CODE = BMP_OK;
/* Row's size is rounded up to the next multiple of 4 bytes */
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
/* Calculate the location of the relevant pixel */
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
*pixel = val;
}
}
/**************************************************************
Gets the color value for the specified palette index.
**************************************************************/
void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b )
{
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
}
else if ( bmp->Header.BitsPerPixel != 8 )
{
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
}
else
{
if ( r ) *r = *( bmp->Palette + index * 4 + 2 );
if ( g ) *g = *( bmp->Palette + index * 4 + 1 );
if ( b ) *b = *( bmp->Palette + index * 4 + 0 );
BMP_LAST_ERROR_CODE = BMP_OK;
}
}
/**************************************************************
Sets the color value for the specified palette index.
**************************************************************/
void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b )
{
if ( bmp == NULL )
{
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
}
else if ( bmp->Header.BitsPerPixel != 8 )
{
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
}
else
{
*( bmp->Palette + index * 4 + 2 ) = r;
*( bmp->Palette + index * 4 + 1 ) = g;
*( bmp->Palette + index * 4 + 0 ) = b;
BMP_LAST_ERROR_CODE = BMP_OK;
}
}
/**************************************************************
Returns the last error code.
**************************************************************/
BMP_STATUS BMP_GetError()
{
return BMP_LAST_ERROR_CODE;
}
/**************************************************************
Returns a description of the last error code.
**************************************************************/
const char* BMP_GetErrorDescription()
{
if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM )
{
return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ];
}
else
{
return NULL;
}
}
/*********************************** Private methods **********************************/
/**************************************************************
Reads the BMP file's header into the data structure.
Returns BMP_OK on success.
**************************************************************/
int ReadHeader( BMP* bmp, FILE* f )
{
if ( bmp == NULL || f == NULL )
{
return BMP_INVALID_ARGUMENT;
}
/* The header's fields are read one by one, and converted from the format's
little endian to the system's native representation. */
if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR;
if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR;
if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR;
if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR;
if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR;
if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR;
return BMP_OK;
}
/**************************************************************
Writes the BMP file's header into the data structure.
Returns BMP_OK on success.
**************************************************************/
int WriteHeader( BMP* bmp, FILE* f )
{
if ( bmp == NULL || f == NULL )
{
return BMP_INVALID_ARGUMENT;
}
/* The header's fields are written one by one, and converted to the format's
little endian representation. */
if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR;
if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR;
if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR;
if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR;
if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR;
if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR;
return BMP_OK;
}
/**************************************************************
Reads a little-endian unsigned int from the file.
Returns non-zero on success.
**************************************************************/
int ReadUINT( UINT* x, FILE* f )
{
UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
if ( x == NULL || f == NULL )
{
return 0;
}
if ( fread( little, 4, 1, f ) != 1 )
{
return 0;
}
*x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] );
return 1;
}
/**************************************************************
Reads a little-endian unsigned short int from the file.
Returns non-zero on success.
**************************************************************/
int ReadUSHORT( USHORT *x, FILE* f )
{
UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
if ( x == NULL || f == NULL )
{
return 0;
}
if ( fread( little, 2, 1, f ) != 1 )
{
return 0;
}
*x = ( little[ 1 ] << 8 | little[ 0 ] );
return 1;
}
/**************************************************************
Writes a little-endian unsigned int to the file.
Returns non-zero on success.
**************************************************************/
int WriteUINT( UINT x, FILE* f )
{
UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 );
little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 );
little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 );
little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 );
return ( f && fwrite( little, 4, 1, f ) == 1 );
}
/**************************************************************
Writes a little-endian unsigned short int to the file.
Returns non-zero on success.
**************************************************************/
int WriteUSHORT( USHORT x, FILE* f )
{
UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 );
little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 );
return ( f && fwrite( little, 2, 1, f ) == 1 );
}

View file

@ -0,0 +1,133 @@
#ifndef _BMP_H_
#define _BMP_H_
/**************************************************************
QDBMP - Quick n' Dirty BMP
v1.0.0 - 2007-04-07
http://qdbmp.sourceforge.net
The library supports the following BMP variants:
1. Uncompressed 32 BPP (alpha values are ignored)
2. Uncompressed 24 BPP
3. Uncompressed 8 BPP (indexed color)
QDBMP is free and open source software, distributed
under the MIT licence.
Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
**************************************************************/
#include <stdio.h>
/* Type definitions */
#ifndef UINT
#define UINT unsigned long int
#endif
#ifndef USHORT
#define USHORT unsigned short
#endif
#ifndef UCHAR
#define UCHAR unsigned char
#endif
/* Version */
#define QDBMP_VERSION_MAJOR 1
#define QDBMP_VERSION_MINOR 0
#define QDBMP_VERSION_PATCH 1
/* Error codes */
typedef enum
{
BMP_OK = 0, /* No error */
BMP_ERROR, /* General error */
BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */
BMP_IO_ERROR, /* General input/output error */
BMP_FILE_NOT_FOUND, /* File not found */
BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */
BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */
BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */
BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */
BMP_ERROR_NUM
} BMP_STATUS;
/* Bitmap image */
typedef struct _BMP BMP;
/*********************************** Public methods **********************************/
/* Construction/destruction */
BMP* BMP_Create ( UINT width, UINT height, USHORT depth );
void BMP_Free ( BMP* bmp );
/* I/O */
BMP* BMP_ReadFile ( const char* filename );
void BMP_WriteFile ( BMP* bmp, const char* filename );
/* Meta info */
UINT BMP_GetWidth ( BMP* bmp );
UINT BMP_GetHeight ( BMP* bmp );
USHORT BMP_GetDepth ( BMP* bmp );
/* Pixel access */
void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b );
void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b );
void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val );
void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val );
/* Palette handling */
void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b );
void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b );
/* Error handling */
BMP_STATUS BMP_GetError ();
const char* BMP_GetErrorDescription ();
/* Useful macro that may be used after each BMP operation to check for an error */
#define BMP_CHECK_ERROR( output_file, return_value ) \
if ( BMP_GetError() != BMP_OK ) \
{ \
fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \
return( return_value ); \
} \
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

View file

@ -0,0 +1,53 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
CFLAGS += -Wall -W
# Build with "make BOOTOBJS=1" to build with embedded bootloaders and the
# --install option and interactive mode. You need the full set of Rockbox
# bootloaders in this directory - download them from
# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
# Releases of ipodpatcher are created with "make RELEASE=1". This
# enables BOOTOBJS and uses the VERSION string defined in main.c
ifdef RELEASE
CFLAGS += -DRELEASE
BOOTOBJS=1
endif
ifdef BOOTOBJS
BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini1g.c \
ipodmini2g.c ipodnano1g.c ipodvideo.c ipodnano2g.c
CFLAGS += -DWITH_BOOTOBJS
endif
# additional frameworks to link on on OS X
LDOPTS_OSX = -framework CoreFoundation -framework IOKit
LIBSOURCES = ipodpatcher.c fat32format.c arc4.c \
ipodio-posix.c ipodio-win32-scsi.c ipodio-win32.c
SOURCES = main.c $(BOOTSRC)
ipodpatcher: SOURCES+= ipodio-posix.c
OUTPUT = ipodpatcher
include ../libtools.make
ipodpatcher.exe: $(OBJDIR)ipodpatcher-rc.o
$(OBJDIR)ipodpatcher-rc.o: ipodpatcher.rc ipodpatcher.manifest
@echo WINDRES $(notdir $<)
$(SILENT)$(CROSS)$(WINDRES) -i $< -o $@
%.c: bootloader-%.ipod $(BIN2C)
@echo BIN2C $<
$(SILENT)$(BIN2C) -i $< $*
%.c: bootloader-%.ipodx $(BIN2C)
@echo BIN2C $<
$(SILENT)$(BIN2C) -i $< $*

108
utils/ipodpatcher/arc4.c Normal file
View file

@ -0,0 +1,108 @@
/*
* arc4.c
* Release $Name: MATRIXSSL_1_8_3_OPEN $
*
* ARC4 stream cipher implementation
*/
/*
* Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; 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 General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from PeerSec Networks
* at http://www.peersec.com
*
* This program is distributed in 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
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#include "arc4.h"
/*
Some accounts, such as O'Reilly's Secure Programming Cookbook say that no
more than 2^30 bytes should be processed without rekeying, so we
enforce that limit here. FYI, this is equal to 1GB of data transferred.
*/
#define ARC4_MAX_BYTES 0x40000000
/******************************************************************************/
/*
SSL_RSA_WITH_RC4_* cipher callbacks
*/
void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen)
{
unsigned char index1, index2, tmp, *state;
int16_t counter;
ctx->byteCount = 0;
state = &ctx->state[0];
for (counter = 0; counter < 256; counter++) {
state[counter] = (unsigned char)counter;
}
ctx->x = 0;
ctx->y = 0;
index1 = 0;
index2 = 0;
for (counter = 0; counter < 256; counter++) {
index2 = (key[index1] + state[counter] + index2) & 0xff;
tmp = state[counter];
state[counter] = state[index2];
state[index2] = tmp;
index1 = (index1 + 1) % keylen;
}
}
int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
unsigned char *out, int32_t len)
{
unsigned char x, y, *state, xorIndex, tmp;
int counter; /* NOTE BY DAVE CHAPMAN: This was a short in
the original code, which caused a segfault
when attempting to process data > 32767
bytes. */
ctx->byteCount += len;
if (ctx->byteCount > ARC4_MAX_BYTES) {
return -1;
}
x = ctx->x;
y = ctx->y;
state = &ctx->state[0];
for (counter = 0; counter < len; counter++) {
x = (x + 1) & 0xff;
y = (state[x] + y) & 0xff;
tmp = state[x];
state[x] = state[y];
state[y] = tmp;
xorIndex = (state[x] + state[y]) & 0xff;
tmp = in[counter];
tmp ^= state[xorIndex];
out[counter] = tmp;
}
ctx->x = x;
ctx->y = y;
return len;
}
/*****************************************************************************/

47
utils/ipodpatcher/arc4.h Normal file
View file

@ -0,0 +1,47 @@
/*
arc4.h - based on matrixssl-1-8-3-open
*/
/*
* Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; 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 General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from PeerSec Networks
* at http://www.peersec.com
*
* This program is distributed in 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
* http://www.gnu.org/copyleft/gpl.html
*/
/*****************************************************************************/
#ifndef _ARC4_H
#include <stdint.h>
struct rc4_key_t
{
unsigned char state[256];
uint32_t byteCount;
unsigned char x;
unsigned char y;
};
void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen);
int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
unsigned char *out, int32_t len);
#endif

View file

@ -0,0 +1,530 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
*
* FAT32 formatting functions. Based on:
*
* Fat32 formatter version 1.03
* (c) Tom Thornhill 2005
* This software is covered by the GPL.
* By using this tool, you agree to absolve Ridgecrop of an liabilities for
* lost data.
* Please backup any data you value before using this tool.
*
*
* Modified June 2007 by Dave Chapman for use in ipodpatcher
*
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include "ipodio.h"
static inline uint16_t swap16(uint16_t value)
{
return (value >> 8) | (value << 8);
}
static inline uint32_t swap32(uint32_t value)
{
uint32_t hi = swap16(value >> 16);
uint32_t lo = swap16(value & 0xffff);
return (lo << 16) | hi;
}
/* The following functions are not the most efficient, but are
self-contained and don't require needing to know endianness of CPU
at compile-time.
Note that htole16/htole32 exist on some platforms, so for
simplicity we use different names.
*/
static uint16_t rb_htole16(uint16_t x)
{
uint16_t test = 0x1234;
unsigned char* p = (unsigned char*)&test;
if (p[0]==0x12) {
/* Big-endian */
return swap16(x);
} else {
return x;
}
}
static uint32_t rb_htole32(uint32_t x)
{
uint32_t test = 0x12345678;
unsigned char* p = (unsigned char*)&test;
if (p[0]==0x12) {
/* Big-endian */
return swap32(x);
} else {
return x;
}
}
/* TODO: Pass these as parameters to the various create_ functions */
/* can be zero for default or 1,2,4,8,16,32 or 64 */
static int sectors_per_cluster = 0;
/* Recommended values */
static uint32_t ReservedSectCount = 32;
static uint32_t NumFATs = 2;
static uint32_t BackupBootSect = 6;
static uint32_t VolumeId=0; /* calculated before format */
/* Calculated later */
static uint32_t FatSize=0;
static uint32_t BytesPerSect=0;
static uint32_t SectorsPerCluster=0;
static uint32_t TotalSectors=0;
static uint32_t SystemAreaSize=0;
static uint32_t UserAreaSize=0;
static uint8_t VolId[12] = "NO NAME ";
struct FAT_BOOTSECTOR32
{
/* Common fields. */
uint8_t sJmpBoot[3];
char sOEMName[8];
uint16_t wBytsPerSec;
uint8_t bSecPerClus;
uint16_t wRsvdSecCnt;
uint8_t bNumFATs;
uint16_t wRootEntCnt;
uint16_t wTotSec16; /* if zero, use dTotSec32 instead */
uint8_t bMedia;
uint16_t wFATSz16;
uint16_t wSecPerTrk;
uint16_t wNumHeads;
uint32_t dHiddSec;
uint32_t dTotSec32;
/* Fat 32/16 only */
uint32_t dFATSz32;
uint16_t wExtFlags;
uint16_t wFSVer;
uint32_t dRootClus;
uint16_t wFSInfo;
uint16_t wBkBootSec;
uint8_t Reserved[12];
uint8_t bDrvNum;
uint8_t Reserved1;
uint8_t bBootSig; /* == 0x29 if next three fields are ok */
uint32_t dBS_VolID;
uint8_t sVolLab[11];
uint8_t sBS_FilSysType[8];
} __attribute__((packed));
struct FAT_FSINFO {
uint32_t dLeadSig; // 0x41615252
uint8_t sReserved1[480]; // zeros
uint32_t dStrucSig; // 0x61417272
uint32_t dFree_Count; // 0xFFFFFFFF
uint32_t dNxt_Free; // 0xFFFFFFFF
uint8_t sReserved2[12]; // zeros
uint32_t dTrailSig; // 0xAA550000
} __attribute__((packed));
/* Write "count" zero sectors, starting at sector "sector" */
static int zero_sectors(struct ipod_t* ipod, uint64_t sector, int count)
{
int n;
if (ipod_seek(ipod, sector * ipod->sector_size) < 0) {
fprintf(stderr,"[ERR] Seek failed\n");
return -1;
}
memset(ipod->sectorbuf, 0, 128 * ipod->sector_size);
/* Write 128 sectors at a time */
while (count) {
if (count >= 128)
n = 128;
else
n = count;
if (ipod_write(ipod,n * ipod->sector_size) < 0) {
perror("[ERR] Write failed in zero_sectors\n");
return -1;
}
count -= n;
}
return 0;
}
/*
28.2 CALCULATING THE VOLUME SERIAL NUMBER
For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
seconds. DOS takes the date and time just before it writes it to the
disk.
Low order word is calculated: Volume Serial Number is:
Month & Day 12/26 0c1ah
Sec & Hundrenths 41:94 295eh 3578:1d02
-----
3578h
High order word is calculated:
Hours & Minutes 21:55 1537h
Year 1995 07cbh
-----
1d02h
*/
static uint32_t get_volume_id ( )
{
/* TODO */
#if 0
SYSTEMTIME s;
uint32_t d;
uint16_t lo,hi,tmp;
GetLocalTime( &s );
lo = s.wDay + ( s.wMonth << 8 );
tmp = (s.wMilliseconds/10) + (s.wSecond << 8 );
lo += tmp;
hi = s.wMinute + ( s.wHour << 8 );
hi += s.wYear;
d = lo + (hi << 16);
return(d);
#endif
return(0);
}
/*
This is the Microsoft calculation from FATGEN
uint32_t RootDirSectors = 0;
uint32_t TmpVal1, TmpVal2, FATSz;
TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
TmpVal2 = (256 * SecPerClus) + NumFATs;
TmpVal2 = TmpVal2 / 2;
FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
return( FatSz );
*/
static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt,
uint32_t SecPerClus, uint32_t NumFATs,
uint32_t BytesPerSect)
{
uint64_t Numerator, Denominator;
uint64_t FatElementSize = 4;
uint64_t FatSz;
/* This is based on
http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
I've made the obvious changes for FAT32
*/
Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
FatSz = Numerator / Denominator;
/* round up */
FatSz += 1;
return((uint32_t)FatSz);
}
static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect)
{
uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
return( (uint8_t) spc );
}
static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors,
uint32_t BytesPerSect)
{
uint8_t ret = 0x01; /* 1 sector per cluster */
uint64_t DiskSizeBytes = (uint64_t)DiskSizeSectors * (uint64_t)BytesPerSect;
int64_t DiskSizeMB = DiskSizeBytes / ( 1024*1024 );
/* 512 MB to 8,191 MB 4 KB */
if ( DiskSizeMB > 512 )
ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */
/* 8,192 MB to 16,383 MB 8 KB */
if ( DiskSizeMB > 8192 )
ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */
/* 16,384 MB to 32,767 MB 16 KB */
if ( DiskSizeMB > 16384 )
ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */
/* Larger than 32,768 MB 32 KB */
if ( DiskSizeMB > 32768 )
ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */
return( ret );
}
static void create_boot_sector(unsigned char* buf,
struct ipod_t* ipod, int partition)
{
struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf;
/* fill out the boot sector and fs info */
pFAT32BootSect->sJmpBoot[0]=0xEB;
pFAT32BootSect->sJmpBoot[1]=0x5A;
pFAT32BootSect->sJmpBoot[2]=0x90;
memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8 );
pFAT32BootSect->wBytsPerSec = rb_htole16(BytesPerSect);
pFAT32BootSect->bSecPerClus = SectorsPerCluster ;
pFAT32BootSect->wRsvdSecCnt = rb_htole16(ReservedSectCount);
pFAT32BootSect->bNumFATs = NumFATs;
pFAT32BootSect->wRootEntCnt = rb_htole16(0);
pFAT32BootSect->wTotSec16 = rb_htole16(0);
pFAT32BootSect->bMedia = 0xF8;
pFAT32BootSect->wFATSz16 = rb_htole16(0);
pFAT32BootSect->wSecPerTrk = rb_htole16(ipod->sectors_per_track);
pFAT32BootSect->wNumHeads = rb_htole16(ipod->num_heads);
pFAT32BootSect->dHiddSec = rb_htole16(ipod->pinfo[partition].start);
pFAT32BootSect->dTotSec32 = rb_htole32(TotalSectors);
pFAT32BootSect->dFATSz32 = rb_htole32(FatSize);
pFAT32BootSect->wExtFlags = rb_htole16(0);
pFAT32BootSect->wFSVer = rb_htole16(0);
pFAT32BootSect->dRootClus = rb_htole32(2);
pFAT32BootSect->wFSInfo = rb_htole16(1);
pFAT32BootSect->wBkBootSec = rb_htole16(BackupBootSect);
pFAT32BootSect->bDrvNum = 0x80;
pFAT32BootSect->Reserved1 = 0;
pFAT32BootSect->bBootSig = 0x29;
pFAT32BootSect->dBS_VolID = rb_htole32(VolumeId);
memcpy(pFAT32BootSect->sVolLab, VolId, 11);
memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 );
buf[510] = 0x55;
buf[511] = 0xaa;
}
static void create_fsinfo(unsigned char* buf)
{
struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf;
/* FSInfo sect */
pFAT32FsInfo->dLeadSig = rb_htole32(0x41615252);
pFAT32FsInfo->dStrucSig = rb_htole32(0x61417272);
pFAT32FsInfo->dFree_Count = rb_htole32((uint32_t) -1);
pFAT32FsInfo->dNxt_Free = rb_htole32((uint32_t) -1);
pFAT32FsInfo->dTrailSig = rb_htole32(0xaa550000);
pFAT32FsInfo->dFree_Count = rb_htole32((UserAreaSize/SectorsPerCluster)-1);
/* clusters 0-1 reserved, we used cluster 2 for the root dir */
pFAT32FsInfo->dNxt_Free = rb_htole32(3);
}
static void create_firstfatsector(unsigned char* buf)
{
uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */
/* First FAT Sector */
p[0] = rb_htole32(0x0ffffff8); /* Reserved cluster 1 media id in low byte */
p[1] = rb_htole32(0x0fffffff); /* Reserved cluster 2 EOC */
p[2] = rb_htole32(0x0fffffff); /* end of cluster chain for root dir */
}
int format_partition(struct ipod_t* ipod, int partition)
{
uint32_t i;
uint64_t qTotalSectors=0;
uint64_t FatNeeded;
VolumeId = get_volume_id( );
/* Only support hard disks at the moment */
if ( ipod->sector_size != 512 )
{
fprintf(stderr,"[ERR] Only disks with 512 bytes per sector are supported.\n");
return -1;
}
BytesPerSect = ipod->sector_size;
/* Checks on Disk Size */
qTotalSectors = ipod->pinfo[partition].size;
/* low end limit - 65536 sectors */
if ( qTotalSectors < 65536 )
{
/* I suspect that most FAT32 implementations would mount this
volume just fine, but the spec says that we shouldn't do
this, so we won't */
fprintf(stderr,"[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" );
return -1;
}
if ( qTotalSectors >= 0xffffffff )
{
/* This is a more fundamental limitation on FAT32 - the total
sector count in the root dir is 32bit. With a bit of
creativity, FAT32 could be extended to handle at least 2^28
clusters There would need to be an extra field in the
FSInfo sector, and the old sector count could be set to
0xffffffff. This is non standard though, the Windows FAT
driver FASTFAT.SYS won't understand this. Perhaps a future
version of FAT32 and FASTFAT will handle this. */
fprintf(stderr,"[ERR] This drive is too big for FAT32 - max 2TB supported\n");
}
if ( sectors_per_cluster ) {
SectorsPerCluster = sectors_per_cluster;
} else {
SectorsPerCluster = get_sectors_per_cluster(ipod->pinfo[partition].size,
BytesPerSect );
}
TotalSectors = (uint32_t) qTotalSectors;
FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount,
SectorsPerCluster, NumFATs, BytesPerSect );
UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
/* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */
SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster);
/* Work out the Cluster count */
FatNeeded = UserAreaSize/SectorsPerCluster;
/* check for a cluster count of >2^28, since the upper 4 bits of
the cluster values in the FAT are reserved. */
if (FatNeeded > 0x0FFFFFFF) {
fprintf(stderr,"[ERR] This drive has more than 2^28 clusters, try to specify a larger cluster size\n" );
return -1;
}
/* Sanity check, make sure the fat is big enough.
Convert the cluster count into a Fat sector count, and check
the fat size value we calculated earlier is OK. */
FatNeeded *=4;
FatNeeded += (BytesPerSect-1);
FatNeeded /= BytesPerSect;
if ( FatNeeded > FatSize ) {
fprintf(stderr,"[ERR] Drive too big to format\n");
return -1;
}
/*
Write boot sector, fats
Sector 0 Boot Sector
Sector 1 FSInfo
Sector 2 More boot code - we write zeros here
Sector 3 unused
Sector 4 unused
Sector 5 unused
Sector 6 Backup boot sector
Sector 7 Backup FSInfo sector
Sector 8 Backup 'more boot code'
zero'd sectors upto ReservedSectCount
FAT1 ReservedSectCount to ReservedSectCount + FatSize
...
FATn ReservedSectCount to ReservedSectCount + FatSize
RootDir - allocated to cluster2
*/
fprintf(stderr,"[INFO] Heads - %d, sectors/track = %d\n",ipod->num_heads,ipod->sectors_per_track);
fprintf(stderr,"[INFO] Size : %" PRIu64 "GB %u sectors\n",
((uint64_t)ipod->pinfo[partition].size * (uint64_t)ipod->sector_size) / (1000*1000*1000), TotalSectors );
fprintf(stderr,"[INFO] %d Bytes Per Sector, Cluster size %d bytes\n", BytesPerSect, SectorsPerCluster*BytesPerSect );
fprintf(stderr,"[INFO] Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff );
fprintf(stderr,"[INFO] %d Reserved Sectors, %d Sectors per FAT, %d fats\n", ReservedSectCount, FatSize, NumFATs );
fprintf (stderr,"[INFO] %d Total clusters\n", UserAreaSize/SectorsPerCluster );
fprintf(stderr,"[INFO] Formatting partition %d:...\n",partition);
/* Once zero_sectors has run, any data on the drive is basically lost... */
fprintf(stderr,"[INFO] Clearing out %d sectors for Reserved sectors, fats and root cluster...\n", SystemAreaSize );
zero_sectors(ipod, ipod->pinfo[partition].start, SystemAreaSize);
fprintf(stderr,"[INFO] Initialising reserved sectors and FATs...\n" );
/* Create the boot sector structure */
create_boot_sector(ipod->sectorbuf, ipod, partition);
create_fsinfo(ipod->sectorbuf + 512);
/* Write boot sector and fsinfo at start of partition */
if (ipod_seek(ipod, ipod->pinfo[partition].start * ipod->sector_size) < 0) {
fprintf(stderr,"[ERR] Seek failed\n");
return -1;
}
if (ipod_write(ipod,512 * 2) < 0) {
perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
return -1;
}
/* Write backup copy of boot sector and fsinfo */
if (ipod_seek(ipod, (ipod->pinfo[partition].start + BackupBootSect) * ipod->sector_size) < 0) {
fprintf(stderr,"[ERR] Seek failed\n");
return -1;
}
if (ipod_write(ipod,512 * 2) < 0) {
perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
return -1;
}
/* Create the first FAT sector */
create_firstfatsector(ipod->sectorbuf);
/* Write the first fat sector in the right places */
for ( i=0; i<NumFATs; i++ ) {
int SectorStart = ReservedSectCount + (i * FatSize );
if (ipod_seek(ipod, (ipod->pinfo[partition].start + SectorStart) * ipod->sector_size) < 0) {
fprintf(stderr,"[ERR] Seek failed\n");
return -1;
}
if (ipod_write(ipod,512) < 0) {
perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
return -1;
}
}
fprintf(stderr,"[INFO] Format successful\n");
return 0;
}

View file

@ -0,0 +1,409 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006-2007 Dave Chapman
*
* 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.
*
****************************************************************************/
#if !defined(_WIN32) /* all non-Windows platforms are considered POSIX. */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include "ipodio.h"
#if defined(linux) || defined (__linux)
#include <sys/mount.h>
#include <linux/hdreg.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>
#define IPOD_SECTORSIZE_IOCTL BLKSSZGET
static void get_geometry(struct ipod_t* ipod)
{
struct hd_geometry geometry;
if (!ioctl(ipod->dh, HDIO_GETGEO, &geometry)) {
/* never use geometry.cylinders - it is truncated */
ipod->num_heads = geometry.heads;
ipod->sectors_per_track = geometry.sectors;
} else {
ipod->num_heads = 0;
ipod->sectors_per_track = 0;
}
}
/* Linux SCSI Inquiry code based on the documentation and example code from
http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html
*/
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
unsigned char* buf, int bufsize)
{
unsigned char cdb[6];
struct sg_io_hdr hdr;
unsigned char sense_buffer[255];
memset(&hdr, 0, sizeof(hdr));
hdr.interface_id = 'S'; /* this is the only choice we have! */
hdr.flags = SG_FLAG_LUN_INHIBIT; /* this would put the LUN to 2nd byte of cdb*/
/* Set xfer data */
hdr.dxferp = buf;
hdr.dxfer_len = bufsize;
/* Set sense data */
hdr.sbp = sense_buffer;
hdr.mx_sb_len = sizeof(sense_buffer);
/* Set the cdb format */
cdb[0] = 0x12;
cdb[1] = 1; /* Enable Vital Product Data (EVPD) */
cdb[2] = page_code & 0xff;
cdb[3] = 0;
cdb[4] = 0xff;
cdb[5] = 0; /* For control filed, just use 0 */
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
hdr.cmdp = cdb;
hdr.cmd_len = 6;
int ret = ioctl(ipod->dh, SG_IO, &hdr);
if (ret < 0) {
return -1;
} else {
return 0;
}
}
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|| defined(__bsdi__) || defined(__DragonFly__)
#include <sys/disk.h>
#define IPOD_SECTORSIZE_IOCTL DIOCGSECTORSIZE
/* TODO: Implement this function for BSD */
static void get_geometry(struct ipod_t* ipod)
{
/* Are these universal for all ipods? */
ipod->num_heads = 255;
ipod->sectors_per_track = 63;
}
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
unsigned char* buf, int bufsize)
{
/* TODO: Implement for BSD */
(void)ipod;
(void)page_code;
(void)buf;
(void)bufsize;
return -1;
}
#elif defined(__APPLE__) && defined(__MACH__)
/* OS X IOKit includes don't like VERSION being defined! */
#undef VERSION
#include <sys/disk.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/scsi/SCSITaskLib.h>
#include <IOKit/scsi/SCSICommandOperationCodes.h>
#define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE
/* TODO: Implement this function for Mac OS X */
static void get_geometry(struct ipod_t* ipod)
{
/* Are these universal for all ipods? */
ipod->num_heads = 255;
ipod->sectors_per_track = 63;
}
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
unsigned char* buf, int bufsize)
{
/* OS X doesn't allow to simply send out a SCSI inquiry request but
* requires registering an interface handler first.
* Currently this is done on each inquiry request which is somewhat
* inefficient but the current ipodpatcher API doesn't really fit here.
* Based on the documentation in Apple's document
* "SCSI Architecture Model Device Interface Guide".
*
* WARNING: this code currently doesn't take the selected device into
* account. It simply looks for an Ipod on the system and uses
* the first match.
*/
(void)ipod;
int result = 0;
/* first, create a dictionary to match the device. This is needed to get the
* service. */
CFMutableDictionaryRef match_dict;
match_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
if(match_dict == NULL)
return -1;
/* set value to match. In case of the Ipod this is "iPodUserClientDevice". */
CFMutableDictionaryRef sub_dict;
sub_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
if(sub_dict == NULL)
return -1;
CFDictionarySetValue(sub_dict, CFSTR(kIOPropertySCSITaskDeviceCategory),
CFSTR("iPodUserClientDevice"));
CFDictionarySetValue(match_dict, CFSTR(kIOPropertyMatchKey), sub_dict);
/* get an iterator for searching for the service. */
kern_return_t kr;
io_iterator_t iterator = IO_OBJECT_NULL;
/* get matching services from IO registry. Consumes one reference to
* the dictionary, so no need to release that. */
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iterator);
if(!iterator | (kr != kIOReturnSuccess))
return -1;
/* get interface and obtain exclusive access */
SInt32 score;
HRESULT herr;
kern_return_t err;
IOCFPlugInInterface **plugin_interface = NULL;
SCSITaskDeviceInterface **interface = NULL;
io_service_t device = IO_OBJECT_NULL;
device = IOIteratorNext(iterator);
err = IOCreatePlugInInterfaceForService(device, kIOSCSITaskDeviceUserClientTypeID,
kIOCFPlugInInterfaceID, &plugin_interface,
&score);
if(err != noErr) {
return -1;
}
/* query the plugin interface for task interface */
herr = (*plugin_interface)->QueryInterface(plugin_interface,
CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), (LPVOID*)&interface);
if(herr != S_OK) {
IODestroyPlugInInterface(plugin_interface);
return -1;
}
err = (*interface)->ObtainExclusiveAccess(interface);
if(err != noErr) {
(*interface)->Release(interface);
IODestroyPlugInInterface(plugin_interface);
return -1;
}
/* do the inquiry */
SCSITaskInterface **task = NULL;
task = (*interface)->CreateSCSITask(interface);
if(task != NULL) {
kern_return_t err;
SCSITaskStatus task_status;
IOVirtualRange* range;
SCSI_Sense_Data sense_data;
SCSICommandDescriptorBlock cdb;
UInt64 transfer_count = 0;
memset(buf, 0, bufsize);
/* allocate virtual range for buffer. */
range = (IOVirtualRange*) malloc(sizeof(IOVirtualRange));
memset(&sense_data, 0, sizeof(sense_data));
memset(cdb, 0, sizeof(cdb));
/* set up range. address is buffer address, length is request size. */
range->address = (IOVirtualAddress)buf;
range->length = bufsize;
/* setup CDB */
cdb[0] = 0x12; /* inquiry */
cdb[1] = 1;
cdb[2] = page_code;
cdb[4] = bufsize;
/* set cdb in task */
err = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte);
if(err != kIOReturnSuccess) {
result = -1;
goto cleanup;
}
err = (*task)->SetScatterGatherEntries(task, range, 1, bufsize,
kSCSIDataTransfer_FromTargetToInitiator);
if(err != kIOReturnSuccess) {
result = -1;
goto cleanup;
}
/* set timeout */
err = (*task)->SetTimeoutDuration(task, 10000);
if(err != kIOReturnSuccess) {
result = -1;
goto cleanup;
}
/* request data */
err = (*task)->ExecuteTaskSync(task, &sense_data, &task_status, &transfer_count);
if(err != kIOReturnSuccess) {
result = -1;
goto cleanup;
}
/* cleanup */
free(range);
/* release task interface */
(*task)->Release(task);
}
else {
result = -1;
}
cleanup:
/* cleanup interface */
(*interface)->ReleaseExclusiveAccess(interface);
(*interface)->Release(interface);
IODestroyPlugInInterface(plugin_interface);
return result;
}
#else
#error No sector-size detection implemented for this platform
#endif
#if defined(__APPLE__) && defined(__MACH__)
static int ipod_unmount(struct ipod_t* ipod)
{
char cmd[4096];
int res;
sprintf(cmd, "/usr/sbin/diskutil unmount \"%ss2\"",ipod->diskname);
fprintf(stderr,"[INFO] ");
res = system(cmd);
if (res==0) {
return 0;
} else {
perror("Unmount failed");
return -1;
}
}
#endif
void ipod_print_error(char* msg)
{
perror(msg);
}
int ipod_open(struct ipod_t* ipod, int silent)
{
ipod->dh=open(ipod->diskname,O_RDONLY);
if (ipod->dh < 0) {
if (!silent) perror(ipod->diskname);
if(errno == EACCES) return -2;
else return -1;
}
/* Read information about the disk */
if(ioctl(ipod->dh,IPOD_SECTORSIZE_IOCTL,&ipod->sector_size) < 0) {
ipod->sector_size=512;
if (!silent) {
fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n"
,ipod->sector_size);
}
}
get_geometry(ipod);
return 0;
}
int ipod_reopen_rw(struct ipod_t* ipod)
{
#if defined(__APPLE__) && defined(__MACH__)
if (ipod_unmount(ipod) < 0)
return -1;
#endif
close(ipod->dh);
ipod->dh=open(ipod->diskname,O_RDWR);
if (ipod->dh < 0) {
perror(ipod->diskname);
return -1;
}
return 0;
}
int ipod_close(struct ipod_t* ipod)
{
close(ipod->dh);
return 0;
}
int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
{
ipod->sectorbuf = malloc(bufsize);
if (ipod->sectorbuf== NULL) {
return -1;
}
return 0;
}
int ipod_dealloc_buffer(struct ipod_t* ipod)
{
if (ipod->sectorbuf == NULL) {
return -1;
}
free(ipod->sectorbuf);
ipod->sectorbuf = NULL;
return 0;
}
int ipod_seek(struct ipod_t* ipod, unsigned long pos)
{
off_t res;
res = lseek(ipod->dh, pos, SEEK_SET);
if (res == -1) {
return -1;
}
return 0;
}
ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
{
if(ipod->sectorbuf == NULL) {
return -1;
}
return read(ipod->dh, ipod->sectorbuf, nbytes);
}
ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
{
if(ipod->sectorbuf == NULL) {
return -1;
}
return write(ipod->dh, ipod->sectorbuf, nbytes);
}
#endif

View file

@ -0,0 +1,147 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 Dave Chapman
*
* 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.
*
*
* Based on the getCapsUsingSCSIPassThrough() function from "cddrv.cpp":
* - http://www.farmanager.com/svn/trunk/unicode_far/cddrv.cpp
*
* Copyright (c) 1996 Eugene Roshal
* Copyright (c) 2000 Far Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#if defined(_WIN32)
#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#include "ipodio.h"
/* from ddk/ntddscsi.h */
#define SCSI_IOCTL_DATA_OUT 0
#define SCSI_IOCTL_DATA_IN 1
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
#define IOCTL_SCSI_PASS_THROUGH \
CTL_CODE(FILE_DEVICE_CONTROLLER, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
typedef struct _SCSI_PASS_THROUGH {
USHORT Length;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR CdbLength;
UCHAR SenseInfoLength;
UCHAR DataIn;
ULONG DataTransferLength;
ULONG TimeOutValue;
ULONG_PTR DataBufferOffset;
ULONG SenseInfoOffset;
UCHAR Cdb[16];
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
SCSI_PASS_THROUGH Spt;
ULONG Filler; /* realign buffers to double word boundary */
UCHAR SenseBuf[32];
UCHAR DataBuf[512];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
unsigned char* buf, int bufsize)
{
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
ULONG length;
DWORD returned;
BOOL status;
if (bufsize > 255) {
fprintf(stderr,"[ERR] Invalid bufsize in ipod_scsi_inquiry\n");
return -1;
}
memset(&sptwb, 0, sizeof(sptwb));
sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
sptwb.Spt.PathId = 0;
sptwb.Spt.TargetId = 1;
sptwb.Spt.Lun = 0;
sptwb.Spt.CdbLength = 6;
sptwb.Spt.SenseInfoLength = 32; /* sbuf size */;
sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;
sptwb.Spt.DataTransferLength = bufsize;
sptwb.Spt.TimeOutValue = 2; /* 2 seconds */
sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf);
sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseBuf);
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf) +
sptwb.Spt.DataTransferLength;
/* Set cdb info */
sptwb.Spt.Cdb[0] = 0x12; /* SCSI Inquiry */
sptwb.Spt.Cdb[1] = 1;
sptwb.Spt.Cdb[2] = page_code;
sptwb.Spt.Cdb[3] = 0;
sptwb.Spt.Cdb[4] = bufsize;
sptwb.Spt.Cdb[5] = 0;
status = DeviceIoControl(ipod->dh,
IOCTL_SCSI_PASS_THROUGH,
&sptwb,
sizeof(SCSI_PASS_THROUGH),
&sptwb,
length,
&returned,
FALSE);
if (status) {
/* W32 sometimes returns more bytes with additional garbage.
* Make sure to not copy that garbage. */
memcpy(buf, sptwb.DataBuf,
(DWORD)bufsize >= returned ? returned : (DWORD)bufsize);
return 0;
} else {
return -1;
}
}
#endif

View file

@ -0,0 +1,226 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006-2007 Dave Chapman
*
* error(), lock_volume() and unlock_volume() functions and inspiration taken
* from:
* RawDisk - Direct Disk Read/Write Access for NT/2000/XP
* Copyright (c) 2003 Jan Kiszka
* http://www.stud.uni-hannover.de/user/73174/RawDisk/
*
* 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.
*
****************************************************************************/
#if defined(_WIN32)
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
#include <stddef.h>
#include <winioctl.h>
#include "ipodio.h"
static int lock_volume(HANDLE hDisk)
{
DWORD dummy;
return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
&dummy, NULL);
}
static int unlock_volume(HANDLE hDisk)
{
DWORD dummy;
return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0,
&dummy, NULL);
}
void ipod_print_error(char* msg)
{
LPSTR pMsgBuf = NULL;
printf(msg);
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pMsgBuf,
0, NULL);
printf(pMsgBuf);
LocalFree(pMsgBuf);
}
int ipod_open(struct ipod_t* ipod, int silent)
{
DISK_GEOMETRY_EX diskgeometry_ex;
DISK_GEOMETRY diskgeometry;
unsigned long n;
ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
if (ipod->dh == INVALID_HANDLE_VALUE) {
if (!silent) ipod_print_error(" Error opening disk: ");
if(GetLastError() == ERROR_ACCESS_DENIED)
return -2;
else
return -1;
}
if (!lock_volume(ipod->dh)) {
if (!silent) ipod_print_error(" Error locking disk: ");
return -1;
}
/* Defaults */
ipod->num_heads = 0;
ipod->sectors_per_track = 0;
if (!DeviceIoControl(ipod->dh,
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
NULL,
0,
&diskgeometry_ex,
sizeof(diskgeometry_ex),
&n,
NULL)) {
if (!DeviceIoControl(ipod->dh,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&diskgeometry,
sizeof(diskgeometry),
&n,
NULL)) {
if (!silent) ipod_print_error(" Error reading disk geometry: ");
return -1;
} else {
ipod->sector_size = diskgeometry.BytesPerSector;
ipod->num_heads = diskgeometry.TracksPerCylinder;
ipod->sectors_per_track = diskgeometry.SectorsPerTrack;
}
} else {
ipod->sector_size = diskgeometry_ex.Geometry.BytesPerSector;
ipod->num_heads = diskgeometry_ex.Geometry.TracksPerCylinder;
ipod->sectors_per_track = diskgeometry_ex.Geometry.SectorsPerTrack;
}
return 0;
}
int ipod_reopen_rw(struct ipod_t* ipod)
{
/* Close existing file and re-open for writing */
unlock_volume(ipod->dh);
CloseHandle(ipod->dh);
ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
if (ipod->dh == INVALID_HANDLE_VALUE) {
ipod_print_error(" Error opening disk: ");
return -1;
}
if (!lock_volume(ipod->dh)) {
ipod_print_error(" Error locking disk: ");
return -1;
}
return 0;
}
int ipod_close(struct ipod_t* ipod)
{
unlock_volume(ipod->dh);
CloseHandle(ipod->dh);
return 0;
}
int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
{
/* The ReadFile function requires a memory buffer aligned to a multiple of
the disk sector size. */
ipod->sectorbuf = (unsigned char*)VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE);
if (ipod->sectorbuf== NULL) {
ipod_print_error(" Error allocating a buffer: ");
return -1;
}
return 0;
}
int ipod_dealloc_buffer(struct ipod_t* ipod)
{
if (ipod->sectorbuf == NULL) {
return -1;
}
if(!VirtualFree(ipod->sectorbuf, 0, MEM_RELEASE)) {
ipod_print_error(" Error releasing buffer ");
return -1;
}
ipod->sectorbuf = NULL;
return 0;
}
int ipod_seek(struct ipod_t* ipod, unsigned long pos)
{
if (SetFilePointer(ipod->dh, pos, NULL, FILE_BEGIN)==0xffffffff) {
ipod_print_error(" Seek error ");
return -1;
}
return 0;
}
ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
{
unsigned long count;
if(ipod->sectorbuf == NULL) {
return -1;
}
if (!ReadFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
ipod_print_error(" Error reading from disk: ");
return -1;
}
return count;
}
ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
{
unsigned long count;
if(ipod->sectorbuf == NULL) {
return -1;
}
if (!WriteFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
ipod_print_error(" Error writing to disk: ");
return -1;
}
return count;
}
#endif

115
utils/ipodpatcher/ipodio.h Normal file
View file

@ -0,0 +1,115 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006-2007 Dave Chapman
*
* 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 __IPODIO_H
#define __IPODIO_H
#include <stdint.h>
#if !defined(_WIN32)
#include <unistd.h>
#elif defined(_MSC_VER)
/* MSVC uses a different name for ssize_t */
#define ssize_t SSIZE_T
#endif
#if defined(__WIN32__) || defined(_WIN32)
#include <windows.h>
#else
#define HANDLE int
#define O_BINARY 0
#endif
/* The maximum number of images in a firmware partition - a guess... */
#define MAX_IMAGES 10
enum firmwaretype_t {
FTYPE_OSOS = 0,
FTYPE_RSRC,
FTYPE_AUPD,
FTYPE_HIBE,
FTYPE_OSBK
};
struct ipod_directory_t {
enum firmwaretype_t ftype;
int id;
uint32_t devOffset; /* Offset of image relative to one sector into bootpart*/
uint32_t len;
uint32_t addr;
uint32_t entryOffset;
uint32_t chksum;
uint32_t vers;
uint32_t loadAddr;
};
/* A fake partition type - DOS partition tables can't include HFS partitions */
#define PARTTYPE_HFS 0xffff
struct partinfo_t {
uint32_t start; /* first sector (LBA) */
uint32_t size; /* number of sectors */
uint32_t type;
};
struct ipod_t {
unsigned char* sectorbuf;
HANDLE dh;
char diskname[4096];
int sector_size;
int sectors_per_track;
int num_heads;
struct ipod_directory_t ipod_directory[MAX_IMAGES];
int nimages;
int ososimage;
off_t diroffset;
off_t start; /* Offset in bytes of firmware partition from start of disk */
off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
struct partinfo_t pinfo[4];
int modelnum;
char* modelname;
char* modelstr;
char* targetname;
int macpod;
char* xmlinfo; /* The XML Device Information (if available) */
int xmlinfo_len;
int ramsize; /* The amount of RAM in the ipod (if available) */
#ifdef WITH_BOOTOBJS
unsigned char* bootloader;
int bootloader_len;
#endif
};
void ipod_print_error(char* msg);
int ipod_open(struct ipod_t* ipod, int silent);
int ipod_reopen_rw(struct ipod_t* ipod);
int ipod_close(struct ipod_t* ipod);
int ipod_seek(struct ipod_t* ipod, unsigned long pos);
int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
unsigned char* buf, int bufsize);
ssize_t ipod_read(struct ipod_t* ipod, int nbytes);
ssize_t ipod_write(struct ipod_t* ipod, int nbytes);
int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize);
int ipod_dealloc_buffer(struct ipod_t* ipod);
/* In fat32format.c */
int format_partition(struct ipod_t* ipod, int partition);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006-2007 Dave Chapman
*
* 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 IPODPATCHER_H
#define IPODPATCHER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "ipodio.h"
/* exit codes */
#define IPOD_OK 0
#define IPOD_WRONG_ARGUMENTS 1
#define IPOD_OPEN_INFILE_FAILED 2
#define IPOD_PARTITION_ERROR 3
#define IPOD_OPEN_OUTFILE_FAILED 4
#define IPOD_CANNOT_REOPEN 5
#define IPOD_ACCESS_DENIED 10
#define IPOD_NOT_FOUND 11
#define IPOD_WRONG_DEVICE_COUNT 12
#define IPOD_IMAGE_ERROR 13
#define IPOD_DUMP_FAILED 14
#define IPOD_MULTIPLE_DEVICES 15
#define IPOD_WRONG_TYPE 16
#define IPOD_UNKNOWN_FW_VERSION -1
/* Size of buffer for disk I/O - 8MB is large enough for any version
of the Apple firmware, but not the Nano's RSRC image. */
#define BUFFER_SIZE 8*1024*1024
extern int ipod_verbose;
#define FILETYPE_DOT_IPOD 0
#define FILETYPE_DOT_BIN 1
#ifdef WITH_BOOTOBJS
#define FILETYPE_INTERNAL 2
#endif
char* get_parttype(unsigned int pt);
int read_partinfo(struct ipod_t* ipod, int silent);
int read_partition(struct ipod_t* ipod, int outfile);
int write_partition(struct ipod_t* ipod, int infile);
int diskmove(struct ipod_t* ipod, int delta);
int add_bootloader(struct ipod_t* ipod, char* filename, int type);
int delete_bootloader(struct ipod_t* ipod);
int write_firmware(struct ipod_t* ipod, char* filename, int type);
int read_firmware(struct ipod_t* ipod, char* filename, int type);
int read_directory(struct ipod_t* ipod);
int list_images(struct ipod_t* ipod);
int getmodel(struct ipod_t* ipod, int ipod_version);
int ipod_scan(struct ipod_t* ipod);
int write_dos_partition_table(struct ipod_t* ipod);
int ipod_get_xmlinfo(struct ipod_t* ipod);
void ipod_get_ramsize(struct ipod_t* ipod);
int read_aupd(struct ipod_t* ipod, char* filename);
int write_aupd(struct ipod_t* ipod, char* filename);
off_t filesize(int fd);
int ipod_has_bootloader(struct ipod_t* ipod);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="ipodpatcher.exe" type="win32"/>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View file

@ -0,0 +1,47 @@
#
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
#
# All files in this archive are subject to the GNU General Public License.
# See the file COPYING in the source tree root for full license agreement.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
TEMPLATE = app
TARGET = ipodpatcher
QT -= core
SOURCES += \
main.c \
ipodpatcher.c \
ipodio-posix.c \
ipodio-win32-scsi.c \
ipodio-win32.c \
fat32format.c \
arc4.c \
HEADERS += \
arc4.h \
ipodio.h \
ipodpatcher.h \
parttypes.h \
DEFINES += RELEASE=1 _LARGEFILE64_SOURCE
RC_FILE = ipodpatcher.rc
macx {
LIBS += -framework CoreFoundation -framework IOKit
}
unix {
target.path = /usr/local/bin
INSTALLS += target
}

View file

@ -0,0 +1 @@
1 24 MOVEABLE PURE "ipodpatcher.manifest"

622
utils/ipodpatcher/main.c Normal file
View file

@ -0,0 +1,622 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006-2007 Dave Chapman
*
* 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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "ipodpatcher.h"
#include "ipodio.h"
#ifdef RELEASE
#undef VERSION
#define VERSION "5.0 with v4.0 bootloaders (v1.0 for 2nd Gen Nano)"
#endif
enum {
NONE,
#ifdef WITH_BOOTOBJS
INSTALL,
#endif
INTERACTIVE,
SHOW_INFO,
LIST_IMAGES,
DELETE_BOOTLOADER,
ADD_BOOTLOADER,
READ_FIRMWARE,
WRITE_FIRMWARE,
READ_AUPD,
WRITE_AUPD,
READ_PARTITION,
WRITE_PARTITION,
FORMAT_PARTITION,
DUMP_XML,
CONVERT_TO_FAT32
};
void print_macpod_warning(void)
{
printf("[INFO] ************************************************************************\n");
printf("[INFO] *** WARNING FOR ROCKBOX USERS\n");
printf("[INFO] *** You must convert this ipod to FAT32 format (aka a \"winpod\")\n");
printf("[INFO] *** if you want to run Rockbox. Rockbox WILL NOT work on this ipod.\n");
printf("[INFO] *** See http://www.rockbox.org/wiki/IpodConversionToFAT32\n");
printf("[INFO] ************************************************************************\n");
}
void print_usage(void)
{
fprintf(stderr,"Usage: ipodpatcher --scan\n");
#ifdef __WIN32__
fprintf(stderr," or ipodpatcher [DISKNO] [action]\n");
#else
fprintf(stderr," or ipodpatcher [device] [action]\n");
#endif
fprintf(stderr,"\n");
fprintf(stderr,"Where [action] is one of the following options:\n");
#ifdef WITH_BOOTOBJS
fprintf(stderr," --install\n");
#endif
fprintf(stderr," -l, --list\n");
fprintf(stderr," -r, --read-partition bootpartition.bin\n");
fprintf(stderr," -w, --write-partition bootpartition.bin\n");
fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
#ifdef WITH_BOOTOBJS
fprintf(stderr," -we, --write-embedded\n");
#endif
fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
fprintf(stderr," -d, --delete-bootloader\n");
fprintf(stderr," -f, --format\n");
fprintf(stderr," -c, --convert\n");
fprintf(stderr," --read-aupd filename.bin\n");
fprintf(stderr," --write-aupd filename.bin\n");
fprintf(stderr," -x --dump-xml filename.xml\n");
fprintf(stderr,"\n");
fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
#ifdef __WIN32__
fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n");
fprintf(stderr,"can identify it as being an ipod.\n");
fprintf(stderr,"\n");
#else
#if defined(linux) || defined (__linux)
fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n");
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your ipod.\n");
#elif defined(__APPLE__) && defined(__MACH__)
fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your ipod.\n");
#endif
fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n");
fprintf(stderr,"an ipod.\n");
#endif
}
void display_partinfo(struct ipod_t* ipod)
{
int i;
double sectors_per_MB = (1024.0*1024.0)/ipod->sector_size;
printf("[INFO] Part Start Sector End Sector Size (MB) Type\n");
for ( i = 0; i < 4; i++ ) {
if (ipod->pinfo[i].start != 0) {
printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n",
i,
(long int)ipod->pinfo[i].start,
(long int)ipod->pinfo[i].start+ipod->pinfo[i].size-1,
ipod->pinfo[i].size/sectors_per_MB,
get_parttype(ipod->pinfo[i].type),
(int)ipod->pinfo[i].type);
}
}
}
int main(int argc, char* argv[])
{
char yesno[4];
int i;
int n;
int infile, outfile;
unsigned int inputsize;
char* filename;
int action = SHOW_INFO;
int type;
struct ipod_t ipod;
fprintf(stderr,"ipodpatcher " VERSION "\n");
fprintf(stderr,"(C) Dave Chapman 2006-2009\n");
fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
print_usage();
return IPOD_OK;
}
if (ipod_alloc_buffer(&ipod,BUFFER_SIZE) < 0) {
fprintf(stderr,"Failed to allocate memory buffer\n");
}
if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) {
if (ipod_scan(&ipod) == 0)
fprintf(stderr,"[ERR] No ipods found.\n");
return IPOD_NOT_FOUND;
}
/* If the first parameter doesn't start with -, then we interpret it as a device */
if ((argc > 1) && (argv[1][0] != '-')) {
ipod.diskname[0]=0;
#ifdef __WIN32__
snprintf(ipod.diskname,sizeof(ipod.diskname),"\\\\.\\PhysicalDrive%s",argv[1]);
#else
strncpy(ipod.diskname,argv[1],sizeof(ipod.diskname));
#endif
i = 2;
} else {
/* Autoscan for ipods */
n = ipod_scan(&ipod);
if (n==0) {
fprintf(stderr,"[ERR] No ipods found, aborting\n");
fprintf(stderr,"[ERR] Please connect your ipod and ensure it is in disk mode\n");
#if defined(__APPLE__) && defined(__MACH__)
fprintf(stderr,"[ERR] Also ensure that itunes is closed, and that your ipod is not mounted.\n");
#elif !defined(__WIN32__)
if (geteuid()!=0) {
fprintf(stderr,"[ERR] You may also need to run ipodpatcher as root.\n");
}
#endif
fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n");
} else if (n > 1) {
fprintf(stderr,"[ERR] %d ipods found, aborting\n",n);
fprintf(stderr,"[ERR] Please connect only one ipod and re-run ipodpatcher.\n");
return IPOD_MULTIPLE_DEVICES;
} else if (n == 1 && ipod.macpod) {
return IPOD_WRONG_TYPE;
}
if (n != 1) {
#ifdef WITH_BOOTOBJS
if (argc==1) {
printf("\nPress ENTER to exit ipodpatcher :");
fgets(yesno,4,stdin);
}
#endif
return IPOD_NOT_FOUND;
}
i = 1;
}
#ifdef WITH_BOOTOBJS
action = INTERACTIVE;
#else
action = NONE;
#endif
while (i < argc) {
if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
action = LIST_IMAGES;
i++;
#ifdef WITH_BOOTOBJS
} else if (strcmp(argv[i],"--install")==0) {
action = INSTALL;
i++;
#endif
} else if ((strcmp(argv[i],"-d")==0) ||
(strcmp(argv[i],"--delete-bootloader")==0)) {
action = DELETE_BOOTLOADER;
i++;
} else if ((strcmp(argv[i],"-a")==0) ||
(strcmp(argv[i],"--add-bootloader")==0)) {
action = ADD_BOOTLOADER;
type = FILETYPE_DOT_IPOD;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-ab")==0) ||
(strcmp(argv[i],"--add-bootloader-bin")==0)) {
action = ADD_BOOTLOADER;
type = FILETYPE_DOT_BIN;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-rf")==0) ||
(strcmp(argv[i],"--read-firmware")==0)) {
action = READ_FIRMWARE;
type = FILETYPE_DOT_IPOD;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-rfb")==0) ||
(strcmp(argv[i],"--read-firmware-bin")==0)) {
action = READ_FIRMWARE;
type = FILETYPE_DOT_BIN;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
#ifdef WITH_BOOTOBJS
} else if ((strcmp(argv[i],"-we")==0) ||
(strcmp(argv[i],"--write-embedded")==0)) {
action = WRITE_FIRMWARE;
type = FILETYPE_INTERNAL;
filename="[embedded bootloader]"; /* Only displayed for user */
i++;
#endif
} else if ((strcmp(argv[i],"-wf")==0) ||
(strcmp(argv[i],"--write-firmware")==0)) {
action = WRITE_FIRMWARE;
type = FILETYPE_DOT_IPOD;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-wfb")==0) ||
(strcmp(argv[i],"--write-firmware-bin")==0)) {
action = WRITE_FIRMWARE;
type = FILETYPE_DOT_BIN;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-r")==0) ||
(strcmp(argv[i],"--read-partition")==0)) {
action = READ_PARTITION;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-w")==0) ||
(strcmp(argv[i],"--write-partition")==0)) {
action = WRITE_PARTITION;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-v")==0) ||
(strcmp(argv[i],"--verbose")==0)) {
ipod_verbose++;
i++;
} else if ((strcmp(argv[i],"-f")==0) ||
(strcmp(argv[i],"--format")==0)) {
action = FORMAT_PARTITION;
i++;
} else if (strcmp(argv[i],"--read-aupd")==0) {
action = READ_AUPD;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if (strcmp(argv[i],"--write-aupd")==0) {
action = WRITE_AUPD;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-x")==0) ||
(strcmp(argv[i],"--dump-xml")==0)) {
action = DUMP_XML;
i++;
if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
filename=argv[i];
i++;
} else if ((strcmp(argv[i],"-c")==0) ||
(strcmp(argv[i],"--convert")==0)) {
action = CONVERT_TO_FAT32;
i++;
} else {
print_usage(); return IPOD_WRONG_ARGUMENTS;
}
}
if (ipod.diskname[0]==0) {
print_usage();
return 1;
}
if (ipod_open(&ipod, 0) < 0) {
return IPOD_ACCESS_DENIED;
}
fprintf(stderr,"[INFO] Reading partition table from %s\n",ipod.diskname);
fprintf(stderr,"[INFO] Sector size is %d bytes\n",ipod.sector_size);
if (read_partinfo(&ipod,0) < 0) {
return IPOD_PARTITION_ERROR;
}
display_partinfo(&ipod);
if (ipod.pinfo[0].start==0) {
fprintf(stderr,"[ERR] No partition 0 on disk:\n");
display_partinfo(&ipod);
return IPOD_PARTITION_ERROR;
}
read_directory(&ipod);
if (ipod.nimages <= 0) {
fprintf(stderr,"[ERR] Failed to read firmware directory - nimages=%d\n",ipod.nimages);
return IPOD_IMAGE_ERROR;
}
if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
ipod.ipod_directory[ipod.ososimage].vers);
return IPOD_UNKNOWN_FW_VERSION;
}
#ifdef __WIN32__
/* Windows requires the ipod in R/W mode for SCSI Inquiry */
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
#endif
/* Read the XML info, and if successful, look for the ramsize
(only available for some models - set to 0 if not known) */
ipod.ramsize = 0;
if (ipod_get_xmlinfo(&ipod) == 0) {
ipod_get_ramsize(&ipod);
}
printf("[INFO] Ipod model: %s ",ipod.modelstr);
if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
if (ipod.macpod) {
print_macpod_warning();
}
if (action==LIST_IMAGES) {
list_images(&ipod);
#ifdef WITH_BOOTOBJS
} else if (action==INTERACTIVE) {
printf("Enter i to install the Rockbox bootloader, u to uninstall\n or c to cancel and do nothing (i/u/c) :");
if (fgets(yesno,4,stdin)) {
if (yesno[0]=='i') {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
} else {
fprintf(stderr,"[ERR] --install failed.\n");
}
} else if (yesno[0]=='u') {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (delete_bootloader(&ipod)==0) {
fprintf(stderr,"[INFO] Bootloader removed.\n");
} else {
fprintf(stderr,"[ERR] Bootloader removal failed.\n");
}
}
}
#endif
} else if (action==DELETE_BOOTLOADER) {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (ipod.ipod_directory[0].entryOffset==0) {
fprintf(stderr,"[ERR] No bootloader detected.\n");
} else {
if (delete_bootloader(&ipod)==0) {
fprintf(stderr,"[INFO] Bootloader removed.\n");
} else {
fprintf(stderr,"[ERR] --delete-bootloader failed.\n");
}
}
} else if (action==ADD_BOOTLOADER) {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (add_bootloader(&ipod, filename, type)==0) {
fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename);
} else {
fprintf(stderr,"[ERR] --add-bootloader failed.\n");
}
#ifdef WITH_BOOTOBJS
} else if (action==INSTALL) {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
} else {
fprintf(stderr,"[ERR] --install failed.\n");
}
#endif
} else if (action==WRITE_FIRMWARE) {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (write_firmware(&ipod, filename,type)==0) {
fprintf(stderr,"[INFO] Firmware %s written to device.\n",filename);
} else {
fprintf(stderr,"[ERR] --write-firmware failed.\n");
}
} else if (action==READ_FIRMWARE) {
if (read_firmware(&ipod, filename, type)==0) {
fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename);
} else {
fprintf(stderr,"[ERR] --read-firmware failed.\n");
}
} else if (action==READ_AUPD) {
if (read_aupd(&ipod, filename)==0) {
fprintf(stderr,"[INFO] AUPD image read to file %s.\n",filename);
} else {
fprintf(stderr,"[ERR] --read-aupd failed.\n");
}
} else if (action==WRITE_AUPD) {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (write_aupd(&ipod, filename)==0) {
fprintf(stderr,"[INFO] AUPD image %s written to device.\n",filename);
} else {
fprintf(stderr,"[ERR] --write-aupd failed.\n");
}
} else if (action==DUMP_XML) {
if (ipod.xmlinfo == NULL) {
fprintf(stderr,"[ERR] No XML to write\n");
return IPOD_DUMP_FAILED;
}
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
if (outfile < 0) {
perror(filename);
return IPOD_OPEN_OUTFILE_FAILED;
}
if (write(outfile, ipod.xmlinfo, ipod.xmlinfo_len) < 0) {
fprintf(stderr,"[ERR] --dump-xml failed.\n");
} else {
fprintf(stderr,"[INFO] XML info written to %s.\n",filename);
}
close(outfile);
} else if (action==READ_PARTITION) {
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
if (outfile < 0) {
perror(filename);
return IPOD_OPEN_OUTFILE_FAILED;
}
if (read_partition(&ipod, outfile) < 0) {
fprintf(stderr,"[ERR] --read-partition failed.\n");
} else {
fprintf(stderr,"[INFO] Partition extracted to %s.\n",filename);
}
close(outfile);
} else if (action==WRITE_PARTITION) {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
infile = open(filename,O_RDONLY|O_BINARY);
if (infile < 0) {
perror(filename);
return IPOD_OPEN_INFILE_FAILED;
}
/* Check filesize is <= partition size */
inputsize=filesize(infile);
if (inputsize > 0) {
if (inputsize <= (ipod.pinfo[0].size*ipod.sector_size)) {
fprintf(stderr,"[INFO] Input file is %u bytes\n",inputsize);
if (write_partition(&ipod,infile) < 0) {
fprintf(stderr,"[ERR] --write-partition failed.\n");
} else {
fprintf(stderr,"[INFO] %s restored to partition\n",filename);
}
} else {
fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n");
}
}
close(infile);
} else if (action==FORMAT_PARTITION) {
printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
printf("Are you sure you want to format your ipod? (y/n):");
if (fgets(yesno,4,stdin)) {
if (yesno[0]=='y') {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (format_partition(&ipod,1) < 0) {
fprintf(stderr,"[ERR] Format failed.\n");
}
} else {
fprintf(stderr,"[INFO] Format cancelled.\n");
}
}
} else if (action==CONVERT_TO_FAT32) {
if (!ipod.macpod) {
printf("[ERR] Ipod is already FAT32, aborting\n");
} else {
printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
printf("Are you sure you want to convert your ipod to FAT32? (y/n):");
if (fgets(yesno,4,stdin)) {
if (yesno[0]=='y') {
if (ipod_reopen_rw(&ipod) < 0) {
return IPOD_CANNOT_REOPEN;
}
if (write_dos_partition_table(&ipod) < 0) {
fprintf(stderr,"[ERR] Partition conversion failed.\n");
}
if (format_partition(&ipod,1) < 0) {
fprintf(stderr,"[ERR] Format failed.\n");
}
} else {
fprintf(stderr,"[INFO] Format cancelled.\n");
}
}
}
}
ipod_close(&ipod);
#ifdef WITH_BOOTOBJS
if (action==INTERACTIVE) {
printf("Press ENTER to exit ipodpatcher :");
fgets(yesno,4,stdin);
}
#endif
ipod_dealloc_buffer(&ipod);
return IPOD_OK;
}

View file

@ -0,0 +1,109 @@
/* DOS partition types - taken from fdisk */
struct parttype {
unsigned char type;
char *name;
};
struct parttype parttypes[] = {
{0x00, "Empty"},
{0x01, "FAT12"},
{0x02, "XENIX root"},
{0x03, "XENIX usr"},
{0x04, "FAT16 <32M"},
{0x05, "Extended"}, /* DOS 3.3+ extended partition */
{0x06, "FAT16"}, /* DOS 16-bit >=32M */
{0x07, "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
{0x08, "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
{0x09, "AIX bootable"}, /* AIX data or Coherent */
{0x0a, "OS/2 Boot Manager"},/* OS/2 Boot Manager */
{0x0b, "W95 FAT32"},
{0x0c, "W95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
{0x0e, "W95 FAT16 (LBA)"},
{0x0f, "W95 Ext'd (LBA)"},
{0x10, "OPUS"},
{0x11, "Hidden FAT12"},
{0x12, "Compaq diagnostics"},
{0x14, "Hidden FAT16 <32M"},
{0x16, "Hidden FAT16"},
{0x17, "Hidden HPFS/NTFS"},
{0x18, "AST SmartSleep"},
{0x1b, "Hidden W95 FAT32"},
{0x1c, "Hidden W95 FAT32 (LBA)"},
{0x1e, "Hidden W95 FAT16 (LBA)"},
{0x24, "NEC DOS"},
{0x39, "Plan 9"},
{0x3c, "PartitionMagic recovery"},
{0x40, "Venix 80286"},
{0x41, "PPC PReP Boot"},
{0x42, "SFS"},
{0x4d, "QNX4.x"},
{0x4e, "QNX4.x 2nd part"},
{0x4f, "QNX4.x 3rd part"},
{0x50, "OnTrack DM"},
{0x51, "OnTrack DM6 Aux1"}, /* (or Novell) */
{0x52, "CP/M"}, /* CP/M or Microport SysV/AT */
{0x53, "OnTrack DM6 Aux3"},
{0x54, "OnTrackDM6"},
{0x55, "EZ-Drive"},
{0x56, "Golden Bow"},
{0x5c, "Priam Edisk"},
{0x61, "SpeedStor"},
{0x63, "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
{0x64, "Novell Netware 286"},
{0x65, "Novell Netware 386"},
{0x70, "DiskSecure Multi-Boot"},
{0x75, "PC/IX"},
{0x80, "Old Minix"}, /* Minix 1.4a and earlier */
{0x81, "Minix / old Linux"},/* Minix 1.4b and later */
{0x82, "Linux swap / Solaris"},
{0x83, "Linux"},
{0x84, "OS/2 hidden C: drive"},
{0x85, "Linux extended"},
{0x86, "NTFS volume set"},
{0x87, "NTFS volume set"},
{0x88, "Linux plaintext"},
{0x8e, "Linux LVM"},
{0x93, "Amoeba"},
{0x94, "Amoeba BBT"}, /* (bad block table) */
{0x9f, "BSD/OS"}, /* BSDI */
{0xa0, "IBM Thinkpad hibernation"},
{0xa5, "FreeBSD"}, /* various BSD flavours */
{0xa6, "OpenBSD"},
{0xa7, "NeXTSTEP"},
{0xa8, "Darwin UFS"},
{0xa9, "NetBSD"},
{0xab, "Darwin boot"},
{0xb7, "BSDI fs"},
{0xb8, "BSDI swap"},
{0xbb, "Boot Wizard hidden"},
{0xbe, "Solaris boot"},
{0xbf, "Solaris"},
{0xc1, "DRDOS/sec (FAT-12)"},
{0xc4, "DRDOS/sec (FAT-16 < 32M)"},
{0xc6, "DRDOS/sec (FAT-16)"},
{0xc7, "Syrinx"},
{0xda, "Non-FS data"},
{0xdb, "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
Concurrent DOS or CTOS */
{0xde, "Dell Utility"}, /* Dell PowerEdge Server utilities */
{0xdf, "BootIt"}, /* BootIt EMBRM */
{0xe1, "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
extended partition */
{0xe3, "DOS R/O"}, /* DOS R/O or SpeedStor */
{0xe4, "SpeedStor"}, /* SpeedStor 16-bit FAT extended
partition < 1024 cyl. */
{0xeb, "BeOS fs"},
{0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
{0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
{0xf0, "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
{0xf1, "SpeedStor"},
{0xf4, "SpeedStor"}, /* SpeedStor large partition */
{0xf2, "DOS secondary"}, /* DOS 3.3+ secondary */
{0xfd, "Linux raid autodetect"},/* New (2.2.x) raid partition with
autodetect using persistent
superblock */
{0xfe, "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
{0xff, "BBT"}, /* Xenix Bad Block Table */
{ 0, 0 }
};

47
utils/jztool/Makefile Normal file
View file

@ -0,0 +1,47 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
CFLAGS += -Wall -Wextra -Iinclude -I../../tools/ucl/include -I../../lib/microtar/src
OUTPUT = jztool
ifdef RELEASE
CFLAGS += -Os -DNDEBUG
else
CFLAGS += -O0 -ggdb
endif
LIBSOURCES := src/buffer.c src/context.c src/device_info.c \
src/identify_file.c src/ucl_unpack.c src/usb.c src/x1000.c
SOURCES := $(LIBSOURCES) jztool.c
EXTRADEPS := libucl.a libmicrotar.a
CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
ifeq ($(findstring WIN32,$(CPPDEFINES)),WIN32)
# TODO: support Windows
else
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
# Mac, tested on x86 only -- may need to adjust paths if building on ARM.
# paths should work with homebrew libusb.
LIBUSB_CFLAGS ?= -I/usr/local/include/libusb-1.0
ifdef STATIC
LIBUSB_LDOPTS ?= /usr/local/lib/libusb-1.0.a -framework IOKit -framework CoreFoundation
else
LIBUSB_LDOPTS ?= -L/usr/local/lib -lusb-1.0
endif
else
# Linux; note for static builds you need to build a copy of libusb without
# udev support and specify the includes / libs manually
LIBUSB_CFLAGS ?= `pkg-config --cflags libusb-1.0`
LIBUSB_LDOPTS ?= `pkg-config --libs libusb-1.0`
endif
endif
CFLAGS += $(LIBUSB_CFLAGS)
LDOPTS += $(LIBUSB_LDOPTS)
include ../libtools.make

135
utils/jztool/README.md Normal file
View file

@ -0,0 +1,135 @@
# jztool -- Ingenic device utility & bootloader installer
The `jztool` utility can help install, backup, and restore the bootloader on
Rockbox players based on a supported Ingenic SoC (currently only the X1000).
## Running jztool
### Getting a bootloader
To use `jztool` you need to compile or download a bootloader for your player.
It's recommended to use only official released bootloaders, since bootloaders
compiled from Git are not tested and might be buggy.
You can download released bootloaders from <https://download.rockbox.org/>.
The bootloader file is named after the target: for example, the FiiO M3K
bootloader is called `bootloader.m3k`. The FiiO M3K is used as an example
here, but the instructions apply to all X1000-based players.
Use `jztool --help` to find out the model name of your player.
### Entering USB boot mode
USB boot mode is a low-level mode provided by the CPU which allows a computer
to load firmware onto the device. You need to put your player into this mode
manually before using `jztool` (unfortunately, it can't be done automatically.)
To connect the player in USB boot mode, follow these steps:
1. Ensure the player is fully powered off.
2. Plug one end of the USB cable into your player.
3. Hold down your player's USB boot key (see below).
4. Plug the other end of the USB cable into your computer.
5. Let go of the USB boot key.
The USB boot key depends on your player:
- FiiO M3K: Volume Down
- Shanling Q1: Play
- Eros Q: Menu
### Linux/Mac
Run the following command in a terminal. Note that on Linux, you will need to
have root access to allow libusb to access the USB device.
```sh
# Linux / Mac
# NOTE: root permissions are required on Linux to access the USB device
# eg. with 'sudo' or 'su -c' depending on your distro.
$ ./jztool fiiom3k load bootloader.m3k
```
### Windows
To allow `jztool` access to your player in USB boot mode, you need to install
the WinUSB driver. The recommended way to install it is using Zadig, which
may be downloaded from its homepage <https://zadig.akeo.ie>. Please note
this is 3rd party software not maintained or supported by Rockbox developers.
(Zadig will require administrator access on the machine you are using.)
When running Zadig you must select the WinUSB driver; the other driver options
will not work properly with `jztool`. You will have to select the correct USB
device in Zadig. All X1000-based players use the same USB ID while in USB boot
mode, listed below. NOTE: the device name may show only as "X" and a hollow
square in Zadig. The IDs will not change, so those are the most reliable way
to confirm you have selected the correct device.
```
Name: Ingenic Semiconductor Co.,Ltd X1000
USB ID: A108 1000
```
Assuming you installed the WinUSB driver successfully, open a command prompt
in the folder containing `jztool`. Administrator access is not required for
this step.
Type the following command to load the Rockbox bootloader:
```sh
# Windows
$ jztool.exe fiiom3k load bootloader.m3k
```
## Using the recovery menu
If `jztool` runs successfully your player will display the Rockbox bootloader's
recovery menu. If you want to permanently install Rockbox to your device, copy
the bootloader file you downloaded to the root of your SD card, insert the SD
card to your player, and choose "Install/update bootloader" from the menu.
It is _highly_ recommended that you take a backup of your existing bootloader
in case of any trouble -- choose "Backup bootloader" from the recovery menu.
The backup file is called `PLAYER-boot.bin`, where `PLAYER` is the model name.
(Example: `fiiom3k-boot.bin`.)
You can restore the backup later by putting it on the root of your SD card and
selecting "Restor bootloader" in the recovery menu.
After installing the Rockbox bootloader, you can access the recovery menu by
holding a key while booting:
- FiiO M3K: Volume Up
- Shanling Q1: Next (button on the lower left)
- Eros Q: Volume Up
### Known issues
- When using the bootloader's USB mode, you may get stuck on "Waiting for USB"
even though the cable is already plugged in. If this occurs, unplug the USB
cable and plug it back in to trigger the connection.
## TODO list
### Add better documentation and logging
There's only a bare minimum of documentation, and logging is sparse, not
really enough to debug problems.
Some of the error messages could be friendlier too.
### Integration with the Rockbox utility
Adding support to the Rockbox utility should be mostly boilerplate since the
jztool library wraps all the troublesome details.
Permissions are an issue on Linux because by default only root can access
"raw" USB devices. If we want to package rbutil for distro we can install
a udev rule to allow access to the specific USB IDs we need, eg. allowing
users in the "wheel" group to access the device.
On Windows and Mac, no special permissions are needed to access USB devices
assuming the drivers are set up. (Zadig does require administrator access
to run, but that's external to the Rockbox utility.)

View file

@ -0,0 +1,202 @@
/***************************************************************************
* __________ __ ___.
* 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 JZTOOL_H
#define JZTOOL_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
* Types, enumerations, etc
*/
#define JZ_CPUINFO_BUFLEN 9
typedef struct jz_context jz_context;
typedef struct jz_usbdev jz_usbdev;
typedef struct jz_device_info jz_device_info;
typedef struct jz_cpu_info jz_cpu_info;
typedef struct jz_buffer jz_buffer;
typedef enum jz_error jz_error;
typedef enum jz_identify_error jz_identify_error;
typedef enum jz_log_level jz_log_level;
typedef enum jz_device_type jz_device_type;
typedef enum jz_cpu_type jz_cpu_type;
typedef void(*jz_log_cb)(jz_log_level, const char*);
enum jz_error {
JZ_SUCCESS = 0,
JZ_ERR_OUT_OF_MEMORY = -1,
JZ_ERR_OPEN_FILE = -2,
JZ_ERR_FILE_IO = -3,
JZ_ERR_USB = -4,
JZ_ERR_NO_DEVICE = -5,
JZ_ERR_BAD_FILE_FORMAT = -6,
JZ_ERR_FLASH_ERROR = -7,
JZ_ERR_OTHER = -99,
};
enum jz_identify_error {
JZ_IDERR_OTHER = -1,
JZ_IDERR_WRONG_SIZE = -2,
JZ_IDERR_BAD_HEADER = -3,
JZ_IDERR_BAD_CHECKSUM = -4,
JZ_IDERR_UNRECOGNIZED_MODEL = -5,
};
enum jz_log_level {
JZ_LOG_IGNORE = -1,
JZ_LOG_ERROR = 0,
JZ_LOG_WARNING = 1,
JZ_LOG_NOTICE = 2,
JZ_LOG_DETAIL = 3,
JZ_LOG_DEBUG = 4,
};
enum jz_device_type {
JZ_DEVICE_FIIOM3K,
JZ_DEVICE_SHANLINGQ1,
JZ_DEVICE_EROSQ,
JZ_NUM_DEVICES,
};
enum jz_cpu_type {
JZ_CPU_X1000,
JZ_NUM_CPUS,
};
struct jz_device_info {
/* internal device name and file extension */
const char* name;
const char* file_ext;
/* human-readable name */
const char* description;
/* device and CPU type */
jz_device_type device_type;
jz_cpu_type cpu_type;
/* USB IDs of the device in mass storage mode */
uint16_t vendor_id;
uint16_t product_id;
};
struct jz_cpu_info {
/* CPU info string, as reported by the boot ROM */
const char* info_str;
/* USB IDs of the boot ROM */
uint16_t vendor_id;
uint16_t product_id;
/* default addresses for running binaries */
uint32_t stage1_load_addr;
uint32_t stage1_exec_addr;
uint32_t stage2_load_addr;
uint32_t stage2_exec_addr;
};
struct jz_buffer {
size_t size;
uint8_t* data;
};
/******************************************************************************
* Library context and general functions
*/
jz_context* jz_context_create(void);
void jz_context_destroy(jz_context* jz);
void jz_context_set_user_data(jz_context* jz, void* ptr);
void* jz_context_get_user_data(jz_context* jz);
void jz_context_set_log_cb(jz_context* jz, jz_log_cb cb);
void jz_context_set_log_level(jz_context* jz, jz_log_level lev);
void jz_log(jz_context* jz, jz_log_level lev, const char* fmt, ...);
void jz_log_cb_stderr(jz_log_level lev, const char* msg);
void jz_sleepms(int ms);
/******************************************************************************
* Device and file info
*/
const jz_device_info* jz_get_device_info(jz_device_type type);
const jz_device_info* jz_get_device_info_named(const char* name);
const jz_device_info* jz_get_device_info_indexed(int index);
const jz_cpu_info* jz_get_cpu_info(jz_cpu_type type);
const jz_cpu_info* jz_get_cpu_info_named(const char* info_str);
int jz_identify_x1000_spl(const void* data, size_t len);
int jz_identify_scramble_image(const void* data, size_t len);
/******************************************************************************
* USB boot ROM protocol
*/
int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t prod_id);
void jz_usb_close(jz_usbdev* dev);
int jz_usb_send(jz_usbdev* dev, uint32_t addr, size_t len, const void* data);
int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data);
int jz_usb_start1(jz_usbdev* dev, uint32_t addr);
int jz_usb_start2(jz_usbdev* dev, uint32_t addr);
int jz_usb_flush_caches(jz_usbdev* dev);
int jz_usb_get_cpu_info(jz_usbdev* dev, char* buffer, size_t buflen);
/******************************************************************************
* Rockbox loader (all functions are model-specific, see docs)
*/
int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename);
/******************************************************************************
* Buffer API and other functions
*/
jz_buffer* jz_buffer_alloc(size_t size, const void* data);
void jz_buffer_free(jz_buffer* buf);
int jz_buffer_load(jz_buffer** buf, const char* filename);
int jz_buffer_save(jz_buffer* buf, const char* filename);
jz_buffer* jz_ucl_unpack(const uint8_t* src, uint32_t src_len, uint32_t* dst_len);
/******************************************************************************
* END
*/
#ifdef __cplusplus
}
#endif
#endif /* JZTOOL_H */

212
utils/jztool/jztool.c Normal file
View file

@ -0,0 +1,212 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
jz_context* jz = NULL;
jz_usbdev* usbdev = NULL;
const jz_device_info* dev_info = NULL;
const jz_cpu_info* cpu_info = NULL;
void usage_x1000(void)
{
printf(
"Usage:\n"
" jztool fiiom3k load <bootloader.m3k>\n"
" jztool shanlingq1 load <bootloader.q1>\n"
" jztool erosq load <bootloader.erosq>\n"
"\n"
"The 'load' command is used to boot the Rockbox bootloader in recovery\n"
"mode, which allows you to install the Rockbox bootloader and backup or\n"
"restore bootloader images. You need to connect your player in USB boot\n"
"mode in order to use this tool.\n"
"\n"
"To connect the player in USB boot mode, follow these steps:\n"
"\n"
"1. Ensure the player is fully powered off.\n"
"2. Plug one end of the USB cable into your player.\n"
"3. Hold down your player's USB boot key (see below).\n"
"4. Plug the other end of the USB cable into your computer.\n"
"5. Let go of the USB boot key.\n"
"\n"
"USB boot keys:\n"
"\n"
" FiiO M3K - Volume Down\n"
" Shanling Q1 - Play\n"
" Eros Q - Menu\n"
"\n"
"Not all players give a visible indication that they are in USB boot mode.\n"
"If you're having trouble connecting your player, try resetting it by\n"
"holding the power button for 10 seconds, and try the above steps again.\n"
"\n"
"Note for Windows users: you need to install the WinUSB driver using a\n"
"3rd-party tool such as Zadig <https://zadig.akeo.ie> before this tool\n"
"can access your player in USB boot mode. You need to run Zadig while the\n"
"player is plugged in and in USB boot mode. For more details check the\n"
"jztool README.md file or visit <https://rockbox.org/wiki/IngenicX1000>.\n"
"\n");
exit(4);
}
int cmdline_x1000(int argc, char** argv)
{
if(argc < 2 || strcmp(argv[0], "load")) {
usage_x1000();
return 2;
}
int rc = jz_usb_open(jz, &usbdev, cpu_info->vendor_id, cpu_info->product_id);
if(rc < 0) {
jz_log(jz, JZ_LOG_ERROR, "Cannot open USB device: %d", rc);
return 1;
}
rc = jz_x1000_boot(usbdev, dev_info->device_type, argv[1]);
if(rc < 0) {
jz_log(jz, JZ_LOG_ERROR, "Boot failed: %d", rc);
return 1;
}
return 0;
}
void usage(void)
{
printf("Usage:\n"
" jztool [global options] <device> <command> [command arguments]\n"
"\n"
"Global options:\n"
" -h, --help Display this help\n"
" -q, --quiet Don't log anything except errors\n"
" -v, --verbose Display detailed logging output\n\n");
printf("Supported devices:\n\n");
for(int i = 0; i < JZ_NUM_DEVICES; ++i) {
const jz_device_info* info = jz_get_device_info_indexed(i);
printf(" %s - %s\n", info->name, info->description);
}
printf("\n"
"For device-specific help run 'jztool DEVICE' without arguments,\n"
"eg. 'jztool fiiom3k' will display help for the FiiO M3K.\n");
exit(4);
}
void cleanup(void)
{
if(usbdev)
jz_usb_close(usbdev);
if(jz)
jz_context_destroy(jz);
}
int main(int argc, char** argv)
{
if(argc < 2)
usage();
/* Library initialization */
jz = jz_context_create();
if(!jz) {
fprintf(stderr, "ERROR: Can't create context");
return 1;
}
atexit(cleanup);
jz_context_set_log_cb(jz, jz_log_cb_stderr);
jz_context_set_log_level(jz, JZ_LOG_NOTICE);
/* Parse global options */
--argc, ++argv;
while(argc > 0 && argv[0][0] == '-') {
if(!strcmp(*argv, "-h") || !strcmp(*argv, "--help"))
usage();
else if(!strcmp(*argv, "-q") || !strcmp(*argv, "--quiet"))
jz_context_set_log_level(jz, JZ_LOG_ERROR);
else if(!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose"))
jz_context_set_log_level(jz, JZ_LOG_DETAIL);
else if(!strcmp(*argv, "-l") || !strcmp(*argv, "--loglevel")) {
++argv;
if(--argc == 0) {
jz_log(jz, JZ_LOG_ERROR, "Missing argument to option %s", *argv);
exit(2);
}
enum jz_log_level level;
if(!strcmp(*argv, "ignore"))
level = JZ_LOG_IGNORE;
else if(!strcmp(*argv, "error"))
level = JZ_LOG_ERROR;
else if(!strcmp(*argv, "warning"))
level = JZ_LOG_WARNING;
else if(!strcmp(*argv, "notice"))
level = JZ_LOG_NOTICE;
else if(!strcmp(*argv, "detail"))
level = JZ_LOG_DETAIL;
else if(!strcmp(*argv, "debug"))
level = JZ_LOG_DEBUG;
else {
jz_log(jz, JZ_LOG_ERROR, "Invalid log level '%s'", *argv);
exit(2);
}
jz_context_set_log_level(jz, level);
} else {
jz_log(jz, JZ_LOG_ERROR, "Invalid global option '%s'", *argv);
exit(2);
}
--argc, ++argv;
}
/* Read the device type */
if(argc == 0) {
jz_log(jz, JZ_LOG_ERROR, "No device specified (try jztool --help)");
exit(2);
}
dev_info = jz_get_device_info_named(*argv);
if(!dev_info) {
jz_log(jz, JZ_LOG_ERROR, "Unknown device '%s' (try jztool --help)", *argv);
exit(2);
}
cpu_info = jz_get_cpu_info(dev_info->cpu_type);
/* Dispatch to device handler */
--argc, ++argv;
switch(dev_info->device_type) {
case JZ_DEVICE_FIIOM3K:
case JZ_DEVICE_SHANLINGQ1:
case JZ_DEVICE_EROSQ:
return cmdline_x1000(argc, argv);
default:
jz_log(jz, JZ_LOG_ERROR, "INTERNAL ERROR: unhandled device type");
return 1;
}
}

134
utils/jztool/src/buffer.c Normal file
View file

@ -0,0 +1,134 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/** \brief Allocate a buffer, optionally providing its contents.
* \param size Number of bytes to allocate
* \param data Initial contents of the buffer, must be at least `size` bytes
* \return Pointer to buffer or NULL if out of memory.
* \note The buffer will not take ownership of the `data` pointer, instead it
* allocates a fresh buffer and copies the contents of `data` into it.
*/
jz_buffer* jz_buffer_alloc(size_t size, const void* data)
{
jz_buffer* buf = malloc(sizeof(struct jz_buffer));
if(!buf)
return NULL;
buf->data = malloc(size);
if(!buf->data) {
free(buf);
return NULL;
}
if(data)
memcpy(buf->data, data, size);
buf->size = size;
return buf;
}
/** \brief Free a buffer
*/
void jz_buffer_free(jz_buffer* buf)
{
if(buf) {
free(buf->data);
free(buf);
}
}
/** \brief Load a buffer from a file
* \param buf Returns loaded buffer on success, unmodified on error
* \param filename Path to the file
* \return either JZ_SUCCESS, or one of the following errors
* \retval JZ_ERR_OPEN_FILE file cannot be opened
* \retval JZ_ERR_OUT_OF_MEMORY cannot allocate buffer to hold file contents
* \retval JZ_ERR_FILE_IO problem reading file data
*/
int jz_buffer_load(jz_buffer** buf, const char* filename)
{
FILE* f;
jz_buffer* b;
int rc;
f = fopen(filename, "rb");
if(!f)
return JZ_ERR_OPEN_FILE;
fseek(f, 0, SEEK_END);
int size = ftell(f);
fseek(f, 0, SEEK_SET);
b = jz_buffer_alloc(size, NULL);
if(!b) {
rc = JZ_ERR_OUT_OF_MEMORY;
goto err_fclose;
}
if(fread(b->data, size, 1, f) != 1) {
rc = JZ_ERR_FILE_IO;
goto err_free_buf;
}
rc = JZ_SUCCESS;
*buf = b;
err_fclose:
fclose(f);
return rc;
err_free_buf:
jz_buffer_free(b);
goto err_fclose;
}
/** \brief Save a buffer to a file
* \param buf Buffer to be written out
* \param filename Path to the file
* \return either JZ_SUCCESS, or one of the following errors
* \retval JZ_ERR_OPEN_FILE file cannot be opened
* \retval JZ_ERR_FILE_IO problem writing file data
*/
int jz_buffer_save(jz_buffer* buf, const char* filename)
{
int rc;
FILE* f;
f = fopen(filename, "wb");
if(!f)
return JZ_ERR_OPEN_FILE;
if(fwrite(buf->data, buf->size, 1, f) != 1) {
rc = JZ_ERR_FILE_IO;
goto err_fclose;
}
rc = JZ_SUCCESS;
err_fclose:
fclose(f);
return rc;
}

177
utils/jztool/src/context.c Normal file
View file

@ -0,0 +1,177 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool_private.h"
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#ifdef WIN32
# include <windows.h>
#endif
/** \brief Allocate a library context
* \returns New context or NULL if out of memory
*/
jz_context* jz_context_create(void)
{
jz_context* jz = malloc(sizeof(struct jz_context));
if(!jz)
return NULL;
memset(jz, 0, sizeof(struct jz_context));
jz->log_level = JZ_LOG_ERROR;
return jz;
}
/** \brief Destroy the context and free its memory */
void jz_context_destroy(jz_context* jz)
{
if(jz->usb_ctx) {
jz_log(jz, JZ_LOG_ERROR, "BUG: USB was not cleaned up properly");
libusb_exit(jz->usb_ctx);
}
free(jz);
}
/** \brief Set a user data pointer. Useful for callbacks. */
void jz_context_set_user_data(jz_context* jz, void* ptr)
{
jz->user_data = ptr;
}
/** \brief Get the user data pointer */
void* jz_context_get_user_data(jz_context* jz)
{
return jz->user_data;
}
/** \brief Set the log message callback.
* \note By default, no message callback is set! No messages will be logged
* in this case, so ensure you set a callback if messages are desired.
*/
void jz_context_set_log_cb(jz_context* jz, jz_log_cb cb)
{
jz->log_cb = cb;
}
/** \brief Set the log level.
*
* Messages of less importance than the set log level are not logged.
* The default log level is `JZ_LOG_WARNING`. The special log level
* `JZ_LOG_IGNORE` can be used to disable all logging temporarily.
*
* The `JZ_LOG_DEBUG` log level is extremely verbose and will log all calls,
* normally it's only useful for catching bugs.
*/
void jz_context_set_log_level(jz_context* jz, jz_log_level lev)
{
jz->log_level = lev;
}
/** \brief Log an informational message.
* \param lev Log level for this message
* \param fmt `printf` style message format string
*/
void jz_log(jz_context* jz, jz_log_level lev, const char* fmt, ...)
{
if(!jz->log_cb)
return;
if(lev == JZ_LOG_IGNORE)
return;
if(lev > jz->log_level)
return;
va_list ap;
va_start(ap, fmt);
int n = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if(n < 0)
return;
char* buf = malloc(n + 1);
if(!buf)
return;
va_start(ap, fmt);
n = vsnprintf(buf, n + 1, fmt, ap);
va_end(ap);
if(n >= 0)
jz->log_cb(lev, buf);
free(buf);
}
/** \brief Log callback which writes messages to `stderr`.
*/
void jz_log_cb_stderr(jz_log_level lev, const char* msg)
{
static const char* const tags[] =
{"ERROR", "WARNING", "NOTICE", "DETAIL", "DEBUG"};
fprintf(stderr, "[%7s] %s\n", tags[lev], msg);
fflush(stderr);
}
/** \brief Sleep for `ms` milliseconds.
*/
void jz_sleepms(int ms)
{
#ifdef WIN32
Sleep(ms);
#else
struct timespec ts;
long ns = ms % 1000;
ts.tv_nsec = ns * 1000 * 1000;
ts.tv_sec = ms / 1000;
nanosleep(&ts, NULL);
#endif
}
/** \brief Add reference to libusb context, allocating it if necessary */
int jz_context_ref_libusb(jz_context* jz)
{
if(jz->usb_ctxref == 0) {
int rc = libusb_init(&jz->usb_ctx);
if(rc < 0) {
jz_log(jz, JZ_LOG_ERROR, "libusb_init: %s", libusb_strerror(rc));
return JZ_ERR_USB;
}
}
jz->usb_ctxref += 1;
return JZ_SUCCESS;
}
/** \brief Remove reference to libusb context, freeing if it hits zero */
void jz_context_unref_libusb(jz_context* jz)
{
if(--jz->usb_ctxref == 0) {
libusb_exit(jz->usb_ctx);
jz->usb_ctx = NULL;
}
}

View file

@ -0,0 +1,109 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool.h"
#include <string.h>
static const jz_device_info infotable[JZ_NUM_DEVICES] = {
[JZ_DEVICE_FIIOM3K] = {
.name = "fiiom3k",
.file_ext = "m3k",
.description = "FiiO M3K",
.device_type = JZ_DEVICE_FIIOM3K,
.cpu_type = JZ_CPU_X1000,
.vendor_id = 0x2972,
.product_id = 0x0003,
},
[JZ_DEVICE_SHANLINGQ1] = {
.name = "shanlingq1",
.file_ext = "q1",
.description = "Shanling Q1",
.device_type = JZ_DEVICE_SHANLINGQ1,
.cpu_type = JZ_CPU_X1000,
.vendor_id = 0x0525,
.product_id = 0xa4a5,
},
[JZ_DEVICE_EROSQ] = {
.name = "erosq",
.file_ext = "erosq",
.description = "AIGO Eros Q",
.device_type = JZ_DEVICE_EROSQ,
.cpu_type = JZ_CPU_X1000,
.vendor_id = 0xc502,
.product_id = 0x0023,
},
};
static const jz_cpu_info cputable[JZ_NUM_CPUS] = {
[JZ_CPU_X1000] = {
.info_str = "X1000_v1",
.vendor_id = 0xa108,
.product_id = 0x1000,
.stage1_load_addr = 0xf4001000,
.stage1_exec_addr = 0xf4001800,
.stage2_load_addr = 0x80004000,
.stage2_exec_addr = 0x80004000,
},
};
/** \brief Lookup info for a device by type, returns NULL if not found. */
const jz_device_info* jz_get_device_info(jz_device_type type)
{
return jz_get_device_info_indexed(type);
}
/** \brief Lookup info for a device by name, returns NULL if not found. */
const jz_device_info* jz_get_device_info_named(const char* name)
{
for(int i = 0; i < JZ_NUM_DEVICES; ++i)
if(!strcmp(infotable[i].name, name))
return &infotable[i];
return NULL;
}
/** \brief Get a device info entry by index, returns NULL if out of range. */
const jz_device_info* jz_get_device_info_indexed(int index)
{
if(index < JZ_NUM_DEVICES)
return &infotable[index];
else
return NULL;
}
/** \brief Lookup info for a CPU, returns NULL if not found. */
const jz_cpu_info* jz_get_cpu_info(jz_cpu_type type)
{
if(type < JZ_NUM_CPUS)
return &cputable[type];
else
return NULL;
}
/** \brief Lookup info for a CPU by info string, returns NULL if not found. */
const jz_cpu_info* jz_get_cpu_info_named(const char* info_str)
{
for(int i = 0; i < JZ_NUM_CPUS; ++i)
if(!strcmp(cputable[i].info_str, info_str))
return &cputable[i];
return NULL;
}

View file

@ -0,0 +1,170 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool.h"
#include <string.h>
/* Following is copied from mkspl-x1000, basically */
struct x1000_spl_header {
uint8_t magic[8];
uint8_t type;
uint8_t crc7;
uint8_t ppb;
uint8_t bpp;
uint32_t length;
};
static const uint8_t x1000_spl_header_magic[8] =
{0x06, 0x05, 0x04, 0x03, 0x02, 0x55, 0xaa, 0x55};
static const size_t X1000_SPL_HEADER_SIZE = 2 * 1024;
static uint8_t crc7(const uint8_t* buf, size_t len)
{
/* table-based computation of CRC7 */
static const uint8_t t[256] = {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
};
uint8_t crc = 0;
while(len--)
crc = t[(crc << 1) ^ *buf++];
return crc;
}
/** \brief Identify a file as an SPL for X1000 CPUs
* \param data File data buffer
* \param len Length of file
* \return JZ_SUCCESS if file looks correct, or one of the following errors
* \retval JZ_IDERR_WRONG_SIZE file too small or size doesn't match header
* \retval JZ_IDERR_BAD_HEADER missing magic bytes from header
* \retval JZ_IDERR_BAD_CHECKSUM CRC7 mismatch
*/
int jz_identify_x1000_spl(const void* data, size_t len)
{
/* Use <= check because a header-only file is not really valid,
* it should have at least one byte in it... */
if(len <= X1000_SPL_HEADER_SIZE)
return JZ_IDERR_WRONG_SIZE;
/* Look for header magic bytes */
const struct x1000_spl_header* header = (const struct x1000_spl_header*)data;
if(memcmp(header->magic, x1000_spl_header_magic, 8))
return JZ_IDERR_BAD_HEADER;
/* Length stored in the header should equal the length of the file */
if(header->length != len)
return JZ_IDERR_WRONG_SIZE;
/* Compute the CRC7 checksum; it only covers the SPL code */
const uint8_t* dat = (const uint8_t*)data;
uint8_t sum = crc7(&dat[X1000_SPL_HEADER_SIZE], len - X1000_SPL_HEADER_SIZE);
if(header->crc7 != sum)
return JZ_IDERR_BAD_CHECKSUM;
return JZ_SUCCESS;
}
static const struct scramble_model_info {
const char* name;
int model_num;
size_t offset_crc;
size_t offset_name;
size_t offset_data;
} scramble_models[] = {
{"fiio", 114, 0, 4, 8},
{"shq1", 115, 0, 4, 8},
{"eros", 116, 0, 4, 8},
{NULL, 0, 0, 0, 0},
};
/** \brief Identify a file as a Rockbox `scramble` image
* \param data File data buffer
* \param len Length of file
* \return JZ_SUCCESS if file looks correct, or one of the following errors
* \retval JZ_IDERR_UNRECOGNIZED_MODEL unsupported/unknown model type
* \retval JZ_IDERR_BAD_CHECKSUM checksum mismatch
*/
int jz_identify_scramble_image(const void* data, size_t len)
{
const uint8_t* dat;
const struct scramble_model_info* model_info;
uint32_t sum, file_sum;
dat = (const uint8_t*)data;
model_info = &scramble_models[0];
/* Look up the model number */
for(; model_info->name != NULL; ++model_info) {
if(model_info->offset_name + 4 > len)
continue;
if(!memcmp(&dat[model_info->offset_name], model_info->name, 4))
break;
}
if(model_info->name == NULL)
return JZ_IDERR_UNRECOGNIZED_MODEL;
/* Compute the checksum */
sum = model_info->model_num;
for(size_t i = model_info->offset_data; i < len; ++i)
sum += dat[i];
/* Compare with file's checksum, it's stored in big-endian form */
dat += model_info->offset_crc;
file_sum = (dat[0] << 24) | (dat[1] << 16) | (dat[2] << 8) | dat[3];
if(sum != file_sum)
return JZ_IDERR_BAD_CHECKSUM;
return JZ_SUCCESS;
}

View file

@ -0,0 +1,44 @@
/***************************************************************************
* __________ __ ___.
* 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 JZTOOL_PRIVATE_H
#define JZTOOL_PRIVATE_H
#include "jztool.h"
#include <libusb.h>
struct jz_context {
void* user_data;
jz_log_cb log_cb;
jz_log_level log_level;
libusb_context* usb_ctx;
int usb_ctxref;
};
struct jz_usbdev {
jz_context* jz;
libusb_device_handle* handle;
};
int jz_context_ref_libusb(jz_context* jz);
void jz_context_unref_libusb(jz_context* jz);
#endif /* JZTOOL_PRIVATE_H */

View file

@ -0,0 +1,128 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool.h"
#include "ucl/ucl.h"
static uint32_t xread32(const uint8_t* d)
{
uint32_t r = 0;
r |= d[0] << 24;
r |= d[1] << 16;
r |= d[2] << 8;
r |= d[3] << 0;
return r;
}
/* adapted from firmware/common/ucl_decompress.c */
jz_buffer* jz_ucl_unpack(const uint8_t* src, uint32_t src_len, uint32_t* dst_len)
{
static const uint8_t magic[8] =
{0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a};
jz_buffer* buffer = NULL;
/* make sure there are enough bytes for the header */
if(src_len < 18)
goto error;
/* avoid memcmp for reasons of code size */
for(size_t i = 0; i < sizeof(magic); ++i)
if(src[i] != magic[i])
goto error;
/* read the other header fields */
/* uint32_t flags = xread32(&src[8]); */
uint8_t method = src[12];
/* uint8_t level = src[13]; */
uint32_t block_size = xread32(&src[14]);
/* check supported compression method */
if(method != 0x2e)
goto error;
/* validate */
if(block_size < 1024 || block_size > 8*1024*1024)
goto error;
src += 18;
src_len -= 18;
/* Calculate amount of space that we might need & allocate a buffer:
* - subtract 4 to account for end of file marker
* - each block is block_size bytes + 8 bytes of header
* - add one to nr_blocks to account for case where file size < block size
* - total size = max uncompressed size of block * nr_blocks
*/
uint32_t nr_blocks = (src_len - 4) / (8 + block_size) + 1;
uint32_t max_size = nr_blocks * (block_size + block_size/8 + 256);
buffer = jz_buffer_alloc(max_size, NULL);
if(!buffer)
goto error;
/* perform the decompression */
uint32_t dst_ilen = buffer->size;
uint8_t* dst = buffer->data;
while(1) {
if(src_len < 4)
goto error;
uint32_t out_len = xread32(src); src += 4, src_len -= 4;
if(out_len == 0)
break;
if(src_len < 4)
goto error;
uint32_t in_len = xread32(src); src += 4, src_len -= 4;
if(in_len > block_size || out_len > block_size ||
in_len == 0 || in_len > out_len)
goto error;
if(src_len < in_len)
goto error;
if(in_len < out_len) {
uint32_t actual_out_len = dst_ilen;
int rc = ucl_nrv2e_decompress_safe_8(src, in_len, dst, &actual_out_len, NULL);
if(rc != UCL_E_OK)
goto error;
if(actual_out_len != out_len)
goto error;
} else {
for(size_t i = 0; i < in_len; ++i)
dst[i] = src[i];
}
src += in_len;
src_len -= in_len;
dst += out_len;
dst_ilen -= out_len;
}
/* subtract leftover number of bytes to get size of compressed output */
*dst_len = buffer->size - dst_ilen;
return buffer;
error:
jz_buffer_free(buffer);
return NULL;
}

291
utils/jztool/src/usb.c Normal file
View file

@ -0,0 +1,291 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool_private.h"
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define VR_GET_CPU_INFO 0
#define VR_SET_DATA_ADDRESS 1
#define VR_SET_DATA_LENGTH 2
#define VR_FLUSH_CACHES 3
#define VR_PROGRAM_START1 4
#define VR_PROGRAM_START2 5
/** \brief Open a USB device
* \param jz Context
* \param devptr Returns pointer to the USB device upon success
* \param vend_id USB vendor ID
* \param prod_id USB product ID
* \return either JZ_SUCCESS if device was opened, or an error below
* \retval JZ_ERR_OUT_OF_MEMORY malloc failed
* \retval JZ_ERR_USB libusb error (details are logged)
* \retval JZ_ERR_NO_DEVICE can't unambiguously find the device
*/
int jz_usb_open(jz_context* jz, jz_usbdev** devptr, uint16_t vend_id, uint16_t prod_id)
{
int rc;
jz_usbdev* dev = NULL;
libusb_device_handle* usb_handle = NULL;
libusb_device** dev_list = NULL;
ssize_t dev_index = -1, dev_count;
rc = jz_context_ref_libusb(jz);
if(rc < 0)
return rc;
dev = malloc(sizeof(struct jz_usbdev));
if(!dev) {
rc = JZ_ERR_OUT_OF_MEMORY;
goto error;
}
dev_count = libusb_get_device_list(jz->usb_ctx, &dev_list);
if(dev_count < 0) {
jz_log(jz, JZ_LOG_ERROR, "libusb_get_device_list: %s", libusb_strerror(dev_count));
rc = JZ_ERR_USB;
goto error;
}
for(ssize_t i = 0; i < dev_count; ++i) {
struct libusb_device_descriptor desc;
rc = libusb_get_device_descriptor(dev_list[i], &desc);
if(rc < 0) {
jz_log(jz, JZ_LOG_WARNING, "libusb_get_device_descriptor: %s",
libusb_strerror(rc));
continue;
}
if(desc.idVendor != vend_id || desc.idProduct != prod_id)
continue;
if(dev_index >= 0) {
/* not the best, but it is the safest thing */
jz_log(jz, JZ_LOG_ERROR, "Multiple devices match ID %04x:%04x",
(unsigned int)vend_id, (unsigned int)prod_id);
jz_log(jz, JZ_LOG_ERROR, "Please ensure only one player is plugged in, and try again");
rc = JZ_ERR_NO_DEVICE;
goto error;
}
dev_index = i;
}
if(dev_index < 0) {
jz_log(jz, JZ_LOG_ERROR, "No device with ID %04x:%04x found",
(unsigned int)vend_id, (unsigned int)prod_id);
rc = JZ_ERR_NO_DEVICE;
goto error;
}
rc = libusb_open(dev_list[dev_index], &usb_handle);
if(rc < 0) {
jz_log(jz, JZ_LOG_ERROR, "libusb_open: %s", libusb_strerror(rc));
rc = JZ_ERR_USB;
goto error;
}
rc = libusb_claim_interface(usb_handle, 0);
if(rc < 0) {
jz_log(jz, JZ_LOG_ERROR, "libusb_claim_interface: %s", libusb_strerror(rc));
rc = JZ_ERR_USB;
goto error;
}
jz_log(jz, JZ_LOG_DEBUG, "Opened device (%p, ID %04x:%04x)",
dev, (unsigned int)vend_id, (unsigned int)prod_id);
dev->jz = jz;
dev->handle = usb_handle;
*devptr = dev;
rc = JZ_SUCCESS;
exit:
if(dev_list)
libusb_free_device_list(dev_list, true);
return rc;
error:
if(dev)
free(dev);
if(usb_handle)
libusb_close(usb_handle);
jz_context_unref_libusb(jz);
goto exit;
}
/** \brief Close a USB device
* \param dev Device to close; memory will be freed automatically
*/
void jz_usb_close(jz_usbdev* dev)
{
jz_log(dev->jz, JZ_LOG_DEBUG, "Closing device (%p)", dev);
libusb_release_interface(dev->handle, 0);
libusb_close(dev->handle);
jz_context_unref_libusb(dev->jz);
free(dev);
}
// Does an Ingenic-specific vendor request
// Written with X1000 in mind but other Ingenic CPUs have the same commands
static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg,
void* buffer, int buflen)
{
int rc = libusb_control_transfer(dev->handle,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
req, arg >> 16, arg & 0xffff, buffer, buflen, 1000);
if(rc < 0) {
jz_log(dev->jz, JZ_LOG_ERROR, "libusb_control_transfer: %s", libusb_strerror(rc));
rc = JZ_ERR_USB;
} else {
static const char* req_names[] = {
"GET_CPU_INFO",
"SET_DATA_ADDRESS",
"SET_DATA_LENGTH",
"FLUSH_CACHES",
"PROGRAM_START1",
"PROGRAM_START2",
};
jz_log(dev->jz, JZ_LOG_DEBUG, "Issued %s %08lu",
req_names[req], (unsigned long)arg);
rc = JZ_SUCCESS;
}
return rc;
}
// Bulk transfer wrapper
static int jz_usb_transfer(jz_usbdev* dev, bool write, size_t len, void* buf)
{
int xfered = 0;
int ep = write ? LIBUSB_ENDPOINT_OUT|1 : LIBUSB_ENDPOINT_IN|1;
int rc = libusb_bulk_transfer(dev->handle, ep, buf, len, &xfered, 10000);
if(rc < 0) {
jz_log(dev->jz, JZ_LOG_ERROR, "libusb_bulk_transfer: %s", libusb_strerror(rc));
rc = JZ_ERR_USB;
} else if(xfered != (int)len) {
jz_log(dev->jz, JZ_LOG_ERROR, "libusb_bulk_transfer: incorrect amount of data transfered");
rc = JZ_ERR_USB;
} else {
jz_log(dev->jz, JZ_LOG_DEBUG, "Transferred %zu bytes %s",
len, write ? "to device" : "from device");
rc = JZ_SUCCESS;
}
return rc;
}
// Memory send/receive primitive, performs the necessary vendor requests
// and then tranfers data using the bulk endpoint
static int jz_usb_sendrecv(jz_usbdev* dev, bool write, uint32_t addr,
size_t len, void* data)
{
int rc;
rc = jz_usb_vendor_req(dev, VR_SET_DATA_ADDRESS, addr, NULL, 0);
if(rc < 0)
return rc;
rc = jz_usb_vendor_req(dev, VR_SET_DATA_LENGTH, len, NULL, 0);
if(rc < 0)
return rc;
return jz_usb_transfer(dev, write, len, data);
}
/** \brief Write data to device memory
* \param dev USB device
* \param addr Address where data should be written
* \param len Length of the data, in bytes, should be positive
* \param data Data buffer
* \return either JZ_SUCCESS on success or a failure code
*/
int jz_usb_send(jz_usbdev* dev, uint32_t addr, size_t len, const void* data)
{
return jz_usb_sendrecv(dev, true, addr, len, (void*)data);
}
/** \brief Read data to device memory
* \param dev USB device
* \param addr Address to read from
* \param len Length of the data, in bytes, should be positive
* \param data Data buffer
* \return either JZ_SUCCESS on success or a failure code
*/
int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data)
{
return jz_usb_sendrecv(dev, false, addr, len, data);
}
/** \brief Execute stage1 program jumping to the specified address
* \param dev USB device
* \param addr Address to begin execution at
* \return either JZ_SUCCESS on success or a failure code
*/
int jz_usb_start1(jz_usbdev* dev, uint32_t addr)
{
return jz_usb_vendor_req(dev, VR_PROGRAM_START1, addr, NULL, 0);
}
/** \brief Execute stage2 program jumping to the specified address
* \param dev USB device
* \param addr Address to begin execution at
* \return either JZ_SUCCESS on success or a failure code
*/
int jz_usb_start2(jz_usbdev* dev, uint32_t addr)
{
return jz_usb_vendor_req(dev, VR_PROGRAM_START2, addr, NULL, 0);
}
/** \brief Ask device to flush CPU caches
* \param dev USB device
* \return either JZ_SUCCESS on success or a failure code
*/
int jz_usb_flush_caches(jz_usbdev* dev)
{
return jz_usb_vendor_req(dev, VR_FLUSH_CACHES, 0, NULL, 0);
}
/** \brief Ask device for CPU info string
* \param dev USB device
* \param buffer Buffer to hold the info string
* \param buflen Size of the buffer, in bytes
* \return either JZ_SUCCESS on success or a failure code
*
* The buffer will always be null terminated, but to ensure the info string is
* not truncated the buffer needs to be at least `JZ_CPUINFO_BUFLEN` byes long.
*/
int jz_usb_get_cpu_info(jz_usbdev* dev, char* buffer, size_t buflen)
{
char tmpbuf[JZ_CPUINFO_BUFLEN];
int rc = jz_usb_vendor_req(dev, VR_GET_CPU_INFO, 0, tmpbuf, 8);
if(rc != JZ_SUCCESS)
return rc;
if(buflen > 0) {
strncpy(buffer, tmpbuf, buflen);
buffer[buflen - 1] = 0;
}
return JZ_SUCCESS;
}

180
utils/jztool/src/x1000.c Normal file
View file

@ -0,0 +1,180 @@
/***************************************************************************
* __________ __ ___.
* 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 "jztool.h"
#include "jztool_private.h"
#include "microtar-stdio.h"
#include <stdbool.h>
#include <string.h>
/* TODO: these functions could be refactored to be CPU-agnostic */
static int run_stage1(jz_usbdev* dev, jz_buffer* buf)
{
int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data);
if(rc < 0)
return rc;
return jz_usb_start1(dev, 0xf4001800);
}
static int run_stage2(jz_usbdev* dev, jz_buffer* buf)
{
int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data);
if(rc < 0)
return rc;
rc = jz_usb_flush_caches(dev);
if(rc < 0)
return rc;
return jz_usb_start2(dev, 0x80004000);
}
static int get_file(jz_context* jz, mtar_t* tar, const char* file,
bool decompress, jz_buffer** buf)
{
jz_buffer* buffer = NULL;
const mtar_header_t* h;
int rc;
rc = mtar_find(tar, file);
if(rc != MTAR_ESUCCESS) {
jz_log(jz, JZ_LOG_ERROR, "can't find %s in boot file, tar error %d", file, rc);
return JZ_ERR_BAD_FILE_FORMAT;
}
h = mtar_get_header(tar);
buffer = jz_buffer_alloc(h->size, NULL);
if(!buffer)
return JZ_ERR_OUT_OF_MEMORY;
rc = mtar_read_data(tar, buffer->data, buffer->size);
if(rc < 0 || (unsigned)rc != buffer->size) {
jz_buffer_free(buffer);
jz_log(jz, JZ_LOG_ERROR, "can't read %s in boot file, tar error %d", file, rc);
return JZ_ERR_BAD_FILE_FORMAT;
}
if(decompress) {
uint32_t dst_len;
jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len);
jz_buffer_free(buffer);
if(!nbuf) {
jz_log(jz, JZ_LOG_ERROR, "error decompressing %s in boot file", file);
return JZ_ERR_BAD_FILE_FORMAT;
}
/* for simplicity just forget original size of buffer */
nbuf->size = dst_len;
buffer = nbuf;
}
*buf = buffer;
return JZ_SUCCESS;
}
static int show_version(jz_context* jz, jz_buffer* info_file)
{
/* Extract the version string and log it for informational purposes */
char* boot_version = (char*)info_file->data;
char* endpos = memchr(boot_version, '\n', info_file->size);
if(!endpos) {
jz_log(jz, JZ_LOG_ERROR, "invalid metadata in boot file");
return JZ_ERR_BAD_FILE_FORMAT;
}
*endpos = 0;
jz_log(jz, JZ_LOG_NOTICE, "Rockbox bootloader version: %s", boot_version);
return JZ_SUCCESS;
}
/** \brief Load the Rockbox bootloader on an X1000 device
* \param dev USB device freshly returned by jz_usb_open()
* \param filename Path to the "bootloader.target" file
* \return either JZ_SUCCESS or an error code
*/
int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename)
{
const jz_device_info* dev_info;
char spl_filename[32];
jz_buffer* spl = NULL, *bootloader = NULL, *info_file = NULL;
mtar_t tar;
int rc;
/* In retrospect using a model-dependent archive format was not a good
* idea, but it's not worth fixing just yet... */
dev_info = jz_get_device_info(type);
if(!dev_info)
return JZ_ERR_OTHER;
/* use of sprintf is safe since file_ext is short */
sprintf(spl_filename, "spl.%s", dev_info->file_ext);
/* Now open the archive */
rc = mtar_open(&tar, filename, "rb");
if(rc != MTAR_ESUCCESS) {
jz_log(dev->jz, JZ_LOG_ERROR, "cannot open file %s (tar error: %d)", filename, rc);
return JZ_ERR_OPEN_FILE;
}
/* Extract all necessary files */
rc = get_file(dev->jz, &tar, spl_filename, false, &spl);
if(rc != JZ_SUCCESS)
goto error;
rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader);
if(rc != JZ_SUCCESS)
goto error;
rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file);
if(rc != JZ_SUCCESS)
goto error;
/* Display the version string */
rc = show_version(dev->jz, info_file);
if(rc != JZ_SUCCESS)
goto error;
/* Stage1 boot of SPL to set up hardware */
rc = run_stage1(dev, spl);
if(rc != JZ_SUCCESS)
goto error;
/* Need a bit of time for SPL to handle init */
jz_sleepms(500);
/* Stage2 boot into the bootloader's recovery menu
* User has to take manual action from there */
rc = run_stage2(dev, bootloader);
if(rc != JZ_SUCCESS)
goto error;
rc = JZ_SUCCESS;
error:
if(spl)
jz_buffer_free(spl);
if(bootloader)
jz_buffer_free(bootloader);
if(info_file)
jz_buffer_free(info_file);
mtar_close(&tar);
return rc;
}

183
utils/libtools.make Normal file
View file

@ -0,0 +1,183 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# libtools.make
#
# Common Makefile for tools used by Rockbox Utility.
# Provides rules for building as library, universal library (OS X) and
# standalone binary.
#
# LIBSOURCES is a list of files to build the lib
# SOURCES is a list of files to build for the main binary
# EXTRADEPS is a list of make targets dependencies
#
ifndef V
SILENT = @
endif
# Get directory this Makefile is in for relative paths.
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
ifeq ($(OS),Windows_NT)
SHELL = cmd.exe
mkdir = if not exist $(subst /,\,$(1)) mkdir $(subst /,\,$(1))
rm = if exist $(subst /,\,$(1)) del /q /s $(subst /,\,$(1))
else
mkdir = mkdir -p $(1)
rm = rm -rf $(1)
endif
# overwrite for releases
APPVERSION ?= $(shell $(TOP)/../tools/version.sh $(TOP)/..)
GCCFLAGS += -DVERSION=\"$(APPVERSION)\"
TARGET_DIR ?= $(abspath .)/
CC := gcc
CXX := g++
# use either CC or CXX to link: this makes sure the compiler knows about its
# internal dependencies. Use CXX if we have at least one c++ file, since we
# then need to link the c++ standard library (which CXX does for us).
ifeq ($(strip $(filter %.cpp,$(SOURCES) $(LIBSOURCES))),)
LD := $(CC)
else
LD := $(CXX)
endif
CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
BINARY = $(OUTPUT)
# when building a Windows binary add the correct file suffix
ifeq ($(findstring CYGWIN,$(CPPDEFINES)),CYGWIN)
BINARY = $(OUTPUT).exe
GCCFLAGS += -mno-cygwin
COMPILETARGET = cygwin
else
ifeq ($(findstring MINGW,$(CPPDEFINES)),MINGW)
BINARY = $(OUTPUT).exe
COMPILETARGET = mingw
# use POSIX/C99 printf on windows
GCCFLAGS += -D__USE_MINGW_ANSI_STDIO=1
else
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
COMPILETARGET = darwin
LDOPTS += $(LDOPTS_OSX)
else
COMPILETARGET = posix
endif
endif
endif
$(info Compiler creates $(COMPILETARGET) binaries)
# OS X specifics. Needs to consider cross compiling for Windows.
ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
# When building for 10.4+ we need to use gcc. Otherwise clang is used, so use
# that to determine if we need to set arch and isysroot.
ifeq ($(findstring __clang__,$(CPPDEFINES)),__clang__)
GCCFLAGS += -mmacosx-version-min=10.5
ifneq ($(ISYSROOT),)
GCCFLAGS += -isysroot $(ISYSROOT)
endif
else
# when building libs for OS X 10.4+ build for both i386 and ppc at the same time.
# This creates fat objects, and ar can only create the archive but not operate
# on it. As a result the ar call must NOT use the u (update) flag.
ARCHFLAGS += -arch ppc -arch i386
# building against SDK 10.4 is not compatible with gcc-4.2 (default on newer Xcode)
# might need adjustment for older Xcode.
CC = gcc-4.0
GCCFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4
endif
endif
BUILD_DIR ?= $(TARGET_DIR)build$(COMPILETARGET)
OBJDIR = $(abspath $(BUILD_DIR))/
all: $(BINARY)
OBJS := $(addsuffix .o,$(addprefix $(OBJDIR),$(notdir $(SOURCES))))
LIBOBJS := $(addsuffix .o,$(addprefix $(OBJDIR),$(notdir $(LIBSOURCES))))
# create dependency files. Make sure to use the same prefix as with OBJS!
$(foreach src,$(SOURCES) $(LIBSOURCES),$(eval $(addprefix $(OBJDIR),$(notdir $(src).o)): $(src)))
$(foreach src,$(SOURCES) $(LIBSOURCES),$(eval $(addprefix $(OBJDIR),$(notdir $(src).d)): $(src)))
DEPS = $(addprefix $(OBJDIR),$(addsuffix .d,$(notdir $(SOURCES) $(LIBSOURCES))))
-include $(DEPS)
# additional link dependencies for the standalone executable
# extra dependencies: libucl
LIBUCL = libucl.a
$(LIBUCL): $(OBJDIR)$(LIBUCL)
$(OBJDIR)$(LIBUCL):
$(SILENT)$(MAKE) -C $(TOP)/../tools/ucl/src TARGET_DIR=$(OBJDIR) CC=$(CC) $@
LIBBZIP2 = libbz2.a
$(LIBBZIP2): $(OBJDIR)$(LIBBZIP2)
$(OBJDIR)$(LIBBZIP2):
$(SILENT)$(MAKE) -C $(TOP)/bzip2 TARGET_DIR=$(OBJDIR) CC=$(CC) $@
LIBMICROTAR = libmicrotar.a
$(LIBMICROTAR): $(OBJDIR)$(LIBMICROTAR)
$(OBJDIR)$(LIBMICROTAR):
$(SILENT)$(MAKE) -C $(TOP)/../lib/microtar/src TARGET_DIR=$(OBJDIR) CC=$(CC) $@
# building the standalone executable
$(BINARY): $(OBJS) $(EXTRADEPS) $(addprefix $(OBJDIR),$(EXTRALIBOBJS)) $(TARGET_DIR)lib$(OUTPUT).a
$(info LD $@)
$(SILENT)$(call mkdir,$(dir $@))
# EXTRADEPS need to be built into OBJDIR.
$(SILENT)$(CROSS)$(LD) $(ARCHFLAGS) $(LDFLAGS) -o $(BINARY) \
$(OBJS) $(addprefix $(OBJDIR),$(EXTRADEPS)) \
$(addprefix $(OBJDIR),$(EXTRALIBOBJS)) lib$(OUTPUT).a $(addprefix $(OBJDIR),$(EXTRADEPS)) $(LDOPTS)
# common rules
$(OBJDIR)%.c.o:
$(info CC $<)
$(SILENT)$(call mkdir,$(dir $@))
$(SILENT)$(CROSS)$(CC) $(ARCHFLAGS) $(GCCFLAGS) $(CFLAGS) -MMD -c -o $@ $<
$(OBJDIR)%.cpp.o:
$(info CXX $<)
$(SILENT)$(call mkdir,$(dir $@))
$(SILENT)$(CROSS)$(CXX) $(ARCHFLAGS) $(GCCFLAGS) $(CXXFLAGS) -MMD -c -o $@ $<
# lib rules
lib$(OUTPUT).a: $(TARGET_DIR)lib$(OUTPUT).a
lib$(OUTPUT): $(TARGET_DIR)lib$(OUTPUT).a
$(TARGET_DIR)lib$(OUTPUT).a: $(LIBOBJS) \
$(addprefix $(OBJDIR),$(EXTRALIBOBJS))
# rules to build a DLL. Only works for W32 as target (i.e. MinGW toolchain)
dll: $(OUTPUT).dll
$(OUTPUT).dll: $(TARGET_DIR)$(OUTPUT).dll
$(TARGET_DIR)$(OUTPUT).dll: $(LIBOBJS) $(addprefix $(OBJDIR),$(EXTRALIBOBJS))
$(info DLL $(notdir $@))
$(SILENT)$(call mkdir,$(dir $@))
$(SILENT)$(CROSS)$(CC) $(ARCHFLAGS) $(GCCFLAGS) -shared -o $@ $^ \
-Wl,--output-def,$(TARGET_DIR)$(OUTPUT).def
# create lib file from objects
$(TARGET_DIR)lib$(OUTPUT).a: $(LIBOBJS) $(addprefix $(OBJDIR),$(EXTRALIBOBJS))
$(info AR $(notdir $@))
$(SILENT)$(call mkdir,$(dir $@))
$(SILENT)$(call rm,$@)
$(SILENT)$(CROSS)$(AR) rcs $@ $^
clean:
$(call rm, $(OBJS) $(OUTPUT) $(TARGET_DIR)lib$(OUTPUT)*.a $(OUTPUT).dmg)
$(call rm, $(OUTPUT)-* i386 ppc $(OBJDIR))
# extra tools
BIN2C = $(TOP)/tools/bin2c
$(BIN2C):
$(MAKE) -C $(TOP)/tools
# OS X specifics
$(OUTPUT).dmg: $(OUTPUT)
$(info DMG $@)
$(SILENT)$(call mkdir,"$(OUTPUT)-$(APPVERSION)")
$(SILENT)cp -p $(OUTPUT) "$(OUTPUT)-$(APPVERSION)"
$(SILENT)hdiutil create -srcfolder "$(OUTPUT)-$(APPVERSION)" $@

2
utils/mkamsboot/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build/
mkamsboot

31
utils/mkamsboot/Makefile Normal file
View file

@ -0,0 +1,31 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# We use the UCL code available in the Rockbox tools/ directory
CFLAGS += -I../../tools/ucl/include -Wall
OUTPUT = mkamsboot
LIBUCL = libucl.a
# inputs
LIBSOURCES := dualboot.c md5.c mkamsboot.c
SOURCES := main.c
# additional link dependencies for the standalone executable
EXTRADEPS := $(LIBUCL)
include ../libtools.make
# explicit dependencies on dualboot.{c,h} and mkamsboot.h
$(OBJDIR)mkamsboot.o: dualboot.h dualboot.c mkamsboot.c mkamsboot.h
$(OBJDIR)main.o: dualboot.h dualboot.c main.c mkamsboot.h
$(TARGET_DIR)$(OUTPUT).dll: EXTRALIBOBJS += $(TARGET_DIR)ucl.dll
$(TARGET_DIR)$(OUTPUT).dll: $(TARGET_DIR)ucl.dll
$(TARGET_DIR)ucl.dll:
$(SILENT)$(MAKE) -C ../../tools/ucl/src/ \
BUILD_DIR=$(BUILD_DIR) CC=$(CC) CROSS=$(CROSS) \
TARGET_DIR=$(TARGET_DIR)/ ucl.dll

67
utils/mkamsboot/README Normal file
View file

@ -0,0 +1,67 @@
mkamsboot
---------
A tool to inject a bootloader into a Sansa V2 (AMS) firmware file.
Usage
-----
mkamsboot <firmware file> <boot file> <output file>
<firmware file> is an original Sansa firmware file obtained from the Sansa
forums for example : http://forums.sandisk.com/sansa/?category.id=devices
<boot file> is the code you want to execute (a rockbox bootloader), previously
scrambled with tools/scramble utility.
<output file> is the resulting firmware file which you'll have to copy on your
Sansa player. See "Firmware filenames".
Supported models
----------------
Sansa Clip : firmware version starting with "01."
Sansa Clip+ : firmware version starting with "01."
Sansa Clipv2: firmware version starting with "02."
Sansa ClipZip: firmware version starting with "01."
Sansa Fuze : firmware version starting with "01."
Sansa Fuzev2: firmware version starting with "02."
Sansa E200v2: firmware version starting with "03."
Sansa C200v2: firmware version starting with "03."
Sansa M200v4: firmware version starting with "4."
Firmware filenames
------------------
For the firmware upgrade to happen, the firmware has to be named specially:
clip v2 : m30pa.bin
clip : m300a.bin
clip+ : clppa.bin
clip zip: clpza.bin
fuze : fuzea.bin
fuzev2 : fuzpa.bin
e200v2 : e200pa.bin
c200v2 : c200pa.bin
m200v4 : m200a.bin
Dual-Boot
---------
The purpose of this program is to provide dual-boot between the original
firmware and the new (rockbox) firmware.
By default the player will boot into the new firmware.
To boot into the Original Firmware, you need to press the Left key.
***Note : on the Clip+ you can alternatively press the Home key.
***Note : on the Clip Zip you can alternatively press the Vol- key.
Hacking
-------
See comments in mkamsboot.c and dualboot/dualboot.S for more information.

152
utils/mkamsboot/dualboot.c Normal file
View file

@ -0,0 +1,152 @@
/* Generated by bin2c */
#include "dualboot.h"
unsigned char nrv2e_d8[168] = {
0x0f, 0x18, 0x01, 0x24, 0x65, 0x42, 0xe4, 0x07, 0x05, 0x26, 0x36, 0x02, 0x0a, 0xe0, 0x00, 0x20,
0x00, 0x47, 0x04, 0x78, 0x64, 0x41, 0x01, 0x30, 0x24, 0x06, 0xf7, 0x46, 0x03, 0x78, 0x01, 0x30,
0x13, 0x70, 0x01, 0x32, 0x24, 0x19, 0xfe, 0x46, 0xf3, 0xd0, 0xf7, 0xd2, 0x01, 0x21, 0x04, 0xe0,
0x01, 0x39, 0x24, 0x19, 0xfe, 0x46, 0xec, 0xd0, 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46, 0xe8, 0xd0,
0x49, 0x41, 0x24, 0x19, 0xfe, 0x46, 0xe4, 0xd0, 0xf2, 0xd3, 0xcb, 0x1e, 0x00, 0x21, 0x08, 0xd3,
0x1b, 0x02, 0x05, 0x78, 0x01, 0x30, 0x1d, 0x43, 0xed, 0x43, 0xd8, 0xd0, 0x6d, 0x10, 0x13, 0xd2,
0x03, 0xe0, 0x24, 0x19, 0xfe, 0x46, 0xd4, 0xd0, 0x0e, 0xd2, 0x01, 0x21, 0x24, 0x19, 0xfe, 0x46,
0xcf, 0xd0, 0x09, 0xd2, 0x24, 0x19, 0xfe, 0x46, 0xcb, 0xd0, 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46,
0xc7, 0xd0, 0xf7, 0xd3, 0x04, 0x31, 0x04, 0xe0, 0x24, 0x19, 0xfe, 0x46, 0xc1, 0xd0, 0x49, 0x41,
0x02, 0x31, 0xee, 0x42, 0x00, 0xd2, 0x01, 0x31, 0x13, 0x78, 0x53, 0x5d, 0x13, 0x70, 0x01, 0x32,
0x01, 0x39, 0xfa, 0xd1, 0xbe, 0xe7, 0x00, 0x00
};
unsigned char dualboot_clip[196] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x6c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x80, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x04, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a, 0x70, 0x00, 0x1f, 0xe5,
0x70, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x84, 0x00, 0x1f, 0xe5, 0x84, 0x10, 0x1f, 0xe5,
0x7c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8,
0x00, 0x00, 0x0c, 0xc8
};
unsigned char dualboot_e200v2[176] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x60, 0x00, 0x1f, 0xe5,
0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
};
unsigned char dualboot_c200v2[272] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0xa8, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x9c, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5,
0x94, 0x20, 0x9f, 0xe5, 0x0c, 0x10, 0xa0, 0xe3, 0x20, 0x14, 0x82, 0xe5, 0x8c, 0x20, 0x9f, 0xe5,
0xff, 0x10, 0xa0, 0xe3, 0x20, 0x14, 0x82, 0xe5, 0x84, 0x00, 0x9f, 0xe5, 0x91, 0x1a, 0xa0, 0xe3,
0x08, 0x10, 0x80, 0xe5, 0x7c, 0x10, 0x9f, 0xe5, 0x10, 0x10, 0x80, 0xe5, 0x0c, 0x10, 0x90, 0xe5,
0x01, 0x1b, 0x11, 0xe2, 0xfc, 0xff, 0xff, 0x0a, 0x6c, 0x10, 0x9f, 0xe5, 0x08, 0x10, 0x80, 0xe5,
0x0c, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x11, 0xe2, 0xfc, 0xff, 0xff, 0x0a, 0xb4, 0x11, 0xd0, 0xe1,
0x04, 0x00, 0x11, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x1f, 0xe5, 0xac, 0x10, 0x1f, 0xe5,
0x01, 0x00, 0x00, 0xea, 0xc0, 0x00, 0x1f, 0xe5, 0xc0, 0x10, 0x1f, 0xe5, 0xb8, 0x30, 0x1f, 0xe5,
0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4,
0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3,
0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x38, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0c, 0xc8,
0x00, 0x00, 0x0d, 0xc8, 0x00, 0x00, 0x12, 0xc8, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0x90, 0x08, 0x00
};
unsigned char dualboot_m200v4[180] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x80, 0x10, 0x80, 0xe5, 0x04, 0x20, 0x90, 0xe5, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x64, 0x00, 0x1f, 0xe5, 0x64, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x78, 0x00, 0x1f, 0xe5,
0x78, 0x10, 0x1f, 0xe5, 0x70, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
0x00, 0x00, 0x0b, 0xc8
};
unsigned char dualboot_fuze[176] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x60, 0x00, 0x1f, 0xe5,
0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
};
unsigned char dualboot_clipv2[240] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x98, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x8c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x0c, 0x10, 0xc1, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x80, 0x00, 0x9f, 0xe5, 0x38, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x08, 0x10, 0xa0, 0xe3, 0x20, 0x10, 0x80, 0xe5, 0x10, 0x10, 0xa0, 0xe3, 0x40, 0x10, 0x80, 0xe5,
0x20, 0x10, 0xa0, 0xe3, 0x80, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x40, 0x10, 0x80, 0xe5,
0x05, 0x10, 0xa0, 0xe3, 0x01, 0x10, 0x51, 0xe2, 0xfd, 0xff, 0xff, 0x1a, 0x04, 0x10, 0x90, 0xe5,
0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x9c, 0x00, 0x1f, 0xe5, 0x9c, 0x10, 0x1f, 0xe5,
0x01, 0x00, 0x00, 0xea, 0xb0, 0x00, 0x1f, 0xe5, 0xb0, 0x10, 0x1f, 0xe5, 0xa8, 0x30, 0x1f, 0xe5,
0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4,
0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3,
0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x0c, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x0e, 0xc8
};
unsigned char dualboot_clipplus[184] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0x90, 0xe5, 0x50, 0x00, 0x9f, 0xe5,
0x08, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x64, 0x00, 0x1f, 0xe5, 0x64, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x78, 0x00, 0x1f, 0xe5,
0x78, 0x10, 0x1f, 0xe5, 0x70, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
0x00, 0x00, 0x0d, 0xc8, 0x00, 0x00, 0x0b, 0xc8
};
unsigned char dualboot_fuzev2[176] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a, 0x60, 0x00, 0x1f, 0xe5,
0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
};
unsigned char dualboot_clipzip[232] = {
0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x2c, 0x30, 0x0f, 0xe5, 0x90, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
0x00, 0x10, 0x80, 0xe5, 0x84, 0x00, 0x9f, 0xe5, 0x00, 0x11, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3,
0x11, 0x00, 0x00, 0x1a, 0x78, 0x00, 0x9f, 0xe5, 0x00, 0x14, 0x90, 0xe5, 0x06, 0x10, 0x81, 0xe3,
0x20, 0x10, 0xc1, 0xe3, 0x00, 0x14, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5,
0x04, 0x10, 0xa0, 0xe3, 0x10, 0x10, 0x80, 0xe5, 0x32, 0x10, 0xa0, 0xe3, 0x01, 0x10, 0x51, 0xe2,
0xfd, 0xff, 0xff, 0x1a, 0x80, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x94, 0x00, 0x1f, 0xe5, 0x94, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0xa8, 0x00, 0x1f, 0xe5,
0xa8, 0x10, 0x1f, 0xe5, 0xa0, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
0x00, 0x00, 0x0b, 0xc8, 0x00, 0x00, 0x0d, 0xc8
};

View file

@ -0,0 +1,12 @@
/* Generated by bin2c */
extern unsigned char nrv2e_d8[168];
extern unsigned char dualboot_clip[196];
extern unsigned char dualboot_e200v2[176];
extern unsigned char dualboot_c200v2[272];
extern unsigned char dualboot_m200v4[180];
extern unsigned char dualboot_fuze[176];
extern unsigned char dualboot_clipv2[240];
extern unsigned char dualboot_clipplus[184];
extern unsigned char dualboot_fuzev2[176];
extern unsigned char dualboot_clipzip[232];

3
utils/mkamsboot/dualboot/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.arm-bin
*.o
bin2c

View file

@ -0,0 +1,61 @@
CC=gcc
CROSS_PREFIX?=arm-elf-eabi
# Edit the following variables (plus copy/paste another set of rules) when
# adding a new target. mkamsboot.c also needs to be edited to refer to these
# new images.
BOOTOBJS = nrv2e_d8.o dualboot_clip.o dualboot_e200v2.o dualboot_c200v2.o dualboot_m200v4.o dualboot_fuze.o dualboot_clipv2.o dualboot_clipplus.o dualboot_fuzev2.o dualboot_clipzip.o
BOOTBINS = nrv2e_d8.arm-bin dualboot_clip.arm-bin dualboot_e200v2.arm-bin dualboot_c200v2.arm-bin dualboot_m200v4.arm-bin dualboot_fuze.arm-bin dualboot_clipv2.arm-bin dualboot_clipplus.arm-bin dualboot_fuzev2.arm-bin dualboot_clipzip.arm-bin
all: ../dualboot.h ../dualboot.c
# Dualboot bootloaders
dualboot_clip.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIP -c -o dualboot_clip.o dualboot.S
dualboot_fuze.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_FUZE -c -o dualboot_fuze.o dualboot.S
dualboot_e200v2.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_E200V2 -c -o dualboot_e200v2.o dualboot.S
dualboot_m200v4.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_M200V4 -c -o dualboot_m200v4.o dualboot.S
dualboot_c200v2.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_C200V2 -c -o dualboot_c200v2.o dualboot.S
dualboot_clipv2.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIPV2 -c -o dualboot_clipv2.o dualboot.S
dualboot_clipplus.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIPPLUS -c -o dualboot_clipplus.o dualboot.S
dualboot_fuzev2.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_FUZEV2 -c -o dualboot_fuzev2.o dualboot.S
dualboot_clipzip.o: dualboot.S
$(CROSS_PREFIX)-$(CC) -DSANSA_CLIPZIP -c -o dualboot_clipzip.o dualboot.S
# Rules for the ucl unpack function
nrv2e_d8.o: nrv2e_d8.S
$(CROSS_PREFIX)-$(CC) -DPURE_THUMB -c -o nrv2e_d8.o nrv2e_d8.S
# Rules for the ARM code embedded in mkamsboot - assemble, link, then extract
# the binary code and finally convert to .h for building in mkamsboot
%.arm-elf: %.o
$(CROSS_PREFIX)-ld -e 0 -Ttext=0 -o $@ $<
%.arm-bin: %.arm-elf
$(CROSS_PREFIX)-objcopy -O binary $< $@
../dualboot.c ../dualboot.h: $(BOOTBINS) bin2c
./bin2c ../dualboot $(BOOTBINS)
bin2c: bin2c.c
$(CC) -o bin2c bin2c.c
clean:
rm -f *~ bin2c $(BOOTBINS) $(BOOTOBJS)

View file

@ -0,0 +1,140 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 Dave Chapman
*
* 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 <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libgen.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
static off_t filesize(int fd)
{
struct stat buf;
fstat(fd,&buf);
return buf.st_size;
}
static void write_cfile(const unsigned char* buf, off_t len, FILE* fp, const char *name)
{
int i;
fprintf(fp,"unsigned char %s[%ld] = {",name,len);
for (i=0;i<len;i++) {
if ((i % 16) == 0) {
fprintf(fp,"\n ");
}
if (i == (len-1)) {
fprintf(fp,"0x%02x",buf[i]);
} else if ((i % 16) == 15) {
fprintf(fp,"0x%02x,",buf[i]);
} else {
fprintf(fp,"0x%02x, ",buf[i]);
}
}
fprintf(fp,"\n};\n");
}
int main (int argc, char* argv[])
{
char* cname;
int i;
FILE *cfile, *hfile;
char cfilename[256], hfilename[256];
if (argc < 3) {
fprintf(stderr,"Usage: bin2c cname file1 [file2 [file3 ...]]\n");
return 1;
}
cname=argv[1];
snprintf(cfilename,256,"%s.c",cname);
cfile = fopen(cfilename,"w+");
if (cfile == NULL) {
fprintf(stderr,"Couldn't open %s\n",cfilename);
return 2;
}
snprintf(hfilename,256,"%s.h",cname);
hfile = fopen(hfilename,"w+");
if (hfile == NULL) {
fprintf(stderr,"Couldn't open %s\n",hfilename);
fclose(cfile);
return 3;
}
fprintf(cfile,"/* Generated by bin2c */\n\n");
fprintf(cfile,"#include \"%s\"\n\n", basename(hfilename));
fprintf(hfile,"/* Generated by bin2c */\n\n");
for(i=0; i < argc - 2; i++) {
unsigned char* buf;
off_t len;
off_t orig_len;
char *ext;
char *array = argv[2+i];
int fd = open(array,O_RDONLY|O_BINARY);
if (fd < 0) {
fprintf(stderr,"Can not open %s\n",argv[2+i]);
fclose(cfile);
fclose(hfile);
return 4;
}
orig_len = filesize(fd);
/* pad to 32bit */
len = (orig_len + 3) & ~3;
buf = malloc(len);
if (read(fd,buf,orig_len) < orig_len) {
fprintf(stderr,"Short read, aborting\n");
return 5;
}
/* pad to 32bit with zeros */
if (len > orig_len)
memset(buf+orig_len, 0, len-orig_len);
/* remove file extension */
ext = strchr (array, '.');
if (ext != NULL)
*ext = '\0';
write_cfile (buf, len, cfile, array);
fprintf(hfile,"extern unsigned char %s[%ld];\n",array,len);
close(fd);
}
fclose(cfile);
fclose(hfile);
return 0;
}

View file

@ -0,0 +1,307 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 Rafaël Carré
*
* 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.
*
****************************************************************************/
.text
/* AS3525 hardware registers */
.set GPIOA, 0xC80B0000
.set GPIOB, 0xC80C0000
.set GPIOC, 0xC80D0000
.set GPIOD, 0xC80E0000
.set CGU_PROC, 0xC80F0010
.set CGU_PERI, 0xC80F0014
.set CGU_DBOP, 0xC80F0038
.set CCU_IO, 0xC810000C
.set DBOP, 0xC8120000
.set I2C_BASE, 0xC8070000
.set I2C_DATA, 0x00
.set I2C_SLAD0, 0x04
.set I2C_CNTRL, 0x0c
.set I2C_DACNT, 0x10
.set I2C_CPSR0, 0x1c
.set I2C_CPSR1, 0x20
.set I2C_IMR, 0x24
.set I2C_SR, 0x30
.set I2C_SADDR, 0x44
.set AS3514_I2C_ADDR, 0x46
.set AS3514_IRQ_ENRD0, 0x25
.set PCLK, 24000000
.set I2C_CLK, 400000
.set I2C_PRESCALER, ((PCLK + I2C_CLK -1) / I2C_CLK)
.set I2C_PRESCALER_LOW, (I2C_PRESCALER & 0xff)
.set I2C_PRESCALER_HIGH, (I2C_PRESCALER >> 8)
#if I2C_PRESCALER_HIGH > 3
#error i2c prescaler too big!
#endif
b start @ skip our data
/* These values are filled in by mkamsboot - don't move them from offset 0x4 */
uclunpack_end: .word 0 /* End of the ucl_unpack function */
uclunpack_size: .word 0 /* Size in bytes of the ucl_unpack function */
ucl_of_end: .word 0 /* End of the ucl-compressed OF image */
ucl_of_size: .word 0 /* Size in bytes of the compressed OF image */
ucl_rb_end: .word 0 /* End of the ucl-compressed RB image */
ucl_rb_size: .word 0 /* Size in bytes of the compressed RB image */
ucl_dest: .word 0 /* End of our destination buffer (end of memory) */
start:
/* First copy the UCL unpack function to the end of RAM */
ldr r0, uclunpack_end /* Source */
ldr r1, uclunpack_size /* Source length */
sub r2, r0, r1 /* Source start - 1*/
ldr r3, ucl_dest /* Destination end */
uclcopy:
ldrb r4, [r0], #-1
strb r4, [r3], #-1
cmp r2, r0
bne uclcopy
/* store the new destination buffer */
str r3, ucl_dest
/* enable gpio clock */
ldr r0, =CGU_PERI
ldr r1, [r0]
orr r1, r1, #(1<<16)
str r1, [r0]
/* Here are model specific tests for dual boot (test left button) */
#ifdef SANSA_CLIP
.set row, (1<<5) /* enable output on C5 */
.set col, (1<<0) /* read keyscan column B0 */
ldr r0, =GPIOC
mov r1, #row
str r1, [r0, #0x400]
str r1, [r0, #(4*row)]
ldr r0, =GPIOB
mov r1, #0
str r1, [r0, #0x400]
ldr r1, [r0, #(4*col)]
cmp r1, #0
bne boot_of
#elif defined(SANSA_CLIPV2)
.set row, (1<<4) /* enable output on D4 */
.set col, (1<<0) /* read keyscan column D0 */
ldr r0, =CCU_IO
ldr r1, [r0]
bic r1, r1, #(3<<2) @ XPD works as general purpose IO
str r1, [r0]
ldr r0, =GPIOD
mov r1, #((1<<5)|(1<<4)|(1<<3)) /* all rows as output */
str r1, [r0, #0x400]
/* all rows high */
mov r1, #(1<<3)
str r1, [r0, #(4*(1<<3))]
mov r1, #(1<<4)
str r1, [r0, #(4*(1<<4))]
mov r1, #(1<<5)
str r1, [r0, #(4*(1<<5))]
mov r1, #0 /* button row low */
str r1, [r0, #(4*row)]
mov r1, #5 /* small delay */
1: subs r1, r1, #1
bne 1b
ldr r1, [r0, #(4*col)]
cmp r1, #0
beq boot_of
#elif defined(SANSA_E200V2) || defined(SANSA_FUZE)
ldr r0, =GPIOC
mov r1, #0
str r1, [r0, #0x400]
ldr r1, [r0, #0x20] /* read pin C3 */
cmp r1, #0 /* C3 = #0 means button pressed */
beq boot_of
#elif defined(SANSA_FUZEV2)
ldr r0, =GPIOC
mov r1, #0
str r1, [r0, #0x400]
ldr r1, [r0, #0x20] /* read pin C3 */
cmp r1, #0 /* C3 != #0 means button pressed */
bne boot_of
#elif defined(SANSA_CLIPPLUS)
@ read pins
ldr r0, =GPIOC
ldr r1, [r0, #4*(1<<3)] @ read pin C3 "|<<"
ldr r0, =GPIOA
ldr r2, [r0, #4*(1<<1)] @ read pin A1 "Home"
orr r2, r2, r1 @ c3 || A1
cmp r2, #0 @ test input from pins
bne boot_of @ branch directly to OF if either pin high
#elif defined(SANSA_CLIPZIP)
@ read pins
ldr r0, =GPIOA
ldr r1, [r0, #4*(1<<6)] @ read GPIO A6 "vol-"
cmp r1, #0 @ test input from pins
bne boot_of @ branch directly to OF if either pin high
ldr r0, =GPIOC
ldr r1, [r0, #0x400]
orr r1, r1, #((1<<1)|(1<<2)) @ output
bic r1, r1, #(1<<5) @ input
str r1, [r0, #0x400]
mov r1, #0
str r1, [r0, #4*(1<<1)] @ zero C1
mov r1, #(1<<2)
str r1, [r0, #4*(1<<2)] @ set C2
mov r1, #50 /* small delay */
1: subs r1, r1, #1
bne 1b
ldr r1, [r0, #4*(1<<5)] @ read C5 = left
cmp r1, #0
bne boot_of
#elif defined(SANSA_C200V2)
.set BUTTON_LEFT, (1<< 2)
.set BUTTON_DOWN, (1<< 3)
.set BUTTON_SELECT, (1<< 4)
.set BUTTON_UP, (1<< 5)
.set BUTTON_RIGHT, (1<< 6)
.set BUTTON_HOLD, (1<<12)
ldr r0, =CGU_DBOP
mov r1, #(1<<3) @ DBOP freq = PCLK, clock enabled
str r1, [r0]
@ AFSEL needs to be set for this to work
ldr r2, =GPIOB
mov r1, #0xc
str r1, [r2, #0x420] @ GPIOB_AFSEL
ldr r2, =GPIOC
mov r1, #0xff
str r1, [r2, #0x420] @ GPIOC_AFSEL
ldr r0, =DBOP
@ TIMPOL doesn't matter here since we don't need
@ the control signals.
@ 16 bit data width
@ enable write
@ tri-state output
ldr r1, =0x00091000
str r1, [r0, #8] @ DBOP_CTRL
ldr r1, =0xf0ff @ precharge
str r1, [r0, #0x10] @ DBOP_DOUT
2: ldr r1, [r0, #0xc] @ DOBP_STAT
ands r1, r1, #(1<<10)
beq 2b @ make sure fifo is empty
@ 16 bit data width
@ start read
@ tri-state output
@ strobe time 31
ldr r1, =0x0008901f
str r1, [r0, #8] @ DBOP_CTRL
3: ldr r1, [r0, #0xc] @ DOBP_STAT
ands r1, r1, #(1<<16)
beq 3b @ wait for valid data
ldrh r1, [r0, #0x14] @ DBOP_DIN
tst r1, #BUTTON_LEFT @ boot of?
beq boot_of
#elif defined(SANSA_M200V4)
.set row, (1<<5) /* enable output on A5 */
.set col, (1<<0) /* read keyscan column A0 */
ldr r0, =GPIOA
mov r1, #row
str r1, [r0, #0x400]
str r1, [r0, #(4*row)]
ldr r2, [r0, #(4*col)]
/* check value read (1 means button pressed) */
cmp r2, #0
bne boot_of
#else
#error No target-specific key check defined!
#endif
/* The dualboot button was not held, so we boot rockbox */
ldr r0, ucl_rb_end /* Address of compressed image */
ldr r1, ucl_rb_size /* Compressed size */
b decompress
boot_of:
ldr r0, ucl_of_end /* Address of compressed image */
ldr r1, ucl_of_size /* Compressed size */
decompress:
/* At this point: */
/* r0 = source_end for UCL image to copy */
/* r1 = size of UCL image to copy */
ldr r3, ucl_dest
add r5, r3, #2 /* r5 is entry point of copy of uclunpack */
/* function, plus one (for thumb mode */
sub r4, r3, r1 /* r4 := destination_start - 1 */
fw_copy:
ldrb r2, [r0], #-1
strb r2, [r3], #-1
cmp r3, r4 /* Stop when we reached dest_start-1 */
bne fw_copy
/* Call the ucl decompress function, which will branch to 0x0 */
/* on completion */
add r0, r3, #1 /* r0 := Start of compressed image */
/* r1 already contains compressed size */
mov r2, #0 /* r2 := Destination for unpacking */
bx r5 /* Branch to uclunpack, switching to thumb */
/* never reached : uclunpack will branch to the reset vector (0x0) */

View file

@ -0,0 +1,198 @@
/* arm_nrv2e_d8.S -- ARM decompressor for NRV2E
This file is part of the UPX executable compressor.
Copyright (C) 1996-2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2008 Laszlo Molnar
Copyright (C) 2000-2008 John F. Reiser
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them 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; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
<markus@oberhumer.com> <ml1050@users.sourceforge.net>
John F. Reiser
<jreiser@users.sourceforge.net>
*/
#define SAFE 0 /* 1 for src+dst bounds checking: cost 40 bytes */
#define src r0
#define len r1 /* overlaps 'cnt' */
#define dst r2
#define tmp r3
#define bits r4
#define off r5
#define wrnk r6 /* 0x500 M2_MAX_OFFSET before "wrinkle" */
#define srclim r7
#if 1==SAFE /*{*/
#define dstlim r12
#endif /*}*/
#define cnt r1 /* overlaps 'len' while reading an offset */
#if 1==SAFE /*{*/
#define CHECK_SRC cmp src,srclim; bhs bad_src_n2e
#define CHECK_DST cmp dst,dstlim; bhs bad_dst_n2e
#else /*}{*/
#define CHECK_SRC /*empty*/
#define CHECK_DST /*empty*/
#endif /*}*/
#if 0 /*{ DEBUG only: check newly-decompressed against original dst */
#define CHECK_BYTE \
push {wrnk}; \
ldrb wrnk,[dst]; \
cmp wrnk,tmp; beq 0f; bkpt; \
0: pop {wrnk}
#else /*}{*/
#define CHECK_BYTE /*empty*/
#endif /*}*/
/* "mov lr,pc; bxx ..." implements conditional subroutine call
*
* NOTE: the lsb will not be set, so you MUST NOT use 'bx lr' to return,
* else the T bit will be cleared and processor will go in ARM state */
#define GETBIT add bits,bits; mov lr,pc; beq get1_n2e
#define getnextb(reg) GETBIT; adc reg,reg
#define jnextb0 GETBIT; bcc
#define jnextb1 GETBIT; bcs
#ifndef PURE_THUMB
ucl_nrv2e_decompress_8: .globl ucl_nrv2e_decompress_8 @ ARM mode
.type ucl_nrv2e_decompress_8, %function
/* error = (*)(char const *src, int len_src, char *dst, int *plen_dst)
Actual decompressed length is stored through plen_dst.
For SAFE mode: at call, *plen_dst must be allowed length of output buffer.
*/
adr r12,1+.thumb_nrv2e_d8; bx r12 @ enter THUMB mode
#endif
.code 16 @ THUMB mode
.thumb_func
.thumb_nrv2e_d8:
#if 0
push {r2,r3, r4,r5,r6,r7, lr}
#define sp_DST0 0 /* stack offset of original dst */
#endif
add srclim,len,src @ srclim= eof_src;
#if 1==SAFE /*{*/
ldr tmp,[r3] @ len_dst
add tmp,dst
mov dstlim,tmp
#endif /*}*/
mov bits,#1; neg off,bits @ off= -1 initial condition
lsl bits,#31 @ 1<<31: refill next time
mov wrnk,#5
lsl wrnk,#8 @ 0x500 @ nrv2e M2_MAX_OFFSET
b top_n2e
#if 1==SAFE /*{*/
bad_dst_n2e: # return value will be 2
add src,srclim,#1
bad_src_n2e: # return value will be 1
add src,#1
#endif /*}*/
eof_n2e:
#if 0
pop {r3,r4} @ r3= orig_dst; r4= plen_dst
sub src,srclim @ 0 if actual src length equals expected length
sub dst,r3 @ actual dst length
str dst,[r4]
pop {r4,r5,r6,r7 /*,pc*/}
pop {r1}; bx r1 @ "pop {,pc}" fails return to ARM mode on ARMv4T
#else
mov r0, #0
bx r0 /* Branch to 0x0, switch to ARM mode */
#endif
get1_n2e: @ In: Carry set [from adding 0x80000000 (1<<31) to itself]
ldrb bits,[src] @ zero-extend next byte
adc bits,bits @ double and insert CarryIn as low bit
CHECK_SRC
add src,#1
lsl bits,#24 @ move to top byte, and set CarryOut from old bit 8
/* NOTE: the following instruction will not work on ARMv7+, because
* it will update the T bit and return into ARM state */
mov pc,lr @ return, stay in current (THUMB) mode
lit_n2e:
CHECK_SRC; ldrb tmp,[src]; add src,#1
CHECK_BYTE
CHECK_DST; strb tmp,[dst]; add dst,#1
top_n2e:
jnextb1 lit_n2e
mov cnt,#1; b getoff_n2e
off_n2e:
sub cnt,#1
getnextb(cnt)
getoff_n2e:
getnextb(cnt)
jnextb0 off_n2e
sub tmp,cnt,#3 @ set Carry
mov len,#0 @ Carry unaffected
blo offprev_n2e @ cnt was 2; tests Carry only
lsl tmp,#8
CHECK_SRC; ldrb off,[src]; add src,#1 @ low 7+1 bits
orr off,tmp
mvn off,off; beq eof_n2e @ off= ~off
asr off,#1; bcs lenlast_n2e
b lenmore_n2e
offprev_n2e:
jnextb1 lenlast_n2e
lenmore_n2e:
mov len,#1
jnextb1 lenlast_n2e
len_n2e:
getnextb(len)
jnextb0 len_n2e
add len,#6-2
b gotlen_n2e
lenlast_n2e:
getnextb(len) @ 0,1,2,3
add len,#2
gotlen_n2e: @ 'cmn': add the inputs, set condition codes, discard the sum
cmn wrnk,off; bcs near_n2e @ within M2_MAX_OFFSET
add len,#1 @ too far away, so minimum match length is 3
near_n2e:
#if 1==SAFE /*{*/
ldr tmp,[sp,#sp_DST0]
sub tmp,dst
sub tmp,off; bhi bad_dst_n2e @ reaching back too far
add tmp,dst,cnt
cmp tmp,dstlim; bhi bad_dst_n2e @ too much output
#endif /*}*/
ldrb tmp,[dst] @ force cacheline allocate
copy_n2e:
ldrb tmp,[dst,off]
CHECK_BYTE
strb tmp,[dst]; add dst,#1
sub len,#1; bne copy_n2e
b top_n2e
#ifndef PURE_THUMB
.size ucl_nrv2e_decompress_8, .-ucl_nrv2e_decompress_8
#endif
/*
vi:ts=8:et:nowrap
*/

174
utils/mkamsboot/main.c Normal file
View file

@ -0,0 +1,174 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* mkamsboot - a tool for merging bootloader code into an Sansa V2
* (AMS) firmware file
*
* Copyright (C) 2008 Dave Chapman
*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ucl/ucl.h>
#include "mkamsboot.h"
/* Header for ARM code binaries */
#include "dualboot.h"
/* Win32 compatibility */
#ifndef O_BINARY
#define O_BINARY 0
#endif
/* standalone executable */
int main(int argc, char* argv[])
{
char *infile, *bootfile, *outfile;
int fdout;
off_t len;
uint32_t n;
unsigned char* buf;
int firmware_size;
int bootloader_size;
unsigned char* of_packed;
int of_packedsize;
unsigned char* rb_packed;
int rb_packedsize;
int patchable;
int totalsize;
int model;
char errstr[200];
struct md5sums sum;
char md5sum[33]; /* 32 digits + \0 */
sum.md5 = md5sum;
/* VERSION comes frome the Makefile */
fprintf(stderr,
"mkamsboot Version " VERSION "\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"\n");
if(argc != 4) {
printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n");
return 1;
}
infile = argv[1];
bootfile = argv[2];
outfile = argv[3];
/* Load bootloader file */
rb_packed = load_rockbox_file(bootfile, &model, &bootloader_size,
&rb_packedsize, errstr, sizeof(errstr));
if (rb_packed == NULL) {
fprintf(stderr, "%s", errstr);
fprintf(stderr, "[ERR] Could not load %s\n", bootfile);
return 1;
}
/* Load original firmware file */
buf = load_of_file(infile, model, &len, &sum,
&firmware_size, &of_packed, &of_packedsize, errstr, sizeof(errstr));
if (buf == NULL) {
free(rb_packed);
fprintf(stderr, "%s", errstr);
fprintf(stderr, "[ERR] Could not load %s\n", infile);
return 1;
}
fprintf(stderr, "[INFO] Original firmware MD5 checksum match\n");
fprintf(stderr, "[INFO] Model: Sansa %s v%d - Firmware version: %s\n",
ams_identity[sum.model].model_name,
ams_identity[sum.model].hw_revision, sum.version);
printf("[INFO] Firmware patching has begun !\n\n");
fprintf(stderr, "[INFO] Original firmware size: %8d bytes\n",
firmware_size);
fprintf(stderr, "[INFO] Packed OF size: %8d bytes\n",
of_packedsize);
fprintf(stderr, "[INFO] Bootloader size: %8d bytes\n",
bootloader_size);
fprintf(stderr, "[INFO] Packed bootloader size: %8d bytes\n",
rb_packedsize);
fprintf(stderr, "[INFO] Dual-boot function size: %8d bytes\n",
ams_identity[sum.model].bootloader_size);
fprintf(stderr, "[INFO] UCL unpack function size: %8zu bytes\n",
sizeof(nrv2e_d8));
fprintf(stderr, "[INFO] Original firmware version: %8u bytes\n",
0x200);
patchable = check_sizes(sum.model, rb_packedsize, bootloader_size,
of_packedsize, firmware_size, &totalsize, errstr, sizeof(errstr));
fprintf(stderr, "[INFO] Total size of new image: %8d bytes\n", totalsize);
if (!patchable) {
fprintf(stderr, "%s", errstr);
free(buf);
free(of_packed);
free(rb_packed);
return 1;
}
patch_firmware(sum.model, ams_identity[sum.model].fw_revision,
firmware_size, buf, len, of_packed, of_packedsize, rb_packed,
rb_packedsize);
/* Write the new firmware */
fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
if (fdout < 0) {
fprintf(stderr, "[ERR] Could not open %s for writing\n", outfile);
free(buf);
free(of_packed);
free(rb_packed);
return 1;
}
n = write(fdout, buf, len);
if (n != (unsigned)len) {
fprintf(stderr, "[ERR] Could not write firmware file\n");
free(buf);
free(of_packed);
free(rb_packed);
return 1;
}
close(fdout);
free(buf);
free(of_packed);
free(rb_packed);
fprintf(stderr, "\n[INFO] Patching succeeded!\n");
return 0;
}

246
utils/mkamsboot/md5.c Normal file
View file

@ -0,0 +1,246 @@
/*
* 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) (b)[(i) ] ) \
| ( (uint32) (b)[(i) + 1] << 8 ) \
| ( (uint32) (b)[(i) + 2] << 16 ) \
| ( (uint32) (b)[(i) + 3] << 24 ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) ); \
(b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 3] = (uint8) ( (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;
}
void md5_process( md5_context *ctx, uint8 data[64] )
{
uint32 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 *input, uint32 length )
{
uint32 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 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 digest[16] )
{
uint32 last, padn;
uint32 high, low;
uint8 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 );
}

25
utils/mkamsboot/md5.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef _MD5_H
#define _MD5_H
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
typedef struct
{
uint32 total[2];
uint32 state[4];
uint8 buffer[64];
}
md5_context;
void md5_starts( md5_context *ctx );
void md5_update( md5_context *ctx, uint8 *input, uint32 length );
void md5_finish( md5_context *ctx, uint8 digest[16] );
#endif /* md5.h */

595
utils/mkamsboot/mkamsboot.c Normal file
View file

@ -0,0 +1,595 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* mkamsboot.c - a tool for merging bootloader code into an Sansa V2
* (AMS) firmware file
*
* Copyright (C) 2008 Dave Chapman
*
* 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.
*
****************************************************************************/
/*
Insert a Rockbox bootloader into a Sansa AMS original firmware file.
Layout of a Sansa AMS original firmware file:
---------------------- 0x0
| HEADER |
|----------------------| 0x400
| FIRMWARE BLOCK | (contains the OF version on some fuzev2 firmwares
|----------------------| 0x600
| FIRMWARE BLOCK |
|----------------------| 0x400 + firmware block size
| LIBRARIES/DATA |
---------------------- END
We replace the main firmware block while preserving the potential OF version
(bytes 0x600..0x400+firmware_size) as follows:
---------------------- 0x0
| |
| Dual-boot code |
| |
|----------------------|
| EMPTY SPACE |
|----------------------|
| |
| compressed RB image |
| |
|----------------------|
| |
| compressed OF image |
| |
|----------------------|
| UCL unpack function |
----------------------
This entire block fits into the space previously occupied by the main
firmware block - the space saved by compressing the OF image is used
to store the compressed version of the Rockbox bootloader.
On version 1 firmwares, the OF image is typically about 120KB, which allows
us to store a Rockbox bootloader with an uncompressed size of about 60KB-70KB.
Version 2 firmwares are bigger and are stored in SDRAM (instead of IRAM).
In both cases, the RAM we are using is mapped at offset 0x0.
mkamsboot then corrects the checksums and writes a new legal firmware
file which can be installed on the device.
When the Sansa device boots, this firmware block is loaded to RAM at
address 0x0 and executed.
Firstly, the dual-boot code will copy the UCL unpack function to the
end of RAM.
Then, depending on the detection of the dual-boot keypress, either the
OF image or the Rockbox image is copied to the end of RAM (just before
the ucl unpack function) and uncompressed to the start of RAM.
Finally, the ucl unpack function branches to address 0x0, passing
execution to the uncompressed firmware.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ucl/ucl.h>
#include "mkamsboot.h"
#include "md5.h"
/* Header for ARM code binaries */
#include "dualboot.h"
/* Win32 compatibility */
#ifndef O_BINARY
#define O_BINARY 0
#endif
/* fw_revision: version 2 is used in Clipv2, Clip+ and Fuzev2 firmwares */
/* hw_revision: 4 for m200, 2 for e200/c200, 1 or 2 for fuze/clip, 1 for clip+ */
const struct ams_models ams_identity[] = {
[MODEL_C200V2] = { 2, 1, "c200", dualboot_c200v2, sizeof(dualboot_c200v2), "c2v2", 44 },
[MODEL_CLIPPLUS]= { 1, 2, "Clip+", dualboot_clipplus, sizeof(dualboot_clipplus), "cli+", 66 },
[MODEL_CLIPV2] = { 2, 2, "Clip", dualboot_clipv2, sizeof(dualboot_clipv2), "clv2", 60 },
[MODEL_CLIP] = { 1, 1, "Clip", dualboot_clip, sizeof(dualboot_clip), "clip", 40 },
[MODEL_E200V2] = { 2, 1, "e200", dualboot_e200v2, sizeof(dualboot_e200v2), "e2v2", 41 },
[MODEL_FUZEV2] = { 2, 2, "Fuze", dualboot_fuzev2, sizeof(dualboot_fuzev2), "fuz2", 68 },
[MODEL_FUZE] = { 1, 1, "Fuze", dualboot_fuze, sizeof(dualboot_fuze), "fuze", 43 },
[MODEL_M200V4] = { 4, 1, "m200", dualboot_m200v4, sizeof(dualboot_m200v4), "m2v4", 42 },
[MODEL_CLIPZIP] = { 1, 2, "ClipZip", dualboot_clipzip, sizeof(dualboot_clipzip), "clzp", 79 },
};
/* Checksums of unmodified original firmwares - for safety, and device
detection */
static struct md5sums sansasums[] = {
/* NOTE: Different regional versions of the firmware normally only
differ in the filename - the md5sums are identical */
/* model version md5 */
{ MODEL_E200V2, "3.01.11", "e622ca8cb6df423f54b8b39628a1f0a3" },
{ MODEL_E200V2, "3.01.14", "2c1d0383fc3584b2cc83ba8cc2243af6" },
{ MODEL_E200V2, "3.01.16", "12563ad71b25a1034cf2092d1e0218c4" },
{ MODEL_FUZE, "1.01.11", "cac8ffa03c599330ac02c4d41de66166" },
{ MODEL_FUZE, "1.01.15", "df0e2c1612727f722c19a3c764cff7f2" },
{ MODEL_FUZE, "1.01.22", "5aff5486fe8dd64239cc71eac470af98" },
{ MODEL_FUZE, "1.02.26", "7c632c479461c48c8833baed74eb5e4f" },
{ MODEL_FUZE, "1.02.28", "5b34260f6470e75f702a9c6825471752" },
{ MODEL_FUZE, "1.02.31", "66d01b37462a5ef7ccc6ad37188b4235" },
{ MODEL_C200V2, "3.02.05", "b6378ebd720b0ade3fad4dc7ab61c1a5" },
{ MODEL_M200V4, "4.00.45", "82e3194310d1514e3bbcd06e84c4add3" },
{ MODEL_M200V4, "4.01.08-A", "fc9dd6116001b3e6a150b898f1b091f0" },
{ MODEL_M200V4, "4.01.08-E", "d3fb7d8ec8624ee65bc99f8dab0e2369" },
{ MODEL_CLIP, "1.01.17", "12caad785d506219d73f538772afd99e" },
{ MODEL_CLIP, "1.01.18", "d720b266bd5afa38a198986ef0508a45" },
{ MODEL_CLIP, "1.01.20", "236d8f75189f468462c03f6d292cf2ac" },
{ MODEL_CLIP, "1.01.29", "c12711342169c66e209540cd1f27cd26" },
{ MODEL_CLIP, "1.01.30", "f2974d47c536549c9d8259170f1dbe4d" },
{ MODEL_CLIP, "1.01.32", "d835d12342500732ffb9c4ee54abec15" },
{ MODEL_CLIP, "1.01.35", "b4d0edb3b8f2a4e8eee0a344f7f8e480" },
{ MODEL_CLIPV2, "2.01.16", "c57fb3fcbe07c2c9b360f060938f80cb" },
{ MODEL_CLIPV2, "2.01.32", "0ad3723e52022509089d938d0fbbf8c5" },
{ MODEL_CLIPV2, "2.01.35", "a3cbbd22b9508d7f8a9a1a39acc342c2" },
{ MODEL_CLIPPLUS, "01.02.09", "656d38114774c2001dc18e6726df3c5d" },
{ MODEL_CLIPPLUS, "01.02.13", "5f89872b79ef440b0e5ee3a7a44328b2" },
{ MODEL_CLIPPLUS, "01.02.15", "680a4f521e790ad25b93b1b16f3a207d" },
{ MODEL_CLIPPLUS, "01.02.16", "055a53de1dfb09f6cb71c504ad48bd13" },
{ MODEL_CLIPPLUS, "01.02.18", "80b547244438b113e2a55ff0305f12c0" },
{ MODEL_FUZEV2, "2.01.17", "8b85fb05bf645d08a4c8c3e344ec9ebe" },
{ MODEL_FUZEV2, "2.02.26", "d4f6f85c3e4a8ea8f2e5acc421641801" },
{ MODEL_FUZEV2, "2.03.31", "74fb197ccd51707388f3b233402186a6" },
{ MODEL_FUZEV2, "2.03.33", "1599cc73d02ea7fe53fe2d4379c24b66" },
{ MODEL_CLIPZIP, "1.01.12", "45adea0873326b5af34f096e5c402f78" },
{ MODEL_CLIPZIP, "1.01.15", "f62af954334cd9ba1a87a7fa58ec6074" },
{ MODEL_CLIPZIP, "1.01.17", "27bcb343d6950f35dc261629e22ba60c" },
{ MODEL_CLIPZIP, "1.01.18", "ef16aa9e02b49885ebede5aa149502e8" },
{ MODEL_CLIPZIP, "1.01.20", "d88c8977cc6a952d3f51ece105869d97" },
{ MODEL_CLIPZIP, "1.01.21", "92c814d6e3250189706a36d2b49b6152" },
};
#define NUM_MD5S (sizeof(sansasums)/sizeof(sansasums[0]))
static unsigned int model_memory_size(int model)
{
/* The OF boots with IRAM (320kB) mapped at 0x0 */
if(model == MODEL_CLIPV2)
{
/* The decompressed Clipv2 OF is around 380kB.
* Let's use the full IRAM (1MB on AMSv2)
*/
return 1 << 20;
}
else
{
/* The IRAM is 320kB on AMSv1, and 320 will be enough on Fuzev1/Clip+ */
return 320 << 10;
}
}
int firmware_revision(int model)
{
return ams_identity[model].fw_revision;
}
static off_t filesize(int fd)
{
struct stat buf;
if (fstat(fd, &buf) < 0) {
perror("[ERR] Checking filesize of input file");
return -1;
} else {
return(buf.st_size);
}
}
static uint32_t get_uint32le(unsigned char* p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
static uint32_t get_uint32be(unsigned char* p)
{
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
}
static void put_uint32le(unsigned char* p, uint32_t x)
{
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
}
void calc_MD5(unsigned char* buf, int len, char *md5str)
{
int i;
md5_context ctx;
unsigned char md5sum[16];
md5_starts(&ctx);
md5_update(&ctx, buf, len);
md5_finish(&ctx, md5sum);
for (i = 0; i < 16; ++i)
sprintf(md5str + 2*i, "%02x", md5sum[i]);
}
/* Calculate a simple checksum used in Sansa Original Firmwares */
static uint32_t calc_checksum(unsigned char* buf, uint32_t n)
{
uint32_t sum = 0;
uint32_t i;
for (i=0;i<n;i+=4)
sum += get_uint32le(buf + i);
return sum;
}
/* Compress using nrv2e algorithm : Thumb decompressor fits in 168 bytes ! */
static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
{
int maxsize;
unsigned char* outbuf;
int r;
/* The following formula comes from the UCL documentation */
maxsize = insize + (insize / 8) + 256;
/* Allocate some memory for the output buffer */
outbuf = malloc(maxsize);
if (outbuf == NULL)
return NULL;
r = ucl_nrv2e_99_compress(
(const ucl_bytep) inbuf,
(ucl_uint) insize,
(ucl_bytep) outbuf,
(ucl_uintp) outsize,
0, 10, NULL, NULL);
if (r != UCL_E_OK || *outsize > maxsize) {
/* this should NEVER happen, and implies memory corruption */
fprintf(stderr, "internal error - compression failed: %d\n", r);
free(outbuf);
return NULL;
}
return outbuf;
}
#define ERROR(format, ...) \
do { \
snprintf(errstr, errstrsize, format, __VA_ARGS__); \
goto error; \
} while(0)
/* Loads a Sansa AMS Original Firmware file into memory */
unsigned char* load_of_file(
char* filename, int model, off_t* bufsize, struct md5sums *sum,
int* firmware_size, unsigned char** of_packed,
int* of_packedsize, char* errstr, int errstrsize)
{
int fd;
unsigned char* buf =NULL;
off_t n;
unsigned int i=0;
uint32_t checksum;
unsigned int last_word;
fd = open(filename, O_RDONLY|O_BINARY);
if (fd < 0)
ERROR("[ERR] Could not open %s for reading\n", filename);
*bufsize = filesize(fd);
buf = malloc(*bufsize);
if (buf == NULL)
ERROR("[ERR] Could not allocate memory for %s\n", filename);
n = read(fd, buf, *bufsize);
if (n != *bufsize)
ERROR("[ERR] Could not read file %s\n", filename);
/* check the file */
/* Calculate MD5 checksum of OF */
calc_MD5(buf, *bufsize, sum->md5);
while ((i < NUM_MD5S) && (strcmp(sansasums[i].md5, sum->md5) != 0))
i++;
if (i < NUM_MD5S) {
*sum = sansasums[i];
if(sum->model != model) {
ERROR("[ERR] OF File provided is %sv%d version %s, not for %sv%d\n",
ams_identity[sum->model].model_name, ams_identity[sum->model].hw_revision,
sum->version, ams_identity[model].model_name, ams_identity[model].hw_revision
);
}
} else {
/* OF unknown, give a list of tested versions for the requested model */
char tested_versions[100];
tested_versions[0] = '\0';
for (i = 0; i < NUM_MD5S ; i++)
if (sansasums[i].model == model) {
if (tested_versions[0] != '\0') {
strncat(tested_versions, ", ",
sizeof(tested_versions) - strlen(tested_versions) - 1);
}
strncat(tested_versions, sansasums[i].version,
sizeof(tested_versions) - strlen(tested_versions) - 1);
}
ERROR("[ERR] Original firmware unknown, please try another version."
" Tested %sv%d versions are: %s\n",
ams_identity[model].model_name, ams_identity[model].hw_revision, tested_versions);
}
/* TODO: Do some more sanity checks on the OF image. Some images (like
m200v4) dont have a checksum at the end, only padding (0xdeadbeef). */
last_word = *bufsize - 4;
checksum = get_uint32le(buf + last_word);
if (checksum != 0xefbeadde && checksum != calc_checksum(buf, last_word))
ERROR("%s", "[ERR] Whole file checksum failed\n");
if (ams_identity[sum->model].bootloader == NULL)
ERROR("[ERR] Unsupported model - \"%s\"\n", ams_identity[sum->model].model_name);
/* Get the firmware size */
if (ams_identity[sum->model].fw_revision == 1)
*firmware_size = get_uint32le(&buf[0x0c]);
else if (ams_identity[sum->model].fw_revision == 2)
*firmware_size = get_uint32le(&buf[0x10]);
/* Compress the original firmware image */
*of_packed = uclpack(buf + 0x400, *firmware_size, of_packedsize);
if (*of_packed == NULL)
ERROR("[ERR] Could not compress %s\n", filename);
return buf;
error:
free(buf);
return NULL;
}
/* Loads a rockbox bootloader file into memory */
unsigned char* load_rockbox_file(
char* filename, int *model, int* bufsize, int* rb_packedsize,
char* errstr, int errstrsize)
{
int fd;
unsigned char* buf = NULL;
unsigned char* packed = NULL;
unsigned char header[8];
uint32_t sum;
off_t n;
int i;
fd = open(filename, O_RDONLY|O_BINARY);
if (fd < 0)
ERROR("[ERR] Could not open %s for reading\n", filename);
/* Read Rockbox header */
n = read(fd, header, sizeof(header));
if (n != sizeof(header))
ERROR("[ERR] Could not read file %s\n", filename);
for(*model = 0; *model < NUM_MODELS; (*model)++)
if (memcmp(ams_identity[*model].rb_model_name, header + 4, 4) == 0)
break;
if(*model == NUM_MODELS)
ERROR("[ERR] Model name \"%4.4s\" unknown. Is this really a rockbox bootloader?\n", header + 4);
*bufsize = filesize(fd) - sizeof(header);
buf = malloc(*bufsize);
if (buf == NULL)
ERROR("[ERR] Could not allocate memory for %s\n", filename);
n = read(fd, buf, *bufsize);
if (n != *bufsize)
ERROR("[ERR] Could not read file %s\n", filename);
/* Check checksum */
sum = ams_identity[*model].rb_model_num;
for (i = 0; i < *bufsize; i++) {
/* add 8 unsigned bits but keep a 32 bit sum */
sum += buf[i];
}
if (sum != get_uint32be(header))
ERROR("[ERR] Checksum mismatch in %s\n", filename);
packed = uclpack(buf, *bufsize, rb_packedsize);
if(packed == NULL)
ERROR("[ERR] Could not compress %s\n", filename);
free(buf);
return packed;
error:
free(buf);
return NULL;
}
#undef ERROR
/* Patches a Sansa AMS Original Firmware file */
void patch_firmware(
int model, int fw_revision, int firmware_size, unsigned char* buf,
int len, unsigned char* of_packed, int of_packedsize,
unsigned char* rb_packed, int rb_packedsize)
{
unsigned char *p;
uint32_t sum, filesum;
uint32_t ucl_dest;
unsigned int i;
/* Zero the original firmware area - not needed, but helps debugging */
memset(buf + 0x600, 0, firmware_size);
/* Insert dual-boot bootloader at offset 0x200, we preserve the OF
* version string located between 0x0 and 0x200 */
memcpy(buf + 0x600, ams_identity[model].bootloader, ams_identity[model].bootloader_size);
/* Insert vectors, they won't overwrite the OF version string */
static const uint32_t goto_start = 0xe3a0fc02; // mov pc, #0x200
static const uint32_t infinite_loop = 0xeafffffe; // 1: b 1b
/* ALL vectors: infinite loop */
for (i=0; i < 8; i++)
put_uint32le(buf + 0x400 + 4*i, infinite_loop);
/* Now change only the interesting vectors */
/* Reset/SWI vectors: branch to our dualboot code at 0x200 */
put_uint32le(buf + 0x400 + 4*0, goto_start); // Reset
put_uint32le(buf + 0x400 + 4*2, goto_start); // SWI
/* We are filling the firmware buffer backwards from the end */
p = buf + 0x400 + firmware_size;
/* 1 - UCL unpack function */
p -= sizeof(nrv2e_d8);
memcpy(p, nrv2e_d8, sizeof(nrv2e_d8));
/* 2 - Compressed copy of original firmware */
p -= of_packedsize;
memcpy(p, of_packed, of_packedsize);
/* 3 - Compressed copy of Rockbox bootloader */
p -= rb_packedsize;
memcpy(p, rb_packed, rb_packedsize);
/* Write the locations of the various images to the variables at the
start of the dualboot image - we save the location of the last byte
in each image, along with the size in bytes */
/* UCL unpack function */
put_uint32le(&buf[0x604], firmware_size - 1);
put_uint32le(&buf[0x608], sizeof(nrv2e_d8));
/* Compressed original firmware image */
put_uint32le(&buf[0x60c], firmware_size - sizeof(nrv2e_d8) - 1);
put_uint32le(&buf[0x610], of_packedsize);
/* Compressed Rockbox image */
put_uint32le(&buf[0x614], firmware_size - sizeof(nrv2e_d8) - of_packedsize
- 1);
put_uint32le(&buf[0x618], rb_packedsize);
ucl_dest = model_memory_size(model) - 1; /* last byte of memory */
put_uint32le(&buf[0x61c], ucl_dest);
/* Update the firmware block checksum */
sum = calc_checksum(buf + 0x400, firmware_size);
if (fw_revision == 1) {
put_uint32le(&buf[0x04], sum);
put_uint32le(&buf[0x204], sum);
} else if (fw_revision == 2) {
put_uint32le(&buf[0x08], sum);
put_uint32le(&buf[0x208], sum);
/* Update the header checksums */
put_uint32le(&buf[0x1fc], calc_checksum(buf, 0x1fc));
put_uint32le(&buf[0x3fc], calc_checksum(buf + 0x200, 0x1fc));
}
/* Update the whole-file checksum */
filesum = 0;
for (i=0;i < (unsigned)len - 4; i+=4)
filesum += get_uint32le(&buf[i]);
put_uint32le(buf + len - 4, filesum);
}
/* returns != 0 if the firmware can be safely patched */
int check_sizes(int model, int rb_packed_size, int rb_unpacked_size,
int of_packed_size, int of_unpacked_size, int *total_size,
char *errstr, int errstrsize)
{
/* XXX: we keep the first 0x200 bytes block unmodified, we just replace
* the ARM vectors */
unsigned int packed_size = ams_identity[model].bootloader_size + sizeof(nrv2e_d8) +
of_packed_size + rb_packed_size + 0x200;
/* how much memory is available */
unsigned int memory_size = model_memory_size(model);
/* the memory used when unpacking the OF */
unsigned int ram_of = sizeof(nrv2e_d8) + of_packed_size + of_unpacked_size;
/* the memory used when unpacking the bootloader */
unsigned int ram_rb = sizeof(nrv2e_d8) + rb_packed_size + rb_unpacked_size;
*total_size = packed_size;
#define ERROR(format, ...) \
do { \
snprintf(errstr, errstrsize, format, __VA_ARGS__); \
return 0; \
} while(0)
/* will packed data fit in the OF file ? */
if(packed_size > of_unpacked_size)
ERROR(
"[ERR] Packed data (%d bytes) doesn't fit in the firmware "
"(%d bytes)\n", packed_size, of_unpacked_size
);
else if(ram_rb > memory_size)
ERROR("[ERR] Rockbox can't be unpacked at runtime, needs %d bytes "
"of memory and only %d available\n", ram_rb, memory_size
);
else if(ram_of > memory_size)
ERROR("[ERR] OF can't be unpacked at runtime, needs %d bytes "
"of memory and only %d available\n", ram_of, memory_size
);
return 1;
#undef ERROR
}

195
utils/mkamsboot/mkamsboot.h Normal file
View file

@ -0,0 +1,195 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* mkamsboot.h - a tool for merging bootloader code into an Sansa V2
* (AMS) firmware file
*
* Copyright (C) 2008 Dave Chapman
*
* 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 MKAMSBOOT_H
#define MKAMSBOOT_H
#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Supported models */
enum {
MODEL_UNKNOWN = -1,
MODEL_FUZE = 0,
MODEL_CLIP,
MODEL_CLIPV2,
MODEL_E200V2,
MODEL_M200V4,
MODEL_C200V2,
MODEL_CLIPPLUS,
MODEL_FUZEV2,
MODEL_CLIPZIP,
/* new models go here */
NUM_MODELS
};
/* Holds info about the OF */
struct md5sums {
int model;
char *version;
char *md5;
};
struct ams_models {
unsigned short hw_revision;
unsigned short fw_revision;
/* Descriptive name of this model */
const char* model_name;
/* Dualboot functions for this model */
const unsigned char* bootloader;
/* Size of dualboot functions for this model */
int bootloader_size;
/* Model name used in the Rockbox header in ".sansa" files - these match the
-add parameter to the "scramble" tool */
const char* rb_model_name;
/* Model number used to initialise the checksum in the Rockbox header in
".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
const int rb_model_num;
};
extern const struct ams_models ams_identity[];
/* load_rockbox_file()
*
* Loads a rockbox bootloader file into memory
*
* ARGUMENTS
*
* filename : bootloader file to load
* model : will be set to this bootloader's model
* bootloader_size : set to the uncompressed bootloader size
* rb_packed_size : set to the size of compressed bootloader
* errstr : provided buffer to store an eventual error
* errstrsize : size of provided error buffer
*
* RETURN VALUE
* pointer to allocated memory containing the content of compressed bootloader
* or NULL in case of error (errstr will hold a description of the error)
*/
unsigned char* load_rockbox_file(
char* filename, int *model, int* bootloader_size, int* rb_packedsize,
char* errstr, int errstrsize);
/* load_of_file()
*
* Loads a Sansa AMS Original Firmware file into memory
*
* ARGUMENTS
*
* filename : firmware file to load
* model : desired player's model
* bufsize : set to firmware file size
* md5sum : set to file md5sum, must be at least 33 bytes long
* firmware_size : set to firmware block's size
* of_packed : pointer to allocated memory containing the compressed
* original firmware block
* of_packedsize : size of compressed original firmware block
* errstr : provided buffer to store an eventual error
* errstrsize : size of provided error buffer
*
* RETURN VALUE
* pointer to allocated memory containing the content of Original Firmware
* or NULL in case of error (errstr will hold a description of the error)
*/
unsigned char* load_of_file(
char* filename, int model, off_t* bufsize, struct md5sums *sum,
int* firmware_size, unsigned char** of_packed,
int* of_packedsize, char* errstr, int errstrsize);
/* patch_firmware()
*
* Patches a Sansa AMS Original Firmware file
*
* ARGUMENTS
*
* model : firmware model (MODEL_XXX)
* fw_version : firmware format version (1 or 2)
* firmware_size : size of uncompressed original firmware block
* buf : pointer to original firmware file
* len : size of original firmware file
* of_packed : pointer to compressed original firmware block
* of_packedsize : size of compressed original firmware block
* rb_packed : pointer to compressed rockbox bootloader
* rb_packed_size : size of compressed rockbox bootloader
*/
void patch_firmware(
int model, int fw_version, int firmware_size, unsigned char* buf,
int len, unsigned char* of_packed, int of_packedsize,
unsigned char* rb_packed, int rb_packedsize);
/* check_sizes()
*
* Verify if the given bootloader can be embedded in the OF file, while still
* allowing both the bootloader and the OF to be unpacked at runtime
*
* ARGUMENTS
*
* model : firmware model (MODEL_XXX)
* rb_packed_size : size of compressed rockbox bootloader
* rb_unpacked_size : size of compressed rockbox bootloader
* of_packed_size : size of compressed original firmware block
* of_unpacked_size : size of compressed original firmware block
* total_size : will contain the size of useful data that would be
* written to the firmware block, even in case of an
* error
* errstr : provided buffer to store an eventual error
* errstrsize : size of provided error buffer
*
* RETURN VALUE
* 0 if the conditions aren't met, 1 if we can go and patch the firmware
*/
int check_sizes(int model, int rb_packed_size, int rb_unpacked_size,
int of_packed_size, int of_unpacked_size, int *total_size,
char *errstr, int errstrsize);
/* firmware_revision()
*
* returns the firmware revision for a particular model
*
* ARGUMENTS
*
* model : firmware model (MODEL_XXX)
*
* RETURN VALUE
* firmware version
*/
int firmware_revision(int model);
#ifdef __cplusplus
};
#endif
#endif

46
utils/mkimxboot/Makefile Normal file
View file

@ -0,0 +1,46 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# We use the SB code available in the Rockbox utils/sbtools directory
IMXTOOLS_DIR=../../utils/imxtools/sbtools/
COMPILEFLAGS := -Wall -g -O3 -I$(IMXTOOLS_DIR)
# std=gnu99 is required by MinGW on Windows (c99 is sufficient for Linux / MXE)
CFLAGS += -std=gnu99 $(COMPILEFLAGS)
TOMCRYPT_DIR := ../../utils/tomcrypt
CFLAGS += -I$(TOMCRYPT_DIR)/src/headers
LDOPTS += -lpthread $(TOMCRYPT_DIR)/librbtomcrypt.a
OUTPUT = mkimxboot
# inputs for lib
IMXTOOLS_SOURCES = misc.c sb.c crypto.c crc.c elf.c
LIBSOURCES := dualboot.c mkimxboot.c md5.c \
$(addprefix $(IMXTOOLS_DIR),$(IMXTOOLS_SOURCES))
# for now build tomcrypt as part of the lib.
LIBSOURCES += $(addprefix $(TOMCRYPT_DIR),$(TOMCRYPT_SOURCES))
# inputs for binary only
SOURCES := $(LIBSOURCES) main.c
# dependencies for binary
EXTRADEPS :=
include ../libtools.make
# explicit dependencies on dualboot.{c,h} and mkimxboot.h
$(OBJDIR)mkimxboot.o: dualboot.h dualboot.c mkimxboot.c mkimxboot.h
$(OBJDIR)main.o: dualboot.h dualboot.c main.c mkimxboot.h
$(BINARY): librbtomcrypt.a
librbtomcrypt.a:
$(MAKE) -C ../../utils/tomcrypt

293
utils/mkimxboot/dualboot.c Normal file
View file

@ -0,0 +1,293 @@
/* Generated by bin2c */
#include "dualboot.h"
unsigned char dualboot_fuzeplus[728] = {
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0xd8, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
0x34, 0x00, 0x00, 0x1a, 0xd0, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
0x25, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
0xc8, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
0xbc, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x3f, 0x34, 0x03, 0xe2, 0x23, 0x3c, 0xa0, 0xe1,
0x20, 0x00, 0x13, 0xe3, 0x01, 0x30, 0xa0, 0x13, 0x02, 0x00, 0x00, 0x1a, 0x10, 0x00, 0x13, 0xe3,
0x02, 0x30, 0xa0, 0x13, 0x00, 0x30, 0xa0, 0x03, 0x98, 0x20, 0x9f, 0xe5, 0x10, 0x26, 0x92, 0xe5,
0x01, 0x01, 0x12, 0xe3, 0x10, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x53, 0xe3, 0x10, 0x00, 0x00, 0x1a,
0x03, 0x20, 0xa0, 0xe1, 0x78, 0x00, 0x9f, 0xe5, 0x7c, 0x10, 0x9f, 0xe5, 0xc0, 0xc0, 0x90, 0xe5,
0x03, 0xc6, 0x0c, 0xe2, 0x01, 0x06, 0x5c, 0xe3, 0x01, 0x20, 0x82, 0x02, 0x01, 0x30, 0x83, 0xe2,
0x01, 0x00, 0x53, 0xe1, 0xf8, 0xff, 0xff, 0x1a, 0x60, 0x30, 0x9f, 0xe5, 0x03, 0x00, 0x52, 0xe1,
0x03, 0x00, 0x00, 0xca, 0x05, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3,
0x70, 0x80, 0xbd, 0xe8, 0x00, 0x40, 0x86, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
0x30, 0x30, 0x9f, 0xe5, 0x03, 0x27, 0xa0, 0xe3, 0x04, 0x21, 0x83, 0xe5, 0x02, 0x2c, 0xa0, 0xe3,
0x00, 0x27, 0x83, 0xe5, 0x00, 0x25, 0x83, 0xe5, 0x24, 0x20, 0x9f, 0xe5, 0x0b, 0x39, 0x83, 0xe2,
0x00, 0x21, 0x83, 0xe5, 0xef, 0xff, 0xff, 0xea, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x00, 0x80, 0x01, 0x80, 0x70, 0x64, 0x08, 0x00,
0x7f, 0x1a, 0x06, 0x00, 0x01, 0x00, 0xff, 0xff
};
unsigned char dualboot_zenxfi2[608] = {
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0x6c, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
0x34, 0x00, 0x00, 0x1a, 0x64, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
0x17, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
0x5c, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
0x50, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x02, 0x02, 0x13, 0xe3, 0x04, 0x00, 0x00, 0x1a,
0x44, 0x30, 0x9f, 0xe5, 0x00, 0x36, 0x93, 0xe5, 0x01, 0x09, 0x13, 0xe3, 0x08, 0x00, 0x00, 0x0a,
0x04, 0x00, 0x00, 0xea, 0x2c, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x03, 0x36, 0x03, 0xe2,
0x01, 0x06, 0x53, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x86, 0xe5, 0x01, 0x00, 0xa0, 0xe3,
0x70, 0x80, 0xbd, 0xe8, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8, 0x63, 0x68, 0x72, 0x67,
0x00, 0x00, 0x05, 0x80, 0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x00, 0x80, 0x01, 0x80
};
unsigned char dualboot_zenxfi3[572] = {
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0x48, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
0x34, 0x00, 0x00, 0x1a, 0x40, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
0x0e, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
0x38, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
0x2c, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x28, 0x30, 0x9f, 0xe5, 0x20, 0x36, 0x93, 0xe5,
0x80, 0x00, 0x13, 0xe3, 0x00, 0x40, 0x86, 0x15, 0x01, 0x00, 0xa0, 0x13, 0x70, 0x80, 0xbd, 0x18,
0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x00, 0x80, 0x01, 0x80
};
unsigned char dualboot_nwze370[896] = {
0x10, 0x40, 0x2d, 0xe9, 0x48, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x54, 0x30, 0x9f, 0xe5,
0x01, 0x20, 0xa0, 0xe3, 0x18, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x83, 0xe5, 0x03, 0x20, 0xa0, 0xe1,
0x10, 0x30, 0x92, 0xe5, 0x01, 0x00, 0x13, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x34, 0x30, 0x9f, 0xe5,
0x50, 0x00, 0x93, 0xe5, 0xff, 0x04, 0xc0, 0xe3, 0x3f, 0x07, 0xc0, 0xe3, 0x41, 0x3e, 0x40, 0xe2,
0x0a, 0x30, 0x43, 0xe2, 0x63, 0x00, 0x53, 0xe3, 0x02, 0x00, 0xa0, 0x93, 0x1e, 0xff, 0x2f, 0x91,
0x16, 0x0d, 0x40, 0xe2, 0x0c, 0x00, 0x40, 0xe2, 0x63, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0x83,
0x01, 0x00, 0xa0, 0x93, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x05, 0x80, 0xf0, 0x41, 0x2d, 0xe9,
0x00, 0x60, 0xa0, 0xe1, 0x01, 0x70, 0xa0, 0xe1, 0x28, 0x32, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
0x34, 0x00, 0x00, 0x1a, 0x20, 0x32, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
0x8d, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x77, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1,
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x87, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x54, 0xe3,
0x31, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
0x18, 0x31, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8,
0x0c, 0x31, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x3f, 0x34, 0x03, 0xe2, 0x23, 0x3c, 0xa0, 0xe1,
0x20, 0x00, 0x13, 0xe3, 0x01, 0x00, 0x00, 0x1a, 0x10, 0x00, 0x13, 0xe3, 0x24, 0x00, 0x00, 0x0a,
0xe4, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2,
0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2, 0x48, 0x21, 0x83, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2, 0x58, 0x20, 0x83, 0xe5, 0xc2, 0x24, 0x82, 0xe2,
0x24, 0x20, 0x83, 0xe5, 0x84, 0xff, 0xff, 0xeb, 0x00, 0x40, 0x50, 0xe2, 0x06, 0x00, 0x00, 0x1a,
0x0a, 0x00, 0x00, 0xea, 0x80, 0xff, 0xff, 0xeb, 0x00, 0x00, 0x54, 0xe1, 0x0a, 0x00, 0x00, 0x1a,
0xc0, 0x30, 0x98, 0xe5, 0x03, 0x00, 0x55, 0xe1, 0xf9, 0xff, 0xff, 0x8a, 0x01, 0x00, 0x54, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3, 0x03, 0x00, 0x00, 0x1a, 0x06, 0x00, 0x00, 0xea,
0x00, 0x60, 0x87, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8, 0x74, 0x20, 0x9f, 0xe5,
0x6c, 0x30, 0x9f, 0xe5, 0x00, 0x21, 0x83, 0xe5, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3,
0xf0, 0x81, 0xbd, 0xe8, 0x50, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2, 0x48, 0x21, 0x83, 0xe5,
0x00, 0x20, 0xa0, 0xe3, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2, 0x58, 0x20, 0x83, 0xe5,
0xc2, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x5f, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1,
0x24, 0x30, 0x9f, 0xe5, 0xc0, 0x50, 0x93, 0xe5, 0x3d, 0x59, 0x85, 0xe2, 0x09, 0x5d, 0x85, 0xe2,
0x03, 0x80, 0xa0, 0xe1, 0xd9, 0xff, 0xff, 0xea, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc0, 0x01, 0x80
};
unsigned char dualboot_nwze360[944] = {
0x10, 0x40, 0x2d, 0xe9, 0x4e, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x68, 0x30, 0x9f, 0xe5,
0x01, 0x20, 0xa0, 0xe3, 0x18, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x83, 0xe5, 0x03, 0x20, 0xa0, 0xe1,
0x10, 0x30, 0x92, 0xe5, 0x01, 0x00, 0x13, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x48, 0x30, 0x9f, 0xe5,
0x50, 0x30, 0x93, 0xe5, 0x44, 0x20, 0x9f, 0xe5, 0x00, 0x26, 0x92, 0xe5, 0x02, 0x0c, 0x12, 0xe3,
0x00, 0x00, 0xa0, 0x03, 0x1e, 0xff, 0x2f, 0x01, 0xff, 0x34, 0xc3, 0xe3, 0x3f, 0x37, 0xc3, 0xe3,
0x41, 0x2e, 0x43, 0xe2, 0x0a, 0x20, 0x42, 0xe2, 0x63, 0x00, 0x52, 0xe3, 0x02, 0x00, 0xa0, 0x93,
0x1e, 0xff, 0x2f, 0x91, 0x16, 0x3d, 0x43, 0xe2, 0x0c, 0x30, 0x43, 0xe2, 0x63, 0x00, 0x53, 0xe3,
0x00, 0x00, 0xa0, 0x83, 0x01, 0x00, 0xa0, 0x93, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x05, 0x80,
0x00, 0x80, 0x01, 0x80, 0xf0, 0x41, 0x2d, 0xe9, 0x00, 0x60, 0xa0, 0xe1, 0x01, 0x70, 0xa0, 0xe1,
0x40, 0x32, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x34, 0x00, 0x00, 0x1a, 0x38, 0x32, 0x9f, 0xe5,
0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5,
0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3, 0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5,
0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5,
0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3, 0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3,
0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3, 0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5,
0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3, 0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5,
0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5, 0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3,
0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5, 0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3,
0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3, 0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5,
0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5, 0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5,
0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3, 0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2,
0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5, 0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5,
0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea,
0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x87, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3,
0x71, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1, 0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
0x81, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x54, 0xe3, 0x34, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3,
0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3, 0x30, 0x31, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5,
0x00, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8, 0x24, 0x31, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5,
0x3f, 0x34, 0x03, 0xe2, 0x23, 0x3c, 0xa0, 0xe1, 0x20, 0x00, 0x13, 0xe3, 0x01, 0x00, 0x00, 0x1a,
0x10, 0x00, 0x13, 0xe3, 0x27, 0x00, 0x00, 0x0a, 0xfc, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3,
0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2,
0x48, 0x21, 0x83, 0xe5, 0x00, 0x20, 0xa0, 0xe3, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2,
0x58, 0x20, 0x83, 0xe5, 0xc2, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x02, 0x2c, 0xa0, 0xe3,
0x0e, 0x39, 0x43, 0xe2, 0x04, 0x24, 0x83, 0xe5, 0x7b, 0xff, 0xff, 0xeb, 0x00, 0x40, 0x50, 0xe2,
0x06, 0x00, 0x00, 0x1a, 0x0a, 0x00, 0x00, 0xea, 0x77, 0xff, 0xff, 0xeb, 0x00, 0x00, 0x54, 0xe1,
0x0a, 0x00, 0x00, 0x1a, 0xc0, 0x30, 0x98, 0xe5, 0x03, 0x00, 0x55, 0xe1, 0xf9, 0xff, 0xff, 0x8a,
0x01, 0x00, 0x54, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x54, 0xe3, 0x03, 0x00, 0x00, 0x1a,
0x06, 0x00, 0x00, 0xea, 0x00, 0x60, 0x87, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8,
0x80, 0x20, 0x9f, 0xe5, 0x78, 0x30, 0x9f, 0xe5, 0x00, 0x21, 0x83, 0xe5, 0xfe, 0xff, 0xff, 0xea,
0x00, 0x00, 0xa0, 0xe3, 0xf0, 0x81, 0xbd, 0xe8, 0x5c, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3,
0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x3f, 0x21, 0x82, 0xe2,
0x48, 0x21, 0x83, 0xe5, 0x00, 0x20, 0xa0, 0xe3, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0x82, 0xe2,
0x58, 0x20, 0x83, 0xe5, 0xc2, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x02, 0x2c, 0xa0, 0xe3,
0x0e, 0x39, 0x43, 0xe2, 0x04, 0x24, 0x83, 0xe5, 0x53, 0xff, 0xff, 0xeb, 0x00, 0x40, 0xa0, 0xe1,
0x24, 0x30, 0x9f, 0xe5, 0xc0, 0x50, 0x93, 0xe5, 0x3d, 0x59, 0x85, 0xe2, 0x09, 0x5d, 0x85, 0xe2,
0x03, 0x80, 0xa0, 0xe1, 0xd6, 0xff, 0xff, 0xea, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80,
0x00, 0xc0, 0x05, 0x80, 0x00, 0x40, 0x04, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc0, 0x01, 0x80
};
unsigned char dualboot_zenxfistyle[660] = {
0x10, 0x40, 0x2d, 0xe9, 0x30, 0x00, 0x00, 0xeb, 0x10, 0x80, 0xbd, 0xe8, 0x40, 0x30, 0x9f, 0xe5,
0xb0, 0x30, 0x93, 0xe5, 0x03, 0x18, 0xa0, 0xe1, 0x21, 0x18, 0xa0, 0xe1, 0x34, 0x20, 0x9f, 0xe5,
0x02, 0x00, 0x51, 0xe1, 0x08, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x50, 0xe3, 0x01, 0x38, 0x03, 0x02,
0x23, 0x08, 0xa0, 0x01, 0x1e, 0xff, 0x2f, 0x01, 0x01, 0x00, 0x50, 0xe3, 0x02, 0x00, 0x00, 0x1a,
0x06, 0x38, 0x03, 0xe2, 0xa3, 0x08, 0xa0, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe3,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x04, 0x40, 0x2d, 0xe5,
0x5c, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x92, 0xe5, 0x03, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xa0, 0xe1,
0x50, 0x20, 0x9f, 0xe5, 0x02, 0x00, 0x54, 0xe1, 0x02, 0x30, 0xa0, 0x11, 0x00, 0x00, 0x50, 0xe3,
0x02, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe3, 0x09, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0xea,
0x01, 0x38, 0xc3, 0xe3, 0x01, 0x18, 0xa0, 0xe1, 0x01, 0x18, 0x01, 0xe2, 0x01, 0x30, 0x83, 0xe1,
0x03, 0x00, 0x00, 0xea, 0x06, 0x38, 0xc3, 0xe3, 0x81, 0x18, 0xa0, 0xe1, 0x06, 0x18, 0x01, 0xe2,
0x01, 0x30, 0x83, 0xe1, 0x08, 0x20, 0x9f, 0xe5, 0xb0, 0x30, 0x82, 0xe5, 0x10, 0x00, 0xbd, 0xe8,
0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xc0, 0x05, 0x80, 0x52, 0x42, 0x00, 0x00, 0x70, 0x40, 0x2d, 0xe9,
0x00, 0x40, 0xa0, 0xe1, 0x01, 0x60, 0xa0, 0xe1, 0xa4, 0x31, 0x9f, 0xe5, 0x03, 0x00, 0x50, 0xe1,
0x34, 0x00, 0x00, 0x1a, 0x9c, 0x31, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3, 0x08, 0x20, 0x83, 0xe5,
0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
0x02, 0x21, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x0f, 0x28, 0xc2, 0xe3,
0x01, 0x28, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0xd0, 0x20, 0x93, 0xe5, 0x7f, 0x2e, 0xc2, 0xe3,
0x0f, 0x20, 0xc2, 0xe3, 0xc8, 0x20, 0x82, 0xe3, 0xd0, 0x20, 0x83, 0xe5, 0x01, 0x26, 0xa0, 0xe3,
0xd4, 0x20, 0x83, 0xe5, 0x34, 0x21, 0x83, 0xe5, 0x30, 0x11, 0x93, 0xe5, 0x03, 0x18, 0xc1, 0xe3,
0x02, 0x18, 0x81, 0xe3, 0x30, 0x11, 0x83, 0xe5, 0x03, 0x39, 0x43, 0xe2, 0x30, 0x10, 0x93, 0xe5,
0x0f, 0x1c, 0xc1, 0xe3, 0x01, 0x1c, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x30, 0x10, 0x93, 0xe5,
0x3f, 0x10, 0xc1, 0xe3, 0x10, 0x10, 0x81, 0xe3, 0x30, 0x10, 0x83, 0xe5, 0x01, 0x18, 0xa0, 0xe3,
0x38, 0x10, 0x83, 0xe5, 0x80, 0x10, 0x93, 0xe5, 0x02, 0x15, 0x81, 0xe3, 0x80, 0x10, 0x83, 0xe5,
0x18, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x3f, 0x2a, 0xc2, 0xe3, 0x01, 0x28, 0x82, 0xe3,
0x10, 0x20, 0x83, 0xe5, 0x01, 0x39, 0x43, 0xe2, 0x00, 0x10, 0xa0, 0xe3, 0x20, 0x20, 0x93, 0xe5,
0x01, 0x2a, 0x82, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x90, 0x1f, 0x07, 0xee, 0x00, 0x00, 0xa0, 0xe1,
0x00, 0x00, 0xa0, 0xe1, 0xf8, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3,
0xa5, 0xff, 0xff, 0xeb, 0x01, 0x00, 0xa0, 0xe3, 0x8f, 0xff, 0xff, 0xeb, 0x00, 0x50, 0xa0, 0xe1,
0x01, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x9f, 0xff, 0xff, 0xeb, 0x01, 0x00, 0x55, 0xe3,
0x25, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x55, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x01, 0x27, 0xa0, 0xe3,
0x94, 0x30, 0x9f, 0xe5, 0x78, 0x20, 0x83, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x70, 0x80, 0xbd, 0xe8,
0x88, 0x30, 0x9f, 0xe5, 0xc0, 0x30, 0x93, 0xe5, 0x78, 0x30, 0x9f, 0xe5, 0x02, 0x21, 0xa0, 0xe3,
0x08, 0x20, 0x83, 0xe5, 0x03, 0x21, 0x82, 0xe2, 0x08, 0x20, 0x83, 0xe5, 0x0f, 0x2c, 0xa0, 0xe3,
0x48, 0x21, 0x83, 0xe5, 0x0d, 0x2c, 0x42, 0xe2, 0x44, 0x21, 0x83, 0xe5, 0x3f, 0x24, 0xa0, 0xe3,
0x78, 0x20, 0x83, 0xe5, 0xc5, 0x24, 0x82, 0xe2, 0x24, 0x20, 0x83, 0xe5, 0x04, 0x20, 0xa0, 0xe3,
0x18, 0x20, 0x83, 0xe5, 0x04, 0x20, 0x83, 0xe5, 0x10, 0x20, 0x93, 0xe5, 0x04, 0x00, 0x12, 0xe3,
0xfc, 0xff, 0xff, 0x0a, 0x2c, 0x30, 0x9f, 0xe5, 0x70, 0x30, 0x93, 0xe5, 0xff, 0x34, 0xc3, 0xe3,
0x3f, 0x37, 0xc3, 0xe3, 0xcb, 0x3f, 0x43, 0xe2, 0x03, 0x30, 0x43, 0xe2, 0x63, 0x00, 0x53, 0xe3,
0x00, 0x40, 0x86, 0x85, 0x01, 0x00, 0xa0, 0x83, 0x70, 0x80, 0xbd, 0x88, 0x00, 0x00, 0xa0, 0xe3,
0x70, 0x80, 0xbd, 0xe8, 0x63, 0x68, 0x72, 0x67, 0x00, 0x00, 0x05, 0x80, 0x00, 0xc0, 0x05, 0x80,
0x00, 0x40, 0x04, 0x80
};

View file

@ -0,0 +1,8 @@
/* Generated by bin2c */
extern unsigned char dualboot_fuzeplus[728];
extern unsigned char dualboot_zenxfi2[608];
extern unsigned char dualboot_zenxfi3[572];
extern unsigned char dualboot_nwze370[896];
extern unsigned char dualboot_nwze360[944];
extern unsigned char dualboot_zenxfistyle[660];

View file

@ -0,0 +1,48 @@
CC=gcc
LD=ld
OC=objcopy
PREFIX?=arm-elf-eabi-
IMX233_PATH=../../../firmware/target/arm/imx233
CFLAGS=-mcpu=arm926ej-s -std=gnu99 -I. -I$(IMX233_PATH) -nostdlib -ffreestanding -fomit-frame-pointer -O
# Edit the following variables when adding a new target.
# mkimxboot.c also needs to be edited to refer to these
# To add a new target x you need to:
# 1) add x to the list in TARGETS
# 2) create a variable named OPT_x of the form:
# OPT_x=target specific defines
TARGETS=fuzeplus zenxfi2 zenxfi3 nwze370 nwze360 zenxfistyle
OPT_fuzeplus=-DSANSA_FUZEPLUS -DIMX233_SUBTARGET=3780
OPT_zenxfi2=-DCREATIVE_ZENXFI2 -DIMX233_SUBTARGET=3780
OPT_zenxfi3=-DCREATIVE_ZENXFI3 -DIMX233_SUBTARGET=3780
OPT_nwze370=-DSONY_NWZE370 -DIMX233_SUBTARGET=3780
OPT_nwze360=-DSONY_NWZE360 -DIMX233_SUBTARGET=3780
OPT_zenxfistyle=-DCREATIVE_ZENXFISTYLE -DIMX233_SUBTARGET=3780
BOOTOBJS=$(patsubst %, dualboot_%.o, $(TARGETS))
BOOTBINS=$(patsubst %, dualboot_%.arm-bin, $(TARGETS))
BOOTELFS=$(patsubst %, dualboot_%.arm-elf, $(TARGETS))
all: ../dualboot.h ../dualboot.c $(BOOTELFS)
# Dualboot bootloaders
dualboot_%.o: dualboot.c
$(PREFIX)$(CC) $(CFLAGS) $(OPT_$(@:dualboot_%.o=%)) -c -o $@ $^
dualboot_%.arm-elf: dualboot_%.o
$(PREFIX)$(LD) $(LDFLAGS) -Tdualboot.lds -o $@ $<
# Rules for the ARM code embedded in mkamsboot - assemble, link, then extract
# the binary code and finally convert to .h for building in mkamsboot
%.arm-bin: %.arm-elf
$(PREFIX)$(OC) -O binary $< $@
../dualboot.c ../dualboot.h: $(BOOTBINS) bin2c
./bin2c ../dualboot $(BOOTBINS)
bin2c: bin2c.c
$(CC) -o bin2c bin2c.c
clean:
rm -f *~ bin2c $(BOOTBINS) $(BOOTOBJS) $(BOOTELFS)

View file

@ -0,0 +1,140 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 Dave Chapman
*
* 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 <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libgen.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
static off_t filesize(int fd)
{
struct stat buf;
fstat(fd,&buf);
return buf.st_size;
}
static void write_cfile(const unsigned char* buf, off_t len, FILE* fp, const char *name)
{
int i;
fprintf(fp,"unsigned char %s[%ld] = {",name,len);
for (i=0;i<len;i++) {
if ((i % 16) == 0) {
fprintf(fp,"\n ");
}
if (i == (len-1)) {
fprintf(fp,"0x%02x",buf[i]);
} else if ((i % 16) == 15) {
fprintf(fp,"0x%02x,",buf[i]);
} else {
fprintf(fp,"0x%02x, ",buf[i]);
}
}
fprintf(fp,"\n};\n");
}
int main (int argc, char* argv[])
{
char* cname;
int i;
FILE *cfile, *hfile;
char cfilename[256], hfilename[256];
if (argc < 3) {
fprintf(stderr,"Usage: bin2c cname file1 [file2 [file3 ...]]\n");
return 1;
}
cname=argv[1];
snprintf(cfilename,256,"%s.c",cname);
cfile = fopen(cfilename,"w+");
if (cfile == NULL) {
fprintf(stderr,"Couldn't open %s\n",cfilename);
return 2;
}
snprintf(hfilename,256,"%s.h",cname);
hfile = fopen(hfilename,"w+");
if (hfile == NULL) {
fprintf(stderr,"Couldn't open %s\n",hfilename);
fclose(cfile);
return 3;
}
fprintf(cfile,"/* Generated by bin2c */\n\n");
fprintf(cfile,"#include \"%s\"\n\n", basename(hfilename));
fprintf(hfile,"/* Generated by bin2c */\n\n");
for(i=0; i < argc - 2; i++) {
unsigned char* buf;
off_t len;
off_t orig_len;
char *ext;
char *array = argv[2+i];
int fd = open(array,O_RDONLY|O_BINARY);
if (fd < 0) {
fprintf(stderr,"Can not open %s\n",argv[2+i]);
fclose(cfile);
fclose(hfile);
return 4;
}
orig_len = filesize(fd);
/* pad to 32bit */
len = (orig_len + 3) & ~3;
buf = malloc(len);
if (read(fd,buf,orig_len) < orig_len) {
fprintf(stderr,"Short read, aborting\n");
return 5;
}
/* pad to 32bit with zeros */
if (len > orig_len)
memset(buf+orig_len, 0, len-orig_len);
/* remove file extension */
ext = strchr (array, '.');
if (ext != NULL)
*ext = '\0';
write_cfile (buf, len, cfile, array);
fprintf(hfile,"extern unsigned char %s[%ld];\n",array,len);
close(fd);
}
fclose(cfile);
fclose(hfile);
return 0;
}

View file

@ -0,0 +1,26 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2013 by Amaury Pouly
*
* 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.
*
****************************************************************************/
/** mostly empty, used by register files and dualboot */
#define COMPILE_DUALBOOT_STUB
/* obviously we have the dualboot stub! */
#define HAVE_DUALBOOT_STUB

View file

@ -0,0 +1,323 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2013 by Amaury Pouly
*
* 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 "regs/pinctrl.h"
#include "regs/power.h"
#include "regs/lradc.h"
#include "regs/digctl.h"
#include "regs/clkctrl.h"
#define BOOT_ROM_CONTINUE 0 /* continue boot */
#define BOOT_ROM_SECTION 1 /* switch to new section *result_id */
#define BOOT_ARG_CHARGE ('c' | 'h' << 8 | 'r' << 16 | 'g' << 24)
/** additional defines */
#define BP_LRADC_CTRL4_LRADCxSELECT(x) (4 * (x))
#define BM_LRADC_CTRL4_LRADCxSELECT(x) (0xf << (4 * (x)))
typedef unsigned long uint32_t;
/* we include the dualboot rtc code directly */
#include "dualboot-imx233.h"
#include "dualboot-imx233.c"
// target specific boot context
enum context_t
{
CONTEXT_NORMAL, /* normal boot */
CONTEXT_USB, /* USB plugged boot */
CONTEXT_RTC, /* RTC wake up boot */
};
// target specific boot decision
enum boot_t
{
BOOT_STOP, /* power down */
BOOT_ROCK, /* boot to Rockbox */
BOOT_OF, /* boot to OF */
};
/**
* Helper functions
*/
static inline int __attribute__((always_inline)) read_gpio(int bank, int pin)
{
return (HW_PINCTRL_DINn(bank) >> pin) & 1;
}
static inline int __attribute__((always_inline)) read_pswitch(void)
{
#if IMX233_SUBTARGET >= 3700
return BF_RD(POWER_STS, PSWITCH);
#else
return BF_RD(DIGCTL_STATUS, PSWITCH);
#endif
}
/* only works for channels <=7, always divide by 2, never accumulates */
static inline void __attribute__((always_inline)) setup_lradc(int src)
{
BF_CLR(LRADC_CTRL0, SFTRST);
BF_CLR(LRADC_CTRL0, CLKGATE);
#if IMX233_SUBTARGET >= 3700
HW_LRADC_CTRL4_CLR = BM_LRADC_CTRL4_LRADCxSELECT(src);
HW_LRADC_CTRL4_SET = src << BP_LRADC_CTRL4_LRADCxSELECT(src);
#endif
HW_LRADC_CHn_CLR(src) = BM_OR(LRADC_CHn, NUM_SAMPLES, ACCUMULATE);
BF_WR(LRADC_CTRL2_SET, DIVIDE_BY_TWO(1 << src));
}
#define BP_LRADC_CTRL1_LRADCx_IRQ(x) (x)
#define BM_LRADC_CTRL1_LRADCx_IRQ(x) (1 << (x))
static inline int __attribute__((always_inline)) read_lradc(int src)
{
BF_CLR(LRADC_CTRL1, LRADCx_IRQ(src));
BF_WR(LRADC_CTRL0_SET, SCHEDULE(1 << src));
while(!BF_RD(LRADC_CTRL1, LRADCx_IRQ(src)));
return BF_RD(LRADC_CHn(src), VALUE);
}
static inline void __attribute__((noreturn)) power_down()
{
#ifdef SANSA_FUZEPLUS
/* B0P09: this pin seems to be important to shutdown the hardware properly */
HW_PINCTRL_MUXSELn_SET(0) = 3 << 18;
HW_PINCTRL_DOEn(0) = 1 << 9;
HW_PINCTRL_DOUTn(0) = 1 << 9;
#endif
/* power down */
HW_POWER_RESET = BM_OR(POWER_RESET, UNLOCK, PWD);
while(1);
}
/**
* Boot decision functions
*/
#if defined(SANSA_FUZEPLUS)
static enum boot_t boot_decision(enum context_t context)
{
/* if volume down is hold, boot to OF */
if(!read_gpio(1, 30))
return BOOT_OF;
/* on normal boot, make sure power button is hold long enough */
if(context == CONTEXT_NORMAL)
{
// monitor PSWITCH
int count = 0;
for(int i = 0; i < 550000; i++)
if(read_pswitch() == 1)
count++;
if(count < 400000)
return BOOT_STOP;
}
return BOOT_ROCK;
}
#elif defined(CREATIVE_ZENXFI2)
static int boot_decision(int context)
{
/* We are lacking buttons on the Zen X-Fi2 because on USB, the select button
* enters recovery mode ! So we can only use power but power is used to power up
* on normal boots and then select is free ! Thus use a non-uniform scheme:
* - normal boot/RTC:
* - no key: Rockbox
* - select: OF
* - USB boot:
* - no key: Rockbox
* - power: OF
*/
if(context == CONTEXT_USB)
return read_pswitch() == 1 ? BOOT_OF : BOOT_ROCK;
else
return !read_gpio(0, 14) ? BOOT_OF : BOOT_ROCK;
}
#elif defined(CREATIVE_ZENXFI3)
static int boot_decision(int context)
{
/* if volume down is hold, boot to OF */
return !read_gpio(2, 7) ? BOOT_OF : BOOT_ROCK;
}
#elif defined(SONY_NWZE360) || defined(SONY_NWZE370)
static int local_decision(void)
{
/* read keys and pswitch */
int val = read_lradc(0);
/* if hold is on, power off
* if back is pressed, boot to OF
* if play is pressed, boot RB
* otherwise power off */
#ifdef SONY_NWZE360
if(read_gpio(0, 9) == 0)
return BOOT_STOP;
#endif
if(val >= 1050 && val < 1150)
return BOOT_OF;
if(val >= 1420 && val < 1520)
return BOOT_ROCK;
return BOOT_STOP;
}
static int boot_decision(int context)
{
setup_lradc(0); // setup LRADC channel 0 to read keys
#ifdef SONY_NWZE360
HW_PINCTRL_PULLn_SET(0) = 1 << 9; // enable pullup on hold key (B0P09)
#endif
/* make a decision */
int decision = local_decision();
/* in USB or alarm context, stick to it */
if(context == CONTEXT_USB || context == CONTEXT_RTC)
{
/* never power down so replace power off decision by rockbox */
return decision == BOOT_STOP ? BOOT_ROCK : decision;
}
/* otherwise start a 1 second timeout. Any decision change
* will result in power down */
uint32_t tmo = HW_DIGCTL_MICROSECONDS + 1000000;
while(HW_DIGCTL_MICROSECONDS < tmo)
{
int new_dec = local_decision();
if(new_dec != decision)
return BOOT_STOP;
}
return decision;
}
#elif defined(CREATIVE_ZENXFISTYLE)
static int boot_decision(int context)
{
setup_lradc(2); // setup LRADC channel 2 to read keys
/* make a decision */
int val = read_lradc(2);
/* boot to OF if left is hold
* NOTE: VDDIO is set to 3.1V initially and the resistor ladder is wired to
* VDDIO so these values are not the same as in the main binary which is
* calibrated for VDDIO=3.3V */
if(val >= 815 && val < 915)
return BOOT_OF;
return BOOT_ROCK;
}
#else
#warning You should define a target specific boot decision function
static int boot_decision(int context)
{
return BOOT_ROCK;
}
#endif
/**
* Context functions
*/
static inline enum context_t get_context(void)
{
#if IMX233_SUBTARGET >= 3780
/* On the imx233 it's easy because we know the power up source */
unsigned pwrup_src = BF_RD(POWER_STS, PWRUP_SOURCE);
if(pwrup_src & (1 << 5))
return CONTEXT_USB;
else if(pwrup_src & (1 << 4))
return CONTEXT_RTC;
else
return CONTEXT_NORMAL;
#else
/* On the other targets, we need to poke a few more registers */
#endif
}
/**
* Charging function
*/
static inline void do_charge(void)
{
BF_CLR(LRADC_CTRL0, SFTRST);
BF_CLR(LRADC_CTRL0, CLKGATE);
BF_WR(LRADC_DELAYn(0), TRIGGER_LRADCS(0x80));
BF_WR(LRADC_DELAYn(0), TRIGGER_DELAYS(0x1));
BF_WR(LRADC_DELAYn(0), DELAY(200));
BF_SET(LRADC_DELAYn(0), KICK);
BF_SET(LRADC_CONVERSION, AUTOMATIC);
BF_WR(LRADC_CONVERSION, SCALE_FACTOR_V(LI_ION));
BF_WR(POWER_CHARGE, STOP_ILIMIT(1));
BF_WR(POWER_CHARGE, BATTCHRG_I(0x10));
BF_CLR(POWER_CHARGE, PWD_BATTCHRG);
#if IMX233_SUBTARGET >= 3780
BF_WR(POWER_DCDC4P2, ENABLE_4P2(1));
BF_CLR(POWER_5VCTRL, PWD_CHARGE_4P2);
BF_WR(POWER_5VCTRL, CHARGE_4P2_ILIMIT(0x10));
#endif
while(1)
{
BF_WR(CLKCTRL_CPU, INTERRUPT_WAIT(1));
asm volatile (
"mcr p15, 0, %0, c7, c0, 4 \n" /* Wait for interrupt */
"nop\n" /* Datasheet unclear: "The lr sent to handler points here after RTI"*/
"nop\n"
: : "r"(0)
);
}
}
static void set_updater_bits(void)
{
/* The OF will continue to updater if we clear 18 of PERSISTENT1.
* See dualboot-imx233.c in firmware/ for more explanation */
HW_RTC_PERSISTENT1_CLR = 1 << 18;
}
int main(uint32_t arg, uint32_t *result_id)
{
if(arg == BOOT_ARG_CHARGE)
do_charge();
/* tell rockbox that we can handle boot mode */
imx233_dualboot_set_field(DUALBOOT_CAP_BOOT, 1);
/* if we were asked to boot in a special mode, do so */
unsigned boot_mode = imx233_dualboot_get_field(DUALBOOT_BOOT);
/* clear boot mode to avoid any loop */
imx233_dualboot_set_field(DUALBOOT_BOOT, IMX233_BOOT_NORMAL);
switch(boot_mode)
{
case IMX233_BOOT_UPDATER:
set_updater_bits();
/* fallthrough */
case IMX233_BOOT_OF:
/* continue booting */
return BOOT_ROM_CONTINUE;
case IMX233_BOOT_NORMAL:
default:
break;
}
/* normal boot */
switch(boot_decision(get_context()))
{
case BOOT_ROCK:
*result_id = arg;
return BOOT_ROM_SECTION;
case BOOT_OF:
return BOOT_ROM_CONTINUE;
case BOOT_STOP:
default:
power_down();
}
}
int __attribute__((section(".start"))) start(uint32_t arg, uint32_t *result_id)
{
return main(arg, result_id);
}

View file

@ -0,0 +1,17 @@
ENTRY(start)
OUTPUT_FORMAT(elf32-littlearm)
OUTPUT_ARCH(arm)
MEMORY
{
OCRAM : ORIGIN = 0, LENGTH = 0x8000
}
SECTIONS
{
.text 0 :
{
*(.start*)
*(.text*)
} > OCRAM
}

289
utils/mkimxboot/main.c Normal file
View file

@ -0,0 +1,289 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Amaury Pouly
*
* 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 <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mkimxboot.h"
struct imx_variant_t
{
const char *name;
enum imx_firmware_variant_t variant;
};
static struct imx_variant_t imx_variants[] =
{
{ "default", VARIANT_DEFAULT },
{ "zenxfi2-recovery", VARIANT_ZENXFI2_RECOVERY },
{ "zenxfi2-nand", VARIANT_ZENXFI2_NAND },
{ "zenxfi2-sd", VARIANT_ZENXFI2_SD },
{ "zenxfistyle-recovery", VARIANT_ZENXFISTYLE_RECOVERY },
{ "zenstyle-recovery", VARIANT_ZENSTYLE_RECOVERY },
};
#define NR_VARIANTS sizeof(imx_variants) / sizeof(imx_variants[0])
struct model_t
{
const char *name;
enum imx_model_t model;
};
struct model_t imx_models[] =
{
{ "unknown", MODEL_UNKNOWN },
{ "fuzeplus", MODEL_FUZEPLUS },
{ "zenxfi2", MODEL_ZENXFI2 },
{ "zenxfi3", MODEL_ZENXFI3 },
{ "zenxfistyle", MODEL_ZENXFISTYLE },
{ "zenstyle", MODEL_ZENSTYLE },
{ "nwze370", MODEL_NWZE370 },
{ "nwze360", MODEL_NWZE360 },
};
#define NR_MODELS sizeof(imx_models) / sizeof(imx_models[0])
static void usage(void)
{
printf("Usage: mkimxboot [options | file]...\n");
printf("Options:\n");
printf(" -?/--help Display this message\n");
printf(" -o <file> Set output file\n");
printf(" -i <file> Set input file\n");
printf(" -b <file> Set boot file\n");
printf(" -d/--debug Enable debug output\n");
printf(" -t <type> Set type (dualboot, singleboot, recovery, origfw, charge)\n");
printf(" -v <v> Set variant\n");
printf(" -x Dump device informations\n");
printf(" -p <ver> Force product and component version\n");
printf(" -5 <type> Compute <type> MD5 sum of the input file\n");
printf(" -m <model> Specify model (useful for soft MD5 sum)\n");
printf("Supported variants: (default is standard)\n");
printf(" ");
for(size_t i = 0; i < NR_VARIANTS; i++)
{
if(i != 0)
printf(", ");
printf("%s", imx_variants[i].name);
}
printf("\n");
printf("Supported models: (default is unknown)\n");
for(size_t i = 0; i < NR_MODELS; i++)
{
if(i != 0)
printf(", ");
printf("%s", imx_models[i].name);
}
printf("\n");
printf("By default a dualboot image is built\n");
printf("This tools supports the following format for the boot file:\n");
printf("- rockbox scramble format\n");
printf("- elf format\n");
printf("Additional checks will be performed on rockbox scramble format to\n");
printf("ensure soundness of operation.\n");
printf("There are two types of MD5 sums: 'full' or 'soft'.\n");
printf("- full MD5 sum applies to the whole file\n");
printf("- soft MD5 sum for SB files accounts for relevant parts only\n");
exit(1);
}
static int print_md5(const char *file, const char *type)
{
uint8_t md5sum[16];
enum imx_error_t err;
if(strcmp(type, "full") == 0)
err = compute_md5sum(file, md5sum);
else if(strcmp(type, "soft") == 0)
err = compute_soft_md5sum(file, md5sum);
else
{
printf("Invalid md5sum type '%s'\n", type);
return 1;
}
if(err != IMX_SUCCESS)
{
printf("There was an error when computing the MD5 sum: %d\n", err);
return 2;
}
printf("%s MD5 sum: ", type);
for(int i = 0; i < 16; i++)
printf("%02x", md5sum[i]);
printf("\n");
return 0;
}
int main(int argc, char *argv[])
{
char *infile = NULL;
char *outfile = NULL;
char *bootfile = NULL;
enum imx_firmware_variant_t variant = VARIANT_DEFAULT;
enum imx_output_type_t type = IMX_DUALBOOT;
enum imx_model_t model = MODEL_UNKNOWN;
bool debug = false;
const char *md5type = NULL;
const char *force_version = NULL;
if(argc == 1)
usage();
while(1)
{
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"in-file", no_argument, 0, 'i'},
{"out-file", required_argument, 0, 'o'},
{"boot-file", required_argument, 0, 'b'},
{"debug", no_argument, 0, 'd'},
{"type", required_argument, 0, 't'},
{"variant", required_argument, 0, 'v'},
{"dev-info", no_argument, 0, 'x'},
{"model", required_argument, 0, 'm'},
{"md5", required_argument, 0, '5'},
{0, 0, 0, 0}
};
int c = getopt_long(argc, argv, "hdi:o:b:t:v:xp:m:5:", long_options, NULL);
if(c == -1)
break;
switch(c)
{
case 'd':
debug = true;
break;
case 'h':
usage();
break;
case 'o':
outfile = optarg;
break;
case 'i':
infile = optarg;
break;
case 'b':
bootfile = optarg;
break;
case 't':
if(strcmp(optarg, "dualboot") == 0)
type = IMX_DUALBOOT;
else if(strcmp(optarg, "singleboot") == 0)
type = IMX_SINGLEBOOT;
else if(strcmp(optarg, "recovery") == 0)
type = IMX_RECOVERY;
else if(strcmp(optarg, "charge") == 0)
type = IMX_CHARGE;
else if(strcmp(optarg, "origfw") == 0)
type = IMX_ORIG_FW;
else
{
printf("Invalid boot type '%s'\n", optarg);
return 1;
}
break;
case 'v':
{
for(size_t i = 0; i < NR_VARIANTS; i++)
{
if(strcmp(optarg, imx_variants[i].name) == 0)
{
variant = imx_variants[i].variant;
goto Lok;
}
}
printf("Invalid variant '%s'\n", optarg);
return 1;
Lok:
break;
}
case 'x':
dump_imx_dev_info("");
printf("variant mapping:\n");
for(int i = 0; i < sizeof(imx_variants) / sizeof(imx_variants[0]); i++)
printf(" %s -> variant=%d\n", imx_variants[i].name, imx_variants[i].variant);
break;
case 'p':
force_version = optarg;
break;
case '5':
md5type = optarg;
break;
case 'm':
if(model != MODEL_UNKNOWN)
{
printf("You cannot specify two models\n");
return 1;
}
for(int i = 0; i < NR_MODELS; i++)
if(strcmp(optarg, imx_models[i].name) == 0)
{
model = imx_models[i].model;
break;
}
if(model == MODEL_UNKNOWN)
printf("Unknown model '%s'\n", optarg);
break;
default:
abort();
}
}
if(!infile)
{
printf("You must specify an input file\n");
return 1;
}
if(md5type)
return print_md5(infile, md5type);
if(!outfile)
{
printf("You must specify an output file\n");
return 1;
}
if(!bootfile && type != IMX_ORIG_FW)
{
printf("You must specify an boot file\n");
return 1;
}
if(optind != argc)
{
printf("Extra arguments on command line\n");
return 1;
}
struct imx_option_t opt;
memset(&opt, 0, sizeof(opt));
opt.debug = debug;
opt.output = type;
opt.fw_variant = variant;
opt.force_version = force_version;
opt.model = model;
enum imx_error_t err = mkimxboot(infile, bootfile, outfile, opt);
printf("Result: %d (%s)\n", err, imx_error_to_string(err));
return 0;
}

246
utils/mkimxboot/md5.c Normal file
View file

@ -0,0 +1,246 @@
/*
* 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) (b)[(i) ] ) \
| ( (uint32) (b)[(i) + 1] << 8 ) \
| ( (uint32) (b)[(i) + 2] << 16 ) \
| ( (uint32) (b)[(i) + 3] << 24 ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) ); \
(b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 3] = (uint8) ( (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;
}
void md5_process( md5_context *ctx, uint8 data[64] )
{
uint32 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 *input, uint32 length )
{
uint32 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 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 digest[16] )
{
uint32 last, padn;
uint32 high, low;
uint8 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 );
}

25
utils/mkimxboot/md5.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef _MD5_H
#define _MD5_H
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
typedef struct
{
uint32 total[2];
uint32 state[4];
uint8 buffer[64];
}
md5_context;
void md5_starts( md5_context *ctx );
void md5_update( md5_context *ctx, uint8 *input, uint32 length );
void md5_finish( md5_context *ctx, uint8 digest[16] );
#endif /* md5.h */

1123
utils/mkimxboot/mkimxboot.c Normal file

File diff suppressed because it is too large Load diff

116
utils/mkimxboot/mkimxboot.h Normal file
View file

@ -0,0 +1,116 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Amaury Pouly
*
* 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 MKIMXBOOT_H
#define MKIMXBOOT_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
enum imx_error_t
{
IMX_SUCCESS = 0,
IMX_ERROR = -1,
IMX_OPEN_ERROR = -2,
IMX_READ_ERROR = -3,
IMX_NO_MATCH = -4,
IMX_BOOT_INVALID = -5,
IMX_BOOT_MISMATCH = -6,
IMX_BOOT_CHECKSUM_ERROR = -7,
IMX_DONT_KNOW_HOW_TO_PATCH = -8,
IMX_VARIANT_MISMATCH = -9,
IMX_WRITE_ERROR = -10,
IMX_FIRST_SB_ERROR = -11,
IMX_MODEL_MISMATCH = -12,
};
enum imx_output_type_t
{
IMX_DUALBOOT = 0,
IMX_RECOVERY,
IMX_SINGLEBOOT,
IMX_CHARGE,
IMX_ORIG_FW,
};
/* Supported models */
enum imx_model_t
{
MODEL_UNKNOWN = 0,
MODEL_FUZEPLUS,
MODEL_ZENXFI2,
MODEL_ZENXFI3,
MODEL_ZENXFISTYLE,
MODEL_ZENSTYLE, /* Style 100 and Style 300 */
MODEL_NWZE370,
MODEL_NWZE360,
/* Last */
MODEL_COUNT
};
/* Supported firmware variants */
enum imx_firmware_variant_t
{
VARIANT_DEFAULT = 0,
/* For the Creative ZEN X-Fi2 */
VARIANT_ZENXFI2_NAND,
VARIANT_ZENXFI2_SD,
VARIANT_ZENXFI2_RECOVERY,
/* For the Creative X-Fi Style */
VARIANT_ZENXFISTYLE_RECOVERY,
/* For the Creative Zen Style 100/300 */
VARIANT_ZENSTYLE_RECOVERY,
/* Last */
VARIANT_COUNT
};
struct imx_option_t
{
bool debug;
enum imx_model_t model;
enum imx_output_type_t output;
enum imx_firmware_variant_t fw_variant;
const char *force_version; // set to NULL to ignore
};
/* Print internal information to stdout about device database */
void dump_imx_dev_info(const char *prefix);
/* Build a SB image from an input firmware and a bootloader, input firmware
* can either be a firmware update or another SB file produced by this tool */
enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
const char *outfile, struct imx_option_t opt);
/* Compute MD5 sum of an entire file */
enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16]);
/* Compute "soft" MD5 sum of a SB file */
enum imx_error_t compute_soft_md5sum(const char *file, uint8_t soft_md5sum[16]);
/* Translate error */
const char *imx_error_to_string(enum imx_error_t err);
#ifdef __cplusplus
}
#endif
#endif

23
utils/mkmpioboot/Makefile Normal file
View file

@ -0,0 +1,23 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
TARGET_DIR ?= $(shell pwd)/
# We use the UCL code available in the Rockbox tools/ directory
CFLAGS += -I../../tools/ucl/include -Wall
OUTPUT = mkmpioboot
# inputs
LIBSOURCES = mkmpioboot.c
SOURCES = main.c
EXTRADEPS = $(LIBUCL)
include ../libtools.make
# explicit dependencies
$(OBJDIR)mkmpioboot.o: mkmpioboot.c mkmpioboot.h

55
utils/mkmpioboot/main.c Normal file
View file

@ -0,0 +1,55 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:$
*
* Copyright (C) 2010 by Marcin Bukat
*
* code taken mostly from mkboot.c
* Copyright (C) 2005 by Linus Nielsen Feltzing
*
* 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 <stdio.h>
#include <stdlib.h>
#include "mkmpioboot.h"
static void usage(void)
{
printf("usage: mkmpioboot <firmware file> <boot file> <output file>\n");
exit(1);
}
int main(int argc, char *argv[])
{
char *infile, *bootfile, *outfile;
int origin = 0xe0000; /* MPIO HD200 bootloader address */
fprintf(stderr,
"mkmpioboot Version " VERSION "\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"\n");
if(argc < 3) {
usage();
}
infile = argv[1];
bootfile = argv[2];
outfile = argv[3];
return mkmpioboot(infile, bootfile, outfile, origin);
}

View file

@ -0,0 +1,243 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:$
*
* Copyright (C) 2010 by Marcin Bukat
*
* code taken mostly from mkboot.c
* Copyright (C) 2005 by Linus Nielsen Feltzing
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mkmpioboot.h"
#define OF_FIRMWARE_LEN 0x100000 /* size of the OF file */
#define MPIO_STRING_OFFSET 0xfffe0 /* offset of the version string in OF */
#define BOOTLOADER_MAX_SIZE 0x1f800 /* free space size */
struct mpio_model {
/* Descriptive name of this model */
const char* model_name;
/* Model name used in the Rockbox header in ".mpio" files - these match the
-add parameter to the "scramble" tool */
const char* rb_model_name;
/* Model number used to initialise the checksum in the Rockbox header in
".mpio" files - these are the same as MODEL_NUMBER in config-target.h */
const int rb_model_num;
/* Strings which indentifies OF version */
const char* of_model_string;
};
static const struct mpio_model mpio_models[] = {
[MODEL_HD200] =
{ "MPIO HD200", "hd20", 69, "HD200 HDD Audio Ver113005" },
[MODEL_HD300] =
{ "MPIO HD300", "hd30", 70, "HD300 HDD Audio Ver113006" },
};
/* MPIO HD200 and HD300 firmware is plain binary image
* 4 bytes of initial SP (loaded on reset)
* 4 bytes of initial PC (loaded on reset)
* binary image with entry point 0x00000008
*
* We put our bootloader code at 0x000e0000
* and patch reset vector to jump directly
* into our code on reset
*/
static unsigned char image[OF_FIRMWARE_LEN];
static unsigned int get_uint32be(unsigned char* p)
{
return ((p[0] << 24) | (p[1] << 16) | (p[2]<<8) | p[3]);
}
static long checksum(unsigned char* buf, int model, unsigned long length)
{
unsigned long chksum = model;
unsigned long i;
if(buf == NULL)
return -1;
for (i = 0; i < length; i++)
{
chksum += *buf++;
}
return chksum;
}
int mkmpioboot(const char* infile, const char* bootfile, const char* outfile, int origin)
{
FILE *f;
int i;
int len;
int model_index;
unsigned long file_checksum;
unsigned char header[8];
memset(image, 0xff, sizeof(image));
/* First, read the mpio original firmware into the image */
f = fopen(infile, "rb");
if(!f)
{
fprintf(stderr, "[ERR] Can not open %s file for reading\n", infile);
return -1;
}
i = fread(image, 1, OF_FIRMWARE_LEN, f);
if(i < OF_FIRMWARE_LEN)
{
fprintf(stderr, "[ERR] %s file read error\n", infile);
fclose(f);
return -2;
}
fclose(f);
/* Now check if we have OF file loaded based on presence
* of the version string in firmware
*/
for(model_index = 0; model_index < NUM_MODELS; model_index++)
if (strcmp(mpio_models[model_index].of_model_string,
(char*)(image + MPIO_STRING_OFFSET)) == 0)
break;
if(model_index == NUM_MODELS)
{
fprintf(stderr, "[ERR] Unknown MPIO original firmware version\n");
return -3;
}
fprintf(stderr, "[INFO] Loading original firmware file for %s\n",
mpio_models[model_index].model_name);
/* Now, read the boot loader into the image */
f = fopen(bootfile, "rb");
if(!f)
{
fprintf(stderr, "[ERR] Can not open %s file for reading\n", bootfile);
return -4;
}
fprintf(stderr, "[INFO] Loading Rockbox bootloader file\n");
/* get bootloader size
* excluding header
*/
fseek(f, 0, SEEK_END);
len = ftell(f) - 8;
if (len > BOOTLOADER_MAX_SIZE)
{
fprintf(stderr, "[ERR] Bootloader doesn't fit in firmware file.\n");
fprintf(stderr, "[ERR] This bootloader is %d bytes long\n", len);
fprintf(stderr, "[ERR] and maximum allowed size is %d bytes\n",
BOOTLOADER_MAX_SIZE);
return -5;
}
/* Now check if the place we want to put
* our bootloader is free
*/
for(i=0;i<len;i++)
{
if (image[origin+i] != 0)
{
fprintf(stderr, "[ERR] Place for bootloader in OF file not empty\n");
return -6;
}
}
fseek(f, 0, SEEK_SET);
/* get bootloader header*/
fread(header,1,8,f);
if ( memcmp(header + 4, mpio_models[model_index].rb_model_name, 4) != 0 )
{
fprintf(stderr, "[ERR] Original firmware and rockbox bootloader mismatch!\n");
fprintf(stderr, "[ERR] Double check that you have bootloader for %s\n",
mpio_models[model_index].model_name);
return -7;
}
/* omit header */
fseek(f, 8, SEEK_SET);
i = fread(image + origin, 1, len, f);
if(i < len)
{
fprintf(stderr, "[ERR] %s file read error\n", bootfile);
fclose(f);
return -8;
}
fclose(f);
/* calculate checksum and compare with data
* from header
*/
file_checksum = checksum(image + origin, mpio_models[model_index].rb_model_num, len);
if ( file_checksum != get_uint32be(header) )
{
fprintf(stderr,"[ERR] Bootloader checksum error\n");
return -9;
}
f = fopen(outfile, "wb");
if(!f)
{
fprintf(stderr, "[ERR] Can not open %s file for writing\n" ,outfile);
return -10;
}
fprintf(stderr, "[INFO] Patching reset vector\n");
/* Patch the stack pointer address */
image[0] = image[origin + 0];
image[1] = image[origin + 1];
image[2] = image[origin + 2];
image[3] = image[origin + 3];
/* Patch the reset vector to start the boot loader */
image[4] = image[origin + 4];
image[5] = image[origin + 5];
image[6] = image[origin + 6];
image[7] = image[origin + 7];
i = fwrite(image, 1, OF_FIRMWARE_LEN, f);
if(i < OF_FIRMWARE_LEN)
{
fprintf(stderr,"[ERR] %s file write error\n", outfile);
fclose(f);
return -11;
}
fprintf(stderr,"[INFO] Wrote 0x%x bytes in %s\n", OF_FIRMWARE_LEN, outfile);
fprintf(stderr,"[INFO] Patching succeeded!\n");
fclose(f);
return 0;
}

View file

@ -0,0 +1,46 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:$
*
* Copyright (C) 2010 by Marcin Bukat
* code based mainly on mkboot.h
* Copyright (C) 2008 by Dominik Riebeling
*
* 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 MKMPIOBOOT_H
#define MKMPIOBOOT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Supported models */
enum {
MODEL_UNKNOWN = -1,
MODEL_HD200 = 0,
MODEL_HD300,
NUM_MODELS
};
int mkmpioboot(const char* infile, const char* bootfile, const char* outfile, int origin);
#ifdef __cplusplus
}
#endif
#endif

52
utils/mknwzboot/Makefile Normal file
View file

@ -0,0 +1,52 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# We use the SB code available in the Rockbox utils/sbtools directory
UPGTOOLS_DIR=../../utils/nwztools/upgtools/
CFLAGS += -I$(UPGTOOLS_DIR) -Wall
# std=gnu99 is required by MinGW on Windows (c99 is sufficient for Linux / MXE)
CFLAGS += -std=gnu99 -g -O3
# dependencies
# FIXME make it work for windows and maybe embed crypto++
# Location to pkg-config binary.
PKGCONFIG := pkg-config
# Distros could use different names for the crypto library. We try a list
# of candidate names, only one of them should be the valid one.
LIBCRYPTO_NAMES = libcryptopp libcrypto++ cryptopp crypto++
$(foreach l,$(LIBCRYPTO_NAMES),\
$(eval LDOPTS += $(shell $(PKGCONFIG) --silence-errors --libs $(l))))
$(foreach l,$(LIBCRYPTO_NAMES),\
$(eval CFLAGS += $(shell $(PKGCONFIG) --silence-errors --cflags $(l))))
$(foreach l,$(LIBCRYPTO_NAMES),\
$(eval CXXFLAGS += $(shell $(PKGCONFIG) --silence-errors --cflags $(l))))
LDOPTS += -lpthread
OUTPUT = mknwzboot
# inputs for lib
UPGTOOLS_SOURCES = misc.c upg.c fwp.c mg.cpp md5.cpp
LIBSOURCES := mknwzboot.c install_script.c uninstall_script.c \
$(addprefix $(UPGTOOLS_DIR),$(UPGTOOLS_SOURCES))
# inputs for binary only
SOURCES := $(LIBSOURCES) main.c
# dependencies for binary
EXTRADEPS :=
include ../libtools.make
install_script.c install_script.h: install_script.sh $(BIN2C)
$(BIN2C) install_script.sh install_script
uninstall_script.c uninstall_script.h: uninstall_script.sh $(BIN2C)
$(BIN2C) uninstall_script.sh uninstall_script
# explicit dependencies on install_script.{c,h} and mknwzboot.h
$(OBJDIR)mknwzboot.o: install_script.h install_script.c uninstall_script.h uninstall_script.c mknwzboot.h
$(OBJDIR)main.o: main.c mknwzboot.h

View file

@ -0,0 +1,157 @@
#!/bin/sh
# NOTE: busybox is using ash, a very posix and very pedantic shell, make sure
# you test your scripts with
# busybox sh -n <script>
# and if you really, really don't want to download busybox to try it, then go
# ahead and brick your device
# The updater script on the NWZ has a major bug/feature:
# it does NOT clear the update flag if the update scrit fails
# thus causing a update/reboot loop and a bricked device
# always clear to make sure we don't end up being screwed
nvpflag fup 0xFFFFFFFF
# go to /tmp
cd /tmp
# get content partition path
CONTENTS="/contents"
CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
# print a message to the screen and also on the standard output
# lcdprint x,y msg
lcdprint ()
{
echo $2
lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2"
}
# clear screen
lcdmsg -c ""
lcdprint 0,3 "Contents partition:\n$CONTENTS_PART"
# We need to remount the contents partition in read-write mode be able to
# write something on it
lcdprint 0,6 "Remount $CONTENTS rw"
mount -o remount,rw $CONTENTS_PART $CONTENTS
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: remount failed"
sleep 3
exit 0
fi
# redirect all output to a log file
exec > "$CONTENTS/install_dualboot_log.txt" 2>&1
# import constants
. /install_script/constant.txt
_UPDATE_FN_=`nvpstr ufn`
ROOTFS_TMP_DIR=/tmp/rootfs
SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
# mount root partition
lcdprint 0,7 "Mount root filesystem"
mkdir $ROOTFS_TMP_DIR
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: mkdir failed"
sleep 3
exit 0
fi
# If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and
# then ext2.
# NOTE some platforms probably use an mtd and this might need some fixing
if [ -e /usr/local/bin/icx_mount.ext4 ]; then
/usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
else
false
fi
if [ "$?" != 0 ]; then
mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
fi
if [ "$?" != 0 ]; then
mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
fi
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: mount failed"
sleep 3
exit 0
fi
# rename the previous main application unless there is already a copy
lcdprint 0,8 "Backup OF"
if [ ! -e $SPIDERAPP_PATH.of ]; then
mv $SPIDERAPP_PATH $SPIDERAPP_PATH.of
fi
# extract our payload: the second file in the upgrade is a tar file
# the files in the archive have paths of the form ./absolute/path and we extract
# it at the rootfs mount it, so it can create/overwrite any file
#
# we need a small trick here: we want to pipe directly the output of the decryption
# tool to tar, to avoid using space in /tmp/ or on the user partition
lcdprint 0,9 "Install rockbox"
FIFO_FILE=/tmp/rb.fifo
mkfifo $FIFO_FILE
if [ "$?" != 0 ]; then
umount "$ROOTFS_TMP_DIR"
lcdprint 0,15 "ERROR: cannot create fifo"
sleep 3
exit 0
fi
fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $FIFO_FILE &
#tar -tvf $FIFO_FILE
tar -C $ROOTFS_TMP_DIR -xvf $FIFO_FILE
if [ "$?" != 0 ]; then
umount "$ROOTFS_TMP_DIR"
lcdprint 0,15 "ERROR: extraction failed"
sleep 3
exit 0
fi
# wait for fwpchk
wait
if [ "$?" != 0 ]; then
umount "$ROOTFS_TMP_DIR"
lcdprint 0,15 "ERROR: no file to extract"
sleep 3
exit 0
fi
# create a symlink from /.rockbox to /contents/.rockbox (see dualboot code
# for why)
lcdprint 0,10 "Create rockbox symlink"
rm -f "$ROOTFS_TMP_DIR/.rockbox"
ln -s "$CONTENTS/.rockbox" "$ROOTFS_TMP_DIR/.rockbox"
if [ "$?" != 0 ]; then
umount "$ROOTFS_TMP_DIR"
lcdprint 0,15 "ERROR: cannot create rockbox symlink"
sleep 3
exit 0
fi
# unmount root partition
lcdprint 0,11 "Unmount root filesystem"
sync
if [ "$?" != 0 ]; then
umount "$ROOTFS_TMP_DIR"
lcdprint 0,15 "ERROR: sync failed"
sleep 3
exit 0
fi
umount $ROOTFS_TMP_DIR
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: umount failed"
sleep 3
exit 0
fi
# Success screen
lcdprint 0,15 "Rebooting in 3 seconds."
sleep 3
sync
echo "Installation successful"
# finish
exit 0

126
utils/mknwzboot/main.c Normal file
View file

@ -0,0 +1,126 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Amaury Pouly
*
* 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 <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mknwzboot.h"
static void usage(void)
{
printf("Usage: mknwzboot [options | file]...\n");
printf("Options:\n");
printf(" -h/--help Display this message\n");
printf(" -o <file> Set output file\n");
printf(" -b <file> Set boot file\n");
printf(" -d/--debug Enable debug output\n");
printf(" -x Dump device informations\n");
printf(" -u Create uninstall update\n");
printf(" -m <model> Specify model\n");
exit(1);
}
int main(int argc, char *argv[])
{
char *outfile = NULL;
char *bootfile = NULL;
bool debug = false;
bool install = true;
const char *model = NULL;
if(argc == 1)
usage();
while(1)
{
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"out-file", required_argument, 0, 'o'},
{"boot-file", required_argument, 0, 'b'},
{"debug", no_argument, 0, 'd'},
{"dev-info", no_argument, 0, 'x'},
{"uninstall", no_argument, 0, 'u'},
{"model", required_argument, 0, 'm'},
{0, 0, 0, 0}
};
int c = getopt_long(argc, argv, "ho:b:dxum:", long_options, NULL);
if(c == -1)
break;
switch(c)
{
case 'd':
debug = true;
break;
case 'h':
usage();
break;
case 'o':
outfile = optarg;
break;
case 'b':
bootfile = optarg;
break;
case 'x':
dump_nwz_dev_info("");
return 0;
case 'u':
install = false;
break;
case 'm':
model = optarg;
break;
default:
abort();
}
}
if(!outfile)
{
printf("You must specify an output file\n");
return 1;
}
if(install && !bootfile)
{
printf("You must specify a boot file for installation\n");
return 1;
}
if(!install && !model)
{
printf("You must provide a model for uninstallation\n");
return 1;
}
if(optind != argc)
{
printf("Extra arguments on command line\n");
return 1;
}
int err;
if(install)
err = mknwzboot(bootfile, outfile, debug);
else
err = mknwzboot_uninst(model, outfile, debug);
printf("Result: %d\n", err);
return err;
}

294
utils/mknwzboot/mknwzboot.c Normal file
View file

@ -0,0 +1,294 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Amaury Pouly
*
* 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "mknwzboot.h"
#include "upg.h"
#include "install_script.h"
#include "uninstall_script.h"
struct nwz_model_desc_t
{
/* Descriptive name of this model */
const char *model_name;
/* Model name used in the Rockbox header in ".sansa" files - these match the
-add parameter to the "scramble" tool */
const char *rb_model_name;
/* Model number used to initialise the checksum in the Rockbox header in
".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
const int rb_model_num;
/* Codename used in upgtool */
const char *codename;
};
static const struct nwz_model_desc_t nwz_models[] =
{
{ "Sony NWZ-E350 Series", "e350", 109, "nwz-e350" },
{ "Sony NWZ-E450 Series", "e450", 100, "nwz-e450" },
{ "Sony NWZ-E460 Series", "e460", 101, "nwz-e460" },
{ "Sony NWZ-E470 Series", "e470", 103, "nwz-e470" },
{ "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" },
{ "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" },
{ "Sony NW-A20 Series", "a20", 106, "nw-a20" },
{ "Sony NWZ-A860 Series", "a860", 107, "nwz-a860" },
{ "Sony NWZ-S750 Series", "s750", 108, "nwz-s750" },
};
#define NR_NWZ_MODELS (sizeof(nwz_models) / sizeof(nwz_models[0]))
void dump_nwz_dev_info(const char *prefix)
{
printf("%smknwzboot models:\n", prefix);
for(int i = 0; i < NR_NWZ_MODELS; i++)
{
printf("%s %s: rb_model=%s rb_num=%d codename=%s\n", prefix,
nwz_models[i].model_name, nwz_models[i].rb_model_name,
nwz_models[i].rb_model_num, nwz_models[i].codename);
}
}
/* read a file to a buffer */
static void *read_file(const char *file, size_t *size)
{
FILE *f = fopen(file, "rb");
if(f == NULL)
{
printf("[ERR] Cannot open file '%s' for reading: %m\n", file);
return NULL;
}
fseek(f, 0, SEEK_END);
*size = ftell(f);
fseek(f, 0, SEEK_SET);
void *buffer = malloc(*size);
if(fread(buffer, *size, 1, f) != 1)
{
free(buffer);
fclose(f);
printf("[ERR] Cannot read file '%s': %m\n", file);
return NULL;
}
fclose(f);
return buffer;
}
/* write a file from a buffer */
static bool write_file(const char *file, void *buffer, size_t size)
{
FILE *f = fopen(file, "wb");
if(f == NULL)
{
printf("[ERR] Cannot open file '%s' for writing: %m\n", file);
return false;
}
if(fwrite(buffer, size, 1, f) != 1)
{
fclose(f);
printf("[ERR] Cannot write file '%s': %m\n", file);
return false;
}
fclose(f);
return true;
}
static unsigned int be2int(unsigned char* buf)
{
return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
}
static int find_model(uint8_t *boot, size_t boot_size)
{
if(boot_size < 8)
{
printf("[ERR] Boot file is too small to be valid\n");
return -1;
}
/* find model by comparing magic scramble value */
int model = 0;
for(; model < NR_NWZ_MODELS; model++)
if(memcmp(boot + 4, nwz_models[model].rb_model_name, 4) == 0)
break;
if(model == NR_NWZ_MODELS)
{
printf("[ERR] This player is not supported: %.4s\n", boot + 4);
return -1;
}
printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
/* verify checksum */
uint32_t sum = nwz_models[model].rb_model_num;
for(int i = 8; i < boot_size; i++)
sum += boot[i];
if(sum != be2int(boot))
{
printf("[ERR] Checksum mismatch\n");
return -1;
}
return model;
}
static int find_model2(const char *model_str)
{
/* since it can be confusing for the user, we accept both rbmodel and codename */
/* find model by comparing magic scramble value */
int model = 0;
for(; model < NR_NWZ_MODELS; model++)
if(strcmp(nwz_models[model].rb_model_name, model_str) == 0 ||
strcmp(nwz_models[model].codename, model_str) == 0)
break;
if(model == NR_NWZ_MODELS)
{
printf("[ERR] Unknown model: %s\n", model_str);
return -1;
}
printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name);
return model;
}
static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE])
{
const char *codename = nwz_models[model].codename;
for(int i = 0; g_model_list[i].model; i++)
if(strcmp(g_model_list[i].model, codename) == 0)
{
if(decrypt_keysig(g_model_list[i].kas, key, sig) == 0)
return true;
printf("[ERR] Cannot decrypt kas '%s'\n", g_model_list[i].kas);
return false;
}
printf("[ERR] Codename '%s' matches to entry in upg database\n", codename);
return false;
}
void nwz_printf(void *u, bool err, color_t c, const char *f, ...)
{
(void)err;
(void)c;
bool *debug = u;
va_list args;
va_start(args, f);
if(err || *debug)
vprintf(f, args);
va_end(args);
}
static void *memdup(void *data, size_t size)
{
void *buf = malloc(size);
memcpy(buf, data, size);
return buf;
}
int mknwzboot(const char *bootfile, const char *outfile, bool debug)
{
size_t boot_size;
uint8_t *boot = read_file(bootfile, &boot_size);
if(boot == NULL)
{
printf("[ERR] Cannot open boot file\n");
return 1;
}
/* check that it is a valid scrambled file */
int model = find_model(boot, boot_size);
if(model < 0)
{
free(boot);
printf("[ERR] Invalid boot file\n");
return 2;
}
/* find keys */
char key[NWZ_KEY_SIZE];
char sig[NWZ_SIG_SIZE];
if(!get_model_keysig(model, key, sig))
{
printf("[ERR][INTERNAL] Cannot get keys for model\n");
return 3;
}
/* create the upg file */
struct upg_file_t *upg = upg_new();
/* first file is the install script: we have to copy data because upg_free()
* will free it */
upg_append(upg, memdup(install_script, LEN_install_script), LEN_install_script);
/* second file is the bootloader content (expected to be a tar file): we have
* to copy data because upg_free() will free it */
upg_append(upg, memdup(boot + 8, boot_size - 8), boot_size - 8);
free(boot);
/* write file to buffer */
size_t upg_size;
void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
upg_free(upg);
if(upg_buf == NULL)
{
printf("[ERR] Cannot create UPG file\n");
return 4;
}
if(!write_file(outfile, upg_buf, upg_size))
{
free(upg_buf);
printf("[ERR] Cannpt write UPG file\n");
return 5;
}
free(upg_buf);
return 0;
}
int mknwzboot_uninst(const char *model_string, const char *outfile, bool debug)
{
/* check that it is a valid scrambled file */
int model = find_model2(model_string);
if(model < 0)
{
printf("[ERR] Invalid model\n");
return 2;
}
/* find keys */
char key[NWZ_KEY_SIZE];
char sig[NWZ_SIG_SIZE];
if(!get_model_keysig(model, key, sig))
{
printf("[ERR][INTERNAL] Cannot get keys for model\n");
return 3;
}
/* create the upg file */
struct upg_file_t *upg = upg_new();
/* first file is the uninstall script: we have to copy data because upg_free()
* will free it */
upg_append(upg, memdup(uninstall_script, LEN_uninstall_script), LEN_uninstall_script);
/* write file to buffer */
size_t upg_size;
void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf);
upg_free(upg);
if(upg_buf == NULL)
{
printf("[ERR] Cannot create UPG file\n");
return 4;
}
if(!write_file(outfile, upg_buf, upg_size))
{
free(upg_buf);
printf("[ERR] Cannpt write UPG file\n");
return 5;
}
free(upg_buf);
return 0;
}

View file

@ -0,0 +1,42 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Amaury Pouly
*
* 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 MKIMXBOOT_H
#define MKIMXBOOT_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
void dump_nwz_dev_info(const char *prefix);
/* return 0 on success */
int mknwzboot(const char *bootfile, const char *outfile, bool debug);
int mknwzboot_uninst(const char *model, const char *outfile, bool debug);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,122 @@
#!/bin/sh
# NOTE: busybox is using ash, a very posix and very pedantic shell, make sure
# you test your scripts with
# busybox sh -n <script>
# and if you really, really don't want to download busybox to try it, then go
# ahead and brick your device
# The updater script on the NWZ has a major bug/feature:
# it does NOT clear the update flag if the update scrit fails
# thus causing a update/reboot loop and a bricked device
# always clear to make sure we don't end up being screwed
nvpflag fup 0xFFFFFFFF
# go to /tmp
cd /tmp
# get content partition path
CONTENTS="/contents"
CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'`
# print a message to the screen and also on the standard output
# lcdprint x,y msg
lcdprint ()
{
echo $2
lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2"
}
# clear screen
lcdmsg -c ""
lcdprint 0,3 "Contents partition:\n$CONTENTS_PART"
# We need to remount the contents partition in read-write mode be able to
# write something on it
lcdprint 0,6 "Remount $CONTENTS rw"
mount -o remount,rw $CONTENTS_PART $CONTENTS
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: remount failed"
sleep 3
exit 0
fi
# redirect all output to a log file
exec > "$CONTENTS/uninstall_dualboot_log.txt" 2>&1
# import constants
. /install_script/constant.txt
ROOTFS_TMP_DIR=/tmp/rootfs
SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp
# mount root partition
lcdprint 0,7 "Mount root filesystem"
mkdir $ROOTFS_TMP_DIR
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: mkdir failed"
sleep 3
exit 0
fi
# If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and
# then ext2.
# NOTE some platforms probably use an mtd and this might need some fixing
if [ -e /usr/local/bin/icx_mount.ext4 ]; then
/usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
else
false
fi
if [ "$?" != 0 ]; then
mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
fi
if [ "$?" != 0 ]; then
mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR
fi
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: mount failed"
sleep 3
exit 0
fi
# the installer renames the OF to $SPIDERAPP_PATH.of so if it does not exists
# print an error
lcdprint 0,8 "Restore OF"
if [ ! -e $SPIDERAPP_PATH.of ]; then
lcdprint 0,15 "ERROR: cannot find OF"
lcdprint 0,16 "ERROR: is Rockbox installed?"
sleep 3
exit 0
fi
# restore the OF
mv $SPIDERAPP_PATH.of $SPIDERAPP_PATH
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: restore failed"
sleep 3
exit 0
fi
# unmount root partition
lcdprint 0,11 "Unmount root filesystem"
sync
if [ "$?" != 0 ]; then
umount "$ROOTFS_TMP_DIR"
lcdprint 0,15 "ERROR: sync failed"
sleep 3
exit 0
fi
umount $ROOTFS_TMP_DIR
if [ "$?" != 0 ]; then
lcdprint 0,15 "ERROR: umount failed"
sleep 3
exit 0
fi
# Success screen
lcdprint 0,15 "Rebooting in 3 seconds."
sleep 3
sync
echo "Uninstallation successful"
# finish
exit 0

39
utils/mkrk27boot/Makefile Normal file
View file

@ -0,0 +1,39 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
FIRMWARE = ../../firmware/
DRIVERS = $(FIRMWARE)drivers/
EXPORT = $(FIRMWARE)export/
BUILDDATE=$(shell date -u +'-DYEAR=%Y -DMONTH=%m -DDAY=%d')
INCLUDE = -I$(EXPORT) -I$(FIRMWARE)include -I$(FIRMWARE)target/hosted -I$(FIRMWARE)target/hosted/sdl
DEFINES = -DTEST_FAT -DDISK_WRITE -DHAVE_FAT16SUPPORT -D__PCTOOL__
CFLAGS = -Wall -g -std=gnu99 -Wno-pointer-sign $(DEFINES) -I. $(INCLUDE)
SIM_FLAGS = $(CFLAGS) $(BUILDDATE) -I$(FIRMWARE)/libc/include
OUTPUT = mkrk27boot
# inputs
LIBSOURCES := $(DRIVERS)fat.c $(FIRMWARE)libc/ctype.c $(FIRMWARE)libc/strtok.c \
$(FIRMWARE)libc/errno.c $(FIRMWARE)common/strlcpy.c $(FIRMWARE)common/unicode.c \
$(FIRMWARE)common/file.c $(FIRMWARE)common/dir_uncached.c $(FIRMWARE)common/disk.c ata-sim.c mkrk27boot.c
SOURCES := $(LIBSOURCES) main.c
include ../libtools.make
SIMOBJS = $(addprefix $(OBJDIR),fat.o ctype.o strtok.o errno.o disk.o dir_uncached.o file.o unicode.o strlcpy.o)
$(SIMOBJS):
@echo CC $<
$(SILENT)mkdir -p $(dir $@)
$(SILENT)$(CROSS)$(CC) $(SIM_FLAGS) -c -o $@ $<

122
utils/mkrk27boot/ata-sim.c Normal file
View file

@ -0,0 +1,122 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id:$
*
* Copyright (C) 2012 by Andrew Ryabinin
*
* major portion of code is taken from firmware/test/fat/ata-sim.c
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "debug.h"
#include "dir.h"
#define BLOCK_SIZE 512
static FILE* file;
extern char *img_filename;
void mutex_init(struct mutex* l) {}
void mutex_lock(struct mutex* l) {}
void mutex_unlock(struct mutex* l) {}
void panicf( char *fmt, ...) {
va_list ap;
va_start( ap, fmt );
fprintf(stderr,"***PANIC*** ");
vfprintf(stderr, fmt, ap );
va_end( ap );
exit(1);
}
void debugf(const char *fmt, ...) {
va_list ap;
va_start( ap, fmt );
fprintf(stderr,"DEBUGF: ");
vfprintf( stderr, fmt, ap );
va_end( ap );
}
void ldebugf(const char* file, int line, const char *fmt, ...) {
va_list ap;
va_start( ap, fmt );
fprintf( stderr, "%s:%d ", file, line );
vfprintf( stderr, fmt, ap );
va_end( ap );
}
int storage_read_sectors(unsigned long start, int count, void* buf)
{
if ( count > 1 )
DEBUGF("[Reading %d blocks: 0x%lx to 0x%lx]\n",
count, start, start+count-1);
else
DEBUGF("[Reading block 0x%lx]\n", start);
if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) {
perror("fseek");
return -1;
}
if(!fread(buf,BLOCK_SIZE,count,file)) {
DEBUGF("ata_write_sectors(0x%lx, 0x%x, %p)\n", start, count, buf );
perror("fread");
panicf("Disk error\n");
}
return 0;
}
int storage_write_sectors(unsigned long start, int count, void* buf)
{
if ( count > 1 )
DEBUGF("[Writing %d blocks: 0x%lx to 0x%lx]\n",
count, start, start+count-1);
else
DEBUGF("[Writing block 0x%lx]\n", start);
if (start == 0)
panicf("Writing on sector 0!\n");
if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) {
perror("fseek");
return -1;
}
if(!fwrite(buf,BLOCK_SIZE,count,file)) {
DEBUGF("ata_write_sectors(0x%lx, 0x%x, %p)\n", start, count, buf );
perror("fwrite");
panicf("Disk error\n");
}
return 0;
}
int ata_init(void)
{
file=fopen(img_filename,"rb+");
if(!file) {
fprintf(stderr, "read_disk() - Could not find \"%s\"\n",img_filename);
return -1;
}
return 0;
}
void ata_exit(void)
{
fclose(file);
}

Some files were not shown because too many files have changed in this diff Show more