1
0
Fork 0
forked from len0rd/rockbox

nwztools: add preliminary dualboot and dualboot install script

At the moment, the script install_duaboot does the following:
- rename SpiderApp to SpiderApp.of (unless it already exists)
- install payload as SpiderApp
- fixes permissions
Since SpiderApp is the main app, it will execute instead of the OF.
The current dualboot code (dualboot.c) is still a preliminary but the current
version displays an "all tools" menu to choose for. When exitting the menu
using BACK, it will run the OF.

With the modifications made by the install script, it should not be possible
to break the device. In the worst case scenario, the dualboot code crashes
and it restarted by the sysmgrd, or hangs. A safe way to recover is to plug
the USB cable and reset the device: the system manager will then start the
USB app and one can reflash the device if necessary.

Change-Id: Id9edab0347538ad2a8651a28aea7fd083feaa626
This commit is contained in:
Amaury Pouly 2016-11-01 17:04:26 +01:00
parent b045e4da34
commit d492f25c54
7 changed files with 363 additions and 6 deletions

View file

@ -7,7 +7,7 @@ INCLUDES=-I.
LIB_FILES=nwz_lib.c nwz_lib_devlist.c 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 \ 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 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) all: $(ALL_ELF)
@ -17,5 +17,8 @@ all: $(ALL_ELF)
all_tools.elf: all_tools.c $(TOOL_FILES) $(LIB_FILES) all_tools.elf: all_tools.c $(TOOL_FILES) $(LIB_FILES)
$(CC) $(CFLAGS) -DNWZ_EMBED_TOOLS $(INCLUDES) -o $@ $^ $(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: clean:
rm -rf $(ALL_ELF) rm -rf $(ALL_ELF)

View file

@ -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 <time.h>
/* 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
}

View file

@ -30,7 +30,7 @@ const char *nwz_get_model_name(unsigned long model_id)
return NULL; 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(); pid_t child_pid = fork();
if(child_pid != 0) if(child_pid != 0)
@ -39,7 +39,10 @@ void nwz_run(const char *file, const char *args[], bool wait)
{ {
int status; int status;
waitpid(child_pid, &status, 0); waitpid(child_pid, &status, 0);
return status;
} }
else
return 0;
} }
else 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) void nwz_lcdmsg(bool clear, int x, int y, const char *msg)
{ {
const char *path_lcdmsg = "/usr/local/bin/lcdmsg"; const char *path_lcdmsg = "/usr/local/bin/lcdmsg";

View file

@ -30,6 +30,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "nwz_keys.h" #include "nwz_keys.h"
#include "nwz_fb.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 /* run a program and exit with nonzero status in case of error
* argument list must be NULL terminated */ * 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 /* invoke /usr/bin/lcdmsg to display a message using the small font, optionally
* clearing the screen before */ * clearing the screen before */

View file

@ -11,6 +11,7 @@ all:
@echo "- exec_file: craft an upgrade that embeds and execute a file" @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 "- exec_file_extern: craft an upgrade that execute a file on the user partition"
@echo "- list_targets: produce of list of available targets" @echo "- list_targets: produce of list of available targets"
@echo "- install_dualboot"
ifndef UPG ifndef UPG
want_upg: want_upg:
@ -33,7 +34,7 @@ endif
ifndef NWZ_TARGET ifndef NWZ_TARGET
want_target: want_target:
$(info Please set NWZ_TARGET to your target. For example:) $(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) $(info Run 'make list_targets' to get a list of all targets)
$(error "") $(error "")
else else
@ -72,6 +73,9 @@ UPGPACK=$(upgtool) -c -m $(NWZ_TARGET) $(UPG) $(1)
exec_file: want_target want_exec want_upg exec_file: want_target want_exec want_upg
$(call UPGPACK, exec_file.sh $(EXEC)) $(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 exec_file_extern.tmp: want_exec want_upg want_log
cat exec_file_extern.sh.in | sed "s|NWZ_EXEC_THIS|$(EXEC)|" |\ cat exec_file_extern.sh.in | sed "s|NWZ_EXEC_THIS|$(EXEC)|" |\
sed "s|NWZ_LOG_THIS|$(LOG)|" > $@ sed "s|NWZ_LOG_THIS|$(LOG)|" > $@

View file

@ -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" 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 # write something on it
lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw" lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw"
if ! mount -o remount,rw $CONTENTS_PART $CONTENTS 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..." lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Running file..."
/tmp/exec >$CONTENTS/exec.txt 2>&1 /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." lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds."
sleep 3 sleep 3
sync sync

View file

@ -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