diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2017-02-23 11:33:19 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2017-09-05 21:42:12 +0200 |
commit | 1d121e8c082fe67757cf0d4df7b9e6ca1e26f755 (patch) | |
tree | 1c93842d99bb8e4a5f3ed5bca38c05e7f17894fa /rbutil | |
parent | 142f80f07d96305f1618c99c28c13319b1b279e6 (diff) | |
download | rockbox-1d121e8c082fe67757cf0d4df7b9e6ca1e26f755.tar.gz rockbox-1d121e8c082fe67757cf0d4df7b9e6ca1e26f755.tar.bz2 rockbox-1d121e8c082fe67757cf0d4df7b9e6ca1e26f755.zip |
Initial commit for the Sony NWZ linux port
SUPPORTED SERIES:
- NWZ-E450
- NWZ-E460
- NWZ-E470
- NWZ-E580
- NWZ-A10
NOTES:
- bootloader makefile convert an extra font to be installed alongside the bootloader
since sysfont is way too small
- the toolsicon bitmap comes from the Oxygen iconset
- touchscreen driver is untested
TODO:
- implement audio routing driver (pcm is handled by pcm-alsa)
- fix playback: it crashes on illegal instruction in DEBUG builds
- find out why the browser starts at / instead of /contents
- implement radio support
- implement return to OF for usb handling
- calibrate battery curve (NB: of can report a battery level on a 0-5 scale but
probabl don't want to use that ?)
- implement simulator build (we need a nice image of the player)
- figure out if we can detect jack removal
POTENTIAL TODOS:
- try to build a usb serial gadget and gdbserver
Change-Id: Ic77d71e0651355d47cc4e423a40fb64a60c69a80
Diffstat (limited to 'rbutil')
-rw-r--r-- | rbutil/mknwzboot/Makefile | 35 | ||||
-rw-r--r-- | rbutil/mknwzboot/install_script.sh | 142 | ||||
-rw-r--r-- | rbutil/mknwzboot/main.c | 105 | ||||
-rw-r--r-- | rbutil/mknwzboot/mknwzboot.c | 230 | ||||
-rw-r--r-- | rbutil/mknwzboot/mknwzboot.h | 41 |
5 files changed, 553 insertions, 0 deletions
diff --git a/rbutil/mknwzboot/Makefile b/rbutil/mknwzboot/Makefile new file mode 100644 index 0000000000..9530ac369e --- /dev/null +++ b/rbutil/mknwzboot/Makefile @@ -0,0 +1,35 @@ +# __________ __ ___. +# 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++ +LDOPTS += `pkg-config --libs libcrypto++` + +OUTPUT = mknwzboot + +# inputs for lib +UPGTOOLS_SOURCES = misc.c upg.c fwp.c mg.cpp md5.cpp +LIBSOURCES := mknwzboot.c install_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 + +# explicit dependencies on install_script.{c,h} and mknwzboot.h +$(OBJDIR)mknwzboot.o: install_script.h install_script.c mknwzboot.h +$(OBJDIR)main.o: install_script.h install_script.c main.c mknwzboot.h diff --git a/rbutil/mknwzboot/install_script.sh b/rbutil/mknwzboot/install_script.sh new file mode 100644 index 0000000000..18296d257e --- /dev/null +++ b/rbutil/mknwzboot/install_script.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +# 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 }'` + +lcdmsg -c -f /usr/local/bin/font_08x12.bmp -l 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 +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw" +mount -o remount,rw $CONTENTS_PART $CONTENTS +if [ "$?" != 0 ]; then + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 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 +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Mount root filesystem" +mkdir $ROOTFS_TMP_DIR +if [ "$?" != 0 ]; then + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 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 + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mount failed" + sleep 3 + exit 0 +fi + +# rename the previous main application unless there is already a copy +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 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 +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Install rockbox" +FIFO_FILE=/tmp/rb.fifo +mkfifo $FIFO_FILE +if [ "$?" != 0 ]; then + umount "$ROOTFS_TMP_DIR" + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 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" + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: extraction failed" + sleep 3 + exit 0 +fi +# wait for fwpchk +wait +if [ "$?" != 0 ]; then + umount "$ROOTFS_TMP_DIR" + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 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) +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 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" + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot create rockbox symlink" + sleep 3 + exit 0 +fi + +# unmount root partition +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,11 "Unmount root filesystem" +sync +if [ "$?" != 0 ]; then + umount "$ROOTFS_TMP_DIR" + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: sync failed" + sleep 3 + exit 0 +fi + +umount $ROOTFS_TMP_DIR +if [ "$?" != 0 ]; then + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: umount failed" + sleep 3 + exit 0 +fi + +# Success screen +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds." +sleep 3 +sync + +echo "Installation successful" +# finish +exit 0 + diff --git a/rbutil/mknwzboot/main.c b/rbutil/mknwzboot/main.c new file mode 100644 index 0000000000..a36c24eaf5 --- /dev/null +++ b/rbutil/mknwzboot/main.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * __________ __ ___. + * 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"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + char *outfile = NULL; + char *bootfile = NULL; + bool debug = false; + + 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'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "ho:b:dx", 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(""); + break; + default: + abort(); + } + } + + if(!outfile) + { + printf("You must specify an output file\n"); + return 1; + } + if(!bootfile) + { + printf("You must specify a boot file\n"); + return 1; + } + if(optind != argc) + { + printf("Extra arguments on command line\n"); + return 1; + } + + int err = mknwzboot(bootfile, outfile, debug); + printf("Result: %d\n", err); + return err; +} diff --git a/rbutil/mknwzboot/mknwzboot.c b/rbutil/mknwzboot/mknwzboot.c new file mode 100644 index 0000000000..1fc105ae48 --- /dev/null +++ b/rbutil/mknwzboot/mknwzboot.c @@ -0,0 +1,230 @@ +/*************************************************************************** + * __________ __ ___. + * 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" + +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-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" }, +}; + +#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 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; +} diff --git a/rbutil/mknwzboot/mknwzboot.h b/rbutil/mknwzboot/mknwzboot.h new file mode 100644 index 0000000000..f46dd75d5c --- /dev/null +++ b/rbutil/mknwzboot/mknwzboot.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * __________ __ ___. + * 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); + +#ifdef __cplusplus +} +#endif +#endif + |