summaryrefslogtreecommitdiff
path: root/utils/mkzenboot
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mkzenboot')
-rw-r--r--utils/mkzenboot/Makefile30
-rw-r--r--utils/mkzenboot/dualboot.c56
-rw-r--r--utils/mkzenboot/dualboot.h6
-rw-r--r--utils/mkzenboot/dualboot/Makefile51
-rw-r--r--utils/mkzenboot/dualboot/bin2c.c140
-rw-r--r--utils/mkzenboot/dualboot/config.h22
-rw-r--r--utils/mkzenboot/dualboot/dualboot.c136
-rw-r--r--utils/mkzenboot/dualboot/dualboot.lds32
-rw-r--r--utils/mkzenboot/main.c123
-rw-r--r--utils/mkzenboot/md5.c246
-rw-r--r--utils/mkzenboot/md5.h25
-rw-r--r--utils/mkzenboot/mkzenboot.c697
-rw-r--r--utils/mkzenboot/mkzenboot.h86
-rw-r--r--utils/mkzenboot/utils.c896
-rw-r--r--utils/mkzenboot/utils.h53
15 files changed, 2599 insertions, 0 deletions
diff --git a/utils/mkzenboot/Makefile b/utils/mkzenboot/Makefile
new file mode 100644
index 0000000000..ebc7a1670a
--- /dev/null
+++ b/utils/mkzenboot/Makefile
@@ -0,0 +1,30 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7
8# We use the HMAC-SHA1 code from tools/
9TOOLS_DIR=../../tools/
10CFLAGS += -Wall -I$(TOOLS_DIR)
11CFLAGS += -std=c99 -g
12LDOPTS += -lz
13
14OUTPUT = mkzenboot
15
16# inputs for lib
17TOOLS_SOURCES = hmac-sha1.c
18LIBSOURCES := dualboot.c mkzenboot.c md5.c utils.c \
19 $(addprefix $(TOOLS_DIR),$(TOOLS_SOURCES))
20
21# inputs for binary only
22SOURCES := main.c
23# dependencies for binary
24EXTRADEPS :=
25
26include ../libtools.make
27
28# explicit dependencies on dualboot.{c,h} and mkimxboot.h
29$(OBJDIR)mkzenboot.o: dualboot.h dualboot.c mkzenboot.c mkzenboot.h
30$(OBJDIR)main.o: dualboot.h dualboot.c main.c mkzenboot.h
diff --git a/utils/mkzenboot/dualboot.c b/utils/mkzenboot/dualboot.c
new file mode 100644
index 0000000000..4c98468b3b
--- /dev/null
+++ b/utils/mkzenboot/dualboot.c
@@ -0,0 +1,56 @@
1/* Generated by bin2c */
2
3#include "dualboot.h"
4
5unsigned char dualboot_zenmozaic[168] = {
6 0x10, 0x40, 0x2d, 0xe9, 0x7c, 0x30, 0x9f, 0xe5, 0x00, 0x30, 0x93, 0xe5, 0x78, 0x20, 0x9f, 0xe5,
7 0x00, 0x00, 0x92, 0xe5, 0x74, 0x20, 0x9f, 0xe5, 0x02, 0x11, 0xa0, 0xe3, 0x08, 0x10, 0x82, 0xe5,
8 0x03, 0x11, 0x81, 0xe2, 0x08, 0x10, 0x82, 0xe5, 0xff, 0x14, 0x81, 0xe2, 0x58, 0x10, 0x82, 0xe5,
9 0xc2, 0x14, 0x81, 0xe2, 0x24, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x18, 0x10, 0x82, 0xe5,
10 0x04, 0x10, 0x82, 0xe5, 0x02, 0x10, 0xa0, 0xe1, 0x10, 0x20, 0x91, 0xe5, 0x01, 0x00, 0x12, 0xe3,
11 0xfc, 0xff, 0xff, 0x0a, 0x34, 0x20, 0x9f, 0xe5, 0x50, 0x20, 0x92, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
12 0x3f, 0x27, 0xc2, 0xe3, 0xa5, 0x2e, 0x42, 0xe2, 0x0a, 0x20, 0x42, 0xe2, 0x63, 0x00, 0x52, 0xe3,
13 0x00, 0x30, 0xa0, 0x93, 0x20, 0x00, 0x83, 0x95, 0x14, 0x20, 0x9f, 0xe5, 0x00, 0x00, 0x92, 0xe5,
14 0x33, 0xff, 0x2f, 0xe1, 0x10, 0x80, 0xbd, 0xe8, 0xa0, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x00, 0x41,
15 0x00, 0x00, 0x05, 0x80, 0xa4, 0x00, 0x00, 0x41, 0xda, 0x00, 0xeb, 0x1c, 0x00, 0x00, 0x00, 0x00,
16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
17};
18unsigned char dualboot_zenxfi[168] = {
19 0x10, 0x40, 0x2d, 0xe9, 0x7c, 0x30, 0x9f, 0xe5, 0x00, 0x30, 0x93, 0xe5, 0x78, 0x20, 0x9f, 0xe5,
20 0x00, 0x00, 0x92, 0xe5, 0x74, 0x20, 0x9f, 0xe5, 0x02, 0x11, 0xa0, 0xe3, 0x08, 0x10, 0x82, 0xe5,
21 0x03, 0x11, 0x81, 0xe2, 0x08, 0x10, 0x82, 0xe5, 0xff, 0x14, 0x81, 0xe2, 0x58, 0x10, 0x82, 0xe5,
22 0xc2, 0x14, 0x81, 0xe2, 0x24, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x18, 0x10, 0x82, 0xe5,
23 0x04, 0x10, 0x82, 0xe5, 0x02, 0x10, 0xa0, 0xe1, 0x10, 0x20, 0x91, 0xe5, 0x01, 0x00, 0x12, 0xe3,
24 0xfc, 0xff, 0xff, 0x0a, 0x34, 0x20, 0x9f, 0xe5, 0x50, 0x20, 0x92, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
25 0x3f, 0x27, 0xc2, 0xe3, 0xa5, 0x2e, 0x42, 0xe2, 0x0a, 0x20, 0x42, 0xe2, 0x63, 0x00, 0x52, 0xe3,
26 0x00, 0x30, 0xa0, 0x93, 0x20, 0x00, 0x83, 0x95, 0x14, 0x20, 0x9f, 0xe5, 0x00, 0x00, 0x92, 0xe5,
27 0x33, 0xff, 0x2f, 0xe1, 0x10, 0x80, 0xbd, 0xe8, 0xa0, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x00, 0x41,
28 0x00, 0x00, 0x05, 0x80, 0xa4, 0x00, 0x00, 0x41, 0xda, 0x00, 0xeb, 0x1c, 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
30};
31unsigned char dualboot_zen[168] = {
32 0x10, 0x40, 0x2d, 0xe9, 0x7c, 0x30, 0x9f, 0xe5, 0x00, 0x30, 0x93, 0xe5, 0x78, 0x20, 0x9f, 0xe5,
33 0x00, 0x00, 0x92, 0xe5, 0x74, 0x20, 0x9f, 0xe5, 0x02, 0x11, 0xa0, 0xe3, 0x08, 0x10, 0x82, 0xe5,
34 0x03, 0x11, 0x81, 0xe2, 0x08, 0x10, 0x82, 0xe5, 0xff, 0x14, 0x81, 0xe2, 0x58, 0x10, 0x82, 0xe5,
35 0xc2, 0x14, 0x81, 0xe2, 0x24, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x18, 0x10, 0x82, 0xe5,
36 0x04, 0x10, 0x82, 0xe5, 0x02, 0x10, 0xa0, 0xe1, 0x10, 0x20, 0x91, 0xe5, 0x01, 0x00, 0x12, 0xe3,
37 0xfc, 0xff, 0xff, 0x0a, 0x34, 0x20, 0x9f, 0xe5, 0x50, 0x20, 0x92, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
38 0x3f, 0x27, 0xc2, 0xe3, 0xa5, 0x2e, 0x42, 0xe2, 0x0a, 0x20, 0x42, 0xe2, 0x63, 0x00, 0x52, 0xe3,
39 0x00, 0x30, 0xa0, 0x93, 0x20, 0x00, 0x83, 0x95, 0x14, 0x20, 0x9f, 0xe5, 0x00, 0x00, 0x92, 0xe5,
40 0x33, 0xff, 0x2f, 0xe1, 0x10, 0x80, 0xbd, 0xe8, 0xa0, 0x00, 0x00, 0x41, 0x9c, 0x00, 0x00, 0x41,
41 0x00, 0x00, 0x05, 0x80, 0xa4, 0x00, 0x00, 0x41, 0xda, 0x00, 0xeb, 0x1c, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
43};
44unsigned char dualboot_zenv[168] = {
45 0x10, 0x40, 0x2d, 0xe9, 0x7c, 0x30, 0x9f, 0xe5, 0x00, 0x30, 0x93, 0xe5, 0x78, 0x20, 0x9f, 0xe5,
46 0x00, 0x00, 0x92, 0xe5, 0x74, 0x20, 0x9f, 0xe5, 0x02, 0x11, 0xa0, 0xe3, 0x08, 0x10, 0x82, 0xe5,
47 0x03, 0x11, 0x81, 0xe2, 0x08, 0x10, 0x82, 0xe5, 0xff, 0x14, 0x81, 0xe2, 0x58, 0x10, 0x82, 0xe5,
48 0xc2, 0x14, 0x81, 0xe2, 0x24, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x18, 0x10, 0x82, 0xe5,
49 0x04, 0x10, 0x82, 0xe5, 0x02, 0x10, 0xa0, 0xe1, 0x10, 0x20, 0x91, 0xe5, 0x01, 0x00, 0x12, 0xe3,
50 0xfc, 0xff, 0xff, 0x0a, 0x34, 0x20, 0x9f, 0xe5, 0x50, 0x20, 0x92, 0xe5, 0xff, 0x24, 0xc2, 0xe3,
51 0x3f, 0x27, 0xc2, 0xe3, 0xa5, 0x2e, 0x42, 0xe2, 0x0a, 0x20, 0x42, 0xe2, 0x63, 0x00, 0x52, 0xe3,
52 0x00, 0x30, 0xa0, 0x93, 0x20, 0x00, 0x83, 0x95, 0x14, 0x20, 0x9f, 0xe5, 0x00, 0x00, 0x92, 0xe5,
53 0x33, 0xff, 0x2f, 0xe1, 0x10, 0x80, 0xbd, 0xe8, 0xa0, 0x00, 0x00, 0x61, 0x9c, 0x00, 0x00, 0x61,
54 0x00, 0x00, 0x05, 0x80, 0xa4, 0x00, 0x00, 0x61, 0xda, 0x00, 0xeb, 0x1c, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
56};
diff --git a/utils/mkzenboot/dualboot.h b/utils/mkzenboot/dualboot.h
new file mode 100644
index 0000000000..2497d2900c
--- /dev/null
+++ b/utils/mkzenboot/dualboot.h
@@ -0,0 +1,6 @@
1/* Generated by bin2c */
2
3extern unsigned char dualboot_zenmozaic[168];
4extern unsigned char dualboot_zenxfi[168];
5extern unsigned char dualboot_zen[168];
6extern unsigned char dualboot_zenv[168];
diff --git a/utils/mkzenboot/dualboot/Makefile b/utils/mkzenboot/dualboot/Makefile
new file mode 100644
index 0000000000..752cc3ca28
--- /dev/null
+++ b/utils/mkzenboot/dualboot/Makefile
@@ -0,0 +1,51 @@
1CC=gcc
2LD=ld
3OC=objcopy
4CROSS_PREFIX=arm-elf-eabi-
5REGS_PATH=../../../firmware/target/arm/imx233/regs
6CFLAGS=-mcpu=arm926ej-s -std=gnu99 -I. -I$(REGS_PATH) -nostdlib -ffreestanding -fomit-frame-pointer -O
7LDFLAGS=
8# Edit the following variables when adding a new target.
9# mkimxboot.c also needs to be edited to refer to these
10# To add a new target x you need to:
11# 1) add x to the list in TARGETS
12# 2) create a variable named OPT_x of the form:
13# OPT_x=target specific defines
14TARGETS=zenmozaic zenxfi zen zenv
15OPT_zenmozaic=-DCREATIVE_ZENMOZAIC -DIMX233_SUBTARGET=3700
16OPT_zenxfi=-DCREATIVE_ZENXFI -DIMX233_SUBTARGET=3700
17OPT_zen=-DCREATIVE_ZEN -DIMX233_SUBTARGET=3700
18OPT_zenv=-DCREATIVE_ZENV -DIMX233_SUBTARGET=3600
19
20BOOTLDS=$(patsubst %, dualboot_%.lds, $(TARGETS))
21BOOTOBJS=$(patsubst %, dualboot_%.o, $(TARGETS))
22BOOTBINS=$(patsubst %, dualboot_%.arm-bin, $(TARGETS))
23BOOTELFS=$(patsubst %, dualboot_%.arm-elf, $(TARGETS))
24
25all: ../dualboot.h ../dualboot.c $(BOOTELFS)
26
27# Dualboot bootloaders
28
29dualboot_%.o: dualboot.c
30 $(CROSS_PREFIX)$(CC) $(CFLAGS) $(OPT_$(@:dualboot_%.o=%)) -c -o $@ $^
31
32dualboot_%.lds: dualboot.lds
33 $(CROSS_PREFIX)$(CC) $(CFLAGS) $(OPT_$(@:dualboot_%.lds=%)) -E -x c - < $< | sed '/#/d' > $@
34
35dualboot_%.arm-elf: dualboot_%.o dualboot_%.lds
36 $(CROSS_PREFIX)$(LD) $(LDFLAGS) -T$(@:dualboot_%.arm-elf=dualboot_%.lds) -o $@ $<
37
38# Rules for the ARM code embedded in mkamsboot - assemble, link, then extract
39# the binary code and finally convert to .h for building in mkamsboot
40
41%.arm-bin: %.arm-elf
42 $(CROSS_PREFIX)$(OC) -O binary $< $@
43
44../dualboot.c ../dualboot.h: $(BOOTBINS) bin2c
45 ./bin2c ../dualboot $(BOOTBINS)
46
47bin2c: bin2c.c
48 $(CC) -o bin2c bin2c.c
49
50clean:
51 rm -f *~ bin2c $(BOOTBINS) $(BOOTOBJS) $(BOOTELFS) $(BOOTLDS)
diff --git a/utils/mkzenboot/dualboot/bin2c.c b/utils/mkzenboot/dualboot/bin2c.c
new file mode 100644
index 0000000000..b02af88a4d
--- /dev/null
+++ b/utils/mkzenboot/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/mkzenboot/dualboot/config.h b/utils/mkzenboot/dualboot/config.h
new file mode 100644
index 0000000000..ff59cee710
--- /dev/null
+++ b/utils/mkzenboot/dualboot/config.h
@@ -0,0 +1,22 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
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/** empty, used by register files */
diff --git a/utils/mkzenboot/dualboot/dualboot.c b/utils/mkzenboot/dualboot/dualboot.c
new file mode 100644
index 0000000000..0b32772afb
--- /dev/null
+++ b/utils/mkzenboot/dualboot/dualboot.c
@@ -0,0 +1,136 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
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#include "regs-pinctrl.h"
22#include "regs-power.h"
23#include "regs-lradc.h"
24#include "regs-digctl.h"
25
26typedef unsigned long uint32_t;
27
28// target specific boot decision
29enum boot_t
30{
31 BOOT_STOP, /* power down */
32 BOOT_ROCK, /* boot to Rockbox */
33 BOOT_OF, /* boot to OF */
34};
35
36/**
37 * Helper functions
38 */
39
40static inline int __attribute__((always_inline)) read_gpio(int bank, int pin)
41{
42 return (HW_PINCTRL_DINn(bank) >> pin) & 1;
43}
44
45static inline int __attribute__((always_inline)) read_pswitch(void)
46{
47#if IMX233_SUBTARGET >= 3700
48 return BF_RD(POWER_STS, PSWITCH);
49#else
50 return BF_RD(DIGCTL_STATUS, PSWITCH);
51#endif
52}
53
54/* only works for channels <=7, always divide by 2, never accumulates */
55static inline void __attribute__((always_inline)) setup_lradc(int src)
56{
57 BF_CLR(LRADC_CTRL0, SFTRST);
58 BF_CLR(LRADC_CTRL0, CLKGATE);
59 /* don't bother changing the source, we are early enough at boot so that
60 * channel x is mapped to source x */
61 HW_LRADC_CHn_CLR(src) = BM_OR2(LRADC_CHn, NUM_SAMPLES, ACCUMULATE);
62 BF_SETV(LRADC_CTRL2, DIVIDE_BY_TWO, 1 << src);
63}
64
65#define BP_LRADC_CTRL1_LRADCx_IRQ(x) (x)
66#define BM_LRADC_CTRL1_LRADCx_IRQ(x) (1 << (x))
67
68static inline int __attribute__((always_inline)) read_lradc(int src)
69{
70 BF_CLR(LRADC_CTRL1, LRADCx_IRQ(src));
71 BF_SETV(LRADC_CTRL0, SCHEDULE, 1 << src);
72 while(!BF_RD(LRADC_CTRL1, LRADCx_IRQ(src)));
73 return BF_RDn(LRADC_CHn, src, VALUE);
74}
75
76static inline void __attribute__((noreturn)) power_down()
77{
78 /* power down */
79 HW_POWER_RESET = BM_OR2(POWER_RESET, UNLOCK, PWD);
80 while(1);
81}
82
83/**
84 * Boot decision functions
85 */
86
87#if defined(CREATIVE_ZENMOZAIC) || defined(CREATIVE_ZEN) || defined(CREATIVE_ZENXFI) \
88 || defined(CREATIVE_ZENV)
89static enum boot_t boot_decision()
90{
91 setup_lradc(0); // setup LRADC channel 0 to read keys
92 /* make a decision */
93 /* read keys */
94 int val = read_lradc(0);
95 /* if back is pressed, boot to OF
96 * otherwise boot to RB */
97 if(val >= 2650 && val < 2750) // conveniently, all players use the same value
98 return BOOT_OF;
99 return BOOT_ROCK;
100}
101#else
102#warning You should define a target specific boot decision function
103static int boot_decision()
104{
105 return BOOT_ROCK;
106}
107#endif
108
109static int main(uint32_t rb_addr, uint32_t of_addr)
110{
111 switch(boot_decision())
112 {
113 case BOOT_ROCK:
114 return rb_addr;
115 case BOOT_OF:
116 /* fix back the loading address
117 /* NOTE: see mkzenboot for more details */
118 *(uint32_t *)0x20 = of_addr;
119 return 0;
120 case BOOT_STOP:
121 default:
122 power_down();
123 }
124}
125
126/** Glue for the linker mostly */
127
128extern uint32_t of_vector;
129extern uint32_t rb_vector;
130extern uint32_t boot_arg;
131
132void __attribute__((section(".start"))) start()
133{
134 uint32_t addr = main(rb_vector, of_vector);
135 ((void (*)(uint32_t))addr)(boot_arg);
136}
diff --git a/utils/mkzenboot/dualboot/dualboot.lds b/utils/mkzenboot/dualboot/dualboot.lds
new file mode 100644
index 0000000000..7444a1e427
--- /dev/null
+++ b/utils/mkzenboot/dualboot/dualboot.lds
@@ -0,0 +1,32 @@
1ENTRY(start)
2OUTPUT_FORMAT(elf32-littlearm)
3OUTPUT_ARCH(arm)
4
5MEMORY
6{
7 /* keep this consistent with the address in mkzenboot.c */
8#if IMX233_SUBTARGET == 3700
9 RAM : ORIGIN = 0x41000000, LENGTH = 0x8000
10#elif IMX233_SUBTARGET == 3600
11 RAM : ORIGIN = 0x61000000, LENGTH = 0x8000
12#else
13#error define me
14#endif
15}
16
17SECTIONS
18{
19 .text :
20 {
21 *(.start*)
22 *(.text*)
23 . = ALIGN(4);
24 LONG(0x1ceb00da)
25 of_vector = .;
26 . += 4;
27 rb_vector = .;
28 . += 4;
29 boot_arg = .;
30 . += 4;
31 } > RAM
32}
diff --git a/utils/mkzenboot/main.c b/utils/mkzenboot/main.c
new file mode 100644
index 0000000000..7aef2b76a3
--- /dev/null
+++ b/utils/mkzenboot/main.c
@@ -0,0 +1,123 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
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 <getopt.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include "mkzenboot.h"
27
28static void usage(void)
29{
30 printf("Usage: mkzenboot [options | file]...\n");
31 printf("Options:\n");
32 printf(" -?/--help Display this message\n");
33 printf(" -i <file> Set input file\n");
34 printf(" -o <file> Set output file\n");
35 printf(" -b <file> Set boot file\n");
36 printf(" -t <type> Set output type\n");
37 printf(" -d/--debug Enable debug output\n");
38 printf("Output types: dualboot, deferred_dualboot, singleboot, recovery\n");
39 printf("By default a dualboot image is built\n");
40 exit(1);
41}
42
43int main(int argc, char *argv[])
44{
45 char *outfile = NULL;
46 char *bootfile = NULL;
47 char *infile = NULL;
48 struct zen_option_t opt;
49 memset(&opt, 0, sizeof(opt));
50
51 if(argc == 1)
52 usage();
53
54 while(1)
55 {
56 static struct option long_options[] =
57 {
58 {"help", no_argument, 0, '?'},
59 {"debug", no_argument, 0, 'd'},
60 {0, 0, 0, 0}
61 };
62
63 int c = getopt_long(argc, argv, "?di:o:b:t:", long_options, NULL);
64 if(c == -1)
65 break;
66 switch(c)
67 {
68 case 'd':
69 opt.debug = true;
70 break;
71 case '?':
72 usage();
73 break;
74 case 'o':
75 outfile = optarg;
76 break;
77 case 'i':
78 infile = optarg;
79 break;
80 case 'b':
81 bootfile = optarg;
82 break;
83 case 't':
84 if(strcmp(optarg, "dualboot") == 0) opt.output = ZEN_DUALBOOT;
85 else if(strcmp(optarg, "mixedboot") == 0) opt.output = ZEN_MIXEDBOOT;
86 else if(strcmp(optarg, "singleboot") == 0) opt.output = ZEN_SINGLEBOOT;
87 else if(strcmp(optarg, "recovery") == 0) opt.output = ZEN_RECOVERY;
88 else
89 {
90 printf("Unknown output type '%s'\n", optarg);
91 return 1;
92 }
93 break;
94 default:
95 abort();
96 }
97 }
98
99 if(!outfile)
100 {
101 printf("You must specify an output file\n");
102 return 1;
103 }
104 if(!bootfile)
105 {
106 printf("You must specify a boot file\n");
107 return 1;
108 }
109 if(!infile)
110 {
111 printf("You must specify an input file\n");
112 return 1;
113 }
114 if(optind != argc)
115 {
116 printf("Extra arguments on command line\n");
117 return 1;
118 }
119
120 enum zen_error_t err = mkzenboot(infile, bootfile, outfile, opt);
121 printf("Result: %d\n", err);
122 return 0;
123}
diff --git a/utils/mkzenboot/md5.c b/utils/mkzenboot/md5.c
new file mode 100644
index 0000000000..530d8df15a
--- /dev/null
+++ b/utils/mkzenboot/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/mkzenboot/md5.h b/utils/mkzenboot/md5.h
new file mode 100644
index 0000000000..71fa395548
--- /dev/null
+++ b/utils/mkzenboot/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/mkzenboot/mkzenboot.c b/utils/mkzenboot/mkzenboot.c
new file mode 100644
index 0000000000..88d6821759
--- /dev/null
+++ b/utils/mkzenboot/mkzenboot.c
@@ -0,0 +1,697 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 * Based on zenutils by Rasmus Ry <rasmus.ry{at}gmail.com>
12 * Copyright (C) 2013 by Amaury Pouly
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include <stdio.h>
24#include <stdlib.h>
25#include <stdarg.h>
26#include <string.h>
27#include "mkzenboot.h"
28#include "utils.h"
29#include "dualboot.h"
30
31/**
32 * Keys used by players
33 */
34static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN.";
35static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP.";
36static const char null_key_v3[] = "CTL:N0MAD|PDE0.DPFP.";
37static const char null_key_v4[] = "CTL:Z3N07|PDE0.DPMP.";
38
39static const char tl_zvm_key[] = "1sN0TM3D az u~may th1nk*"
40 "Creative Zen Vision:M";
41static const char tl_zvm60_key[] = "1sN0TM3D az u~may th1nk*"
42 "Creative Zen Vision:M (D"
43 "VP-HD0004)";
44static const char tl_zen_key[] = "1sN0TM3D az u~may th1nk*"
45 "Creative ZEN";
46static const char tl_zenxf_key[] = "1sN0TM3D az u~may th1nk*"
47 "Creative ZEN X-Fi";
48static const char tl_zenmo_key[] = "1sN0TM3D az u~may th1nk*"
49 "Creative ZEN Mozaic";
50static const char tl_zv_key[] = "1sN0TM3D az u~may th1nk*"
51 "Creative Zen Vision";
52static const char tl_zvw_key[] = "1sN0TM3D az u~may th1nk*"
53 "Creative ZEN Vision W";
54static const char tl_zm_key[] = "1sN0TM3D az u~may th1nk*"
55 "Creative Zen Micro";
56static const char tl_zmp_key[] = "1sN0TM3D az u~may th1nk*"
57 "Creative Zen MicroPhoto";
58static const char tl_zs_key[] = "1sN0TM3D az u~may th1nk*"
59 "Creative Zen Sleek";
60static const char tl_zsp_key[] = "1sN0TM3D az u~may th1nk*"
61 "Creative Zen Sleek Photo";
62static const char tl_zt_key[] = "1sN0TM3D az u~may th1nk*"
63 "Creative Zen Touch";
64static const char tl_zx_key[] = "1sN0TM3D az u~may th1nk*"
65 "NOMAD Jukebox Zen Xtra";
66static const char tl_zenv_key[] = "1sN0TM3D az u~may th1nk*"
67 "Creative ZEN V";
68static const char tl_zenvp_key[] = "1sN0TM3D az u~may th1nk*"
69 "Creative ZEN V Plus";
70static const char tl_zenvv_key[] = "1sN0TM3D az u~may th1nk*"
71 "Creative ZEN V (Video)";
72
73struct player_info_t
74{
75 const char* name;
76 const char* null_key; /* HMAC-SHA1 key */
77 const char* tl_key; /* BlowFish key */
78 bool big_endian;
79 char *cinf;
80};
81
82static struct player_info_t zen_players[] =
83{
84 {"Zen Vision:M", null_key_v2, tl_zvm_key, false, NULL},
85 {"Zen Vision:M 60GB", null_key_v2, tl_zvm60_key, false, NULL},
86 {"Zen", null_key_v4, tl_zen_key, false, "Creative ZEN"},
87 {"Zen X-Fi", null_key_v4, tl_zenxf_key, false, "Creative ZEN X-Fi"},
88 {"Zen Mozaic", null_key_v4, tl_zenmo_key, false, "Creative ZEN Mozaic"},
89 {"Zen Vision", null_key_v2, tl_zv_key, false, NULL},
90 {"Zen Vision W", null_key_v2, tl_zvw_key, false, NULL},
91 {"Zen Micro", null_key_v1, tl_zm_key, true, NULL},
92 {"Zen MicroPhoto", null_key_v1, tl_zmp_key, true, NULL},
93 {"Zen Sleek", null_key_v1, tl_zs_key, true, NULL},
94 {"Zen SleekPhoto", null_key_v1, tl_zsp_key, true, NULL},
95 {"Zen Touch", null_key_v1, tl_zt_key, true, NULL},
96 {"Zen Xtra", null_key_v1, tl_zx_key, true, NULL},
97 {"Zen V", null_key_v3, tl_zenv_key, false, "Creative ZEN V"},
98 {"Zen V Plus", null_key_v3, tl_zenvp_key, false, NULL},
99 {"Zen V Video", null_key_v3, tl_zenvv_key, false, NULL},
100 {NULL, NULL, NULL, false, NULL}
101};
102
103/**
104 * Information on how to patch firmwares
105 */
106struct zen_model_desc_t
107{
108 /* Descriptive name of this model (must match player in zen_players[]) */
109 const char *model_name;
110 /* Model name used in the Rockbox header in ".zen" files - these match the
111 -add parameter to the "scramble" tool */
112 const char *rb_model_name;
113 /* Model number used to initialise the checksum in the Rockbox header in
114 ".zen" files - these are the same as MODEL_NUMBER in config-target.h */
115 const int rb_model_num;
116 /* Bootloader load address */
117 uint32_t bootloader_addr;
118 /* Dualboot code for this model */
119 const unsigned char *dualboot;
120 /* Size of dualboot functions for this model */
121 int dualboot_size;
122};
123
124/* keep this consistent with the address in dualboot.lds */
125static const struct zen_model_desc_t zen_models[] =
126{
127 [MODEL_UNKNOWN] =
128 {
129 "Unknown", " ", 0, 0, NULL, 0
130 },
131 [MODEL_ZENV] =
132 {
133 "Zen V", "zenv", 92, 0x61000000, dualboot_zenv, sizeof(dualboot_zenv)
134 },
135 [MODEL_ZENXFI] =
136 {
137 "Zen X-Fi", "zxfi", 86, 0x41000000, dualboot_zenxfi, sizeof(dualboot_zenxfi)
138 },
139 [MODEL_ZENMOZAIC] =
140 {
141 "Zen Mozaic", "zmoz", 87, 0x41000000, dualboot_zenmozaic, sizeof(dualboot_zenmozaic)
142 },
143 [MODEL_ZEN] =
144 {
145 "Zen", "zen", 90, 0x41000000, dualboot_zen, sizeof(dualboot_zen)
146 },
147};
148
149/**
150 * MD5 knowledge base
151 */
152
153struct zen_md5sum_t
154{
155 /* Device model */
156 enum zen_model_t model;
157 /* md5sum of the file */
158 char *md5sum;
159 /* Version string */
160 const char *version;
161};
162
163static const struct zen_md5sum_t zen_sums[] =
164{
165 /** Zen Mozaic */
166 {
167 /* Version 1.06.01 */
168 MODEL_ZENMOZAIC, "8441402a8db9f92659b05f05c0abe8fb", "1.06.01"
169 },
170 {
171 /* Version 1.06.01e */
172 MODEL_ZENMOZAIC, "88a856f8273b2bc3fcacf1f067a44aa8", "1.06.01e"
173 },
174 /** Zen X-Fi */
175 {
176 /* Version 1.04.08e */
177 MODEL_ZENXFI, "f07e2e75069289a2aa14c6583bd9643b", "1.04.08e"
178 },
179 {
180 /* Version 1.04.08 */
181 MODEL_ZENXFI, "c3cddf8468d8c8982e93aa9986c5a152", "1.04.08"
182 },
183 /** Zen V */
184 {
185 /* Version 1.32.01e */
186 MODEL_ZENV, "2f6d3e619557583c30132ac87221bc3e", "1.32.01e"
187 },
188 /** Zen */
189 {
190 /* Version 1.21.03e */
191 MODEL_ZEN, "1fe28f587f87ac3c280281db28c42465", "1.21.03e"
192 }
193};
194
195#define NR_ZEN_PLAYERS (sizeof(zen_players) / sizeof(zen_players[0]))
196#define NR_ZEN_SUMS (sizeof(zen_sums) / sizeof(zen_sums[0]))
197#define NR_ZEN_MODELS (sizeof(zen_models) / sizeof(zen_models[0]))
198
199#define MAGIC_ROCK 0x726f636b /* 'rock' */
200#define MAGIC_RECOVERY 0xfee1dead
201#define MAGIC_NORMAL 0xcafebabe
202
203/**
204 * Stolen from various places in our codebase
205 */
206
207/**
208 * EDOC file format
209 */
210struct edoc_header_t
211{
212 char magic[4];
213 uint32_t total_size;
214 uint32_t zero;
215};
216
217struct edoc_section_header_t
218{
219 uint32_t addr;
220 uint32_t size;
221 uint32_t checksum;
222};
223
224uint32_t edoc_checksum(void *buffer, size_t size)
225{
226 uint32_t c = 0;
227 uint32_t *p = buffer;
228 while(size >= 4)
229 {
230 c += *p + (*p >> 16);
231 p++;
232 size -= 4;
233 }
234 if(size != 0)
235 printf("[WARN] EDOC Checksum section size is not a multiple of 4 bytes, result is undefined!\n");
236 return c & 0xffff;
237}
238
239#define errorf(err, ...) do { printf(__VA_ARGS__); return err; } while(0)
240
241/**
242 * How does patching code work
243 * ---------------------------
244 *
245 * All Creative firmwares work the same: they start at 0 and the code sequence at
246 * 0 always contains the vector table with ldr with offsets:
247 * 0: e59ff018 ldr pc, [pc, #24] ; 0x20
248 * 4: e59ff018 ldr pc, [pc, #24] ; 0x24
249 * 8: e59ff018 ldr pc, [pc, #24] ; 0x28
250 * c: e59ff018 ldr pc, [pc, #24] ; 0x2c
251 * 10: e59ff018 ldr pc, [pc, #24] ; 0x30
252 * 14: e59ff018 ldr pc, [pc, #24] ; 0x34
253 * 18: e59ff018 ldr pc, [pc, #24] ; 0x38
254 * 1c: e59ff018 ldr pc, [pc, #24] ; 0x3c
255 * 20: 0000dbd4 .word start
256 * 24: 0000dcac .word undef_instr_handler
257 * 28: 0000dcb0 .word software_int_handler
258 * 2c: 0000dcb4 .word prefetch_abort_handler
259 * 30: 0000dcb8 .word data_abort_handler
260 * 34: 0000dcbc .word reserved_handler
261 * 38: 0000dcc0 .word irq_handler
262 * 3c: 0000dd08 .word fiq_handler
263 *
264 * To build a dual-boot image, we modify the start address to point to some
265 * code we added to the image. Specifically we first add the stub, then
266 * the rockbox image. We also write the old start address to this
267 * stub so that it can either decide to run rockbox or patch back the
268 * start address and jump to 0.
269 * Singleboot and recovery is handled the same way except that both targets use
270 * the same address and we drop the OF, so we create a fake vector table!
271 */
272
273struct dualboot_footer_t
274{
275 uint32_t magic;
276 uint32_t of_addr;
277 uint32_t rb_addr;
278 uint32_t boot_arg;
279} __attribute__((packed));
280
281#define FOOTER_MAGIC 0x1ceb00da
282
283static enum zen_error_t create_fake_image(uint8_t **fw, uint32_t *fw_size)
284{
285 /** We need to create a fake EDOC image, so first a header and one section
286 * header with one data chunk. */
287 /** The fake image is as follows:
288 * 0: e59ff018 ldr pc, [pc, #24] ; 0x20
289 * 4: e59ff018 ldr pc, [pc, #24] ; 0x24
290 * 8: e59ff018 ldr pc, [pc, #24] ; 0x28
291 * c: e59ff018 ldr pc, [pc, #24] ; 0x2c
292 * 10: e59ff018 ldr pc, [pc, #24] ; 0x30
293 * 14: e59ff018 ldr pc, [pc, #24] ; 0x34
294 * 18: e59ff018 ldr pc, [pc, #24] ; 0x38
295 * 1c: e59ff018 ldr pc, [pc, #24] ; 0x3c
296 * 20: 00000040 .word hang
297 * 24: 00000040 .word hang
298 * 28: 00000040 .word hang
299 * 2c: 00000040 .word hang
300 * 30: 00000040 .word hang
301 * 34: 00000040 .word hang
302 * 38: 00000040 .word hang
303 * 3c: 00000040 .word hang
304 * 40 <hang>:
305 * 40: eafffffe b 40 <hang> */
306 *fw_size = sizeof(struct edoc_header_t) + sizeof(struct edoc_section_header_t) + 0x44;
307 *fw = malloc(*fw_size);
308 if(*fw == NULL)
309 errorf(ZEN_ERROR, "[ERR] Allocation failed");
310 struct edoc_header_t *hdr = (void *)*fw;
311 memcpy(hdr->magic, "EDOC", 4);
312 hdr->total_size = *fw_size - sizeof(struct edoc_header_t) + 4;
313 hdr->zero = 0;
314 struct edoc_section_header_t *sec = (void *)(hdr + 1);
315 sec->addr = 0;
316 sec->size = 0x44;
317 uint32_t *p = (void *)(sec + 1);
318 p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = 0xe59ff018;
319 p[8] = p[9] = p[10] = p[11] = p[12] = p[13] = p[14] = p[15] = 0x40;
320 p[16] = 0xeafffffe;
321 sec->checksum = edoc_checksum(p, 0x44);
322 return ZEN_SUCCESS;
323}
324
325static enum zen_error_t patch_firmware(uint8_t **fw, uint32_t *fw_size,
326 void *boot, size_t boot_size, struct zen_option_t opt)
327{
328 /* check if dualboot stub is available */
329 const void *dualboot = zen_models[opt.model].dualboot;
330 int dualboot_size = zen_models[opt.model].dualboot_size;
331 uint32_t dualboot_addr = zen_models[opt.model].bootloader_addr;
332 if(dualboot == NULL)
333 errorf(ZEN_DONT_KNOW_HOW_TO_PATCH, "[ERR] I don't have a dualboot stub for this model\n");
334 /* if not asked to dualboot, drop OF and create a fake image */
335 if(opt.output != ZEN_DUALBOOT)
336 {
337 enum zen_error_t ret = create_fake_image(fw, fw_size);
338 if(ret != ZEN_SUCCESS)
339 return ret;
340 }
341 /* compute final image size: add stub + bootloader in one block as a section */
342 int extra_size = sizeof(struct edoc_section_header_t) + dualboot_size + boot_size;
343 *fw_size += extra_size;
344 *fw = realloc(*fw, *fw_size);
345 if(*fw == NULL)
346 errorf(ZEN_ERROR, "[ERR] Allocation failed");
347 /* sanity check */
348 struct edoc_header_t *hdr = (void *)*fw;
349 if(memcmp(hdr->magic, "EDOC", 4) != 0)
350 errorf(ZEN_FW_INVALID, "[ERR] Firmware doesn't use EDOC format\n");
351 /* validate image and find OF start addr */
352 uint32_t of_addr = 0;
353 struct edoc_section_header_t *sec_hdr = (void *)(hdr + 1);
354 while((void *)sec_hdr - (void *)&hdr->zero < hdr->total_size)
355 {
356 if(sec_hdr->checksum != edoc_checksum(sec_hdr + 1, sec_hdr->size))
357 errorf(ZEN_FW_INVALID, "[ERR] Firmware checksum error\n");
358 if(sec_hdr->addr == 0)
359 {
360 uint32_t *start_vector = ((void *)(sec_hdr + 1) + 0x20);
361 /* extract address */
362 of_addr = *(uint32_t *)start_vector;
363 /* patch vector */
364 *start_vector = dualboot_addr;
365 /* fix checksum */
366 sec_hdr->checksum = edoc_checksum(sec_hdr + 1, sec_hdr->size);
367 }
368 sec_hdr = (void *)(sec_hdr + 1) + sec_hdr->size;
369 }
370 if(of_addr == 0)
371 errorf(ZEN_FW_INVALID, "[ERR] Firmware doesn't have the expected format\n");
372 printf("[INFO] OF start address: %#x\n", of_addr);
373 /* add extra section */
374 sec_hdr->addr = dualboot_addr;
375 sec_hdr->size = dualboot_size + boot_size;
376 /* add extra data */
377 memcpy(sec_hdr + 1, dualboot, dualboot_size);
378 memcpy((void *)(sec_hdr + 1) + dualboot_size, boot, boot_size);
379 /* locate and patch dualboot footer */
380 struct dualboot_footer_t *footer = (void *)(sec_hdr + 1) + dualboot_size -
381 sizeof(struct dualboot_footer_t);
382 if(footer->magic != FOOTER_MAGIC)
383 errorf(ZEN_FW_INVALID, "[ERR] Footer magic mismatch\n");
384 uint32_t rb_addr = dualboot_addr + dualboot_size;
385 printf("[INFO] RB start address: %#x\n", rb_addr);
386 footer->of_addr = opt.output == ZEN_DUALBOOT ? of_addr : rb_addr;
387 footer->rb_addr = rb_addr;
388 footer->boot_arg = opt.output == ZEN_RECOVERY ? 0xfee1dead : 0xcafebabe;
389 printf("[INFO] Footer: 0x%08x 0x%08x 0x%08x\n", footer->of_addr, footer->rb_addr,
390 footer->boot_arg);
391 /* fix image */
392 sec_hdr->checksum = edoc_checksum(sec_hdr + 1, sec_hdr->size);
393 hdr->total_size += extra_size;
394 return ZEN_SUCCESS;
395}
396
397struct player_info_t *get_player_info(enum zen_model_t model)
398{
399 for(int i = 0; zen_players[i].name; i++)
400 if(strcmp(zen_models[model].model_name, zen_players[i].name) == 0)
401 return &zen_players[i];
402 return NULL;
403}
404
405enum zen_error_t build_firmware(void *exec, size_t exec_size, void *boot, size_t boot_size,
406 const char *outfile, struct zen_option_t opt)
407{
408 uint8_t *buffer = exec;
409 /** find player info */
410 struct player_info_t *player = get_player_info(opt.model);
411 if(player == NULL)
412 errorf(ZEN_UNSUPPORTED, "[ERR] There is no player info for this model\n");
413 if(player->big_endian)
414 errorf(ZEN_UNSUPPORTED, "[ERR] Big-endian players are currently unsupported\n");
415
416 /** Find Win32 PE .data section */
417 uint32_t data_ptr;
418 uint32_t data_size;
419 enum zen_error_t err = find_pe_data(exec, exec_size, &data_ptr, &data_size);
420 if(err != ZEN_SUCCESS)
421 errorf(err, "[ERR] Cannot find .data section\n");
422 printf("[INFO] .data section is at 0x%x with size 0x%x\n", data_ptr, data_size);
423
424 /** look for firmware and key in data section */
425 uint32_t fw_offset = find_firmware_offset(&buffer[data_ptr], data_size);
426 if(fw_offset == 0)
427 errorf(ZEN_FW_INVALID, "[ERR] Couldn't find firmware offset\n");
428 uint32_t fw_size = le2int(&buffer[data_ptr + fw_offset]);
429 printf("[INFO] Firmware offset is at 0x%x with size 0x%x\n", data_ptr + fw_offset, fw_size);
430 const char *fw_key = find_firmware_key(exec, exec_size);
431 if(fw_key == NULL)
432 errorf(ZEN_FW_INVALID, "[ERR] Couldn't find firmware key\n");
433 printf("[INFO] Firmware key is %s\n", fw_key);
434
435 /** descramble firmware */
436 printf("[INFO] Descrambling firmware... ");
437 if(!crypt_firmware(fw_key, &buffer[data_ptr + fw_offset + 4], fw_size))
438 errorf(ZEN_ERROR, "Fail!\n");
439 else
440 printf("Done!\n");
441 /** decompress it */
442 uint8_t *out_buffer = malloc(fw_size * 2);
443 if(out_buffer == NULL)
444 errorf(ZEN_ERROR, "[ERR] Couldn't allocate memory");
445 memset(out_buffer, 0, fw_size * 2);
446 printf("[INFO] Decompressing firmware... ");
447 char *err_msg;
448 if(!inflate_to_buffer(&buffer[data_ptr + fw_offset + 4], fw_size, out_buffer,
449 fw_size * 2, &err_msg))
450 errorf(ZEN_ERROR, "Fail!\n[ERR] ZLib error: %s\n", err_msg);
451 else
452 printf("Done!\n");
453
454 /** check format and resize the buffer */
455 if(memcmp(out_buffer, "FFIC", 4) != 0)
456 errorf(ZEN_FW_INVALID, "[ERR] CIFF header doesn't match\n");
457 uint32_t ciff_size = le2int(&out_buffer[4]) + 8 + 28; /* CIFF block + NULL block*/
458 printf("[INFO] Total firmware size: %d\n", ciff_size);
459 out_buffer = realloc(out_buffer, ciff_size);
460 if(out_buffer == NULL)
461 errorf(ZEN_ERROR, "[ERR] Cannot resize memory block\n");
462
463 /** look for firmware file */
464 printf("[INFO] Locating encoded block... ");
465 uint32_t fw_off = 8;
466 uint8_t *cinf_ptr = NULL;
467 while(memcmp(&out_buffer[fw_off], " LT\xa9", 4) != 0 && fw_off < ciff_size)
468 {
469 if(memcmp(&out_buffer[fw_off], "FNIC", 4) == 0)
470 {
471 cinf_ptr = &out_buffer[fw_off + 8];
472 fw_off += 4 + 4 + 96;
473 }
474 else if(memcmp(&out_buffer[fw_off], "ATAD", 4) == 0)
475 {
476 fw_off += 4;
477 fw_off += le2int(&out_buffer[fw_off]);
478 fw_off += 4;
479 }
480 else
481 errorf(ZEN_FW_INVALID, "Fail!\n[ERR] Unknown block\n");
482 }
483 if(fw_off >= ciff_size || memcmp(&out_buffer[fw_off], " LT\xa9", 4) != 0)
484 errorf(ZEN_FW_INVALID, "Fail!\n[ERR] Couldn't find encoded block\n");
485 if(!cinf_ptr)
486 errorf(ZEN_FW_INVALID, "Fail!\n[ERR] Couldn't find CINF\n");
487 printf("Done!\n");
488
489 /** validate player if possible */
490 printf("[INFO] Checking player model...");
491 if(player->cinf)
492 {
493 char cinf_ascii[96];
494 for(int j = 0; j < 96; j++)
495 cinf_ascii[j] = *(unsigned short *)&cinf_ptr[2 * j];
496 if(strncmp(cinf_ascii, player->cinf, 96) != 0)
497 errorf(ZEN_FW_MISMATCH, "Fail!\n[ERR] Player mismatch: CINF indicates '%s' instead of '%s'\n",
498 cinf_ascii, player->cinf);
499 else
500 printf("Done!\n");
501 }
502 else
503 printf("Bypass!\n");
504
505 /** decrypt firmware */
506 printf("[INFO] Decrypting encoded block... ");
507 uint32_t iv[2];
508 iv[0] = 0;
509 iv[1] = swap(le2int(&out_buffer[fw_off + 4]));
510 if(!bf_cbc_decrypt((unsigned char*)player->tl_key, strlen(player->tl_key) + 1,
511 &out_buffer[fw_off + 8], le2int(&out_buffer[fw_off + 4]), (const unsigned char*)&iv))
512 errorf(ZEN_ERROR, "Fail!\n[ERR] Couldn't decrypt encoded block\n");
513 printf("Done!\n");
514
515 /** sanity checks on firmware */
516 uint32_t jrm_size = le2int(&out_buffer[fw_off + 8]);
517 if(jrm_size > le2int(&out_buffer[fw_off + 4]) * 3)
518 errorf(ZEN_FW_INVALID, "[ERR] Decrypted length of encoded block is unexpectedly large: 0x%08x\n", jrm_size);
519 printf("[INFO] Firmware size: %d\n", jrm_size);
520 uint8_t *jrm = malloc(jrm_size);
521 if(jrm == NULL)
522 errorf(ZEN_ERROR, "[ERR] Couldn't allocate memory\n");
523 memset(buffer, 0, jrm_size);
524
525 /** decompress firmware */
526 printf("[INFO] Decompressing encoded block... ");
527 if(!cenc_decode(&out_buffer[fw_off + 12], le2int(&out_buffer[fw_off + 4]) - 4, jrm, jrm_size))
528 errorf(ZEN_ERROR, "Fail!\n[ERR] Couldn't decompress the encoded block\n");
529 printf("Done!\n");
530
531 /** Copy OF because patching might modify it */
532 void *jrm_save = malloc(jrm_size);
533 uint32_t jrm_save_size = jrm_size;
534 if(jrm_save == NULL)
535 errorf(ZEN_ERROR, "[ERR] Couldn't allocate memory");
536 memcpy(jrm_save, jrm, jrm_size);
537
538 /** Patch firmware */
539 err = patch_firmware(&jrm, &jrm_size, boot, boot_size, opt);
540 if(err != ZEN_SUCCESS)
541 errorf(err, "[ERR] Couldn't patch firmware\n");
542
543 /** Rebuild archive */
544 bool keep_old_bits = opt.output == ZEN_DUALBOOT || opt.output == ZEN_MIXEDBOOT;
545 bool keep_of = opt.output == ZEN_MIXEDBOOT;
546 /* if we keep old stuff, keep everything up to LT block, otherwise just CIFF header */
547 uint32_t off = keep_old_bits ? fw_off : 8;
548 /* move the rest of the archive if keeping old stuff */
549 if(keep_old_bits)
550 {
551 uint32_t copy_off = fw_off + 8 + le2int(&out_buffer[fw_off + 4]);
552 uint32_t copy_size = ciff_size - fw_off - 8 - le2int(&out_buffer[fw_off + 4]) - 28;
553 memmove(&out_buffer[off], &out_buffer[copy_off], copy_size);
554 off += copy_size;
555 }
556 /* if we keep the OF, put a copy of it after renaming it to Hcreativeos.jrm */
557 if(keep_of)
558 {
559 out_buffer = realloc(out_buffer, off + jrm_save_size + 40);
560 if(out_buffer == NULL)
561 errorf(ZEN_ERROR, "[ERR] Couldn't resize memory block\n");
562 printf("[INFO] Renaming encoded block to Hcreativeos.jrm... ");
563 memcpy(&out_buffer[off], "ATAD", 4);
564 int2le(jrm_save_size + 32, &out_buffer[off + 4]);
565 memset(&out_buffer[off + 8], 0, 32);
566 memcpy(&out_buffer[off + 8], "H\0c\0r\0e\0a\0t\0i\0v\0e\0o\0s\0.\0j\0r\0m", 30);
567 memcpy(&out_buffer[off + 40], jrm_save, jrm_save_size);
568 off += jrm_save_size + 40;
569 printf("Done!\n");
570 }
571 /* put modified firmware */
572 out_buffer = realloc(out_buffer, off + jrm_size + 40);
573 if(out_buffer == NULL)
574 errorf(ZEN_ERROR, "[ERR] Couldn't resize memory block\n");
575 printf("[INFO] Adding Hjukebox2.jrm... ");
576 memcpy(&out_buffer[off], "ATAD", 4);
577 int2le(jrm_size + 32, &out_buffer[off + 4]);
578 memset(&out_buffer[off + 8], 0, 32);
579 memcpy(&out_buffer[off + 8], "H\0j\0u\0k\0e\0b\0o\0x\0""2\0.\0j\0r\0m", 26);
580 memcpy(&out_buffer[off + 40], jrm, jrm_size);
581 off += jrm_size + 40;
582 printf("Done!\n");
583
584 /** fix header */
585 int2le(off - 8, &out_buffer[4]);
586
587 /** update checksum */
588 printf("[INFO] Updating checksum... ");
589 out_buffer = realloc(out_buffer, off + 28);
590 if(out_buffer == NULL)
591 errorf(ZEN_ERROR, "[ERR] Couldn't resize memory block\n");
592 memcpy(&out_buffer[off], "LLUN", 4);
593 int2le(20, &out_buffer[off + 4]);
594 hmac_sha1((unsigned char*)player->null_key, strlen(player->null_key), out_buffer,
595 off, &out_buffer[off + 8]);
596 off += 28;
597 printf("Done!\n");
598
599 err = write_file(outfile, out_buffer, off);
600
601 free(jrm);
602 free(jrm_save);
603 free(out_buffer);
604 return err;
605}
606
607/* find an entry into zen_sums which matches the MD5 sum of a file */
608static enum zen_error_t find_model_by_md5sum(uint8_t file_md5sum[16], int *md5_idx)
609{
610 int i = 0;
611 while(i < NR_ZEN_SUMS)
612 {
613 uint8_t md5[20];
614 if(strlen(zen_sums[i].md5sum) != 32)
615 errorf(ZEN_ERROR, "[ERR][INTERNAL] Invalid MD5 sum in zen_sums\n");
616 for(int j = 0; j < 16; j++)
617 {
618 uint8_t a, b;
619 if(convxdigit(zen_sums[i].md5sum[2 * j], &a) || convxdigit(zen_sums[i].md5sum[2 * j + 1], &b))
620 errorf(ZEN_ERROR, "[ERR][INTERNAL] Bad checksum format: %s\n", zen_sums[i].md5sum);
621 md5[j] = (a << 4) | b;
622 }
623 if(memcmp(file_md5sum, md5, 16) == 0)
624 break;
625 i++;
626 }
627 if(i == NR_ZEN_SUMS)
628 errorf(ZEN_NO_MATCH, "[ERR] MD5 sum doesn't match any known file\n");
629 *md5_idx = i;
630 return ZEN_SUCCESS;
631}
632
633enum zen_error_t mkzenboot(const char *infile, const char *bootfile,
634 const char *outfile, struct zen_option_t opt)
635{
636 /* determine firmware model */
637 void *fw;
638 size_t fw_size;
639 enum zen_error_t err = read_file(infile, &fw, &fw_size);
640 uint8_t file_md5sum[16];
641 err = compute_md5sum_buf(fw, fw_size, file_md5sum);
642 if(err != ZEN_SUCCESS)
643 {
644 free(fw);
645 return err;
646 }
647 printf("[INFO] MD5 sum of the file: ");
648 for(int i = 0; i < 16; i++)
649 printf("%02X ", file_md5sum[i]);
650 printf("\n");
651 if(opt.model == MODEL_UNKNOWN)
652 {
653 int idx;
654 err = find_model_by_md5sum(file_md5sum, &idx);
655 if(err != ZEN_SUCCESS)
656 {
657 free(fw);
658 errorf(err, "[ERR] Cannot determine model type\n");
659 }
660 opt.model = zen_sums[idx].model;
661 printf("[INFO] MD5 matches %s, version %s\n",
662 zen_models[opt.model].model_name, zen_sums[idx].version);
663 }
664 printf("[INFO] Model is: %s\n", zen_models[opt.model].model_name);
665 /* load rockbox file */
666 uint8_t *boot;
667 size_t boot_size;
668 err = read_file(bootfile, (void **)&boot, &boot_size);
669 if(err != ZEN_SUCCESS)
670 {
671 free(fw);
672 errorf(err, "[ERR] Cannot read boot file\n");
673 }
674 /* validate checksum */
675 if(memcmp(boot + 4, zen_models[opt.model].rb_model_name, 4) != 0)
676 {
677 free(fw);
678 free(boot);
679 errorf(ZEN_BOOT_MISMATCH, "[ERR] Boot model mismatch\n");
680 }
681 printf("[INFO] Bootloader file matches model\n");
682 uint32_t sum = zen_models[opt.model].rb_model_num;
683 for(int i = 8; i < boot_size; i++)
684 sum += boot[i];
685 if(sum != be2int(boot))
686 {
687 free(fw);
688 free(boot);
689 errorf(ZEN_BOOT_CHECKSUM_ERROR, "[ERR] Checksum mismatch\n");
690 }
691 printf("[INFO] Bootloader file checksum is correct\n");
692 /* produce file */
693 err = build_firmware(fw, fw_size, boot + 8, boot_size - 8, outfile, opt);
694 free(boot);
695 free(fw);
696 return err;
697}
diff --git a/utils/mkzenboot/mkzenboot.h b/utils/mkzenboot/mkzenboot.h
new file mode 100644
index 0000000000..8da3e25762
--- /dev/null
+++ b/utils/mkzenboot/mkzenboot.h
@@ -0,0 +1,86 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
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#ifndef MKZENBOOT_H
23#define MKZENBOOT_H
24
25#include <stdbool.h>
26#include <stdint.h>
27#include <sys/types.h>
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33enum zen_error_t
34{
35 ZEN_SUCCESS = 0,
36 ZEN_ERROR = -1,
37 ZEN_OPEN_ERROR = -2,
38 ZEN_READ_ERROR = -3,
39 ZEN_NO_MATCH = -4,
40 ZEN_BOOT_INVALID = -5,
41 ZEN_BOOT_MISMATCH = -6,
42 ZEN_BOOT_CHECKSUM_ERROR = -7,
43 ZEN_DONT_KNOW_HOW_TO_PATCH = -8,
44 ZEN_WRITE_ERROR = -9,
45 ZEN_UNSUPPORTED = 10,
46 ZEN_FW_INVALID = -11,
47 ZEN_FW_MISMATCH = -12,
48 ZEN_FIRST_ZENTOOLS_ERROR = -12,
49};
50
51enum zen_output_type_t
52{
53 ZEN_DUALBOOT = 0, /* keep all OF data and pack OF+RB into firmware for dualboot */
54 ZEN_MIXEDBOOT, /* rename OF, keep data, put RB as firmware, use RB bootloader to dualboot */
55 ZEN_RECOVERY, /* only put rockbox with recovery mode */
56 ZEN_SINGLEBOOT, /* only put rockbox with recovery mode */
57};
58
59/* Supported models */
60enum zen_model_t
61{
62 MODEL_UNKNOWN = 0,
63 MODEL_ZENMOZAIC,
64 MODEL_ZENV,
65 MODEL_ZENXFI,
66 MODEL_ZEN,
67 /* new models go here */
68
69 NUM_MODELS
70};
71
72struct zen_option_t
73{
74 bool debug;
75 enum zen_output_type_t output;
76 enum zen_model_t model; /* pass MODEL_UNKNOWN to use MD5 knowledge base */
77};
78
79enum zen_error_t mkzenboot(const char *infile, const char *bootfile,
80 const char *outfile, struct zen_option_t opt);
81
82#ifdef __cplusplus
83}
84#endif
85#endif
86
diff --git a/utils/mkzenboot/utils.c b/utils/mkzenboot/utils.c
new file mode 100644
index 0000000000..b8ef3be237
--- /dev/null
+++ b/utils/mkzenboot/utils.c
@@ -0,0 +1,896 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 * Based on zenutils by Rasmus Ry <rasmus.ry{at}gmail.com>
12 * Copyright (C) 2013 by Amaury Pouly
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "utils.h"
24#include "md5.h"
25#include <zlib.h>
26//#include "hmac-sha1.h"
27
28int filesize(FILE* fd)
29{
30 int tmp, tmp2 = ftell(fd);
31 fseek(fd, 0, SEEK_END);
32 tmp = ftell(fd);
33 fseek(fd, tmp2, SEEK_SET);
34 return tmp;
35}
36
37unsigned int le2int(unsigned char* buf)
38{
39 return ((buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]);
40}
41
42unsigned int be2int(unsigned char* buf)
43{
44 return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
45}
46
47void int2le(unsigned int val, unsigned char* addr)
48{
49 addr[0] = val & 0xFF;
50 addr[1] = (val >> 8) & 0xff;
51 addr[2] = (val >> 16) & 0xff;
52 addr[3] = (val >> 24) & 0xff;
53}
54
55const char* find_firmware_key(const unsigned char* buffer, size_t len)
56{
57 char szkey1[] = "34d1";
58 size_t cchkey1 = strlen(szkey1);
59 char szkey2[] = "TbnCboEbn";
60 size_t cchkey2 = strlen(szkey2);
61 uint32_t i;
62 for (i = 0; i < (uint32_t)len; i++)
63 {
64 if (len >= cchkey1)
65 {
66 if (!strncmp((char*)&buffer[i], szkey1, cchkey1))
67 return (const char*)&buffer[i];
68 }
69 if (len >= cchkey2)
70 {
71 if (!strncmp((char*)&buffer[i], szkey2, cchkey2))
72 return (const char*)&buffer[i];
73 }
74 }
75 return NULL;
76}
77
78uint32_t find_firmware_offset(unsigned char* buffer, size_t len)
79{
80 uint32_t i;
81 for (i = 0; i < (uint32_t)len; i += 0x10)
82 {
83 if (buffer[i + sizeof(uint32_t)] != 0
84 && buffer[i + sizeof(uint32_t) + 1] != 0
85 && buffer[i + sizeof(uint32_t) + 2] != 0
86 && buffer[i + sizeof(uint32_t) + 3] != 0)
87 {
88 return i;
89 }
90 if(i > 0xFF) /* Arbitrary guess */
91 return 0;
92 }
93 return 0;
94}
95
96bool crypt_firmware(const char* key, unsigned char* buffer, size_t len)
97{
98 char key_cpy[255];
99 unsigned int i;
100 unsigned int tmp = 0;
101 int key_length = strlen(key);
102
103 strcpy(key_cpy, key);
104 for(i=0; i < strlen(key); i++)
105 key_cpy[i] = key[i] - 1;
106
107 for(i=0; i < len; i++)
108 {
109 buffer[i] ^= key_cpy[tmp] | 0x80;
110 tmp = (tmp + 1) % key_length;
111 }
112
113 return true;
114}
115
116bool inflate_to_buffer(const unsigned char *buffer, size_t len, unsigned char* out_buffer, size_t out_len, char** err_msg)
117{
118 /* Initialize Zlib */
119 z_stream d_stream;
120 int ret;
121
122 d_stream.zalloc = Z_NULL;
123 d_stream.zfree = Z_NULL;
124 d_stream.opaque = Z_NULL;
125
126 d_stream.next_in = (unsigned char*)buffer;
127 d_stream.avail_in = len;
128
129 ret = inflateInit(&d_stream);
130 if (ret != Z_OK)
131 {
132 *err_msg = d_stream.msg;
133 return false;
134 }
135
136 d_stream.next_out = out_buffer;
137 d_stream.avail_out = out_len;
138
139 ret = inflate(&d_stream, Z_SYNC_FLUSH);
140 if(ret < 0)
141 {
142 *err_msg = d_stream.msg;
143 return false;
144 }
145 else
146 inflateEnd(&d_stream);
147
148 return true;
149}
150
151#define CODE_MASK 0xC0
152#define ARGS_MASK 0x3F
153
154#define REPEAT_CODE 0x00
155#define BLOCK_CODE 0x40
156#define LONG_RUN_CODE 0x80
157#define SHORT_RUN_CODE 0xC0
158
159#define BLOCK_ARGS 0x1F
160#define BLOCK_MODE 0x20
161
162
163static void decode_run(unsigned char* dst, uint16_t len, unsigned char val,
164 int* dstidx)
165{
166 memset(dst + *dstidx, val, len);
167 *dstidx += len;
168}
169
170static void decode_pattern(unsigned char* src, unsigned char* dst,
171 uint16_t len, int* srcidx, int* dstidx,
172 bool bdecode, int npasses)
173{
174 int i, j;
175 for (i = 0; i < npasses; i++)
176 {
177 if (bdecode)
178 {
179 for (j = 0; j < len; j++)
180 {
181 uint16_t c, d;
182 c = src[*srcidx + j];
183 d = (c >> 5) & 7;
184 c = (c << 3) & 0xF8;
185 src[*srcidx + j] = (unsigned char)(c | d);
186 }
187 bdecode = false;
188 }
189 memcpy(dst + *dstidx, src + *srcidx, len);
190 *dstidx += len;
191 }
192 *srcidx += len;
193}
194
195int cenc_decode(unsigned char* src, int srclen, unsigned char* dst, int dstlen)
196{
197 int i = 0, j = 0;
198 do
199 {
200 uint16_t c, d, e;
201 c = src[i++];
202 switch (c & CODE_MASK)
203 {
204 case REPEAT_CODE: /* 2 unsigned chars */
205 d = src[i++];
206 d = d + 2;
207
208 e = (c & ARGS_MASK) + 2;
209
210 decode_pattern(src, dst, e, &i, &j, false, d);
211 break;
212
213 case BLOCK_CODE: /* 1/2/3 unsigned chars */
214 d = c & BLOCK_ARGS;
215 if (!(c & BLOCK_MODE))
216 {
217 e = src[i++];
218 e = (d << 8) + (e + 0x21);
219
220 d = (uint16_t)(i ^ j);
221 }
222 else
223 {
224 e = d + 1;
225
226 d = (uint16_t)(i ^ j);
227 }
228 if (d & 1)
229 {
230 i++;
231 }
232
233 decode_pattern(src, dst, e, &i, &j, true, 1);
234 break;
235
236 case LONG_RUN_CODE: /* 3 unsigned chars */
237 d = src[i++];
238 e = ((c & ARGS_MASK) << 8) + (d + 0x42);
239
240 d = src[i++];
241 d = ((d & 7) << 5) | ((d >> 3) & 0x1F);
242
243 decode_run(dst, e, (unsigned char)(d), &j);
244 break;
245
246 case SHORT_RUN_CODE: /* 2 unsigned chars */
247 d = src[i++];
248 d = ((d & 3) << 6) | ((d >> 2) & 0x3F);
249
250 e = (c & ARGS_MASK) + 2;
251
252 decode_run(dst, e, (unsigned char)(d), &j);
253 break;
254 };
255 } while (i < srclen && j < dstlen);
256
257 return j;
258}
259
260/*
261 * Copyright (c) 1999, 2000, 2002 Virtual Unlimited B.V.
262 *
263 * This library is free software; you can redistribute it and/or
264 * modify it under the terms of the GNU Lesser General Public
265 * License as published by the Free Software Foundation; either
266 * version 2.1 of the License, or (at your option) any later version.
267 *
268 * This library is distributed in the hope that it will be useful,
269 * but WITHOUT ANY WARRANTY; without even the implied warranty of
270 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
271 * Lesser General Public License for more details.
272 *
273 * You should have received a copy of the GNU Lesser General Public
274 * License along with this library; if not, write to the Free Software
275 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
276 *
277 */
278
279#define BLOWFISHROUNDS 16
280#define BLOWFISHPSIZE (BLOWFISHROUNDS+2)
281#define WORDS_BIGENDIAN 0
282
283struct blowfishParam
284{
285 uint32_t p[BLOWFISHPSIZE];
286 uint32_t s[1024];
287 uint32_t fdback[2];
288};
289
290typedef enum
291{
292 NOCRYPT,
293 ENCRYPT,
294 DECRYPT
295} cipherOperation;
296
297static inline uint32_t swapu32(uint32_t n)
298{
299 return ( ((n & 0xffU) << 24) |
300 ((n & 0xff00U) << 8) |
301 ((n & 0xff0000U) >> 8) |
302 ((n & 0xff000000U) >> 24) );
303}
304
305static uint32_t _bf_p[BLOWFISHPSIZE] = {
306 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
307 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
308 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
309 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
310 0x9216d5d9, 0x8979fb1b
311};
312
313static uint32_t _bf_s[1024] = {
314 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
315 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
316 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
317 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
318 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
319 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
320 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
321 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
322 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
323 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
324 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
325 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
326 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
327 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
328 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
329 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
330 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
331 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
332 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
333 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
334 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
335 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
336 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
337 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
338 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
339 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
340 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
341 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
342 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
343 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
344 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
345 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
346 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
347 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
348 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
349 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
350 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
351 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
352 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
353 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
354 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
355 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
356 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
357 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
358 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
359 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
360 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
361 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
362 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
363 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
364 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
365 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
366 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
367 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
368 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
369 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
370 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
371 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
372 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
373 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
374 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
375 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
376 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
377 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
378 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
379 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
380 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
381 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
382 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
383 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
384 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
385 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
386 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
387 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
388 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
389 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
390 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
391 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
392 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
393 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
394 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
395 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
396 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
397 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
398 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
399 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
400 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
401 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
402 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
403 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
404 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
405 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
406 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
407 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
408 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
409 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
410 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
411 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
412 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
413 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
414 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
415 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
416 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
417 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
418 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
419 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
420 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
421 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
422 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
423 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
424 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
425 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
426 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
427 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
428 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
429 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
430 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
431 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
432 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
433 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
434 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
435 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
436 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
437 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
438 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
439 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
440 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
441 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
442 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
443 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
444 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
445 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
446 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
447 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
448 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
449 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
450 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
451 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
452 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
453 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
454 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
455 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
456 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
457 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
458 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
459 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
460 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
461 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
462 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
463 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
464 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
465 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
466 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
467 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
468 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
469 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
470 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
471 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
472 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
473 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
474 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
475 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
476 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
477 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
478 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
479 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
480 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
481 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
482 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
483 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
484 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
485 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
486 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
487 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
488 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
489 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
490 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
491 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
492 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
493 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
494 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
495 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
496 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
497 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
498 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
499 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
500 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
501 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
502 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
503 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
504 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
505 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
506 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
507 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
508 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
509 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
510 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
511 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
512 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
513 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
514 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
515 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
516 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
517 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
518 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
519 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
520 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
521 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
522 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
523 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
524 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
525 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
526 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
527 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
528 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
529 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
530 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
531 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
532 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
533 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
534 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
535 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
536 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
537 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
538 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
539 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
540 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
541 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
542 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
543 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
544 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
545 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
546 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
547 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
548 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
549 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
550 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
551 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
552 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
553 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
554 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
555 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
556 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
557 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
558 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
559 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
560 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
561 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
562 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
563 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
564 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
565 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
566 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
567 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
568 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
569 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
570};
571
572#define EROUND(l,r) l ^= *(p++); r ^= ((s[((l>>24)&0xff)+0x000]+s[((l>>16)&0xff)+0x100])^s[((l>>8)&0xff)+0x200])+s[((l>>0)&0xff)+0x300]
573#define DROUND(l,r) l ^= *(p--); r ^= ((s[((l>>24)&0xff)+0x000]+s[((l>>16)&0xff)+0x100])^s[((l>>8)&0xff)+0x200])+s[((l>>0)&0xff)+0x300]
574
575static int blowfishEncrypt(struct blowfishParam* bp, uint32_t* dst, const uint32_t* src)
576{
577 #if WORDS_BIGENDIAN
578 register uint32_t xl = src[0], xr = src[1];
579 #else
580 register uint32_t xl = swapu32(src[0]), xr = swapu32(src[1]);
581 #endif
582 register uint32_t* p = bp->p;
583 register uint32_t* s = bp->s;
584
585 EROUND(xl, xr); EROUND(xr, xl);
586 EROUND(xl, xr); EROUND(xr, xl);
587 EROUND(xl, xr); EROUND(xr, xl);
588 EROUND(xl, xr); EROUND(xr, xl);
589 EROUND(xl, xr); EROUND(xr, xl);
590 EROUND(xl, xr); EROUND(xr, xl);
591 EROUND(xl, xr); EROUND(xr, xl);
592 EROUND(xl, xr); EROUND(xr, xl);
593
594 #if WORDS_BIGENDIAN
595 dst[1] = xl ^ *(p++);
596 dst[0] = xr ^ *(p++);
597 #else
598 dst[1] = swapu32(xl ^ *(p++));
599 dst[0] = swapu32(xr ^ *(p++));
600 #endif
601
602 return 0;
603}
604
605static int blowfishDecrypt(struct blowfishParam* bp, uint32_t* dst, const uint32_t* src)
606{
607 #if WORDS_BIGENDIAN
608 register uint32_t xl = src[0], xr = src[1];
609 #else
610 register uint32_t xl = swapu32(src[0]), xr = swapu32(src[1]);
611 #endif
612 register uint32_t* p = bp->p+BLOWFISHPSIZE-1;
613 register uint32_t* s = bp->s;
614
615 DROUND(xl, xr); DROUND(xr, xl);
616 DROUND(xl, xr); DROUND(xr, xl);
617 DROUND(xl, xr); DROUND(xr, xl);
618 DROUND(xl, xr); DROUND(xr, xl);
619 DROUND(xl, xr); DROUND(xr, xl);
620 DROUND(xl, xr); DROUND(xr, xl);
621 DROUND(xl, xr); DROUND(xr, xl);
622 DROUND(xl, xr); DROUND(xr, xl);
623
624 #if WORDS_BIGENDIAN
625 dst[1] = xl ^ *(p--);
626 dst[0] = xr ^ *(p--);
627 #else
628 dst[1] = swapu32(xl ^ *(p--));
629 dst[0] = swapu32(xr ^ *(p--));
630 #endif
631
632 return 0;
633}
634
635static int blowfishSetup(struct blowfishParam* bp, const unsigned char* key, size_t keybits, cipherOperation op)
636{
637 if ((op != ENCRYPT) && (op != DECRYPT))
638 return -1;
639
640 if (((keybits & 7) == 0) && (keybits >= 32) && (keybits <= 448))
641 {
642 register uint32_t* p = bp->p;
643 register uint32_t* s = bp->s;
644 register unsigned int i, j, k;
645
646 uint32_t tmp, work[2];
647
648 memcpy(s, _bf_s, 1024 * sizeof(uint32_t));
649
650 for (i = 0, k = 0; i < BLOWFISHPSIZE; i++)
651 {
652 tmp = 0;
653 for (j = 0; j < 4; j++)
654 {
655 tmp <<= 8;
656 tmp |= key[k++];
657 if (k >= (keybits >> 3))
658 k = 0;
659 }
660 p[i] = _bf_p[i] ^ tmp;
661 }
662
663 work[0] = work[1] = 0;
664
665 for (i = 0; i < BLOWFISHPSIZE; i += 2, p += 2)
666 {
667 blowfishEncrypt(bp, work, work);
668 #if WORDS_BIGENDIAN
669 p[0] = work[0];
670 p[1] = work[1];
671 #else
672 p[0] = swapu32(work[0]);
673 p[1] = swapu32(work[1]);
674 #endif
675 }
676
677 for (i = 0; i < 1024; i += 2, s += 2)
678 {
679 blowfishEncrypt(bp, work, work);
680 #if WORDS_BIGENDIAN
681 s[0] = work[0];
682 s[1] = work[1];
683 #else
684 s[0] = swapu32(work[0]);
685 s[1] = swapu32(work[1]);
686 #endif
687 }
688
689 /* clear fdback/iv */
690 bp->fdback[0] = 0;
691 bp->fdback[1] = 0;
692
693 return 0;
694 }
695 return -1;
696}
697
698static int blowfishSetIV(struct blowfishParam* bp, const unsigned char* iv)
699{
700 if (iv)
701 memcpy(bp->fdback, iv, 8);
702 else
703 memset(bp->fdback, 0, 8);
704
705 return 0;
706}
707
708#define BLOWFISH_BLOCKSIZE 8
709static int blowfishDecryptCBC(struct blowfishParam* bp, uint32_t* dst, const uint32_t* src, unsigned int nblocks)
710{
711 register const unsigned int blockwords = BLOWFISH_BLOCKSIZE >> 2;
712 register uint32_t* fdback = bp->fdback;
713 register uint32_t* buf = (uint32_t*) malloc(blockwords * sizeof(uint32_t));
714
715 if (buf)
716 {
717 while (nblocks > 0)
718 {
719 register uint32_t tmp;
720 register unsigned int i;
721
722 blowfishDecrypt(bp, buf, src);
723
724 for (i = 0; i < blockwords; i++)
725 {
726 tmp = src[i];
727 dst[i] = buf[i] ^ fdback[i];
728 fdback[i] = tmp;
729 }
730
731 dst += blockwords;
732 src += blockwords;
733
734 nblocks--;
735 }
736 free(buf);
737 return 0;
738 }
739
740 return -1;
741}
742
743bool bf_cbc_decrypt(const unsigned char* key, size_t keylen,
744 unsigned char* data, size_t datalen,
745 const unsigned char* iv)
746{
747 struct blowfishParam param;
748 unsigned char *cipher;
749 unsigned int nblocks;
750
751 if (datalen % BLOWFISH_BLOCKSIZE)
752 return false;
753
754 if (blowfishSetup(&param, key, keylen * 8, ENCRYPT))
755 return false;
756 if (blowfishSetIV(&param, iv))
757 return false;
758
759 cipher = malloc(datalen);
760 memcpy(cipher, data, datalen);
761
762 nblocks = datalen / BLOWFISH_BLOCKSIZE;
763 if (blowfishDecryptCBC(&param, (uint32_t*)data, (uint32_t*)cipher,
764 nblocks))
765 {
766 free(cipher);
767 return false;
768 }
769
770 free(cipher);
771 return true;
772}
773
774uint32_t swap(uint32_t val)
775{
776 return ((val & 0xFF) << 24)
777 | ((val & 0xFF00) << 8)
778 | ((val & 0xFF0000) >> 8)
779 | ((val & 0xFF000000) >> 24);
780}
781
782/* read a file to a buffer */
783enum zen_error_t read_file(const char *file, void **buffer, size_t *size)
784{
785 FILE *f = fopen(file, "rb");
786 if(f == NULL)
787 {
788 printf("[ERR] Cannot open file '%s' for reading: %m\n", file);
789 return ZEN_OPEN_ERROR;
790 }
791 fseek(f, 0, SEEK_END);
792 *size = ftell(f);
793 fseek(f, 0, SEEK_SET);
794 *buffer = malloc(*size);
795 if(fread(*buffer, *size, 1, f) != 1)
796 {
797 free(*buffer);
798 fclose(f);
799 printf("[ERR] Cannot read file '%s': %m\n", file);
800 return ZEN_READ_ERROR;
801 }
802 fclose(f);
803 return ZEN_SUCCESS;
804}
805
806/* write a file from a buffer */
807enum zen_error_t write_file(const char *file, void *buffer, size_t size)
808{
809 FILE *f = fopen(file, "wb");
810 if(f == NULL)
811 {
812 printf("[ERR] Cannot open file '%s' for writing: %m\n", file);
813 return ZEN_OPEN_ERROR;
814 }
815 if(fwrite(buffer, size, 1, f) != 1)
816 {
817 fclose(f);
818 printf("[ERR] Cannot write file '%s': %m\n", file);
819 return ZEN_WRITE_ERROR;
820 }
821 fclose(f);
822 return ZEN_SUCCESS;
823}
824
825/* compute MD5 sum of a buffer */
826enum zen_error_t compute_md5sum_buf(void *buf, size_t sz, uint8_t file_md5sum[16])
827{
828 md5_context ctx;
829 md5_starts(&ctx);
830 md5_update(&ctx, buf, sz);
831 md5_finish(&ctx, file_md5sum);
832 return ZEN_SUCCESS;
833}
834
835/* compute MD5 of a file */
836enum zen_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16])
837{
838 void *buf;
839 size_t sz;
840 enum zen_error_t err = read_file(file, &buf, &sz);
841 if(err != ZEN_SUCCESS)
842 return err;
843 compute_md5sum_buf(buf, sz, file_md5sum);
844 free(buf);
845 return ZEN_SUCCESS;
846}
847
848enum zen_error_t find_pe_data(void *fw, size_t fw_size, uint32_t *data_ptr, uint32_t *data_size)
849{
850 uint8_t *buffer = fw;
851 /* Rudimentary Win32 PE reading to find .data section */
852 if(memcmp(&buffer[0], "MZ", 2) != 0 && memcmp(&buffer[0x118], "PE", 2) != 0)
853 {
854 printf("[ERR] Input file isn't an executable\n");
855 return ZEN_FW_INVALID;
856 }
857 *data_ptr = 0, *data_size = 0;
858 uint32_t start_sec_addr = /*sizeof NT headers */ 0xf8 +
859 /* address of opt header */*(uint32_t *)&buffer[0x3c];
860 for(uint32_t i = start_sec_addr; i < 0x1000; i += 0x28)
861 {
862 if(strcmp((char*)&buffer[i], ".data") == 0)
863 {
864 *data_ptr = le2int(&buffer[i + 0x14]);
865 *data_size = le2int(&buffer[i + 0x10]);
866 break;
867 }
868 }
869 if(*data_ptr == 0 || *data_size == 0)
870 {
871 printf("[ERR] Couldn't find .data section\n");
872 return ZEN_FW_INVALID;
873 }
874 return ZEN_SUCCESS;
875}
876
877int convxdigit(char digit, uint8_t *val)
878{
879 if(digit >= '0' && digit <= '9')
880 {
881 *val = digit - '0';
882 return 0;
883 }
884 else if(digit >= 'A' && digit <= 'F')
885 {
886 *val = digit - 'A' + 10;
887 return 0;
888 }
889 else if(digit >= 'a' && digit <= 'f')
890 {
891 *val = digit - 'a' + 10;
892 return 0;
893 }
894 else
895 return 1;
896}
diff --git a/utils/mkzenboot/utils.h b/utils/mkzenboot/utils.h
new file mode 100644
index 0000000000..56edb4e20b
--- /dev/null
+++ b/utils/mkzenboot/utils.h
@@ -0,0 +1,53 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
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#ifndef __UTILS__
22#define __UTILS__
23
24#include <stddef.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <stdbool.h>
29#include <string.h>
30#include "mkzenboot.h"
31#include "hmac-sha1.h"
32
33int filesize(FILE* fd);
34unsigned int le2int(unsigned char* buf);
35unsigned int be2int(unsigned char* buf);
36void int2le(unsigned int val, unsigned char* addr);
37const char* find_firmware_key(const unsigned char* buffer, size_t len);
38uint32_t find_firmware_offset(unsigned char* buffer, size_t len);
39bool crypt_firmware(const char* key, unsigned char* buffer, size_t len);
40bool inflate_to_buffer(const unsigned char *buffer, size_t len,
41 unsigned char* out_buffer, size_t out_len, char** err_msg);
42int cenc_decode(unsigned char* src, int srclen, unsigned char* dst, int dstlen);
43bool bf_cbc_decrypt(const unsigned char* key, size_t keylen, unsigned char* data,
44 size_t datalen, const unsigned char* iv);
45uint32_t swap(uint32_t val);
46enum zen_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16]);
47enum zen_error_t compute_md5sum_buf(void *buf, size_t sz, uint8_t file_md5sum[16]);
48enum zen_error_t read_file(const char *file, void **buffer, size_t *size);
49enum zen_error_t write_file(const char *file, void *buffer, size_t size);
50enum zen_error_t find_pe_data(void *fw, size_t fw_size, uint32_t *data_ptr, uint32_t *data_size);
51int convxdigit(char digit, uint8_t *val);
52
53#endif /* __UTILS__ */ \ No newline at end of file