summaryrefslogtreecommitdiffstats
path: root/rbutil
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-02-23 11:33:19 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-09-05 21:42:12 +0200
commit1d121e8c082fe67757cf0d4df7b9e6ca1e26f755 (patch)
tree1c93842d99bb8e4a5f3ed5bca38c05e7f17894fa /rbutil
parent142f80f07d96305f1618c99c28c13319b1b279e6 (diff)
downloadrockbox-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/Makefile35
-rw-r--r--rbutil/mknwzboot/install_script.sh142
-rw-r--r--rbutil/mknwzboot/main.c105
-rw-r--r--rbutil/mknwzboot/mknwzboot.c230
-rw-r--r--rbutil/mknwzboot/mknwzboot.h41
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
+