diff --git a/utils/nwztools/plattools/Makefile b/utils/nwztools/plattools/Makefile index 8251afaf0a..f4e88cd778 100644 --- a/utils/nwztools/plattools/Makefile +++ b/utils/nwztools/plattools/Makefile @@ -7,7 +7,7 @@ INCLUDES=-I. LIB_FILES=nwz_lib.c nwz_lib_devlist.c TOOL_FILES=dest_tool.c test_adc.c test_adc.c test_bl.c test_display.c \ test_keys.c test_power.c test_ts.c -ALL_ELF=$(patsubst %.c,%.elf,$(TOOL_FILES)) all_tools.elf +ALL_ELF=$(patsubst %.c,%.elf,$(TOOL_FILES)) all_tools.elf dualboot.elf all: $(ALL_ELF) @@ -17,5 +17,8 @@ all: $(ALL_ELF) all_tools.elf: all_tools.c $(TOOL_FILES) $(LIB_FILES) $(CC) $(CFLAGS) -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^ +dualboot.elf: dualboot.c all_tools.c $(TOOL_FILES) $(LIB_FILES) + $(CC) $(CFLAGS) -DNWZ_DUALBOOT -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^ + clean: rm -rf $(ALL_ELF) diff --git a/utils/nwztools/plattools/dualboot.c b/utils/nwztools/plattools/dualboot.c new file mode 100644 index 0000000000..965fabed72 --- /dev/null +++ b/utils/nwztools/plattools/dualboot.c @@ -0,0 +1,181 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing + * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach + * + * 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 "nwz_lib.h" +#include "nwz_plattools.h" +#include + +/* Important Note: this bootloader is carefully written so that in case of + * error, the OF is run. This seems like the safest option since the OF is + * always there and might do magic things. */ + +bool boot_rockbox(void) +{ + /* get time */ + struct timeval deadline; + if(gettimeofday(&deadline, NULL) != 0) + { + nwz_lcdmsg(false, 0, 2, "Cannot get time"); + sleep(2); + return false; + } + /* open input device */ + int input_fd = nwz_key_open(); + if(input_fd < 0) + { + nwz_lcdmsg(false, 0, 2, "Cannot open input device"); + sleep(2); + return false; + } + deadline.tv_sec += 5; + /* wait for user action */ + bool boot_rb = false; + while(true) + { + /* get time */ + struct timeval cur_time; + if(gettimeofday(&cur_time, NULL) != 0) + { + nwz_lcdmsg(false, 0, 4, "Cannot get time"); + sleep(2); + break; + } + /* check timeout */ + if(cur_time.tv_sec > deadline.tv_sec) + break; + if(cur_time.tv_sec == deadline.tv_sec && cur_time.tv_usec >= deadline.tv_usec) + break; + /* print message */ + int sec_left = deadline.tv_sec - cur_time.tv_sec; + sec_left += (deadline.tv_usec - cur_time.tv_usec + 999999) / 1000000; /* round up */ + nwz_lcdmsgf(false, 0, 2, "Booting OF in %d seconds ", sec_left); + nwz_lcdmsg(false, 0, 3, "Press BACK to boot RB"); + /* wait for a key (1s) */ + int ret = nwz_key_wait_event(input_fd, 1000000); + if(ret != 1) + continue; + struct input_event evt; + if(nwz_key_read_event(input_fd, &evt) != 1) + continue; + if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt)) + { + boot_rb = true; + break; + } + } + nwz_key_close(input_fd); + return boot_rb; +} + +static char *boot_rb_argv[] = +{ + "lcdmsg", + "-c", + "-l", + "0,3", + "Hello from RB", + NULL +}; + +static void wait_key(void) +{ + int input_fd = nwz_key_open(); + /* display input state in a loop */ + while(1) + { + /* wait for event (10ms) */ + int ret = nwz_key_wait_event(input_fd, 10000); + if(ret != 1) + continue; + struct input_event evt; + if(nwz_key_read_event(input_fd, &evt) != 1) + continue; + if(nwz_key_event_get_keycode(&evt) == NWZ_KEY_BACK && !nwz_key_event_is_press(&evt)) + break; + } + /* finish nicely */ + nwz_key_close(input_fd); +} + +int NWZ_TOOL_MAIN(all_tools)(int argc, char **argv); + +int main(int argc, char **argv) +{ +#if 0 + nwz_lcdmsg(true, 0, 0, "dualboot"); + if(boot_rockbox()) + { + /* boot rockox */ + nwz_lcdmsg(true, 0, 3, "Booting rockbox..."); + execvp("/usr/local/bin/lcdmsg", boot_rb_argv); + nwz_lcdmsg(false, 0, 4, "failed."); + sleep(5); + } + /* if for some reason, running rockbox failed, then try to run the OF */ + /* boot OF */ + nwz_lcdmsg(true, 0, 3, "Booting OF..."); + execvp("/usr/local/bin/SpiderApp.of", argv); + nwz_lcdmsg(false, 0, 4, "failed."); + sleep(5); + /* if we reach this point, everything failed, so return an error so that + * sysmgrd knows something is wrong */ + return 1; +#elif 0 + const char *args_mount[] = {"mount", NULL}; + int status; + char *output = nwz_run_pipe("mount", args_mount, &status); + nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output); + free(output); + wait_key(); + const char *args_ls[] = {"ls", "/var", NULL}; + output = nwz_run_pipe("ls", args_ls, &status); + nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output); + free(output); + wait_key(); + const char *args_glogctl[] = {"glogctl", "flush", NULL}; + output = nwz_run_pipe("/usr/local/bin/glogctl", args_glogctl, &status); + nwz_lcdmsgf(true, 0, 0, "%d\n%s", status, output); + free(output); + wait_key(); + system("cp /var/GEMINILOG* /contents/"); + sync(); + execvp("/usr/local/bin/SpiderApp.of", argv); + return 0; +#else + /* make sure backlight is on */ + int fb_fd = nwz_fb_open(true); + if(fb_fd >= 0) + { + struct nwz_fb_brightness bl; + nwz_fb_get_brightness(fb_fd, &bl); + bl.level = NWZ_FB_BL_MAX_LEVEL; + nwz_fb_set_brightness(fb_fd, &bl); + nwz_fb_close(fb_fd); + } + /* run all tools menu */ + NWZ_TOOL_MAIN(all_tools)(argc, argv); + /* run OF */ + execvp("/usr/local/bin/SpiderApp.of", argv); + return 0; +#endif +} diff --git a/utils/nwztools/plattools/nwz_lib.c b/utils/nwztools/plattools/nwz_lib.c index 4f49bec909..087db8834a 100644 --- a/utils/nwztools/plattools/nwz_lib.c +++ b/utils/nwztools/plattools/nwz_lib.c @@ -30,7 +30,7 @@ const char *nwz_get_model_name(unsigned long model_id) return NULL; } -void nwz_run(const char *file, const char *args[], bool wait) +int nwz_run(const char *file, const char *args[], bool wait) { pid_t child_pid = fork(); if(child_pid != 0) @@ -39,7 +39,10 @@ void nwz_run(const char *file, const char *args[], bool wait) { int status; waitpid(child_pid, &status, 0); + return status; } + else + return 0; } else { @@ -48,6 +51,40 @@ void nwz_run(const char *file, const char *args[], bool wait) } } +char *nwz_run_pipe(const char *file, const char *args[], int *status) +{ + int pipe_fds[2]; + pipe(pipe_fds); + pid_t child_pid = fork(); + if(child_pid == 0) + { + dup2(pipe_fds[1], 1); /* redirect stdout */ + dup2(pipe_fds[1], 2); /* redirect stderr */ + close(pipe_fds[0]); /* close reading */ + close(pipe_fds[1]); /* close writing */ + execvp(file, (char * const *)args); + _exit(1); + } + else + { + close(pipe_fds[1]); /* close writing */ + char buffer[1024]; + char *output = malloc(1); + ssize_t count; + size_t size = 0; + while((count = read(pipe_fds[0], buffer, sizeof(buffer))) > 0) + { + output = realloc(output, size + count + 1); + memcpy(output + size, buffer, count); + size += count; + } + close(pipe_fds[0]); + output[size] = 0; + waitpid(child_pid, status, 0); + return output; + } +} + void nwz_lcdmsg(bool clear, int x, int y, const char *msg) { const char *path_lcdmsg = "/usr/local/bin/lcdmsg"; diff --git a/utils/nwztools/plattools/nwz_lib.h b/utils/nwztools/plattools/nwz_lib.h index 90d122003a..df0105a13d 100644 --- a/utils/nwztools/plattools/nwz_lib.h +++ b/utils/nwztools/plattools/nwz_lib.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "nwz_keys.h" #include "nwz_fb.h" @@ -47,7 +48,9 @@ const char *nwz_get_model_name(unsigned long model_id); /* run a program and exit with nonzero status in case of error * argument list must be NULL terminated */ -void nwz_run(const char *file, const char *args[], bool wait); +int nwz_run(const char *file, const char *args[], bool wait); +/* run a program and return program output */ +char *nwz_run_pipe(const char *file, const char *args[], int *status); /* invoke /usr/bin/lcdmsg to display a message using the small font, optionally * clearing the screen before */ diff --git a/utils/nwztools/scripts/Makefile b/utils/nwztools/scripts/Makefile index 207534a006..345fd0f4cb 100644 --- a/utils/nwztools/scripts/Makefile +++ b/utils/nwztools/scripts/Makefile @@ -11,6 +11,7 @@ all: @echo "- exec_file: craft an upgrade that embeds and execute a file" @echo "- exec_file_extern: craft an upgrade that execute a file on the user partition" @echo "- list_targets: produce of list of available targets" + @echo "- install_dualboot" ifndef UPG want_upg: @@ -33,7 +34,7 @@ endif ifndef NWZ_TARGET want_target: $(info Please set NWZ_TARGET to your target. For example:) - $(info make dump_rootfs NWZ_TARGET=nwz-e463) + $(info make dump_rootfs NWZ_TARGET=nwz-e460) $(info Run 'make list_targets' to get a list of all targets) $(error "") else @@ -72,6 +73,9 @@ UPGPACK=$(upgtool) -c -m $(NWZ_TARGET) $(UPG) $(1) exec_file: want_target want_exec want_upg $(call UPGPACK, exec_file.sh $(EXEC)) +install_dualboot: want_target want_exec want_upg + $(call UPGPACK, install_dualboot.sh $(EXEC)) + exec_file_extern.tmp: want_exec want_upg want_log cat exec_file_extern.sh.in | sed "s|NWZ_EXEC_THIS|$(EXEC)|" |\ sed "s|NWZ_LOG_THIS|$(LOG)|" > $@ diff --git a/utils/nwztools/scripts/exec_file.sh b/utils/nwztools/scripts/exec_file.sh index a624e4df35..b005156c37 100644 --- a/utils/nwztools/scripts/exec_file.sh +++ b/utils/nwztools/scripts/exec_file.sh @@ -20,7 +20,7 @@ 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" -# 2) We need to remount the contents partition in read-write mode be able to +# 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" if ! mount -o remount,rw $CONTENTS_PART $CONTENTS @@ -55,7 +55,7 @@ fi lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Running file..." /tmp/exec >$CONTENTS/exec.txt 2>&1 -# 4) Success screen +# Success screen lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds." sleep 3 sync diff --git a/utils/nwztools/scripts/install_dualboot.sh b/utils/nwztools/scripts/install_dualboot.sh new file mode 100644 index 0000000000..ece5b9e3a3 --- /dev/null +++ b/utils/nwztools/scripts/install_dualboot.sh @@ -0,0 +1,129 @@ +#!/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 + +# +# FIXME document this +# + + +# 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 + +# import constants +. /install_script/constant.txt +_UPDATE_FN_=`nvpstr ufn` +ROOTFS_TMP_DIR=/tmp/rootfs +ROCKBOX_NAME=Rockbox +ROCKBOX_PATH=$ROOTFS_TMP_DIR/usr/local/bin/$ROCKBOX_NAME +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 + +# NOTE some platforms use ext3 and some ext4 with a custom mount program +# (/usr/local/bin/icx_mount.ext4), some probably use an mtd too +mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR +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 executable +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Install rockbox" +fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $SPIDERAPP_PATH +if [ "$?" != 0 ]; then + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: no file to extract" + sleep 3 + exit 0 +fi + +# make it executable and change user/group +chmod 775 $SPIDERAPP_PATH +if [ "$?" != 0 ]; then + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot make it executable" + sleep 3 + exit 0 +fi +chown 500:500 $SPIDERAPP_PATH +if [ "$?" != 0 ]; then + lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot change owner" + sleep 3 + exit 0 +fi + +# # change main application +# lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Modify app list" +# sed -i 's/Rockbox/SpiderApp/' $ROOTFS_TMP_DIR/etc/AppList.conf +# if [ "$?" != 0 ]; then +# lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,14 "ERROR: sed failed" +# sleep 3 +# exit 0 +# fi +# # and fix ownership +# chown 500:500 $ROOTFS_TMP_DIR/etc/AppList.conf +# if [ "$?" != 0 ]; then +# lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,14 "ERROR: cannot change group" +# sleep 3 +# exit 0 +# fi +cat $ROOTFS_TMP_DIR/etc/AppList.conf >$CONTENTS/AppList.conf +ls -l $ROOTFS_TMP_DIR/usr/local/bin/ >$CONTENTS/ls.txt +ls -l $ROOTFS_TMP_DIR/etc/ >$CONTENTS/ls2.txt + +# unmount root partition +lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,10 "Unmount root filesystem" +sync +if [ "$?" != 0 ]; then + 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 + +# finish +exit 0