summaryrefslogtreecommitdiff
path: root/rbutil/mks5lboot/dualboot
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-02-04 23:05:17 +0100
committerCástor Muñoz <cmvidal@gmail.com>2017-04-14 00:03:42 +0200
commit346423c040fe4ac31dae7c1afcb1d853cc80635c (patch)
treebd8dd4c55f083a1162f7019188977213a20dc41c /rbutil/mks5lboot/dualboot
parenteefc7c73e2495decdc6f242515696fe0e3f85609 (diff)
mks5lboot v1.0 - dualboot installer for s5l8702 targets
A tool to install/uninstall a bootloader into a s5l8702 based device: - iPod Classic 6G - iPod Nano 3G (TODO) See mks5lboot/README for detailed info. Change-Id: I451d2aaff34509ebd356e4660647e5222c5d3409
Diffstat (limited to 'rbutil/mks5lboot/dualboot')
-rw-r--r--rbutil/mks5lboot/dualboot/.gitignore3
-rw-r--r--rbutil/mks5lboot/dualboot/Makefile97
-rw-r--r--rbutil/mks5lboot/dualboot/autoconf.h74
-rw-r--r--rbutil/mks5lboot/dualboot/bin2c.c140
-rw-r--r--rbutil/mks5lboot/dualboot/dualboot.c287
-rw-r--r--rbutil/mks5lboot/dualboot/dualboot.lds59
-rw-r--r--rbutil/mks5lboot/dualboot/init.S43
7 files changed, 703 insertions, 0 deletions
diff --git a/rbutil/mks5lboot/dualboot/.gitignore b/rbutil/mks5lboot/dualboot/.gitignore
new file mode 100644
index 0000000000..34c53b3c82
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/.gitignore
@@ -0,0 +1,3 @@
+build/
+*.arm-bin
+bin2c
diff --git a/rbutil/mks5lboot/dualboot/Makefile b/rbutil/mks5lboot/dualboot/Makefile
new file mode 100644
index 0000000000..51ce816ca0
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/Makefile
@@ -0,0 +1,97 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+ifndef V
+SILENT = @
+endif
+
+CC = gcc
+LD = ld
+OC = objcopy
+CROSS ?= arm-elf-eabi-
+
+ROOTDIR = ../../..
+FIRMDIR = $(ROOTDIR)/firmware
+FWARM = $(FIRMDIR)/target/arm
+FW8702 = $(FWARM)/s5l8702
+BUILDDIR = build/
+LINKFILE = dualboot.lds
+
+# Edit the following variables when adding a new target.
+# mks5lboot.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 = ipod6g
+OPT_ipod6g = -DIPOD_6G -DMEMORYSIZE=64
+
+LOADERS = install uninstall
+OPT_install =
+OPT_uninstall = -DDUALBOOT_UNINSTALL
+
+# target/loader specific options
+$(foreach l, $(LOADERS),$(foreach t, $(TARGETS),\
+ $(eval OPT_$(l)_$(t) = $(OPT_$(l)) $(OPT_$(t)))))
+
+DEFINES = -DBOOTLOADER
+
+SOURCES = init.S dualboot.c
+SOURCES += $(ROOTDIR)/lib/arm_support/support-arm.S
+SOURCES += $(wildcard $(FIRMDIR)/asm/mem*.c $(FIRMDIR)/libc/mem*.c)
+SOURCES += $(addprefix $(FWARM)/, mmu-arm.S)
+SOURCES += $(addprefix $(FW8702)/, clocking-s5l8702.c spi-s5l8702.c nor-s5l8702.c crypto-s5l8702.c)
+# target/loader specific sources
+SRCTARGET = piezo-.c
+$(foreach l, $(LOADERS), $(foreach t, $(TARGETS),\
+ $(eval SRC_$(l)_$(t) = $(addprefix $(FW8702)/$(t)/, $(subst -.,-$(subst ipod,,$(t)).,$(SRCTARGET))))))
+
+INCLUDES += -I. -I.. -I$(FIRMDIR) -I$(FWARM) -I$(FW8702)
+INCLUDES += $(addprefix -I$(FIRMDIR)/, export include libc/include kernel/include)
+# target/loader specific includes
+$(foreach l,$(LOADERS),$(foreach t,$(TARGETS),$(eval INC_$(l)_$(t) = -I$(FW8702)/$(t))))
+
+CFLAGS = $(INCLUDES) -mcpu=arm926ej-s -std=gnu99 -nostdlib -ffreestanding -Os -W -Wall\
+ -Wundef -Wstrict-prototypes -ffunction-sections -fdata-sections -Wl,--gc-sections $(DEFINES)
+
+# Build filenames prefix
+PFX = dualboot_
+
+BOOTBINS = $(foreach l, $(LOADERS),$(foreach t, $(TARGETS),$(PFX)$(l)_$(t).arm-bin))
+
+OUTPUTDUALBOOT = ../dualboot.h ../dualboot.c
+OUTPUTDEBUG = $(BOOTBINS:%.arm-bin=$(BUILDDIR)%.arm-elf) $(BOOTBINS:%.arm-bin=$(BUILDDIR)%.lds)
+
+
+all: $(BUILDDIR) $(OUTPUTDUALBOOT)
+
+$(BUILDDIR)$(PFX)%.lds: $(LINKFILE)
+ @echo Creating $@
+ $(SILENT)$(CROSS)$(CC) $(INC_$*) $(CFLAGS) $(OPT_$*) -E -x c - < $< | sed '/#/d' > $@
+
+$(BUILDDIR)$(PFX)%.arm-elf: $(BUILDDIR)$(PFX)%.lds $(SOURCES)
+ @echo CC -T $(notdir $^ $(SRC_$*))
+ $(SILENT)$(CROSS)$(CC) $(INC_$*) $(CFLAGS) $(OPT_$*) -o $@ -T$^ $(SRC_$*)
+
+$(PFX)%.arm-bin: $(BUILDDIR)$(PFX)%.arm-elf
+ @echo OC $<
+ $(SILENT)$(CROSS)$(OC) -O binary $< $@
+
+bin2c: bin2c.c
+ $(CC) -o $@ $<
+
+$(OUTPUTDUALBOOT): bin2c $(BOOTBINS)
+ ./bin2c ../dualboot $(BOOTBINS)
+
+$(BUILDDIR):
+ mkdir -p $@
+
+clean:
+ rm -rf bin2c $(BOOTBINS) $(BUILDDIR)
+
+.PRECIOUS: $(OUTPUTDEBUG)
diff --git a/rbutil/mks5lboot/dualboot/autoconf.h b/rbutil/mks5lboot/dualboot/autoconf.h
new file mode 100644
index 0000000000..cd5b3f9aeb
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/autoconf.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id:$
+ *
+ * Copyright (C) 2012 by Andrew Ryabinin
+ *
+ * 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 __BUILD_AUTOCONF_H
+#define __BUILD_AUTOCONF_H
+
+/* lower case names match the what's exported in the Makefile
+ * upper case name looks nicer in the code */
+
+#define arch_none 0
+#define ARCH_NONE 0
+
+#define arch_sh 1
+#define ARCH_SH 1
+
+#define arch_m68k 2
+#define ARCH_M68K 2
+
+#define arch_arm 3
+#define ARCH_ARM 3
+
+#define arch_mips 4
+#define ARCH_MIPS 4
+
+#define arch_x86 5
+#define ARCH_X86 5
+
+#define arch_amd64 6
+#define ARCH_AMD64 6
+
+/* Define target machine architecture */
+#define ARCH arch_arm
+/* Optionally define architecture version */
+#define ARCH_VERSION 5
+
+/* Define endianess for the target or simulator platform */
+#define ROCKBOX_LITTLE_ENDIAN 1
+
+/* Define this if you build rockbox to support the logf logging and display */
+#undef ROCKBOX_HAS_LOGF
+
+/* Define this if you want logf to output to the serial port */
+#undef LOGF_SERIAL
+
+/* Define this to record a chart with timings for the stages of boot */
+#undef DO_BOOTCHART
+
+/* the threading backend we use */
+#define ASSEMBLER_THREADS
+
+/* root of Rockbox */
+#define ROCKBOX_DIR "/.rockbox"
+#define ROCKBOX_SHARE_PATH ""
+#define ROCKBOX_BINARY_PATH ""
+#define ROCKBOX_LIBRARY_PATH ""
+
+#endif /* __BUILD_AUTOCONF_H */
diff --git a/rbutil/mks5lboot/dualboot/bin2c.c b/rbutil/mks5lboot/dualboot/bin2c.c
new file mode 100644
index 0000000000..4d74a19696
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/bin2c.c
@@ -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;
+}
diff --git a/rbutil/mks5lboot/dualboot/dualboot.c b/rbutil/mks5lboot/dualboot/dualboot.c
new file mode 100644
index 0000000000..b8167ec124
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/dualboot.c
@@ -0,0 +1,287 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2015 by Cástor Muñoz
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+#include "config.h"
+#include "system.h"
+#include "button.h"
+
+#include "s5l8702.h"
+#include "clocking-s5l8702.h"
+#include "spi-s5l8702.h"
+#include "nor-target.h"
+#include "piezo.h"
+
+/* How it works:
+ *
+ * - dualboot-installer: installs or updates a RB bootloader, the bootloader
+ * to install/update is already included into dualboot-installer.dfu file,
+ * once it is executed by the iPod device:
+ *
+ * 1) locates an original NORBOOT (ONB): first it looks at offset=32KB, if
+ * a NORBOOT is found but it is not an ONB then it is supposed it is a
+ * RB bootloader (that should be updated), then the ONB is loaded from
+ * offset=32KB+old_BLSIZE).
+ * 2) write ONB at 32KB+new_BLSIZE, if it fails then:
+ * 2a) try to restore ONB to its 'pristine' place (offset=32KB), if it
+ * also fails then the NOR got corrupted (ONB probably destroyed)
+ * and iTunes should be used to restore the iPod.
+ * 3) write new (included) RB bootloader at offset=32KB, it it fails then
+ * goto 2a)
+ *
+ * - dualboot-uninstaller: uninstall RB bootloader from NOR, leaving it at
+ * it's previous (pristine) state.
+ *
+ * See bootloader/ipod6g.c for notes on how the RB bootloader works.
+ *
+ *
+ * Pristine NOR Rockboxed NOR
+ * 1MB ______________
+ * | |
+ * | flsh DIR |
+ * 1MB-0x200 |______________|
+ * | |
+ * | File 1 |
+ * |..............|
+ * | |
+ * . .
+ * . .
+ * . .
+ * | |
+ * |..............|
+ * | | . .
+ * | File N | . .
+ * |______________| |______________|
+ * | | | |
+ * | | | |
+ * | | | Unused |
+ * | | | |
+ * | Unused | 160KB+BLSZ |______________|
+ * | | | |
+ * | | | Original |
+ * | | | NOR boot |
+ * 160KB |______________| | (decrypted) |
+ * | | | |
+ * | | 32KB+BLSZ |______________|
+ * | Original | | |
+ * | NOR boot | | Decrypted |
+ * | (encrypted) | | Rockbox |
+ * | | | Bootloader |
+ * 32KB |______________| 32KB |______________|
+ * | | | |
+ * | | . .
+ * | | . .
+ * |______________|
+ * | |
+ * | SysCfg |
+ * 0 |______________|
+ *
+ */
+
+#define OF_LOADADDR IRAM1_ORIG
+
+/* tone sequences: period (uS), duration (ms), silence (ms) */
+static uint16_t alive[] = { 500,100,0, 0 };
+static uint16_t happy[] = { 1000,100,0, 500,150,0, 0 };
+static uint16_t fatal[] = { 3000,500,500, 3000,500,500, 3000,500,0, 0 };
+#define sad2 (&fatal[3])
+#define sad (&fatal[6])
+
+/* iPod Classic: decrypted hashes for known OFs */
+static unsigned char of_sha[][SIGN_SZ] = {
+ "\x66\x66\x76\xDC\x1D\x32\xB2\x46\xA6\xC9\x7D\x5A\x61\xD3\x49\x4C", /* v1.1.2 */
+ "\x1E\xF0\xD9\xDE\xC2\x7E\xEC\x02\x7C\x15\x76\xBB\x5C\x4F\x2D\x95", /* v2.0.1 */
+ "\x06\x85\xDF\x28\xE4\xD7\xF4\x82\xC0\x73\xB0\x53\x26\xFC\xB0\xFE", /* v2.0.4 */
+ "\x60\x80\x7D\x33\xA8\xDE\xF8\x49\xBB\xBE\x01\x45\xFF\x62\x40\x19" /* v2.0.5 */
+};
+#define N_OF (int)(sizeof(of_sha)/SIGN_SZ)
+
+/* we can assume that unknown FW is a RB bootloader */
+#define FW_RB N_OF
+
+static int identify_fw(struct Im3Info *hinfo)
+{
+ unsigned char hash[SIGN_SZ];
+ int of;
+
+ /* decrypt hash to identify OF */
+ memcpy(hash, hinfo->u.enc12.data_sign, SIGN_SZ);
+ hwkeyaes(HWKEYAES_DECRYPT, HWKEYAES_UKEY, hash, SIGN_SZ);
+
+ for (of = 0; of < N_OF; of++)
+ if (memcmp(hash, of_sha[of], SIGN_SZ) == 0)
+ break;
+
+ return of;
+}
+
+#ifdef DUALBOOT_UNINSTALL
+/* Uninstall RB bootloader */
+void main(void)
+{
+ struct Im3Info *hinfo;
+ void *fw_addr;
+ uint16_t *status;
+ unsigned bl_nor_sz;
+
+ usec_timer_init();
+ piezo_seq(alive);
+ spi_clkdiv(SPI_PORT, 4); /* SPI clock = 27/5 MHz. */
+
+ hinfo = (struct Im3Info*)OF_LOADADDR;
+ fw_addr = (void*)hinfo + IM3HDR_SZ;
+
+ if (im3_read(NORBOOT_OFF, hinfo, NULL) != 0) {
+ status = sad;
+ goto bye; /* no FW found */
+ }
+
+ if (identify_fw(hinfo) != FW_RB) {
+ status = happy;
+ goto bye; /* RB bootloader not installed, nothing to do */
+ }
+
+ /* if found FW is a RB bootloader, OF should start just behind it */
+ bl_nor_sz = im3_nor_sz(hinfo);
+ if ((im3_read(NORBOOT_OFF + bl_nor_sz, hinfo, fw_addr) != 0)
+ || (identify_fw(hinfo) == FW_RB)) {
+ status = sad;
+ goto bye; /* OF not found */
+ }
+
+ /* decrypted OF correctly loaded, encrypt it before restoration */
+ im3_crypt(HWKEYAES_ENCRYPT, hinfo, fw_addr);
+
+ /* restore OF to it's original place */
+ if (!im3_write(NORBOOT_OFF, hinfo)) {
+ status = fatal;
+ goto bye; /* corrupted NOR, use iTunes to restore */
+ }
+
+ /* erase freed NOR blocks */
+ bootflash_init(SPI_PORT);
+ bootflash_erase_blocks(SPI_PORT,
+ (NORBOOT_OFF + im3_nor_sz(hinfo)) >> 12, bl_nor_sz >> 12);
+ bootflash_close(SPI_PORT);
+
+ status = happy;
+
+bye:
+ /* minimum time between the initial and the final beeps */
+ while (USEC_TIMER < 2000000);
+ piezo_seq(status);
+ WDTCON = 0x100000; /* WDT reset */
+ while (1);
+}
+
+#else
+/* Install RB bootloader */
+struct Im3Info bl_hinfo __attribute__((section(".im3info.data"))) =
+{
+ .ident = IM3_IDENT,
+ .version = IM3_VERSION,
+ .enc_type = 2,
+};
+
+static uint32_t get_uint32le(unsigned char *p)
+{
+ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+void main(void)
+{
+ uint16_t *status = happy;
+ int single_boot;
+ struct Im3Info *hinfo;
+ void *fw_addr;
+ unsigned bl_nor_sz;
+
+ usec_timer_init();
+ piezo_seq(alive);
+ spi_clkdiv(SPI_PORT, 4); /* SPI clock = 27/5 MHz. */
+
+ /* check for single boot installation, is is configured when
+ mks5lboot.exe builds the .dfu image */
+ single_boot = bl_hinfo.info_sign[0];
+
+ /* sign RB bootloader (data and header), but don't encrypt it,
+ use current decrypted image for faster load */
+ im3_sign(HWKEYAES_UKEY, (void*)&bl_hinfo + IM3HDR_SZ,
+ get_uint32le(bl_hinfo.data_sz), bl_hinfo.u.enc12.data_sign);
+ im3_sign(HWKEYAES_UKEY, &bl_hinfo, IM3INFOSIGN_SZ, bl_hinfo.info_sign);
+
+ if (single_boot) {
+ if (!im3_write(NORBOOT_OFF, &bl_hinfo))
+ status = sad;
+ goto bye;
+ }
+
+ hinfo = (struct Im3Info*)OF_LOADADDR;
+ fw_addr = (void*)hinfo + IM3HDR_SZ;
+
+ if (im3_read(NORBOOT_OFF, hinfo, fw_addr) != 0) {
+ status = sad;
+ goto bye; /* no FW found */
+ }
+
+ if (identify_fw(hinfo) == FW_RB) {
+ /* FW found, but not OF, assume it is a RB bootloader,
+ already decrypted OF should be located just behind */
+ int nor_offset = NORBOOT_OFF + im3_nor_sz(hinfo);
+ if ((im3_read(nor_offset, hinfo, fw_addr) != 0)
+ || (identify_fw(hinfo) == FW_RB)) {
+ status = sad;
+ goto bye; /* OF not found, use iTunes to restore */
+ }
+ }
+
+ bl_nor_sz = im3_nor_sz(&bl_hinfo);
+ /* safety check - verify we are not going to overwrite useful data */
+ if (flsh_get_unused() < bl_nor_sz) {
+ status = sad2;
+ goto bye; /* no space if flash, use iTunes to restore */
+ }
+
+ /* write decrypted OF and RB bootloader, if any of these fails we
+ will try to retore OF to its original place */
+ if (!im3_write(NORBOOT_OFF + bl_nor_sz, hinfo)
+ || !im3_write(NORBOOT_OFF, &bl_hinfo)) {
+ im3_crypt(HWKEYAES_ENCRYPT, hinfo, fw_addr);
+ if (!im3_write(NORBOOT_OFF, hinfo)) {
+ /* corrupted NOR, use iTunes to restore */
+ status = fatal;
+ }
+ else {
+ /* RB bootloader not succesfully intalled, but device
+ was restored and should be working as before */
+ status = sad;
+ }
+ }
+
+bye:
+ /* minimum time between the initial and the final beeps */
+ while (USEC_TIMER < 2000000);
+ piezo_seq(status);
+ WDTCON = 0x100000; /* WDT reset */
+ while (1);
+}
+#endif /* DUALBOOT_UNINSTALL */
diff --git a/rbutil/mks5lboot/dualboot/dualboot.lds b/rbutil/mks5lboot/dualboot/dualboot.lds
new file mode 100644
index 0000000000..cb92e2a286
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/dualboot.lds
@@ -0,0 +1,59 @@
+#define ASM
+#include "config.h"
+#include "cpu.h"
+#include "mks5lboot.h"
+
+ENTRY(_start)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+#define BIN_ORIG DFU_LOADADDR + BIN_OFFSET
+#define BIN_SIZE MAX_PAYLOAD
+
+MEMORY
+{
+ IRAM : ORIGIN = BIN_ORIG, LENGTH = BIN_SIZE
+}
+
+SECTIONS
+{
+ .text : {
+ *(.init.text*)
+ *(.text*)
+ *(.icode*)
+ . = ALIGN(4);
+ } > IRAM
+
+ /* include initialized BSS (if any) into DFU image */
+ .bss : {
+ *(.bss*)
+ *(.ibss*)
+ *(COMMON)
+ . = ALIGN(4);
+ } > IRAM
+
+#if 1
+ /* reuse pwnage as stack, 0x30c bytes available */
+ _exception_stack = BIN_ORIG;
+ _supervisor_stack = _exception_stack;
+#else
+ /* include stack into DFU image */
+ .stack : {
+ . += 0x400;
+ _supervisor_stack = .;
+ . += 0x200;
+ _exception_stack = .;
+ } > IRAM
+#endif
+
+ .data : {
+ *(.data*)
+ *(.rodata*)
+ *(.idata*)
+ *(.irodata*)
+ /* place bootloader IM3 header at the end, mkdfu
+ will concatenate the bootloader binary here */
+ . = ALIGN(16);
+ *(.im3info.data*)
+ } > IRAM
+}
diff --git a/rbutil/mks5lboot/dualboot/init.S b/rbutil/mks5lboot/dualboot/init.S
new file mode 100644
index 0000000000..bd049515f4
--- /dev/null
+++ b/rbutil/mks5lboot/dualboot/init.S
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id:
+ *
+ * Copyright © 2009 Michael Sparmann
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+ .section .init.text, "ax", %progbits
+ .global _start
+
+_start:
+ mov r0, #0xD7
+ msr CPSR_c, r0 @ Abort mode, IRQs/FIQs disabled
+ ldr sp, =_exception_stack
+
+ mov r0, #0xDB
+ msr CPSR_c, r0 @ Undefined Instruction mode, IRQs/FIQs disabled
+ ldr sp, =_exception_stack
+
+ mov r0, #0xD3
+ msr CPSR_c, r0 @ Supervisor mode, IRQs/FIQs disabled
+ ldr sp, =_supervisor_stack
+
+ MOV R0, #0x00050000
+ ORR R0, #0x00000078
+ MCR p15, 0, R0, c1, c0, 0 @ Get rid of some CPU "features" likely to cause trouble
+
+ bl main
+ .ltorg