summaryrefslogtreecommitdiff
path: root/utils/mkamsboot
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mkamsboot')
-rw-r--r--utils/mkamsboot/.gitignore2
-rw-r--r--utils/mkamsboot/Makefile31
-rw-r--r--utils/mkamsboot/README67
-rw-r--r--utils/mkamsboot/dualboot.c152
-rw-r--r--utils/mkamsboot/dualboot.h12
-rw-r--r--utils/mkamsboot/dualboot/.gitignore3
-rw-r--r--utils/mkamsboot/dualboot/Makefile61
-rw-r--r--utils/mkamsboot/dualboot/bin2c.c140
-rw-r--r--utils/mkamsboot/dualboot/dualboot.S307
-rw-r--r--utils/mkamsboot/dualboot/nrv2e_d8.S198
-rw-r--r--utils/mkamsboot/main.c174
-rw-r--r--utils/mkamsboot/md5.c246
-rw-r--r--utils/mkamsboot/md5.h25
-rw-r--r--utils/mkamsboot/mkamsboot.c595
-rw-r--r--utils/mkamsboot/mkamsboot.h195
15 files changed, 2208 insertions, 0 deletions
diff --git a/utils/mkamsboot/.gitignore b/utils/mkamsboot/.gitignore
new file mode 100644
index 0000000000..568b1d5a87
--- /dev/null
+++ b/utils/mkamsboot/.gitignore
@@ -0,0 +1,2 @@
1build/
2mkamsboot
diff --git a/utils/mkamsboot/Makefile b/utils/mkamsboot/Makefile
new file mode 100644
index 0000000000..7100bd9512
--- /dev/null
+++ b/utils/mkamsboot/Makefile
@@ -0,0 +1,31 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7
8# We use the UCL code available in the Rockbox tools/ directory
9CFLAGS += -I../../tools/ucl/include -Wall
10
11OUTPUT = mkamsboot
12LIBUCL = libucl.a
13
14# inputs
15LIBSOURCES := dualboot.c md5.c mkamsboot.c
16SOURCES := main.c
17# additional link dependencies for the standalone executable
18EXTRADEPS := $(LIBUCL)
19
20include ../libtools.make
21# explicit dependencies on dualboot.{c,h} and mkamsboot.h
22$(OBJDIR)mkamsboot.o: dualboot.h dualboot.c mkamsboot.c mkamsboot.h
23$(OBJDIR)main.o: dualboot.h dualboot.c main.c mkamsboot.h
24
25
26$(TARGET_DIR)$(OUTPUT).dll: EXTRALIBOBJS += $(TARGET_DIR)ucl.dll
27$(TARGET_DIR)$(OUTPUT).dll: $(TARGET_DIR)ucl.dll
28$(TARGET_DIR)ucl.dll:
29 $(SILENT)$(MAKE) -C ../../tools/ucl/src/ \
30 BUILD_DIR=$(BUILD_DIR) CC=$(CC) CROSS=$(CROSS) \
31 TARGET_DIR=$(TARGET_DIR)/ ucl.dll
diff --git a/utils/mkamsboot/README b/utils/mkamsboot/README
new file mode 100644
index 0000000000..8e3f202f38
--- /dev/null
+++ b/utils/mkamsboot/README
@@ -0,0 +1,67 @@
1mkamsboot
2---------
3
4A tool to inject a bootloader into a Sansa V2 (AMS) firmware file.
5
6
7Usage
8-----
9
10mkamsboot <firmware file> <boot file> <output file>
11
12<firmware file> is an original Sansa firmware file obtained from the Sansa
13 forums for example : http://forums.sandisk.com/sansa/?category.id=devices
14
15<boot file> is the code you want to execute (a rockbox bootloader), previously
16 scrambled with tools/scramble utility.
17
18<output file> is the resulting firmware file which you'll have to copy on your
19 Sansa player. See "Firmware filenames".
20
21
22Supported models
23----------------
24
25Sansa Clip : firmware version starting with "01."
26Sansa Clip+ : firmware version starting with "01."
27Sansa Clipv2: firmware version starting with "02."
28Sansa ClipZip: firmware version starting with "01."
29Sansa Fuze : firmware version starting with "01."
30Sansa Fuzev2: firmware version starting with "02."
31Sansa E200v2: firmware version starting with "03."
32Sansa C200v2: firmware version starting with "03."
33Sansa M200v4: firmware version starting with "4."
34
35
36Firmware filenames
37------------------
38
39For the firmware upgrade to happen, the firmware has to be named specially:
40
41clip v2 : m30pa.bin
42clip : m300a.bin
43clip+ : clppa.bin
44clip zip: clpza.bin
45fuze : fuzea.bin
46fuzev2 : fuzpa.bin
47e200v2 : e200pa.bin
48c200v2 : c200pa.bin
49m200v4 : m200a.bin
50
51
52Dual-Boot
53---------
54
55 The purpose of this program is to provide dual-boot between the original
56firmware and the new (rockbox) firmware.
57
58 By default the player will boot into the new firmware.
59
60 To boot into the Original Firmware, you need to press the Left key.
61 ***Note : on the Clip+ you can alternatively press the Home key.
62 ***Note : on the Clip Zip you can alternatively press the Vol- key.
63
64Hacking
65-------
66
67See comments in mkamsboot.c and dualboot/dualboot.S for more information.
diff --git a/utils/mkamsboot/dualboot.c b/utils/mkamsboot/dualboot.c
new file mode 100644
index 0000000000..d97ab0e95b
--- /dev/null
+++ b/utils/mkamsboot/dualboot.c
@@ -0,0 +1,152 @@
1/* Generated by bin2c */
2
3#include "dualboot.h"
4
5unsigned char nrv2e_d8[168] = {
6 0x0f, 0x18, 0x01, 0x24, 0x65, 0x42, 0xe4, 0x07, 0x05, 0x26, 0x36, 0x02, 0x0a, 0xe0, 0x00, 0x20,
7 0x00, 0x47, 0x04, 0x78, 0x64, 0x41, 0x01, 0x30, 0x24, 0x06, 0xf7, 0x46, 0x03, 0x78, 0x01, 0x30,
8 0x13, 0x70, 0x01, 0x32, 0x24, 0x19, 0xfe, 0x46, 0xf3, 0xd0, 0xf7, 0xd2, 0x01, 0x21, 0x04, 0xe0,
9 0x01, 0x39, 0x24, 0x19, 0xfe, 0x46, 0xec, 0xd0, 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46, 0xe8, 0xd0,
10 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46, 0xe4, 0xd0, 0xf2, 0xd3, 0xcb, 0x1e, 0x00, 0x21, 0x08, 0xd3,
11 0x1b, 0x02, 0x05, 0x78, 0x01, 0x30, 0x1d, 0x43, 0xed, 0x43, 0xd8, 0xd0, 0x6d, 0x10, 0x13, 0xd2,
12 0x03, 0xe0, 0x24, 0x19, 0xfe, 0x46, 0xd4, 0xd0, 0x0e, 0xd2, 0x01, 0x21, 0x24, 0x19, 0xfe, 0x46,
13 0xcf, 0xd0, 0x09, 0xd2, 0x24, 0x19, 0xfe, 0x46, 0xcb, 0xd0, 0x49, 0x41, 0x24, 0x19, 0xfe, 0x46,
14 0xc7, 0xd0, 0xf7, 0xd3, 0x04, 0x31, 0x04, 0xe0, 0x24, 0x19, 0xfe, 0x46, 0xc1, 0xd0, 0x49, 0x41,
15 0x02, 0x31, 0xee, 0x42, 0x00, 0xd2, 0x01, 0x31, 0x13, 0x78, 0x53, 0x5d, 0x13, 0x70, 0x01, 0x32,
16 0x01, 0x39, 0xfa, 0xd1, 0xbe, 0xe7, 0x00, 0x00
17};
18unsigned char dualboot_clip[196] = {
19 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
22 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
23 0x2c, 0x30, 0x0f, 0xe5, 0x6c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
24 0x00, 0x10, 0x80, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
25 0x80, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
26 0x04, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a, 0x70, 0x00, 0x1f, 0xe5,
27 0x70, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x84, 0x00, 0x1f, 0xe5, 0x84, 0x10, 0x1f, 0xe5,
28 0x7c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
29 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
30 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8,
31 0x00, 0x00, 0x0c, 0xc8
32};
33unsigned char dualboot_e200v2[176] = {
34 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
37 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
38 0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
39 0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
40 0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x60, 0x00, 0x1f, 0xe5,
41 0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
42 0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
43 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
44 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
45};
46unsigned char dualboot_c200v2[272] = {
47 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
50 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
51 0x2c, 0x30, 0x0f, 0xe5, 0xa8, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
52 0x00, 0x10, 0x80, 0xe5, 0x9c, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5,
53 0x94, 0x20, 0x9f, 0xe5, 0x0c, 0x10, 0xa0, 0xe3, 0x20, 0x14, 0x82, 0xe5, 0x8c, 0x20, 0x9f, 0xe5,
54 0xff, 0x10, 0xa0, 0xe3, 0x20, 0x14, 0x82, 0xe5, 0x84, 0x00, 0x9f, 0xe5, 0x91, 0x1a, 0xa0, 0xe3,
55 0x08, 0x10, 0x80, 0xe5, 0x7c, 0x10, 0x9f, 0xe5, 0x10, 0x10, 0x80, 0xe5, 0x0c, 0x10, 0x90, 0xe5,
56 0x01, 0x1b, 0x11, 0xe2, 0xfc, 0xff, 0xff, 0x0a, 0x6c, 0x10, 0x9f, 0xe5, 0x08, 0x10, 0x80, 0xe5,
57 0x0c, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x11, 0xe2, 0xfc, 0xff, 0xff, 0x0a, 0xb4, 0x11, 0xd0, 0xe1,
58 0x04, 0x00, 0x11, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x1f, 0xe5, 0xac, 0x10, 0x1f, 0xe5,
59 0x01, 0x00, 0x00, 0xea, 0xc0, 0x00, 0x1f, 0xe5, 0xc0, 0x10, 0x1f, 0xe5, 0xb8, 0x30, 0x1f, 0xe5,
60 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4,
61 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3,
62 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x38, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0c, 0xc8,
63 0x00, 0x00, 0x0d, 0xc8, 0x00, 0x00, 0x12, 0xc8, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0x90, 0x08, 0x00
64};
65unsigned char dualboot_m200v4[180] = {
66 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
69 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
70 0x2c, 0x30, 0x0f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
71 0x00, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
72 0x80, 0x10, 0x80, 0xe5, 0x04, 0x20, 0x90, 0xe5, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x1a,
73 0x64, 0x00, 0x1f, 0xe5, 0x64, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x78, 0x00, 0x1f, 0xe5,
74 0x78, 0x10, 0x1f, 0xe5, 0x70, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
75 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
76 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
77 0x00, 0x00, 0x0b, 0xc8
78};
79unsigned char dualboot_fuze[176] = {
80 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
83 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
84 0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
85 0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
86 0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x60, 0x00, 0x1f, 0xe5,
87 0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
88 0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
89 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
90 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
91};
92unsigned char dualboot_clipv2[240] = {
93 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
96 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
97 0x2c, 0x30, 0x0f, 0xe5, 0x98, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
98 0x00, 0x10, 0x80, 0xe5, 0x8c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x0c, 0x10, 0xc1, 0xe3,
99 0x00, 0x10, 0x80, 0xe5, 0x80, 0x00, 0x9f, 0xe5, 0x38, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
100 0x08, 0x10, 0xa0, 0xe3, 0x20, 0x10, 0x80, 0xe5, 0x10, 0x10, 0xa0, 0xe3, 0x40, 0x10, 0x80, 0xe5,
101 0x20, 0x10, 0xa0, 0xe3, 0x80, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x40, 0x10, 0x80, 0xe5,
102 0x05, 0x10, 0xa0, 0xe3, 0x01, 0x10, 0x51, 0xe2, 0xfd, 0xff, 0xff, 0x1a, 0x04, 0x10, 0x90, 0xe5,
103 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x9c, 0x00, 0x1f, 0xe5, 0x9c, 0x10, 0x1f, 0xe5,
104 0x01, 0x00, 0x00, 0xea, 0xb0, 0x00, 0x1f, 0xe5, 0xb0, 0x10, 0x1f, 0xe5, 0xa8, 0x30, 0x1f, 0xe5,
105 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4,
106 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3,
107 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x0c, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x0e, 0xc8
108};
109unsigned char dualboot_clipplus[184] = {
110 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
113 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
114 0x2c, 0x30, 0x0f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
115 0x00, 0x10, 0x80, 0xe5, 0x54, 0x00, 0x9f, 0xe5, 0x20, 0x10, 0x90, 0xe5, 0x50, 0x00, 0x9f, 0xe5,
116 0x08, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe1, 0x00, 0x00, 0x52, 0xe3, 0x02, 0x00, 0x00, 0x1a,
117 0x64, 0x00, 0x1f, 0xe5, 0x64, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x78, 0x00, 0x1f, 0xe5,
118 0x78, 0x10, 0x1f, 0xe5, 0x70, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
119 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
120 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
121 0x00, 0x00, 0x0d, 0xc8, 0x00, 0x00, 0x0b, 0xc8
122};
123unsigned char dualboot_fuzev2[176] = {
124 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
127 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
128 0x2c, 0x30, 0x0f, 0xe5, 0x5c, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
129 0x00, 0x10, 0x80, 0xe5, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x14, 0x80, 0xe5,
130 0x20, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a, 0x60, 0x00, 0x1f, 0xe5,
131 0x60, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0x74, 0x00, 0x1f, 0xe5, 0x74, 0x10, 0x1f, 0xe5,
132 0x6c, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0, 0x01, 0x20, 0x50, 0xe4,
133 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a, 0x01, 0x00, 0x83, 0xe2,
134 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8, 0x00, 0x00, 0x0d, 0xc8
135};
136unsigned char dualboot_clipzip[232] = {
137 0x06, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x24, 0x00, 0x1f, 0xe5, 0x24, 0x10, 0x1f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x18, 0x30, 0x1f, 0xe5,
140 0x01, 0x40, 0x50, 0xe4, 0x01, 0x40, 0x43, 0xe4, 0x00, 0x00, 0x52, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
141 0x2c, 0x30, 0x0f, 0xe5, 0x90, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x18, 0x81, 0xe3,
142 0x00, 0x10, 0x80, 0xe5, 0x84, 0x00, 0x9f, 0xe5, 0x00, 0x11, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3,
143 0x11, 0x00, 0x00, 0x1a, 0x78, 0x00, 0x9f, 0xe5, 0x00, 0x14, 0x90, 0xe5, 0x06, 0x10, 0x81, 0xe3,
144 0x20, 0x10, 0xc1, 0xe3, 0x00, 0x14, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5,
145 0x04, 0x10, 0xa0, 0xe3, 0x10, 0x10, 0x80, 0xe5, 0x32, 0x10, 0xa0, 0xe3, 0x01, 0x10, 0x51, 0xe2,
146 0xfd, 0xff, 0xff, 0x1a, 0x80, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x00, 0x00, 0x1a,
147 0x94, 0x00, 0x1f, 0xe5, 0x94, 0x10, 0x1f, 0xe5, 0x01, 0x00, 0x00, 0xea, 0xa8, 0x00, 0x1f, 0xe5,
148 0xa8, 0x10, 0x1f, 0xe5, 0xa0, 0x30, 0x1f, 0xe5, 0x02, 0x50, 0x83, 0xe2, 0x01, 0x40, 0x43, 0xe0,
149 0x01, 0x20, 0x50, 0xe4, 0x01, 0x20, 0x43, 0xe4, 0x04, 0x00, 0x53, 0xe1, 0xfb, 0xff, 0xff, 0x1a,
150 0x01, 0x00, 0x83, 0xe2, 0x00, 0x20, 0xa0, 0xe3, 0x15, 0xff, 0x2f, 0xe1, 0x14, 0x00, 0x0f, 0xc8,
151 0x00, 0x00, 0x0b, 0xc8, 0x00, 0x00, 0x0d, 0xc8
152};
diff --git a/utils/mkamsboot/dualboot.h b/utils/mkamsboot/dualboot.h
new file mode 100644
index 0000000000..774c35c119
--- /dev/null
+++ b/utils/mkamsboot/dualboot.h
@@ -0,0 +1,12 @@
1/* Generated by bin2c */
2
3extern unsigned char nrv2e_d8[168];
4extern unsigned char dualboot_clip[196];
5extern unsigned char dualboot_e200v2[176];
6extern unsigned char dualboot_c200v2[272];
7extern unsigned char dualboot_m200v4[180];
8extern unsigned char dualboot_fuze[176];
9extern unsigned char dualboot_clipv2[240];
10extern unsigned char dualboot_clipplus[184];
11extern unsigned char dualboot_fuzev2[176];
12extern unsigned char dualboot_clipzip[232];
diff --git a/utils/mkamsboot/dualboot/.gitignore b/utils/mkamsboot/dualboot/.gitignore
new file mode 100644
index 0000000000..a0ed5f4ee1
--- /dev/null
+++ b/utils/mkamsboot/dualboot/.gitignore
@@ -0,0 +1,3 @@
1*.arm-bin
2*.o
3bin2c
diff --git a/utils/mkamsboot/dualboot/Makefile b/utils/mkamsboot/dualboot/Makefile
new file mode 100644
index 0000000000..0aa1e3f7d9
--- /dev/null
+++ b/utils/mkamsboot/dualboot/Makefile
@@ -0,0 +1,61 @@
1CC=gcc
2CROSS_PREFIX?=arm-elf-eabi
3# Edit the following variables (plus copy/paste another set of rules) when
4# adding a new target. mkamsboot.c also needs to be edited to refer to these
5# new images.
6
7BOOTOBJS = nrv2e_d8.o dualboot_clip.o dualboot_e200v2.o dualboot_c200v2.o dualboot_m200v4.o dualboot_fuze.o dualboot_clipv2.o dualboot_clipplus.o dualboot_fuzev2.o dualboot_clipzip.o
8BOOTBINS = nrv2e_d8.arm-bin dualboot_clip.arm-bin dualboot_e200v2.arm-bin dualboot_c200v2.arm-bin dualboot_m200v4.arm-bin dualboot_fuze.arm-bin dualboot_clipv2.arm-bin dualboot_clipplus.arm-bin dualboot_fuzev2.arm-bin dualboot_clipzip.arm-bin
9
10all: ../dualboot.h ../dualboot.c
11
12# Dualboot bootloaders
13
14dualboot_clip.o: dualboot.S
15 $(CROSS_PREFIX)-$(CC) -DSANSA_CLIP -c -o dualboot_clip.o dualboot.S
16
17dualboot_fuze.o: dualboot.S
18 $(CROSS_PREFIX)-$(CC) -DSANSA_FUZE -c -o dualboot_fuze.o dualboot.S
19
20dualboot_e200v2.o: dualboot.S
21 $(CROSS_PREFIX)-$(CC) -DSANSA_E200V2 -c -o dualboot_e200v2.o dualboot.S
22
23dualboot_m200v4.o: dualboot.S
24 $(CROSS_PREFIX)-$(CC) -DSANSA_M200V4 -c -o dualboot_m200v4.o dualboot.S
25
26dualboot_c200v2.o: dualboot.S
27 $(CROSS_PREFIX)-$(CC) -DSANSA_C200V2 -c -o dualboot_c200v2.o dualboot.S
28
29dualboot_clipv2.o: dualboot.S
30 $(CROSS_PREFIX)-$(CC) -DSANSA_CLIPV2 -c -o dualboot_clipv2.o dualboot.S
31
32dualboot_clipplus.o: dualboot.S
33 $(CROSS_PREFIX)-$(CC) -DSANSA_CLIPPLUS -c -o dualboot_clipplus.o dualboot.S
34
35dualboot_fuzev2.o: dualboot.S
36 $(CROSS_PREFIX)-$(CC) -DSANSA_FUZEV2 -c -o dualboot_fuzev2.o dualboot.S
37
38dualboot_clipzip.o: dualboot.S
39 $(CROSS_PREFIX)-$(CC) -DSANSA_CLIPZIP -c -o dualboot_clipzip.o dualboot.S
40
41# Rules for the ucl unpack function
42nrv2e_d8.o: nrv2e_d8.S
43 $(CROSS_PREFIX)-$(CC) -DPURE_THUMB -c -o nrv2e_d8.o nrv2e_d8.S
44
45# Rules for the ARM code embedded in mkamsboot - assemble, link, then extract
46# the binary code and finally convert to .h for building in mkamsboot
47
48%.arm-elf: %.o
49 $(CROSS_PREFIX)-ld -e 0 -Ttext=0 -o $@ $<
50
51%.arm-bin: %.arm-elf
52 $(CROSS_PREFIX)-objcopy -O binary $< $@
53
54../dualboot.c ../dualboot.h: $(BOOTBINS) bin2c
55 ./bin2c ../dualboot $(BOOTBINS)
56
57bin2c: bin2c.c
58 $(CC) -o bin2c bin2c.c
59
60clean:
61 rm -f *~ bin2c $(BOOTBINS) $(BOOTOBJS)
diff --git a/utils/mkamsboot/dualboot/bin2c.c b/utils/mkamsboot/dualboot/bin2c.c
new file mode 100644
index 0000000000..b02af88a4d
--- /dev/null
+++ b/utils/mkamsboot/dualboot/bin2c.c
@@ -0,0 +1,140 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30
31#ifndef O_BINARY
32#define O_BINARY 0
33#endif
34
35static off_t filesize(int fd)
36{
37 struct stat buf;
38
39 fstat(fd,&buf);
40 return buf.st_size;
41}
42
43static void write_cfile(const unsigned char* buf, off_t len, FILE* fp, const char *name)
44{
45 int i;
46
47 fprintf(fp,"unsigned char %s[%ld] = {",name,len);
48
49 for (i=0;i<len;i++) {
50 if ((i % 16) == 0) {
51 fprintf(fp,"\n ");
52 }
53 if (i == (len-1)) {
54 fprintf(fp,"0x%02x",buf[i]);
55 } else if ((i % 16) == 15) {
56 fprintf(fp,"0x%02x,",buf[i]);
57 } else {
58 fprintf(fp,"0x%02x, ",buf[i]);
59 }
60 }
61 fprintf(fp,"\n};\n");
62}
63
64int main (int argc, char* argv[])
65{
66 char* cname;
67 int i;
68 FILE *cfile, *hfile;
69 char cfilename[256], hfilename[256];
70
71 if (argc < 3) {
72 fprintf(stderr,"Usage: bin2c cname file1 [file2 [file3 ...]]\n");
73 return 1;
74 }
75
76 cname=argv[1];
77
78 snprintf(cfilename,256,"%s.c",cname);
79 cfile = fopen(cfilename,"w+");
80 if (cfile == NULL) {
81 fprintf(stderr,"Couldn't open %s\n",cfilename);
82 return 2;
83 }
84
85 snprintf(hfilename,256,"%s.h",cname);
86 hfile = fopen(hfilename,"w+");
87 if (hfile == NULL) {
88 fprintf(stderr,"Couldn't open %s\n",hfilename);
89 fclose(cfile);
90 return 3;
91 }
92
93 fprintf(cfile,"/* Generated by bin2c */\n\n");
94 fprintf(cfile,"#include \"%s\"\n\n", basename(hfilename));
95 fprintf(hfile,"/* Generated by bin2c */\n\n");
96
97 for(i=0; i < argc - 2; i++) {
98 unsigned char* buf;
99 off_t len;
100 off_t orig_len;
101 char *ext;
102 char *array = argv[2+i];
103
104 int fd = open(array,O_RDONLY|O_BINARY);
105 if (fd < 0) {
106 fprintf(stderr,"Can not open %s\n",argv[2+i]);
107 fclose(cfile);
108 fclose(hfile);
109 return 4;
110 }
111
112 orig_len = filesize(fd);
113 /* pad to 32bit */
114 len = (orig_len + 3) & ~3;
115
116 buf = malloc(len);
117 if (read(fd,buf,orig_len) < orig_len) {
118 fprintf(stderr,"Short read, aborting\n");
119 return 5;
120 }
121
122 /* pad to 32bit with zeros */
123 if (len > orig_len)
124 memset(buf+orig_len, 0, len-orig_len);
125
126 /* remove file extension */
127 ext = strchr (array, '.');
128 if (ext != NULL)
129 *ext = '\0';
130 write_cfile (buf, len, cfile, array);
131 fprintf(hfile,"extern unsigned char %s[%ld];\n",array,len);
132
133 close(fd);
134 }
135
136 fclose(cfile);
137 fclose(hfile);
138
139 return 0;
140}
diff --git a/utils/mkamsboot/dualboot/dualboot.S b/utils/mkamsboot/dualboot/dualboot.S
new file mode 100644
index 0000000000..4e4dbe5505
--- /dev/null
+++ b/utils/mkamsboot/dualboot/dualboot.S
@@ -0,0 +1,307 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 Rafaël Carré
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22.text
23
24/* AS3525 hardware registers */
25.set GPIOA, 0xC80B0000
26.set GPIOB, 0xC80C0000
27.set GPIOC, 0xC80D0000
28.set GPIOD, 0xC80E0000
29.set CGU_PROC, 0xC80F0010
30.set CGU_PERI, 0xC80F0014
31.set CGU_DBOP, 0xC80F0038
32.set CCU_IO, 0xC810000C
33.set DBOP, 0xC8120000
34.set I2C_BASE, 0xC8070000
35.set I2C_DATA, 0x00
36.set I2C_SLAD0, 0x04
37.set I2C_CNTRL, 0x0c
38.set I2C_DACNT, 0x10
39.set I2C_CPSR0, 0x1c
40.set I2C_CPSR1, 0x20
41.set I2C_IMR, 0x24
42.set I2C_SR, 0x30
43.set I2C_SADDR, 0x44
44.set AS3514_I2C_ADDR, 0x46
45.set AS3514_IRQ_ENRD0, 0x25
46.set PCLK, 24000000
47.set I2C_CLK, 400000
48.set I2C_PRESCALER, ((PCLK + I2C_CLK -1) / I2C_CLK)
49.set I2C_PRESCALER_LOW, (I2C_PRESCALER & 0xff)
50.set I2C_PRESCALER_HIGH, (I2C_PRESCALER >> 8)
51#if I2C_PRESCALER_HIGH > 3
52#error i2c prescaler too big!
53#endif
54
55 b start @ skip our data
56
57/* These values are filled in by mkamsboot - don't move them from offset 0x4 */
58
59uclunpack_end: .word 0 /* End of the ucl_unpack function */
60uclunpack_size: .word 0 /* Size in bytes of the ucl_unpack function */
61
62ucl_of_end: .word 0 /* End of the ucl-compressed OF image */
63ucl_of_size: .word 0 /* Size in bytes of the compressed OF image */
64
65ucl_rb_end: .word 0 /* End of the ucl-compressed RB image */
66ucl_rb_size: .word 0 /* Size in bytes of the compressed RB image */
67
68ucl_dest: .word 0 /* End of our destination buffer (end of memory) */
69
70start:
71 /* First copy the UCL unpack function to the end of RAM */
72 ldr r0, uclunpack_end /* Source */
73 ldr r1, uclunpack_size /* Source length */
74 sub r2, r0, r1 /* Source start - 1*/
75
76 ldr r3, ucl_dest /* Destination end */
77
78uclcopy:
79 ldrb r4, [r0], #-1
80 strb r4, [r3], #-1
81 cmp r2, r0
82 bne uclcopy
83
84 /* store the new destination buffer */
85 str r3, ucl_dest
86
87 /* enable gpio clock */
88 ldr r0, =CGU_PERI
89 ldr r1, [r0]
90 orr r1, r1, #(1<<16)
91 str r1, [r0]
92
93 /* Here are model specific tests for dual boot (test left button) */
94
95#ifdef SANSA_CLIP
96.set row, (1<<5) /* enable output on C5 */
97.set col, (1<<0) /* read keyscan column B0 */
98
99 ldr r0, =GPIOC
100 mov r1, #row
101 str r1, [r0, #0x400]
102 str r1, [r0, #(4*row)]
103
104 ldr r0, =GPIOB
105 mov r1, #0
106 str r1, [r0, #0x400]
107 ldr r1, [r0, #(4*col)]
108
109 cmp r1, #0
110 bne boot_of
111#elif defined(SANSA_CLIPV2)
112.set row, (1<<4) /* enable output on D4 */
113.set col, (1<<0) /* read keyscan column D0 */
114
115 ldr r0, =CCU_IO
116 ldr r1, [r0]
117 bic r1, r1, #(3<<2) @ XPD works as general purpose IO
118 str r1, [r0]
119
120 ldr r0, =GPIOD
121 mov r1, #((1<<5)|(1<<4)|(1<<3)) /* all rows as output */
122 str r1, [r0, #0x400]
123
124 /* all rows high */
125 mov r1, #(1<<3)
126 str r1, [r0, #(4*(1<<3))]
127 mov r1, #(1<<4)
128 str r1, [r0, #(4*(1<<4))]
129 mov r1, #(1<<5)
130 str r1, [r0, #(4*(1<<5))]
131
132 mov r1, #0 /* button row low */
133 str r1, [r0, #(4*row)]
134
135 mov r1, #5 /* small delay */
1361: subs r1, r1, #1
137 bne 1b
138
139 ldr r1, [r0, #(4*col)]
140
141 cmp r1, #0
142 beq boot_of
143#elif defined(SANSA_E200V2) || defined(SANSA_FUZE)
144 ldr r0, =GPIOC
145 mov r1, #0
146 str r1, [r0, #0x400]
147 ldr r1, [r0, #0x20] /* read pin C3 */
148
149 cmp r1, #0 /* C3 = #0 means button pressed */
150 beq boot_of
151
152#elif defined(SANSA_FUZEV2)
153 ldr r0, =GPIOC
154 mov r1, #0
155 str r1, [r0, #0x400]
156 ldr r1, [r0, #0x20] /* read pin C3 */
157
158 cmp r1, #0 /* C3 != #0 means button pressed */
159 bne boot_of
160
161#elif defined(SANSA_CLIPPLUS)
162 @ read pins
163 ldr r0, =GPIOC
164 ldr r1, [r0, #4*(1<<3)] @ read pin C3 "|<<"
165
166 ldr r0, =GPIOA
167 ldr r2, [r0, #4*(1<<1)] @ read pin A1 "Home"
168
169 orr r2, r2, r1 @ c3 || A1
170
171 cmp r2, #0 @ test input from pins
172 bne boot_of @ branch directly to OF if either pin high
173
174#elif defined(SANSA_CLIPZIP)
175 @ read pins
176 ldr r0, =GPIOA
177 ldr r1, [r0, #4*(1<<6)] @ read GPIO A6 "vol-"
178
179 cmp r1, #0 @ test input from pins
180 bne boot_of @ branch directly to OF if either pin high
181
182 ldr r0, =GPIOC
183
184 ldr r1, [r0, #0x400]
185 orr r1, r1, #((1<<1)|(1<<2)) @ output
186 bic r1, r1, #(1<<5) @ input
187 str r1, [r0, #0x400]
188
189 mov r1, #0
190 str r1, [r0, #4*(1<<1)] @ zero C1
191 mov r1, #(1<<2)
192 str r1, [r0, #4*(1<<2)] @ set C2
193
194 mov r1, #50 /* small delay */
1951: subs r1, r1, #1
196 bne 1b
197
198 ldr r1, [r0, #4*(1<<5)] @ read C5 = left
199
200 cmp r1, #0
201 bne boot_of
202
203#elif defined(SANSA_C200V2)
204.set BUTTON_LEFT, (1<< 2)
205.set BUTTON_DOWN, (1<< 3)
206.set BUTTON_SELECT, (1<< 4)
207.set BUTTON_UP, (1<< 5)
208.set BUTTON_RIGHT, (1<< 6)
209.set BUTTON_HOLD, (1<<12)
210
211 ldr r0, =CGU_DBOP
212 mov r1, #(1<<3) @ DBOP freq = PCLK, clock enabled
213 str r1, [r0]
214
215 @ AFSEL needs to be set for this to work
216 ldr r2, =GPIOB
217 mov r1, #0xc
218 str r1, [r2, #0x420] @ GPIOB_AFSEL
219 ldr r2, =GPIOC
220 mov r1, #0xff
221 str r1, [r2, #0x420] @ GPIOC_AFSEL
222
223 ldr r0, =DBOP
224 @ TIMPOL doesn't matter here since we don't need
225 @ the control signals.
226
227 @ 16 bit data width
228 @ enable write
229 @ tri-state output
230 ldr r1, =0x00091000
231 str r1, [r0, #8] @ DBOP_CTRL
232
233 ldr r1, =0xf0ff @ precharge
234 str r1, [r0, #0x10] @ DBOP_DOUT
235
2362: ldr r1, [r0, #0xc] @ DOBP_STAT
237 ands r1, r1, #(1<<10)
238 beq 2b @ make sure fifo is empty
239
240 @ 16 bit data width
241 @ start read
242 @ tri-state output
243 @ strobe time 31
244 ldr r1, =0x0008901f
245 str r1, [r0, #8] @ DBOP_CTRL
246
2473: ldr r1, [r0, #0xc] @ DOBP_STAT
248 ands r1, r1, #(1<<16)
249 beq 3b @ wait for valid data
250
251 ldrh r1, [r0, #0x14] @ DBOP_DIN
252
253 tst r1, #BUTTON_LEFT @ boot of?
254 beq boot_of
255#elif defined(SANSA_M200V4)
256.set row, (1<<5) /* enable output on A5 */
257.set col, (1<<0) /* read keyscan column A0 */
258
259 ldr r0, =GPIOA
260 mov r1, #row
261 str r1, [r0, #0x400]
262 str r1, [r0, #(4*row)]
263
264 ldr r2, [r0, #(4*col)]
265
266 /* check value read (1 means button pressed) */
267 cmp r2, #0
268 bne boot_of
269#else
270 #error No target-specific key check defined!
271#endif
272
273 /* The dualboot button was not held, so we boot rockbox */
274 ldr r0, ucl_rb_end /* Address of compressed image */
275 ldr r1, ucl_rb_size /* Compressed size */
276 b decompress
277
278boot_of:
279 ldr r0, ucl_of_end /* Address of compressed image */
280 ldr r1, ucl_of_size /* Compressed size */
281
282
283decompress:
284 /* At this point: */
285 /* r0 = source_end for UCL image to copy */
286 /* r1 = size of UCL image to copy */
287
288 ldr r3, ucl_dest
289 add r5, r3, #2 /* r5 is entry point of copy of uclunpack */
290 /* function, plus one (for thumb mode */
291
292 sub r4, r3, r1 /* r4 := destination_start - 1 */
293
294fw_copy:
295 ldrb r2, [r0], #-1
296 strb r2, [r3], #-1
297 cmp r3, r4 /* Stop when we reached dest_start-1 */
298 bne fw_copy
299
300 /* Call the ucl decompress function, which will branch to 0x0 */
301 /* on completion */
302 add r0, r3, #1 /* r0 := Start of compressed image */
303 /* r1 already contains compressed size */
304 mov r2, #0 /* r2 := Destination for unpacking */
305 bx r5 /* Branch to uclunpack, switching to thumb */
306
307 /* never reached : uclunpack will branch to the reset vector (0x0) */
diff --git a/utils/mkamsboot/dualboot/nrv2e_d8.S b/utils/mkamsboot/dualboot/nrv2e_d8.S
new file mode 100644
index 0000000000..d24fb94b2a
--- /dev/null
+++ b/utils/mkamsboot/dualboot/nrv2e_d8.S
@@ -0,0 +1,198 @@
1/* arm_nrv2e_d8.S -- ARM decompressor for NRV2E
2
3 This file is part of the UPX executable compressor.
4
5 Copyright (C) 1996-2008 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 1996-2008 Laszlo Molnar
7 Copyright (C) 2000-2008 John F. Reiser
8 All Rights Reserved.
9
10 UPX and the UCL library are free software; you can redistribute them
11 and/or modify them under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; see the file COPYING.
22 If not, write to the Free Software Foundation, Inc.,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 Markus F.X.J. Oberhumer Laszlo Molnar
26 <markus@oberhumer.com> <ml1050@users.sourceforge.net>
27
28 John F. Reiser
29 <jreiser@users.sourceforge.net>
30*/
31#define SAFE 0 /* 1 for src+dst bounds checking: cost 40 bytes */
32
33#define src r0
34#define len r1 /* overlaps 'cnt' */
35#define dst r2
36#define tmp r3
37#define bits r4
38#define off r5
39#define wrnk r6 /* 0x500 M2_MAX_OFFSET before "wrinkle" */
40#define srclim r7
41#if 1==SAFE /*{*/
42#define dstlim r12
43#endif /*}*/
44
45#define cnt r1 /* overlaps 'len' while reading an offset */
46
47#if 1==SAFE /*{*/
48#define CHECK_SRC cmp src,srclim; bhs bad_src_n2e
49#define CHECK_DST cmp dst,dstlim; bhs bad_dst_n2e
50#else /*}{*/
51#define CHECK_SRC /*empty*/
52#define CHECK_DST /*empty*/
53#endif /*}*/
54
55#if 0 /*{ DEBUG only: check newly-decompressed against original dst */
56#define CHECK_BYTE \
57 push {wrnk}; \
58 ldrb wrnk,[dst]; \
59 cmp wrnk,tmp; beq 0f; bkpt; \
600: pop {wrnk}
61#else /*}{*/
62#define CHECK_BYTE /*empty*/
63#endif /*}*/
64
65/* "mov lr,pc; bxx ..." implements conditional subroutine call
66 *
67 * NOTE: the lsb will not be set, so you MUST NOT use 'bx lr' to return,
68 * else the T bit will be cleared and processor will go in ARM state */
69#define GETBIT add bits,bits; mov lr,pc; beq get1_n2e
70
71#define getnextb(reg) GETBIT; adc reg,reg
72#define jnextb0 GETBIT; bcc
73#define jnextb1 GETBIT; bcs
74
75#ifndef PURE_THUMB
76ucl_nrv2e_decompress_8: .globl ucl_nrv2e_decompress_8 @ ARM mode
77 .type ucl_nrv2e_decompress_8, %function
78/* error = (*)(char const *src, int len_src, char *dst, int *plen_dst)
79 Actual decompressed length is stored through plen_dst.
80 For SAFE mode: at call, *plen_dst must be allowed length of output buffer.
81*/
82 adr r12,1+.thumb_nrv2e_d8; bx r12 @ enter THUMB mode
83#endif
84 .code 16 @ THUMB mode
85 .thumb_func
86
87.thumb_nrv2e_d8:
88#if 0
89 push {r2,r3, r4,r5,r6,r7, lr}
90#define sp_DST0 0 /* stack offset of original dst */
91#endif
92 add srclim,len,src @ srclim= eof_src;
93#if 1==SAFE /*{*/
94 ldr tmp,[r3] @ len_dst
95 add tmp,dst
96 mov dstlim,tmp
97#endif /*}*/
98 mov bits,#1; neg off,bits @ off= -1 initial condition
99 lsl bits,#31 @ 1<<31: refill next time
100 mov wrnk,#5
101 lsl wrnk,#8 @ 0x500 @ nrv2e M2_MAX_OFFSET
102 b top_n2e
103
104#if 1==SAFE /*{*/
105bad_dst_n2e: # return value will be 2
106 add src,srclim,#1
107bad_src_n2e: # return value will be 1
108 add src,#1
109#endif /*}*/
110eof_n2e:
111#if 0
112 pop {r3,r4} @ r3= orig_dst; r4= plen_dst
113 sub src,srclim @ 0 if actual src length equals expected length
114 sub dst,r3 @ actual dst length
115 str dst,[r4]
116 pop {r4,r5,r6,r7 /*,pc*/}
117 pop {r1}; bx r1 @ "pop {,pc}" fails return to ARM mode on ARMv4T
118#else
119 mov r0, #0
120 bx r0 /* Branch to 0x0, switch to ARM mode */
121#endif
122
123get1_n2e: @ In: Carry set [from adding 0x80000000 (1<<31) to itself]
124 ldrb bits,[src] @ zero-extend next byte
125 adc bits,bits @ double and insert CarryIn as low bit
126 CHECK_SRC
127 add src,#1
128 lsl bits,#24 @ move to top byte, and set CarryOut from old bit 8
129 /* NOTE: the following instruction will not work on ARMv7+, because
130 * it will update the T bit and return into ARM state */
131 mov pc,lr @ return, stay in current (THUMB) mode
132
133lit_n2e:
134 CHECK_SRC; ldrb tmp,[src]; add src,#1
135 CHECK_BYTE
136 CHECK_DST; strb tmp,[dst]; add dst,#1
137top_n2e:
138 jnextb1 lit_n2e
139 mov cnt,#1; b getoff_n2e
140
141off_n2e:
142 sub cnt,#1
143 getnextb(cnt)
144getoff_n2e:
145 getnextb(cnt)
146 jnextb0 off_n2e
147
148 sub tmp,cnt,#3 @ set Carry
149 mov len,#0 @ Carry unaffected
150 blo offprev_n2e @ cnt was 2; tests Carry only
151 lsl tmp,#8
152 CHECK_SRC; ldrb off,[src]; add src,#1 @ low 7+1 bits
153 orr off,tmp
154 mvn off,off; beq eof_n2e @ off= ~off
155 asr off,#1; bcs lenlast_n2e
156 b lenmore_n2e
157
158offprev_n2e:
159 jnextb1 lenlast_n2e
160lenmore_n2e:
161 mov len,#1
162 jnextb1 lenlast_n2e
163len_n2e:
164 getnextb(len)
165 jnextb0 len_n2e
166 add len,#6-2
167 b gotlen_n2e
168
169lenlast_n2e:
170 getnextb(len) @ 0,1,2,3
171 add len,#2
172gotlen_n2e: @ 'cmn': add the inputs, set condition codes, discard the sum
173 cmn wrnk,off; bcs near_n2e @ within M2_MAX_OFFSET
174 add len,#1 @ too far away, so minimum match length is 3
175near_n2e:
176#if 1==SAFE /*{*/
177 ldr tmp,[sp,#sp_DST0]
178 sub tmp,dst
179 sub tmp,off; bhi bad_dst_n2e @ reaching back too far
180
181 add tmp,dst,cnt
182 cmp tmp,dstlim; bhi bad_dst_n2e @ too much output
183#endif /*}*/
184 ldrb tmp,[dst] @ force cacheline allocate
185copy_n2e:
186 ldrb tmp,[dst,off]
187 CHECK_BYTE
188 strb tmp,[dst]; add dst,#1
189 sub len,#1; bne copy_n2e
190 b top_n2e
191
192#ifndef PURE_THUMB
193 .size ucl_nrv2e_decompress_8, .-ucl_nrv2e_decompress_8
194#endif
195
196/*
197vi:ts=8:et:nowrap
198 */
diff --git a/utils/mkamsboot/main.c b/utils/mkamsboot/main.c
new file mode 100644
index 0000000000..cf40811ace
--- /dev/null
+++ b/utils/mkamsboot/main.c
@@ -0,0 +1,174 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * mkamsboot - a tool for merging bootloader code into an Sansa V2
11 * (AMS) firmware file
12 *
13 * Copyright (C) 2008 Dave Chapman
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <stdint.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <string.h>
33
34#include <ucl/ucl.h>
35
36#include "mkamsboot.h"
37
38/* Header for ARM code binaries */
39#include "dualboot.h"
40
41/* Win32 compatibility */
42#ifndef O_BINARY
43#define O_BINARY 0
44#endif
45
46/* standalone executable */
47int main(int argc, char* argv[])
48{
49 char *infile, *bootfile, *outfile;
50 int fdout;
51 off_t len;
52 uint32_t n;
53 unsigned char* buf;
54 int firmware_size;
55 int bootloader_size;
56 unsigned char* of_packed;
57 int of_packedsize;
58 unsigned char* rb_packed;
59 int rb_packedsize;
60 int patchable;
61 int totalsize;
62 int model;
63 char errstr[200];
64 struct md5sums sum;
65 char md5sum[33]; /* 32 digits + \0 */
66
67 sum.md5 = md5sum;
68
69/* VERSION comes frome the Makefile */
70 fprintf(stderr,
71"mkamsboot Version " VERSION "\n"
72"This is free software; see the source for copying conditions. There is NO\n"
73"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
74"\n");
75
76 if(argc != 4) {
77 printf("Usage: mkamsboot <firmware file> <boot file> <output file>\n");
78 return 1;
79 }
80
81 infile = argv[1];
82 bootfile = argv[2];
83 outfile = argv[3];
84
85 /* Load bootloader file */
86 rb_packed = load_rockbox_file(bootfile, &model, &bootloader_size,
87 &rb_packedsize, errstr, sizeof(errstr));
88 if (rb_packed == NULL) {
89 fprintf(stderr, "%s", errstr);
90 fprintf(stderr, "[ERR] Could not load %s\n", bootfile);
91 return 1;
92 }
93
94 /* Load original firmware file */
95 buf = load_of_file(infile, model, &len, &sum,
96 &firmware_size, &of_packed, &of_packedsize, errstr, sizeof(errstr));
97
98 if (buf == NULL) {
99 free(rb_packed);
100 fprintf(stderr, "%s", errstr);
101 fprintf(stderr, "[ERR] Could not load %s\n", infile);
102 return 1;
103 }
104
105 fprintf(stderr, "[INFO] Original firmware MD5 checksum match\n");
106 fprintf(stderr, "[INFO] Model: Sansa %s v%d - Firmware version: %s\n",
107 ams_identity[sum.model].model_name,
108 ams_identity[sum.model].hw_revision, sum.version);
109
110
111 printf("[INFO] Firmware patching has begun !\n\n");
112
113 fprintf(stderr, "[INFO] Original firmware size: %8d bytes\n",
114 firmware_size);
115 fprintf(stderr, "[INFO] Packed OF size: %8d bytes\n",
116 of_packedsize);
117 fprintf(stderr, "[INFO] Bootloader size: %8d bytes\n",
118 bootloader_size);
119 fprintf(stderr, "[INFO] Packed bootloader size: %8d bytes\n",
120 rb_packedsize);
121 fprintf(stderr, "[INFO] Dual-boot function size: %8d bytes\n",
122 ams_identity[sum.model].bootloader_size);
123 fprintf(stderr, "[INFO] UCL unpack function size: %8zu bytes\n",
124 sizeof(nrv2e_d8));
125 fprintf(stderr, "[INFO] Original firmware version: %8u bytes\n",
126 0x200);
127
128 patchable = check_sizes(sum.model, rb_packedsize, bootloader_size,
129 of_packedsize, firmware_size, &totalsize, errstr, sizeof(errstr));
130
131 fprintf(stderr, "[INFO] Total size of new image: %8d bytes\n", totalsize);
132
133 if (!patchable) {
134 fprintf(stderr, "%s", errstr);
135 free(buf);
136 free(of_packed);
137 free(rb_packed);
138 return 1;
139 }
140
141 patch_firmware(sum.model, ams_identity[sum.model].fw_revision,
142 firmware_size, buf, len, of_packed, of_packedsize, rb_packed,
143 rb_packedsize);
144
145 /* Write the new firmware */
146 fdout = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
147
148 if (fdout < 0) {
149 fprintf(stderr, "[ERR] Could not open %s for writing\n", outfile);
150 free(buf);
151 free(of_packed);
152 free(rb_packed);
153 return 1;
154 }
155
156 n = write(fdout, buf, len);
157
158 if (n != (unsigned)len) {
159 fprintf(stderr, "[ERR] Could not write firmware file\n");
160 free(buf);
161 free(of_packed);
162 free(rb_packed);
163 return 1;
164 }
165
166 close(fdout);
167 free(buf);
168 free(of_packed);
169 free(rb_packed);
170 fprintf(stderr, "\n[INFO] Patching succeeded!\n");
171
172 return 0;
173}
174
diff --git a/utils/mkamsboot/md5.c b/utils/mkamsboot/md5.c
new file mode 100644
index 0000000000..530d8df15a
--- /dev/null
+++ b/utils/mkamsboot/md5.c
@@ -0,0 +1,246 @@
1/*
2 * RFC 1321 compliant MD5 implementation
3 *
4 * Copyright (C) 2001-2003 Christophe Devine
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <string.h>
22
23#include "md5.h"
24
25#define GET_UINT32(n,b,i) \
26{ \
27 (n) = ( (uint32) (b)[(i) ] ) \
28 | ( (uint32) (b)[(i) + 1] << 8 ) \
29 | ( (uint32) (b)[(i) + 2] << 16 ) \
30 | ( (uint32) (b)[(i) + 3] << 24 ); \
31}
32
33#define PUT_UINT32(n,b,i) \
34{ \
35 (b)[(i) ] = (uint8) ( (n) ); \
36 (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
37 (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
38 (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
39}
40
41void md5_starts( md5_context *ctx )
42{
43 ctx->total[0] = 0;
44 ctx->total[1] = 0;
45
46 ctx->state[0] = 0x67452301;
47 ctx->state[1] = 0xEFCDAB89;
48 ctx->state[2] = 0x98BADCFE;
49 ctx->state[3] = 0x10325476;
50}
51
52void md5_process( md5_context *ctx, uint8 data[64] )
53{
54 uint32 X[16], A, B, C, D;
55
56 GET_UINT32( X[0], data, 0 );
57 GET_UINT32( X[1], data, 4 );
58 GET_UINT32( X[2], data, 8 );
59 GET_UINT32( X[3], data, 12 );
60 GET_UINT32( X[4], data, 16 );
61 GET_UINT32( X[5], data, 20 );
62 GET_UINT32( X[6], data, 24 );
63 GET_UINT32( X[7], data, 28 );
64 GET_UINT32( X[8], data, 32 );
65 GET_UINT32( X[9], data, 36 );
66 GET_UINT32( X[10], data, 40 );
67 GET_UINT32( X[11], data, 44 );
68 GET_UINT32( X[12], data, 48 );
69 GET_UINT32( X[13], data, 52 );
70 GET_UINT32( X[14], data, 56 );
71 GET_UINT32( X[15], data, 60 );
72
73#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
74
75#define P(a,b,c,d,k,s,t) \
76{ \
77 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
78}
79
80 A = ctx->state[0];
81 B = ctx->state[1];
82 C = ctx->state[2];
83 D = ctx->state[3];
84
85#define F(x,y,z) (z ^ (x & (y ^ z)))
86
87 P( A, B, C, D, 0, 7, 0xD76AA478 );
88 P( D, A, B, C, 1, 12, 0xE8C7B756 );
89 P( C, D, A, B, 2, 17, 0x242070DB );
90 P( B, C, D, A, 3, 22, 0xC1BDCEEE );
91 P( A, B, C, D, 4, 7, 0xF57C0FAF );
92 P( D, A, B, C, 5, 12, 0x4787C62A );
93 P( C, D, A, B, 6, 17, 0xA8304613 );
94 P( B, C, D, A, 7, 22, 0xFD469501 );
95 P( A, B, C, D, 8, 7, 0x698098D8 );
96 P( D, A, B, C, 9, 12, 0x8B44F7AF );
97 P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
98 P( B, C, D, A, 11, 22, 0x895CD7BE );
99 P( A, B, C, D, 12, 7, 0x6B901122 );
100 P( D, A, B, C, 13, 12, 0xFD987193 );
101 P( C, D, A, B, 14, 17, 0xA679438E );
102 P( B, C, D, A, 15, 22, 0x49B40821 );
103
104#undef F
105
106#define F(x,y,z) (y ^ (z & (x ^ y)))
107
108 P( A, B, C, D, 1, 5, 0xF61E2562 );
109 P( D, A, B, C, 6, 9, 0xC040B340 );
110 P( C, D, A, B, 11, 14, 0x265E5A51 );
111 P( B, C, D, A, 0, 20, 0xE9B6C7AA );
112 P( A, B, C, D, 5, 5, 0xD62F105D );
113 P( D, A, B, C, 10, 9, 0x02441453 );
114 P( C, D, A, B, 15, 14, 0xD8A1E681 );
115 P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
116 P( A, B, C, D, 9, 5, 0x21E1CDE6 );
117 P( D, A, B, C, 14, 9, 0xC33707D6 );
118 P( C, D, A, B, 3, 14, 0xF4D50D87 );
119 P( B, C, D, A, 8, 20, 0x455A14ED );
120 P( A, B, C, D, 13, 5, 0xA9E3E905 );
121 P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
122 P( C, D, A, B, 7, 14, 0x676F02D9 );
123 P( B, C, D, A, 12, 20, 0x8D2A4C8A );
124
125#undef F
126
127#define F(x,y,z) (x ^ y ^ z)
128
129 P( A, B, C, D, 5, 4, 0xFFFA3942 );
130 P( D, A, B, C, 8, 11, 0x8771F681 );
131 P( C, D, A, B, 11, 16, 0x6D9D6122 );
132 P( B, C, D, A, 14, 23, 0xFDE5380C );
133 P( A, B, C, D, 1, 4, 0xA4BEEA44 );
134 P( D, A, B, C, 4, 11, 0x4BDECFA9 );
135 P( C, D, A, B, 7, 16, 0xF6BB4B60 );
136 P( B, C, D, A, 10, 23, 0xBEBFBC70 );
137 P( A, B, C, D, 13, 4, 0x289B7EC6 );
138 P( D, A, B, C, 0, 11, 0xEAA127FA );
139 P( C, D, A, B, 3, 16, 0xD4EF3085 );
140 P( B, C, D, A, 6, 23, 0x04881D05 );
141 P( A, B, C, D, 9, 4, 0xD9D4D039 );
142 P( D, A, B, C, 12, 11, 0xE6DB99E5 );
143 P( C, D, A, B, 15, 16, 0x1FA27CF8 );
144 P( B, C, D, A, 2, 23, 0xC4AC5665 );
145
146#undef F
147
148#define F(x,y,z) (y ^ (x | ~z))
149
150 P( A, B, C, D, 0, 6, 0xF4292244 );
151 P( D, A, B, C, 7, 10, 0x432AFF97 );
152 P( C, D, A, B, 14, 15, 0xAB9423A7 );
153 P( B, C, D, A, 5, 21, 0xFC93A039 );
154 P( A, B, C, D, 12, 6, 0x655B59C3 );
155 P( D, A, B, C, 3, 10, 0x8F0CCC92 );
156 P( C, D, A, B, 10, 15, 0xFFEFF47D );
157 P( B, C, D, A, 1, 21, 0x85845DD1 );
158 P( A, B, C, D, 8, 6, 0x6FA87E4F );
159 P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
160 P( C, D, A, B, 6, 15, 0xA3014314 );
161 P( B, C, D, A, 13, 21, 0x4E0811A1 );
162 P( A, B, C, D, 4, 6, 0xF7537E82 );
163 P( D, A, B, C, 11, 10, 0xBD3AF235 );
164 P( C, D, A, B, 2, 15, 0x2AD7D2BB );
165 P( B, C, D, A, 9, 21, 0xEB86D391 );
166
167#undef F
168
169 ctx->state[0] += A;
170 ctx->state[1] += B;
171 ctx->state[2] += C;
172 ctx->state[3] += D;
173}
174
175void md5_update( md5_context *ctx, uint8 *input, uint32 length )
176{
177 uint32 left, fill;
178
179 if( ! length ) return;
180
181 left = ctx->total[0] & 0x3F;
182 fill = 64 - left;
183
184 ctx->total[0] += length;
185 ctx->total[0] &= 0xFFFFFFFF;
186
187 if( ctx->total[0] < length )
188 ctx->total[1]++;
189
190 if( left && length >= fill )
191 {
192 memcpy( (void *) (ctx->buffer + left),
193 (void *) input, fill );
194 md5_process( ctx, ctx->buffer );
195 length -= fill;
196 input += fill;
197 left = 0;
198 }
199
200 while( length >= 64 )
201 {
202 md5_process( ctx, input );
203 length -= 64;
204 input += 64;
205 }
206
207 if( length )
208 {
209 memcpy( (void *) (ctx->buffer + left),
210 (void *) input, length );
211 }
212}
213
214static uint8 md5_padding[64] =
215{
216 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
220};
221
222void md5_finish( md5_context *ctx, uint8 digest[16] )
223{
224 uint32 last, padn;
225 uint32 high, low;
226 uint8 msglen[8];
227
228 high = ( ctx->total[0] >> 29 )
229 | ( ctx->total[1] << 3 );
230 low = ( ctx->total[0] << 3 );
231
232 PUT_UINT32( low, msglen, 0 );
233 PUT_UINT32( high, msglen, 4 );
234
235 last = ctx->total[0] & 0x3F;
236 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
237
238 md5_update( ctx, md5_padding, padn );
239 md5_update( ctx, msglen, 8 );
240
241 PUT_UINT32( ctx->state[0], digest, 0 );
242 PUT_UINT32( ctx->state[1], digest, 4 );
243 PUT_UINT32( ctx->state[2], digest, 8 );
244 PUT_UINT32( ctx->state[3], digest, 12 );
245}
246
diff --git a/utils/mkamsboot/md5.h b/utils/mkamsboot/md5.h
new file mode 100644
index 0000000000..71fa395548
--- /dev/null
+++ b/utils/mkamsboot/md5.h
@@ -0,0 +1,25 @@
1#ifndef _MD5_H
2#define _MD5_H
3
4#ifndef uint8
5#define uint8 unsigned char
6#endif
7
8#ifndef uint32
9#define uint32 unsigned long int
10#endif
11
12typedef struct
13{
14 uint32 total[2];
15 uint32 state[4];
16 uint8 buffer[64];
17}
18md5_context;
19
20void md5_starts( md5_context *ctx );
21void md5_update( md5_context *ctx, uint8 *input, uint32 length );
22void md5_finish( md5_context *ctx, uint8 digest[16] );
23
24#endif /* md5.h */
25
diff --git a/utils/mkamsboot/mkamsboot.c b/utils/mkamsboot/mkamsboot.c
new file mode 100644
index 0000000000..09eb15ee43
--- /dev/null
+++ b/utils/mkamsboot/mkamsboot.c
@@ -0,0 +1,595 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * mkamsboot.c - a tool for merging bootloader code into an Sansa V2
11 * (AMS) firmware file
12 *
13 * Copyright (C) 2008 Dave Chapman
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25/*
26
27Insert a Rockbox bootloader into a Sansa AMS original firmware file.
28
29Layout of a Sansa AMS original firmware file:
30
31 ---------------------- 0x0
32| HEADER |
33|----------------------| 0x400
34| FIRMWARE BLOCK | (contains the OF version on some fuzev2 firmwares
35|----------------------| 0x600
36| FIRMWARE BLOCK |
37|----------------------| 0x400 + firmware block size
38| LIBRARIES/DATA |
39 ---------------------- END
40
41We replace the main firmware block while preserving the potential OF version
42(bytes 0x600..0x400+firmware_size) as follows:
43
44
45 ---------------------- 0x0
46| |
47| Dual-boot code |
48| |
49|----------------------|
50| EMPTY SPACE |
51|----------------------|
52| |
53| compressed RB image |
54| |
55|----------------------|
56| |
57| compressed OF image |
58| |
59|----------------------|
60| UCL unpack function |
61 ----------------------
62
63This entire block fits into the space previously occupied by the main
64firmware block - the space saved by compressing the OF image is used
65to store the compressed version of the Rockbox bootloader.
66
67On version 1 firmwares, the OF image is typically about 120KB, which allows
68us to store a Rockbox bootloader with an uncompressed size of about 60KB-70KB.
69Version 2 firmwares are bigger and are stored in SDRAM (instead of IRAM).
70In both cases, the RAM we are using is mapped at offset 0x0.
71
72mkamsboot then corrects the checksums and writes a new legal firmware
73file which can be installed on the device.
74
75When the Sansa device boots, this firmware block is loaded to RAM at
76address 0x0 and executed.
77
78Firstly, the dual-boot code will copy the UCL unpack function to the
79end of RAM.
80
81Then, depending on the detection of the dual-boot keypress, either the
82OF image or the Rockbox image is copied to the end of RAM (just before
83the ucl unpack function) and uncompressed to the start of RAM.
84
85Finally, the ucl unpack function branches to address 0x0, passing
86execution to the uncompressed firmware.
87
88
89*/
90
91#include <stdio.h>
92#include <stdlib.h>
93#include <stdint.h>
94#include <sys/types.h>
95#include <sys/stat.h>
96#include <fcntl.h>
97#include <unistd.h>
98#include <string.h>
99
100#include <ucl/ucl.h>
101
102#include "mkamsboot.h"
103
104#include "md5.h"
105
106/* Header for ARM code binaries */
107#include "dualboot.h"
108
109/* Win32 compatibility */
110#ifndef O_BINARY
111#define O_BINARY 0
112#endif
113
114/* fw_revision: version 2 is used in Clipv2, Clip+ and Fuzev2 firmwares */
115/* hw_revision: 4 for m200, 2 for e200/c200, 1 or 2 for fuze/clip, 1 for clip+ */
116const struct ams_models ams_identity[] = {
117 [MODEL_C200V2] = { 2, 1, "c200", dualboot_c200v2, sizeof(dualboot_c200v2), "c2v2", 44 },
118 [MODEL_CLIPPLUS]= { 1, 2, "Clip+", dualboot_clipplus, sizeof(dualboot_clipplus), "cli+", 66 },
119 [MODEL_CLIPV2] = { 2, 2, "Clip", dualboot_clipv2, sizeof(dualboot_clipv2), "clv2", 60 },
120 [MODEL_CLIP] = { 1, 1, "Clip", dualboot_clip, sizeof(dualboot_clip), "clip", 40 },
121 [MODEL_E200V2] = { 2, 1, "e200", dualboot_e200v2, sizeof(dualboot_e200v2), "e2v2", 41 },
122 [MODEL_FUZEV2] = { 2, 2, "Fuze", dualboot_fuzev2, sizeof(dualboot_fuzev2), "fuz2", 68 },
123 [MODEL_FUZE] = { 1, 1, "Fuze", dualboot_fuze, sizeof(dualboot_fuze), "fuze", 43 },
124 [MODEL_M200V4] = { 4, 1, "m200", dualboot_m200v4, sizeof(dualboot_m200v4), "m2v4", 42 },
125 [MODEL_CLIPZIP] = { 1, 2, "ClipZip", dualboot_clipzip, sizeof(dualboot_clipzip), "clzp", 79 },
126};
127
128
129/* Checksums of unmodified original firmwares - for safety, and device
130 detection */
131static struct md5sums sansasums[] = {
132 /* NOTE: Different regional versions of the firmware normally only
133 differ in the filename - the md5sums are identical */
134
135 /* model version md5 */
136 { MODEL_E200V2, "3.01.11", "e622ca8cb6df423f54b8b39628a1f0a3" },
137 { MODEL_E200V2, "3.01.14", "2c1d0383fc3584b2cc83ba8cc2243af6" },
138 { MODEL_E200V2, "3.01.16", "12563ad71b25a1034cf2092d1e0218c4" },
139
140 { MODEL_FUZE, "1.01.11", "cac8ffa03c599330ac02c4d41de66166" },
141 { MODEL_FUZE, "1.01.15", "df0e2c1612727f722c19a3c764cff7f2" },
142 { MODEL_FUZE, "1.01.22", "5aff5486fe8dd64239cc71eac470af98" },
143 { MODEL_FUZE, "1.02.26", "7c632c479461c48c8833baed74eb5e4f" },
144 { MODEL_FUZE, "1.02.28", "5b34260f6470e75f702a9c6825471752" },
145 { MODEL_FUZE, "1.02.31", "66d01b37462a5ef7ccc6ad37188b4235" },
146
147 { MODEL_C200V2, "3.02.05", "b6378ebd720b0ade3fad4dc7ab61c1a5" },
148
149 { MODEL_M200V4, "4.00.45", "82e3194310d1514e3bbcd06e84c4add3" },
150 { MODEL_M200V4, "4.01.08-A", "fc9dd6116001b3e6a150b898f1b091f0" },
151 { MODEL_M200V4, "4.01.08-E", "d3fb7d8ec8624ee65bc99f8dab0e2369" },
152
153 { MODEL_CLIP, "1.01.17", "12caad785d506219d73f538772afd99e" },
154 { MODEL_CLIP, "1.01.18", "d720b266bd5afa38a198986ef0508a45" },
155 { MODEL_CLIP, "1.01.20", "236d8f75189f468462c03f6d292cf2ac" },
156 { MODEL_CLIP, "1.01.29", "c12711342169c66e209540cd1f27cd26" },
157 { MODEL_CLIP, "1.01.30", "f2974d47c536549c9d8259170f1dbe4d" },
158 { MODEL_CLIP, "1.01.32", "d835d12342500732ffb9c4ee54abec15" },
159 { MODEL_CLIP, "1.01.35", "b4d0edb3b8f2a4e8eee0a344f7f8e480" },
160
161 { MODEL_CLIPV2, "2.01.16", "c57fb3fcbe07c2c9b360f060938f80cb" },
162 { MODEL_CLIPV2, "2.01.32", "0ad3723e52022509089d938d0fbbf8c5" },
163 { MODEL_CLIPV2, "2.01.35", "a3cbbd22b9508d7f8a9a1a39acc342c2" },
164
165 { MODEL_CLIPPLUS, "01.02.09", "656d38114774c2001dc18e6726df3c5d" },
166 { MODEL_CLIPPLUS, "01.02.13", "5f89872b79ef440b0e5ee3a7a44328b2" },
167 { MODEL_CLIPPLUS, "01.02.15", "680a4f521e790ad25b93b1b16f3a207d" },
168 { MODEL_CLIPPLUS, "01.02.16", "055a53de1dfb09f6cb71c504ad48bd13" },
169 { MODEL_CLIPPLUS, "01.02.18", "80b547244438b113e2a55ff0305f12c0" },
170
171 { MODEL_FUZEV2, "2.01.17", "8b85fb05bf645d08a4c8c3e344ec9ebe" },
172 { MODEL_FUZEV2, "2.02.26", "d4f6f85c3e4a8ea8f2e5acc421641801" },
173 { MODEL_FUZEV2, "2.03.31", "74fb197ccd51707388f3b233402186a6" },
174 { MODEL_FUZEV2, "2.03.33", "1599cc73d02ea7fe53fe2d4379c24b66" },
175
176 { MODEL_CLIPZIP, "1.01.12", "45adea0873326b5af34f096e5c402f78" },
177 { MODEL_CLIPZIP, "1.01.15", "f62af954334cd9ba1a87a7fa58ec6074" },
178 { MODEL_CLIPZIP, "1.01.17", "27bcb343d6950f35dc261629e22ba60c" },
179 { MODEL_CLIPZIP, "1.01.18", "ef16aa9e02b49885ebede5aa149502e8" },
180 { MODEL_CLIPZIP, "1.01.20", "d88c8977cc6a952d3f51ece105869d97" },
181 { MODEL_CLIPZIP, "1.01.21", "92c814d6e3250189706a36d2b49b6152" },
182};
183
184#define NUM_MD5S (sizeof(sansasums)/sizeof(sansasums[0]))
185
186static unsigned int model_memory_size(int model)
187{
188 /* The OF boots with IRAM (320kB) mapped at 0x0 */
189
190 if(model == MODEL_CLIPV2)
191 {
192 /* The decompressed Clipv2 OF is around 380kB.
193 * Let's use the full IRAM (1MB on AMSv2)
194 */
195 return 1 << 20;
196 }
197 else
198 {
199 /* The IRAM is 320kB on AMSv1, and 320 will be enough on Fuzev1/Clip+ */
200 return 320 << 10;
201 }
202}
203
204int firmware_revision(int model)
205{
206 return ams_identity[model].fw_revision;
207}
208
209static off_t filesize(int fd)
210{
211 struct stat buf;
212
213 if (fstat(fd, &buf) < 0) {
214 perror("[ERR] Checking filesize of input file");
215 return -1;
216 } else {
217 return(buf.st_size);
218 }
219}
220
221static uint32_t get_uint32le(unsigned char* p)
222{
223 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
224}
225
226static uint32_t get_uint32be(unsigned char* p)
227{
228 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
229}
230
231static void put_uint32le(unsigned char* p, uint32_t x)
232{
233 p[0] = x & 0xff;
234 p[1] = (x >> 8) & 0xff;
235 p[2] = (x >> 16) & 0xff;
236 p[3] = (x >> 24) & 0xff;
237}
238
239void calc_MD5(unsigned char* buf, int len, char *md5str)
240{
241 int i;
242 md5_context ctx;
243 unsigned char md5sum[16];
244
245 md5_starts(&ctx);
246 md5_update(&ctx, buf, len);
247 md5_finish(&ctx, md5sum);
248
249 for (i = 0; i < 16; ++i)
250 sprintf(md5str + 2*i, "%02x", md5sum[i]);
251}
252
253/* Calculate a simple checksum used in Sansa Original Firmwares */
254static uint32_t calc_checksum(unsigned char* buf, uint32_t n)
255{
256 uint32_t sum = 0;
257 uint32_t i;
258
259 for (i=0;i<n;i+=4)
260 sum += get_uint32le(buf + i);
261
262 return sum;
263}
264
265/* Compress using nrv2e algorithm : Thumb decompressor fits in 168 bytes ! */
266static unsigned char* uclpack(unsigned char* inbuf, int insize, int* outsize)
267{
268 int maxsize;
269 unsigned char* outbuf;
270 int r;
271
272 /* The following formula comes from the UCL documentation */
273 maxsize = insize + (insize / 8) + 256;
274
275 /* Allocate some memory for the output buffer */
276 outbuf = malloc(maxsize);
277
278 if (outbuf == NULL)
279 return NULL;
280
281 r = ucl_nrv2e_99_compress(
282 (const ucl_bytep) inbuf,
283 (ucl_uint) insize,
284 (ucl_bytep) outbuf,
285 (ucl_uintp) outsize,
286 0, 10, NULL, NULL);
287
288 if (r != UCL_E_OK || *outsize > maxsize) {
289 /* this should NEVER happen, and implies memory corruption */
290 fprintf(stderr, "internal error - compression failed: %d\n", r);
291 free(outbuf);
292 return NULL;
293 }
294
295 return outbuf;
296}
297
298#define ERROR(format, ...) \
299 do { \
300 snprintf(errstr, errstrsize, format, __VA_ARGS__); \
301 goto error; \
302 } while(0)
303
304/* Loads a Sansa AMS Original Firmware file into memory */
305unsigned char* load_of_file(
306 char* filename, int model, off_t* bufsize, struct md5sums *sum,
307 int* firmware_size, unsigned char** of_packed,
308 int* of_packedsize, char* errstr, int errstrsize)
309{
310 int fd;
311 unsigned char* buf =NULL;
312 off_t n;
313 unsigned int i=0;
314 uint32_t checksum;
315 unsigned int last_word;
316
317 fd = open(filename, O_RDONLY|O_BINARY);
318 if (fd < 0)
319 ERROR("[ERR] Could not open %s for reading\n", filename);
320
321 *bufsize = filesize(fd);
322
323 buf = malloc(*bufsize);
324 if (buf == NULL)
325 ERROR("[ERR] Could not allocate memory for %s\n", filename);
326
327 n = read(fd, buf, *bufsize);
328
329 if (n != *bufsize)
330 ERROR("[ERR] Could not read file %s\n", filename);
331
332 /* check the file */
333
334 /* Calculate MD5 checksum of OF */
335 calc_MD5(buf, *bufsize, sum->md5);
336
337 while ((i < NUM_MD5S) && (strcmp(sansasums[i].md5, sum->md5) != 0))
338 i++;
339
340 if (i < NUM_MD5S) {
341 *sum = sansasums[i];
342 if(sum->model != model) {
343 ERROR("[ERR] OF File provided is %sv%d version %s, not for %sv%d\n",
344 ams_identity[sum->model].model_name, ams_identity[sum->model].hw_revision,
345 sum->version, ams_identity[model].model_name, ams_identity[model].hw_revision
346 );
347 }
348 } else {
349 /* OF unknown, give a list of tested versions for the requested model */
350
351 char tested_versions[100];
352 tested_versions[0] = '\0';
353
354 for (i = 0; i < NUM_MD5S ; i++)
355 if (sansasums[i].model == model) {
356 if (tested_versions[0] != '\0') {
357 strncat(tested_versions, ", ",
358 sizeof(tested_versions) - strlen(tested_versions) - 1);
359 }
360 strncat(tested_versions, sansasums[i].version,
361 sizeof(tested_versions) - strlen(tested_versions) - 1);
362 }
363
364 ERROR("[ERR] Original firmware unknown, please try another version."
365 " Tested %sv%d versions are: %s\n",
366 ams_identity[model].model_name, ams_identity[model].hw_revision, tested_versions);
367 }
368
369 /* TODO: Do some more sanity checks on the OF image. Some images (like
370 m200v4) dont have a checksum at the end, only padding (0xdeadbeef). */
371 last_word = *bufsize - 4;
372 checksum = get_uint32le(buf + last_word);
373 if (checksum != 0xefbeadde && checksum != calc_checksum(buf, last_word))
374 ERROR("%s", "[ERR] Whole file checksum failed\n");
375
376 if (ams_identity[sum->model].bootloader == NULL)
377 ERROR("[ERR] Unsupported model - \"%s\"\n", ams_identity[sum->model].model_name);
378
379 /* Get the firmware size */
380 if (ams_identity[sum->model].fw_revision == 1)
381 *firmware_size = get_uint32le(&buf[0x0c]);
382 else if (ams_identity[sum->model].fw_revision == 2)
383 *firmware_size = get_uint32le(&buf[0x10]);
384
385 /* Compress the original firmware image */
386 *of_packed = uclpack(buf + 0x400, *firmware_size, of_packedsize);
387 if (*of_packed == NULL)
388 ERROR("[ERR] Could not compress %s\n", filename);
389
390 return buf;
391
392error:
393 free(buf);
394 return NULL;
395}
396
397/* Loads a rockbox bootloader file into memory */
398unsigned char* load_rockbox_file(
399 char* filename, int *model, int* bufsize, int* rb_packedsize,
400 char* errstr, int errstrsize)
401{
402 int fd;
403 unsigned char* buf = NULL;
404 unsigned char* packed = NULL;
405 unsigned char header[8];
406 uint32_t sum;
407 off_t n;
408 int i;
409
410 fd = open(filename, O_RDONLY|O_BINARY);
411 if (fd < 0)
412 ERROR("[ERR] Could not open %s for reading\n", filename);
413
414 /* Read Rockbox header */
415 n = read(fd, header, sizeof(header));
416 if (n != sizeof(header))
417 ERROR("[ERR] Could not read file %s\n", filename);
418
419 for(*model = 0; *model < NUM_MODELS; (*model)++)
420 if (memcmp(ams_identity[*model].rb_model_name, header + 4, 4) == 0)
421 break;
422
423 if(*model == NUM_MODELS)
424 ERROR("[ERR] Model name \"%4.4s\" unknown. Is this really a rockbox bootloader?\n", header + 4);
425
426 *bufsize = filesize(fd) - sizeof(header);
427
428 buf = malloc(*bufsize);
429 if (buf == NULL)
430 ERROR("[ERR] Could not allocate memory for %s\n", filename);
431
432 n = read(fd, buf, *bufsize);
433
434 if (n != *bufsize)
435 ERROR("[ERR] Could not read file %s\n", filename);
436
437 /* Check checksum */
438 sum = ams_identity[*model].rb_model_num;
439 for (i = 0; i < *bufsize; i++) {
440 /* add 8 unsigned bits but keep a 32 bit sum */
441 sum += buf[i];
442 }
443
444 if (sum != get_uint32be(header))
445 ERROR("[ERR] Checksum mismatch in %s\n", filename);
446
447 packed = uclpack(buf, *bufsize, rb_packedsize);
448 if(packed == NULL)
449 ERROR("[ERR] Could not compress %s\n", filename);
450
451 free(buf);
452 return packed;
453
454error:
455 free(buf);
456 return NULL;
457}
458
459#undef ERROR
460
461/* Patches a Sansa AMS Original Firmware file */
462void patch_firmware(
463 int model, int fw_revision, int firmware_size, unsigned char* buf,
464 int len, unsigned char* of_packed, int of_packedsize,
465 unsigned char* rb_packed, int rb_packedsize)
466{
467 unsigned char *p;
468 uint32_t sum, filesum;
469 uint32_t ucl_dest;
470 unsigned int i;
471
472 /* Zero the original firmware area - not needed, but helps debugging */
473 memset(buf + 0x600, 0, firmware_size);
474
475 /* Insert dual-boot bootloader at offset 0x200, we preserve the OF
476 * version string located between 0x0 and 0x200 */
477 memcpy(buf + 0x600, ams_identity[model].bootloader, ams_identity[model].bootloader_size);
478
479 /* Insert vectors, they won't overwrite the OF version string */
480 static const uint32_t goto_start = 0xe3a0fc02; // mov pc, #0x200
481 static const uint32_t infinite_loop = 0xeafffffe; // 1: b 1b
482 /* ALL vectors: infinite loop */
483 for (i=0; i < 8; i++)
484 put_uint32le(buf + 0x400 + 4*i, infinite_loop);
485 /* Now change only the interesting vectors */
486 /* Reset/SWI vectors: branch to our dualboot code at 0x200 */
487 put_uint32le(buf + 0x400 + 4*0, goto_start); // Reset
488 put_uint32le(buf + 0x400 + 4*2, goto_start); // SWI
489
490 /* We are filling the firmware buffer backwards from the end */
491 p = buf + 0x400 + firmware_size;
492
493 /* 1 - UCL unpack function */
494 p -= sizeof(nrv2e_d8);
495 memcpy(p, nrv2e_d8, sizeof(nrv2e_d8));
496
497 /* 2 - Compressed copy of original firmware */
498 p -= of_packedsize;
499 memcpy(p, of_packed, of_packedsize);
500
501 /* 3 - Compressed copy of Rockbox bootloader */
502 p -= rb_packedsize;
503 memcpy(p, rb_packed, rb_packedsize);
504
505 /* Write the locations of the various images to the variables at the
506 start of the dualboot image - we save the location of the last byte
507 in each image, along with the size in bytes */
508
509 /* UCL unpack function */
510 put_uint32le(&buf[0x604], firmware_size - 1);
511 put_uint32le(&buf[0x608], sizeof(nrv2e_d8));
512
513 /* Compressed original firmware image */
514 put_uint32le(&buf[0x60c], firmware_size - sizeof(nrv2e_d8) - 1);
515 put_uint32le(&buf[0x610], of_packedsize);
516
517 /* Compressed Rockbox image */
518 put_uint32le(&buf[0x614], firmware_size - sizeof(nrv2e_d8) - of_packedsize
519 - 1);
520 put_uint32le(&buf[0x618], rb_packedsize);
521
522 ucl_dest = model_memory_size(model) - 1; /* last byte of memory */
523 put_uint32le(&buf[0x61c], ucl_dest);
524
525 /* Update the firmware block checksum */
526 sum = calc_checksum(buf + 0x400, firmware_size);
527
528 if (fw_revision == 1) {
529 put_uint32le(&buf[0x04], sum);
530 put_uint32le(&buf[0x204], sum);
531 } else if (fw_revision == 2) {
532 put_uint32le(&buf[0x08], sum);
533 put_uint32le(&buf[0x208], sum);
534
535 /* Update the header checksums */
536 put_uint32le(&buf[0x1fc], calc_checksum(buf, 0x1fc));
537 put_uint32le(&buf[0x3fc], calc_checksum(buf + 0x200, 0x1fc));
538 }
539
540 /* Update the whole-file checksum */
541 filesum = 0;
542 for (i=0;i < (unsigned)len - 4; i+=4)
543 filesum += get_uint32le(&buf[i]);
544
545 put_uint32le(buf + len - 4, filesum);
546}
547
548/* returns != 0 if the firmware can be safely patched */
549int check_sizes(int model, int rb_packed_size, int rb_unpacked_size,
550 int of_packed_size, int of_unpacked_size, int *total_size,
551 char *errstr, int errstrsize)
552{
553 /* XXX: we keep the first 0x200 bytes block unmodified, we just replace
554 * the ARM vectors */
555 unsigned int packed_size = ams_identity[model].bootloader_size + sizeof(nrv2e_d8) +
556 of_packed_size + rb_packed_size + 0x200;
557
558 /* how much memory is available */
559 unsigned int memory_size = model_memory_size(model);
560
561 /* the memory used when unpacking the OF */
562 unsigned int ram_of = sizeof(nrv2e_d8) + of_packed_size + of_unpacked_size;
563
564 /* the memory used when unpacking the bootloader */
565 unsigned int ram_rb = sizeof(nrv2e_d8) + rb_packed_size + rb_unpacked_size;
566
567 *total_size = packed_size;
568
569#define ERROR(format, ...) \
570 do { \
571 snprintf(errstr, errstrsize, format, __VA_ARGS__); \
572 return 0; \
573 } while(0)
574
575 /* will packed data fit in the OF file ? */
576 if(packed_size > of_unpacked_size)
577 ERROR(
578 "[ERR] Packed data (%d bytes) doesn't fit in the firmware "
579 "(%d bytes)\n", packed_size, of_unpacked_size
580 );
581
582 else if(ram_rb > memory_size)
583 ERROR("[ERR] Rockbox can't be unpacked at runtime, needs %d bytes "
584 "of memory and only %d available\n", ram_rb, memory_size
585 );
586
587 else if(ram_of > memory_size)
588 ERROR("[ERR] OF can't be unpacked at runtime, needs %d bytes "
589 "of memory and only %d available\n", ram_of, memory_size
590 );
591
592 return 1;
593
594#undef ERROR
595}
diff --git a/utils/mkamsboot/mkamsboot.h b/utils/mkamsboot/mkamsboot.h
new file mode 100644
index 0000000000..263fe9e9c1
--- /dev/null
+++ b/utils/mkamsboot/mkamsboot.h
@@ -0,0 +1,195 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * mkamsboot.h - a tool for merging bootloader code into an Sansa V2
11 * (AMS) firmware file
12 *
13 * Copyright (C) 2008 Dave Chapman
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#ifndef MKAMSBOOT_H
26#define MKAMSBOOT_H
27
28#include <stdint.h>
29#include <sys/types.h>
30
31#ifdef __cplusplus
32extern "C" {
33#endif
34
35/* Supported models */
36enum {
37 MODEL_UNKNOWN = -1,
38 MODEL_FUZE = 0,
39 MODEL_CLIP,
40 MODEL_CLIPV2,
41 MODEL_E200V2,
42 MODEL_M200V4,
43 MODEL_C200V2,
44 MODEL_CLIPPLUS,
45 MODEL_FUZEV2,
46 MODEL_CLIPZIP,
47 /* new models go here */
48
49 NUM_MODELS
50};
51
52
53/* Holds info about the OF */
54struct md5sums {
55 int model;
56 char *version;
57 char *md5;
58};
59
60struct ams_models {
61 unsigned short hw_revision;
62 unsigned short fw_revision;
63 /* Descriptive name of this model */
64 const char* model_name;
65 /* Dualboot functions for this model */
66 const unsigned char* bootloader;
67 /* Size of dualboot functions for this model */
68 int bootloader_size;
69 /* Model name used in the Rockbox header in ".sansa" files - these match the
70 -add parameter to the "scramble" tool */
71 const char* rb_model_name;
72 /* Model number used to initialise the checksum in the Rockbox header in
73 ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
74 const int rb_model_num;
75};
76extern const struct ams_models ams_identity[];
77
78/* load_rockbox_file()
79 *
80 * Loads a rockbox bootloader file into memory
81 *
82 * ARGUMENTS
83 *
84 * filename : bootloader file to load
85 * model : will be set to this bootloader's model
86 * bootloader_size : set to the uncompressed bootloader size
87 * rb_packed_size : set to the size of compressed bootloader
88 * errstr : provided buffer to store an eventual error
89 * errstrsize : size of provided error buffer
90 *
91 * RETURN VALUE
92 * pointer to allocated memory containing the content of compressed bootloader
93 * or NULL in case of error (errstr will hold a description of the error)
94 */
95
96unsigned char* load_rockbox_file(
97 char* filename, int *model, int* bootloader_size, int* rb_packedsize,
98 char* errstr, int errstrsize);
99
100
101/* load_of_file()
102 *
103 * Loads a Sansa AMS Original Firmware file into memory
104 *
105 * ARGUMENTS
106 *
107 * filename : firmware file to load
108 * model : desired player's model
109 * bufsize : set to firmware file size
110 * md5sum : set to file md5sum, must be at least 33 bytes long
111 * firmware_size : set to firmware block's size
112 * of_packed : pointer to allocated memory containing the compressed
113 * original firmware block
114 * of_packedsize : size of compressed original firmware block
115 * errstr : provided buffer to store an eventual error
116 * errstrsize : size of provided error buffer
117 *
118 * RETURN VALUE
119 * pointer to allocated memory containing the content of Original Firmware
120 * or NULL in case of error (errstr will hold a description of the error)
121 */
122
123unsigned char* load_of_file(
124 char* filename, int model, off_t* bufsize, struct md5sums *sum,
125 int* firmware_size, unsigned char** of_packed,
126 int* of_packedsize, char* errstr, int errstrsize);
127
128
129/* patch_firmware()
130 *
131 * Patches a Sansa AMS Original Firmware file
132 *
133 * ARGUMENTS
134 *
135 * model : firmware model (MODEL_XXX)
136 * fw_version : firmware format version (1 or 2)
137 * firmware_size : size of uncompressed original firmware block
138 * buf : pointer to original firmware file
139 * len : size of original firmware file
140 * of_packed : pointer to compressed original firmware block
141 * of_packedsize : size of compressed original firmware block
142 * rb_packed : pointer to compressed rockbox bootloader
143 * rb_packed_size : size of compressed rockbox bootloader
144 */
145
146void patch_firmware(
147 int model, int fw_version, int firmware_size, unsigned char* buf,
148 int len, unsigned char* of_packed, int of_packedsize,
149 unsigned char* rb_packed, int rb_packedsize);
150
151
152/* check_sizes()
153 *
154 * Verify if the given bootloader can be embedded in the OF file, while still
155 * allowing both the bootloader and the OF to be unpacked at runtime
156 *
157 * ARGUMENTS
158 *
159 * model : firmware model (MODEL_XXX)
160 * rb_packed_size : size of compressed rockbox bootloader
161 * rb_unpacked_size : size of compressed rockbox bootloader
162 * of_packed_size : size of compressed original firmware block
163 * of_unpacked_size : size of compressed original firmware block
164 * total_size : will contain the size of useful data that would be
165 * written to the firmware block, even in case of an
166 * error
167 * errstr : provided buffer to store an eventual error
168 * errstrsize : size of provided error buffer
169 *
170 * RETURN VALUE
171 * 0 if the conditions aren't met, 1 if we can go and patch the firmware
172*/
173
174int check_sizes(int model, int rb_packed_size, int rb_unpacked_size,
175 int of_packed_size, int of_unpacked_size, int *total_size,
176 char *errstr, int errstrsize);
177
178/* firmware_revision()
179 *
180 * returns the firmware revision for a particular model
181 *
182 * ARGUMENTS
183 *
184 * model : firmware model (MODEL_XXX)
185 *
186 * RETURN VALUE
187 * firmware version
188*/
189int firmware_revision(int model);
190
191#ifdef __cplusplus
192};
193#endif
194
195#endif