summaryrefslogtreecommitdiffstats
path: root/utils/imxtools
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-11-06 01:49:13 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-11-06 01:49:13 +0000
commit5827937270bac874ae9e04679b3130fef9e306c4 (patch)
tree51bc262dedecdb7620300b46f23005c4b0eed311 /utils/imxtools
parent33d6bd61b51178b42a07a97118a689d849666331 (diff)
downloadrockbox-5827937270bac874ae9e04679b3130fef9e306c4.tar.gz
rockbox-5827937270bac874ae9e04679b3130fef9e306c4.zip
sbtools: rename to imxtools, move imx_hid_recovery to imxtools/sbloader, fix tools to correctly handle/free memory, properly return error codes
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30907 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/imxtools')
-rw-r--r--utils/imxtools/Makefile26
-rw-r--r--utils/imxtools/README32
-rw-r--r--utils/imxtools/aes128.c284
-rw-r--r--utils/imxtools/crc.c83
-rw-r--r--utils/imxtools/crypto.c188
-rw-r--r--utils/imxtools/crypto.h115
-rw-r--r--utils/imxtools/dbparser.c849
-rw-r--r--utils/imxtools/dbparser.h118
-rw-r--r--utils/imxtools/elf.c575
-rw-r--r--utils/imxtools/elf.h94
-rw-r--r--utils/imxtools/elftosb.c461
-rw-r--r--utils/imxtools/fuze+_key_file.txt1
-rw-r--r--utils/imxtools/misc.c248
-rw-r--r--utils/imxtools/misc.h59
-rw-r--r--utils/imxtools/sb.c1181
-rw-r--r--utils/imxtools/sb.h237
-rw-r--r--utils/imxtools/sbloader.c174
-rw-r--r--utils/imxtools/sbtoelf.c302
-rw-r--r--utils/imxtools/sha1.c150
19 files changed, 5177 insertions, 0 deletions
diff --git a/utils/imxtools/Makefile b/utils/imxtools/Makefile
new file mode 100644
index 0000000000..7a09d86d24
--- /dev/null
+++ b/utils/imxtools/Makefile
@@ -0,0 +1,26 @@
+DEFINES=-DCRYPTO_LIBUSB
+CC=gcc
+LD=gcc
+CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
+LDFLAGS=`pkg-config --libs libusb-1.0`
+BINS=elftosb sbtoelf sbloader
+
+all: $(BINS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+sbloader: sbloader.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+clean:
+ rm -fr *.o
+
+veryclean:
+ rm -rf $(BINS)
diff --git a/utils/imxtools/README b/utils/imxtools/README
new file mode 100644
index 0000000000..8bf6fd5f8e
--- /dev/null
+++ b/utils/imxtools/README
@@ -0,0 +1,32 @@
+This file document the format of the command file used by the elftosb tool.
+By no way our tools tries to be compatible with Freescale's elftosb2.
+However, our format is more subset of the general one.
+
+The parse supports a limited form of comments: comments starting with // and ending at the end of the line.
+
+A file first contains the list of sources:
+
+sources
+{
+ hw_init = "sdram_init.elf";
+ rockbox = "rockbox.elf";
+}
+
+It can then contain an arbitrary number of section. A section is identified by a number.
+Within a section, three commands are supported: "load", "jump" and "call":
+
+section(0x626f6f74) // hex for 'boot'
+{
+ load hw_init;
+ call hw_init;
+ load rockbox;
+ jump rockbox;
+}
+
+Finally, both elftosb and sbtoelf tools use key files. A key file is a list of keys.
+Each key consist is 128-bit long and is written in hexadecimal:
+
+00000000000000000000000000000000
+
+The parser does not handle blank line and only allows a final newline at the end of the file.
+A file is allowed to contain zero (0) keys.
diff --git a/utils/imxtools/aes128.c b/utils/imxtools/aes128.c
new file mode 100644
index 0000000000..5870813db8
--- /dev/null
+++ b/utils/imxtools/aes128.c
@@ -0,0 +1,284 @@
+// Simple, thoroughly commented implementation of 128-bit AES / Rijndael using C
+// Chris Hulbert - chris.hulbert@gmail.com - http://splinter.com.au/blog
+// References:
+// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+// http://en.wikipedia.org/wiki/Rijndael_key_schedule
+// http://en.wikipeia.org/wiki/Rijndael_mix_columns
+// http://en.wikipedia.org/wiki/Rijndael_S-box
+// This code is public domain, or any OSI-approved license, your choice. No warranty.
+#include "crypto.h"
+
+// Here are all the lookup tables for the row shifts, rcon, s-boxes, and galois field multiplications
+byte shift_rows_table[] = {0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11};
+byte shift_rows_table_inv[] = {0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3};
+byte lookup_rcon[]={0x8d,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a};
+byte lookup_sbox[]={0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16};
+byte lookup_sbox_inv[]={0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d};
+byte lookup_g2 []={0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,0x1b,0x19,0x1f,0x1d,0x13,0x11,0x17,0x15,0x0b,0x09,0x0f,0x0d,0x03,0x01,0x07,0x05,0x3b,0x39,0x3f,0x3d,0x33,0x31,0x37,0x35,0x2b,0x29,0x2f,0x2d,0x23,0x21,0x27,0x25,0x5b,0x59,0x5f,0x5d,0x53,0x51,0x57,0x55,0x4b,0x49,0x4f,0x4d,0x43,0x41,0x47,0x45,0x7b,0x79,0x7f,0x7d,0x73,0x71,0x77,0x75,0x6b,0x69,0x6f,0x6d,0x63,0x61,0x67,0x65,0x9b,0x99,0x9f,0x9d,0x93,0x91,0x97,0x95,0x8b,0x89,0x8f,0x8d,0x83,0x81,0x87,0x85,0xbb,0xb9,0xbf,0xbd,0xb3,0xb1,0xb7,0xb5,0xab,0xa9,0xaf,0xad,0xa3,0xa1,0xa7,0xa5,0xdb,0xd9,0xdf,0xdd,0xd3,0xd1,0xd7,0xd5,0xcb,0xc9,0xcf,0xcd,0xc3,0xc1,0xc7,0xc5,0xfb,0xf9,0xff,0xfd,0xf3,0xf1,0xf7,0xf5,0xeb,0xe9,0xef,0xed,0xe3,0xe1,0xe7,0xe5};
+byte lookup_g3 []={0x00,0x03,0x06,0x05,0x0c,0x0f,0x0a,0x09,0x18,0x1b,0x1e,0x1d,0x14,0x17,0x12,0x11,0x30,0x33,0x36,0x35,0x3c,0x3f,0x3a,0x39,0x28,0x2b,0x2e,0x2d,0x24,0x27,0x22,0x21,0x60,0x63,0x66,0x65,0x6c,0x6f,0x6a,0x69,0x78,0x7b,0x7e,0x7d,0x74,0x77,0x72,0x71,0x50,0x53,0x56,0x55,0x5c,0x5f,0x5a,0x59,0x48,0x4b,0x4e,0x4d,0x44,0x47,0x42,0x41,0xc0,0xc3,0xc6,0xc5,0xcc,0xcf,0xca,0xc9,0xd8,0xdb,0xde,0xdd,0xd4,0xd7,0xd2,0xd1,0xf0,0xf3,0xf6,0xf5,0xfc,0xff,0xfa,0xf9,0xe8,0xeb,0xee,0xed,0xe4,0xe7,0xe2,0xe1,0xa0,0xa3,0xa6,0xa5,0xac,0xaf,0xaa,0xa9,0xb8,0xbb,0xbe,0xbd,0xb4,0xb7,0xb2,0xb1,0x90,0x93,0x96,0x95,0x9c,0x9f,0x9a,0x99,0x88,0x8b,0x8e,0x8d,0x84,0x87,0x82,0x81,0x9b,0x98,0x9d,0x9e,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8f,0x8c,0x89,0x8a,0xab,0xa8,0xad,0xae,0xa7,0xa4,0xa1,0xa2,0xb3,0xb0,0xb5,0xb6,0xbf,0xbc,0xb9,0xba,0xfb,0xf8,0xfd,0xfe,0xf7,0xf4,0xf1,0xf2,0xe3,0xe0,0xe5,0xe6,0xef,0xec,0xe9,0xea,0xcb,0xc8,0xcd,0xce,0xc7,0xc4,0xc1,0xc2,0xd3,0xd0,0xd5,0xd6,0xdf,0xdc,0xd9,0xda,0x5b,0x58,0x5d,0x5e,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4f,0x4c,0x49,0x4a,0x6b,0x68,0x6d,0x6e,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7f,0x7c,0x79,0x7a,0x3b,0x38,0x3d,0x3e,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2f,0x2c,0x29,0x2a,0x0b,0x08,0x0d,0x0e,0x07,0x04,0x01,0x02,0x13,0x10,0x15,0x16,0x1f,0x1c,0x19,0x1a};
+byte lookup_g9 []={0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7,0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc,0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01,0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91,0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a,0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa,0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b,0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b,0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0,0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30,0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed,0x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d,0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6,0x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46};
+byte lookup_g11 []={0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69,0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9,0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12,0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2,0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f,0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f,0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4,0x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54,0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e,0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e,0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5,0x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55,0x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68,0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8,0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13,0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3};
+byte lookup_g13 []={0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b,0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b,0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0,0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20,0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26,0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6,0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d,0x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d,0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91,0x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41,0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a,0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa,0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc,0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c,0x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47,0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97};
+byte lookup_g14 []={0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a,0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba,0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81,0x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61,0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7,0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17,0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c,0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc,0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b,0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb,0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0,0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20,0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6,0x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56,0x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d,0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d};
+
+// Xor's all elements in a n byte array a by b
+void xor_(byte *a, byte *b, int n) {
+ int i;
+ for (i=0;i<n;i++)
+ a[i] ^= b[i];
+}
+
+// Xor the current cipher state by a specific round key
+static void xor_round_key(byte *state, byte *keys, int round) {
+ xor_(state,keys+round*16,16);
+}
+
+// Apply and reverse the rijndael s-box to all elements in an array
+// http://en.wikipedia.org/wiki/Rijndael_S-box
+static void sub_bytes(byte *a,int n) {
+ int i;
+ for (i=0;i<n;i++)
+ a[i] = lookup_sbox[a[i]];
+}
+static void sub_bytes_inv(byte *a,int n) {
+ int i;
+ for (i=0;i<n;i++)
+ a[i] = lookup_sbox_inv[a[i]];
+}
+
+// Perform the core key schedule transform on 4 bytes, as part of the key expansion process
+// http://en.wikipedia.org/wiki/Rijndael_key_schedule#Key_schedule_core
+static void key_schedule_core(byte *a, int i) {
+ byte temp = a[0]; // Rotate the output eight bits to the left
+ a[0]=a[1];
+ a[1]=a[2];
+ a[2]=a[3];
+ a[3]=temp;
+ sub_bytes(a,4); // Apply Rijndael's S-box on all four individual bytes in the output word
+ a[0]^=lookup_rcon[i]; // On just the first (leftmost) byte of the output word, perform the rcon operation with i
+ // as the input, and exclusive or the rcon output with the first byte of the output word
+}
+
+// Expand the 16-byte key to 11 round keys (176 bytes)
+// http://en.wikipedia.org/wiki/Rijndael_key_schedule#The_key_schedule
+static void expand_key(byte *key, byte *keys) {
+ int bytes=16; // The count of how many bytes we've created so far
+ int i=1; // The rcon iteration value i is set to 1
+ int j; // For repeating the second stage 3 times
+ byte t[4]; // Temporary working area known as 't' in the Wiki article
+ memcpy(keys,key,16); // The first 16 bytes of the expanded key are simply the encryption key
+
+ while (bytes<176) { // Until we have 176 bytes of expanded key, we do the following:
+ memcpy(t,keys+bytes-4,4); // We assign the value of the previous four bytes in the expanded key to t
+ key_schedule_core(t, i); // We perform the key schedule core on t, with i as the rcon iteration value
+ i++; // We increment i by 1
+ xor_(t,keys+bytes-16,4); // We exclusive-or t with the four-byte block 16 bytes before the new expanded key.
+ memcpy(keys+bytes,t,4); // This becomes the next 4 bytes in the expanded key
+ bytes+=4; // Keep track of how many expanded key bytes we've added
+
+ // We then do the following three times to create the next twelve bytes
+ for (j=0;j<3;j++) {
+ memcpy(t,keys+bytes-4,4); // We assign the value of the previous 4 bytes in the expanded key to t
+ xor_(t,keys+bytes-16,4); // We exclusive-or t with the four-byte block n bytes before
+ memcpy(keys+bytes,t,4); // This becomes the next 4 bytes in the expanded key
+ bytes+=4; // Keep track of how many expanded key bytes we've added
+ }
+ }
+}
+
+// Apply / reverse the shift rows step on the 16 byte cipher state
+// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard#The_ShiftRows_step
+static void shift_rows(byte *state) {
+ int i;
+ byte temp[16];
+ memcpy(temp,state,16);
+ for (i=0;i<16;i++)
+ state[i]=temp[shift_rows_table[i]];
+}
+static void shift_rows_inv(byte *state) {
+ int i;
+ byte temp[16];
+ memcpy(temp,state,16);
+ for (i=0;i<16;i++)
+ state[i]=temp[shift_rows_table_inv[i]];
+}
+
+// Perform the mix columns matrix on one column of 4 bytes
+// http://en.wikipedia.org/wiki/Rijndael_mix_columns
+static void mix_col (byte *state) {
+ byte a0 = state[0];
+ byte a1 = state[1];
+ byte a2 = state[2];
+ byte a3 = state[3];
+ state[0] = lookup_g2[a0] ^ lookup_g3[a1] ^ a2 ^ a3;
+ state[1] = lookup_g2[a1] ^ lookup_g3[a2] ^ a3 ^ a0;
+ state[2] = lookup_g2[a2] ^ lookup_g3[a3] ^ a0 ^ a1;
+ state[3] = lookup_g2[a3] ^ lookup_g3[a0] ^ a1 ^ a2;
+}
+
+// Perform the mix columns matrix on each column of the 16 bytes
+static void mix_cols (byte *state) {
+ mix_col(state);
+ mix_col(state+4);
+ mix_col(state+8);
+ mix_col(state+12);
+}
+
+// Perform the inverse mix columns matrix on one column of 4 bytes
+// http://en.wikipedia.org/wiki/Rijndael_mix_columns
+static void mix_col_inv (byte *state) {
+ byte a0 = state[0];
+ byte a1 = state[1];
+ byte a2 = state[2];
+ byte a3 = state[3];
+ state[0] = lookup_g14[a0] ^ lookup_g9[a3] ^ lookup_g13[a2] ^ lookup_g11[a1];
+ state[1] = lookup_g14[a1] ^ lookup_g9[a0] ^ lookup_g13[a3] ^ lookup_g11[a2];
+ state[2] = lookup_g14[a2] ^ lookup_g9[a1] ^ lookup_g13[a0] ^ lookup_g11[a3];
+ state[3] = lookup_g14[a3] ^ lookup_g9[a2] ^ lookup_g13[a1] ^ lookup_g11[a0];
+}
+
+// Perform the inverse mix columns matrix on each column of the 16 bytes
+static void mix_cols_inv (byte *state) {
+ mix_col_inv(state);
+ mix_col_inv(state+4);
+ mix_col_inv(state+8);
+ mix_col_inv(state+12);
+}
+
+// Encrypt a single 128 bit block by a 128 bit key using AES
+// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+void EncryptAES(byte *msg, byte *key, byte *c) {
+ int i; // To count the rounds
+
+ // Key expansion
+ byte keys[176];
+ expand_key(key,keys);
+
+ // First Round
+ memmove(c, msg, 16);
+ xor_round_key(c,keys,0);
+
+ // Middle rounds
+ for(i=0; i<9; i++) {
+ sub_bytes(c,16);
+ shift_rows(c);
+ mix_cols(c);
+ xor_round_key(c, keys, i+1);
+ }
+
+ // Final Round
+ sub_bytes(c,16);
+ shift_rows(c);
+ xor_round_key(c, keys, 10);
+}
+
+// Decrypt a single 128 bit block by a 128 bit key using AES
+// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+void DecryptAES(byte *c, byte *key, byte *m) {
+ int i; // To count the rounds
+
+ // Key expansion
+ byte keys[176];
+ expand_key(key,keys);
+
+ // Reverse the final Round
+ memcpy(m,c,16);
+ xor_round_key(m,keys,10);
+ shift_rows_inv(m);
+ sub_bytes_inv(m, 16);
+
+ // Reverse the middle rounds
+ for (i=0; i<9; i++) {
+ xor_round_key(m,keys,9-i);
+ mix_cols_inv(m);
+ shift_rows_inv(m);
+ sub_bytes_inv(m, 16);
+ }
+
+ // Reverse the first Round
+ xor_round_key(m, keys, 0);
+}
+
+/*
+// Pretty-print a key (or any smallish buffer) onto screen as hex
+void Pretty(byte* b,int len,const char* label)
+{
+ char out[100];
+ int i;
+ for (i=0;i<len;i++)
+ sprintf(out+i*2,"%02x",b[i]);
+
+ printf("%s%s",label, out);
+}
+*/
+
+/*
+// Test AES
+int main(void)
+{
+ byte key[] = {0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12};
+ byte msg[] = {0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab};
+ byte encrypted[16], decrypted[16];
+
+ printf("Test AES\r\n\n");
+ Pretty(key,16,"Key: ");
+ Pretty(msg,16,"Original: ");
+
+ EncryptAES(msg,key,encrypted);
+ printf("Encrypted should be: 85E5A3D7356A61E29A8AFA559AD67102\r\n");
+ Pretty(encrypted,16,"Encrypted: ");
+
+ DecryptAES(encrypted,key,decrypted);
+ Pretty(decrypted,16,"Decrypted: ");
+
+ return 0;
+}
+*/
+
+void cbc_mac(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */
+ byte key[16], /* Key */
+ byte iv[16], /* Initialisation Vector */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt /* 1 to encrypt, 0 to decrypt */
+ )
+{
+ byte feedback[16];
+ memcpy(feedback, iv, 16);
+
+ if(encrypt)
+ {
+ /* for each block */
+ for(int i = 0; i < nr_blocks; i++)
+ {
+ /* xor it with feedback */
+ xor_(feedback, &in_data[i * 16], 16);
+ /* encrypt it using aes */
+ EncryptAES(feedback, key, feedback);
+ /* write cipher to output */
+ if(out_data)
+ memcpy(&out_data[i * 16], feedback, 16);
+ }
+ if(out_cbc_mac)
+ memcpy(out_cbc_mac, feedback, 16);
+ }
+ else
+ {
+ /* nothing to do ? */
+ if(out_data == NULL)
+ return;
+
+ /* for each block */
+ for(int i = 0; i < nr_blocks; i++)
+ {
+ /* decrypt it using aes */
+ DecryptAES(&in_data[i * 16], key, &out_data[i * 16]);
+ /* xor it with iv */
+ xor_(&out_data[i * 16], feedback, 16);
+ /* copy cipher to iv */
+ memcpy(feedback, &in_data[i * 16], 16);
+ }
+ }
+}
diff --git a/utils/imxtools/crc.c b/utils/imxtools/crc.c
new file mode 100644
index 0000000000..eaf257ddfe
--- /dev/null
+++ b/utils/imxtools/crc.c
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "crypto.h"
+
+/* Table extracted from firmware, don't know if this is regular CRC32 */
+
+static uint32_t crc_table[256] = {
+ 0x0, 0x4C11DB7, 0x9823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2,
+ 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64,
+ 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E,
+ 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8,
+ 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
+ 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C,
+ 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0x0BE2B5B58, 0x0BAEA46EF, 0x0B7A96036,
+ 0x0B3687D81, 0x0AD2F2D84, 0x0A9EE3033, 0x0A4AD16EA, 0x0A06C0B5D, 0x0D4326D90,
+ 0x0D0F37027, 0x0DDB056FE, 0x0D9714B49, 0x0C7361B4C, 0x0C3F706FB, 0x0CEB42022,
+ 0x0CA753D95, 0x0F23A8028, 0x0F6FB9D9F, 0x0FBB8BB46, 0x0FF79A6F1, 0x0E13EF6F4,
+ 0x0E5FFEB43, 0x0E8BCCD9A, 0x0EC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19,
+ 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF,
+ 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x18AEB13, 0x54BF6A4, 0x808D07D,
+ 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB,
+ 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
+ 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0x0ACA5C697,
+ 0x0A864DB20, 0x0A527FDF9, 0x0A1E6E04E, 0x0BFA1B04B, 0x0BB60ADFC, 0x0B6238B25,
+ 0x0B2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3,
+ 0x9D684044, 0x902B669D, 0x94EA7B2A, 0x0E0B41DE7, 0x0E4750050, 0x0E9362689,
+ 0x0EDF73B3E, 0x0F3B06B3B, 0x0F771768C, 0x0FA325055, 0x0FEF34DE2, 0x0C6BCF05F,
+ 0x0C27DEDE8, 0x0CF3ECB31, 0x0CBFFD686, 0x0D5B88683, 0x0D1799B34, 0x0DC3ABDED,
+ 0x0D8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632,
+ 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638,
+ 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E,
+ 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
+ 0x3B5A6B9B, 0x315D626, 0x7D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA,
+ 0x14D0BD4D, 0x19939B94, 0x1D528623, 0x0F12F560E, 0x0F5EE4BB9, 0x0F8AD6D60,
+ 0x0FC6C70D7, 0x0E22B20D2, 0x0E6EA3D65, 0x0EBA91BBC, 0x0EF68060B, 0x0D727BBB6,
+ 0x0D3E6A601, 0x0DEA580D8, 0x0DA649D6F, 0x0C423CD6A, 0x0C0E2D0DD, 0x0CDA1F604,
+ 0x0C960EBB3, 0x0BD3E8D7E, 0x0B9FF90C9, 0x0B4BCB610, 0x0B07DABA7, 0x0AE3AFBA2,
+ 0x0AAFBE615, 0x0A7B8C0CC, 0x0A379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8,
+ 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099,
+ 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B,
+ 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD,
+ 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
+ 0x1CD86D30, 0x29F3D35, 0x65E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651,
+ 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3,
+ 0x29D4F654, 0x0C5A92679, 0x0C1683BCE, 0x0CC2B1D17, 0x0C8EA00A0, 0x0D6AD50A5,
+ 0x0D26C4D12, 0x0DF2F6BCB, 0x0DBEE767C, 0x0E3A1CBC1, 0x0E760D676, 0x0EA23F0AF,
+ 0x0EEE2ED18, 0x0F0A5BD1D, 0x0F464A0AA, 0x0F9278673, 0x0FDE69BC4, 0x89B8FD09,
+ 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB,
+ 0x97FFAD0C, 0x0AFB010B1, 0x0AB710D06, 0x0A6322BDF, 0x0A2F33668, 0x0BCB4666D,
+ 0x0B8757BDA, 0x0B5365D03, 0x0B1F740B4
+};
+
+uint32_t crc(byte *data, int size)
+{
+ return crc_continue(0xffffffff, data, size);
+}
+
+uint32_t crc_continue(uint32_t previous_crc, byte *data, int size)
+{
+ uint32_t c = previous_crc;
+ /* normal CRC */
+ for(int i = 0; i < size; i++)
+ c = crc_table[data[i] ^ (c >> 24)] ^ (c << 8);
+ return c;
+}
diff --git a/utils/imxtools/crypto.c b/utils/imxtools/crypto.c
new file mode 100644
index 0000000000..d4afc6c816
--- /dev/null
+++ b/utils/imxtools/crypto.c
@@ -0,0 +1,188 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "crypto.h"
+#include <stdio.h>
+#include <stdbool.h>
+#ifdef CRYPTO_LIBUSB
+#include "libusb.h"
+#endif
+#include "misc.h"
+
+static enum crypto_method_t cur_method = CRYPTO_NONE;
+static byte key[16];
+static uint16_t usb_vid, usb_pid;
+
+void crypto_setup(enum crypto_method_t method, void *param)
+{
+ cur_method = method;
+ switch(method)
+ {
+ case CRYPTO_KEY:
+ memcpy(key, param, sizeof(key));
+ break;
+ case CRYPTO_USBOTP:
+ {
+ uint32_t value = *(uint32_t *)param;
+ usb_vid = value >> 16;
+ usb_pid = value & 0xffff;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+int crypto_apply(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ byte iv[16], /* Key */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt)
+{
+ if(cur_method == CRYPTO_KEY)
+ {
+ cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt);
+ return CRYPTO_ERROR_SUCCESS;
+ }
+ #ifdef CRYPTO_LIBUSB
+ else if(cur_method == CRYPTO_USBOTP)
+ {
+ if(out_cbc_mac && !encrypt)
+ memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16);
+
+ libusb_device_handle *handle = NULL;
+ libusb_context *ctx;
+ /* init library */
+ libusb_init(&ctx);
+ libusb_set_debug(NULL,3);
+ /* open device */
+ handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid);
+ if(handle == NULL)
+ {
+ printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid);
+ return CRYPTO_ERROR_NODEVICE;
+ }
+ /* get device pointer */
+ libusb_device *mydev = libusb_get_device(handle);
+ if(g_debug)
+ printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev),
+ libusb_get_device_address(mydev));
+ int config_id;
+ /* explore configuration */
+ libusb_get_configuration(handle, &config_id);
+ struct libusb_config_descriptor *config;
+ libusb_get_active_config_descriptor(mydev, &config);
+
+ if(g_debug)
+ {
+ printf("usbotp: configuration: %d\n", config_id);
+ printf("usbotp: interfaces: %d\n", config->bNumInterfaces);
+ }
+
+ const struct libusb_endpoint_descriptor *endp = NULL;
+ int intf, intf_alt;
+ for(intf = 0; intf < config->bNumInterfaces; intf++)
+ for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++)
+ for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++)
+ {
+ endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep];
+ if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
+ (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
+ goto Lfound;
+ }
+ libusb_close(handle);
+ printf("usbotp: No suitable endpoint found\n");
+ return CRYPTO_ERROR_BADENDP;
+
+ if(g_debug)
+ {
+ printf("usbotp: use interface %d, alt %d\n", intf, intf_alt);
+ printf("usbotp: use endpoint %d\n", endp->bEndpointAddress);
+ }
+ Lfound:
+ if(libusb_claim_interface(handle, intf) != 0)
+ {
+ if(g_debug)
+ printf("usbotp: claim error\n");
+ return CRYPTO_ERROR_CLAIMFAIL;
+ }
+
+ int buffer_size = 16 + 16 * nr_blocks;
+ unsigned char *buffer = xmalloc(buffer_size);
+ memcpy(buffer, iv, 16);
+ memcpy(buffer + 16, in_data, 16 * nr_blocks);
+ int ret = libusb_control_transfer(handle,
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
+ 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000);
+ if(ret < 0)
+ {
+ if(g_debug)
+ printf("usbotp: control transfer failed: %d\n", ret);
+ libusb_release_interface(handle, intf);
+ libusb_close(handle);
+ return CRYPTO_ERROR_DEVREJECT;
+ }
+
+ int recv_size;
+ ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer,
+ buffer_size, &recv_size, 1000);
+ libusb_release_interface(handle, intf);
+ libusb_close(handle);
+
+ if(ret < 0)
+ {
+ if(g_debug)
+ printf("usbotp: interrupt transfer failed: %d\n", ret);
+ return CRYPTO_ERROR_DEVSILENT;
+ }
+ if(recv_size != buffer_size)
+ {
+ if(g_debug)
+ printf("usbotp: device returned %d bytes, expected %d\n", recv_size,
+ buffer_size);
+ return CRYPTO_ERROR_DEVERR;
+ }
+
+ if(out_data)
+ memcpy(out_data, buffer + 16, 16 * nr_blocks);
+ if(out_cbc_mac && encrypt)
+ memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16);
+
+ return CRYPTO_ERROR_SUCCESS;
+ }
+ #endif
+ else
+ return CRYPTO_ERROR_BADSETUP;
+}
+
+int crypto_cbc(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ struct crypto_key_t *key, /* Key */
+ byte iv[16], /* IV */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt)
+{
+ crypto_setup(key->method, (void *)key->u.param);
+ return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt);
+}
diff --git a/utils/imxtools/crypto.h b/utils/imxtools/crypto.h
new file mode 100644
index 0000000000..452db6a28d
--- /dev/null
+++ b/utils/imxtools/crypto.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __CRYPTO_H__
+#define __CRYPTO_H__
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+typedef uint8_t byte;
+
+/* aes128.c */
+void xor_(byte *a, byte *b, int n);
+void EncryptAES(byte *msg, byte *key, byte *c);
+void DecryptAES(byte *c, byte *key, byte *m);
+void Pretty(byte* b,int len,const char* label);
+void cbc_mac(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */
+ byte key[16], /* Key */
+ byte iv[16], /* Initialisation Vector */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt /* 1 to encrypt, 0 to decrypt */
+ );
+
+/* crypto.c */
+enum crypto_method_t
+{
+ CRYPTO_NONE, /* disable */
+ CRYPTO_KEY, /* key */
+ CRYPTO_USBOTP, /* use usbotp device */
+};
+
+/* parameter can be:
+ * - CRYPTO_KEY: array of 16-bytes (the key)
+ * - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */
+void crypto_setup(enum crypto_method_t method, void *param);
+
+#define CRYPTO_ERROR_SUCCESS 0
+#define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */
+#define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */
+#define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */
+#define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */
+#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
+#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
+#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
+#define CRYPTO_NUM_ERRORS 8
+/* return 0 on success, <0 on error */
+int crypto_apply(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ byte iv[16], /* IV */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt);
+
+/* all-in-one function */
+struct crypto_key_t
+{
+ enum crypto_method_t method;
+ union
+ {
+ byte key[16];
+ uint32_t vid_pid;
+ byte param[0];
+ }u;
+};
+
+int crypto_cbc(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ struct crypto_key_t *key, /* Key */
+ byte iv[16], /* IV */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt);
+
+/* crc.c */
+uint32_t crc(byte *data, int size);
+uint32_t crc_continue(uint32_t previous_crc, byte *data, int size);
+
+/* sha1.c */
+struct sha_1_params_t
+{
+ uint32_t hash[5];
+ uint64_t buffer_nr_bits;
+ uint32_t w[80];
+};
+
+void sha_1_init(struct sha_1_params_t *params);
+void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data);
+void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size);
+void sha_1_finish(struct sha_1_params_t *params);
+void sha_1_output(struct sha_1_params_t *params, byte *out);
+
+#endif /* __CRYPTO_H__ */
diff --git a/utils/imxtools/dbparser.c b/utils/imxtools/dbparser.c
new file mode 100644
index 0000000000..b2027e5ad7
--- /dev/null
+++ b/utils/imxtools/dbparser.c
@@ -0,0 +1,849 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#define _POSIX_C_SOURCE 200809L /* for strdup */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <string.h>
+#include "dbparser.h"
+#include "misc.h"
+
+enum lexem_type_t
+{
+ LEX_IDENTIFIER,
+ LEX_LPAREN,
+ LEX_RPAREN,
+ LEX_NUMBER,
+ LEX_STRING, /* double-quoted string */
+ LEX_EQUAL,
+ LEX_SEMICOLON,
+ LEX_LBRACE,
+ LEX_RBRACE,
+ LEX_RANGLE,
+ LEX_OR,
+ LEX_LSHIFT,
+ LEX_COLON,
+ LEX_LE,
+ LEX_EOF
+};
+
+struct lexem_t
+{
+ enum lexem_type_t type;
+ /* if str is not NULL, it must be a malloc'd pointer */
+ char *str;
+ uint32_t num;
+ int line;
+ const char *file;
+};
+
+struct context_t
+{
+ const char *file;
+ char *begin;
+ char *end;
+ char *ptr;
+ int line;
+};
+
+#define parse_error(ctx, ...) \
+ do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \
+ fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
+
+static void advance(struct context_t *ctx, int nr_chars)
+{
+ while(nr_chars--)
+ {
+ if(*(ctx->ptr++) == '\n')
+ ctx->line++;
+ }
+}
+
+static inline bool eof(struct context_t *ctx)
+{
+ return ctx->ptr == ctx->end;
+}
+
+static inline bool next_valid(struct context_t *ctx, int nr)
+{
+ return ctx->ptr + nr < ctx->end;
+}
+
+static inline char cur_char(struct context_t *ctx)
+{
+ return *ctx->ptr;
+}
+
+static inline char next_char(struct context_t *ctx, int nr)
+{
+ return ctx->ptr[nr];
+}
+
+static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx)
+{
+ lex->file = ctx->file;
+ lex->line = ctx->line;
+}
+
+static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c))
+{
+ while(!eof(ctx))
+ {
+ if(cur_char(ctx) == '"')
+ break;
+ else if(cur_char(ctx) == '\\')
+ {
+ advance(ctx, 1);
+ if(eof(ctx))
+ parse_error(ctx, "Unfinished string\n");
+ if(cur_char(ctx) == '\\') emit_fn(user, '\\');
+ else if(cur_char(ctx) == '\'') emit_fn(user, '\'');
+ else if(cur_char(ctx) == '\"') emit_fn(user, '\"');
+ else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx));
+ advance(ctx, 1);
+ }
+ else
+ {
+ emit_fn(user, cur_char(ctx));
+ advance(ctx, 1);
+ }
+ }
+ if(eof(ctx) || cur_char(ctx) != '"')
+ parse_error(ctx, "Unfinished string\n");
+ advance(ctx, 1);
+}
+
+static void __parse_string_emit(void *user, char c)
+{
+ char **pstr = (char **)user;
+ *(*pstr)++ = c;
+}
+
+static void __parse_string_count(void *user, char c)
+{
+ (void) c;
+ (*(int *)user)++;
+}
+
+static void parse_string(struct context_t *ctx, struct lexem_t *lexem)
+{
+ locate_lexem(lexem, ctx);
+ /* skip " */
+ advance(ctx, 1);
+ /* compute length */
+ struct context_t cpy_ctx = *ctx;
+ int length = 0;
+ __parse_string(&cpy_ctx, (void *)&length, __parse_string_count);
+ /* parse again */
+ lexem->type = LEX_STRING;
+ lexem->str = xmalloc(length + 1);
+ lexem->str[length] = 0;
+ char *pstr = lexem->str;
+ __parse_string(ctx, (void *)&pstr, __parse_string_emit);
+}
+
+static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem)
+{
+ locate_lexem(lexem, ctx);
+ /* skip ' */
+ advance(ctx, 1);
+ /* we expect n<=4 character and then ' */
+ int len = 0;
+ uint32_t value = 0;
+ while(!eof(ctx))
+ {
+ if(cur_char(ctx) != '\'')
+ {
+ value = value << 8 | cur_char(ctx);
+ len++;
+ advance(ctx, 1);
+ }
+ else
+ break;
+ }
+ if(eof(ctx) || cur_char(ctx) != '\'')
+ parse_error(ctx, "Unterminated ascii number literal\n");
+ if(len == 0 || len > 4)
+ parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n");
+ /* skip ' */
+ advance(ctx, 1);
+ lexem->type = LEX_NUMBER;
+ lexem->num = value;
+}
+
+static void parse_number(struct context_t *ctx, struct lexem_t *lexem)
+{
+ locate_lexem(lexem, ctx);
+ /* check base */
+ int base = 10;
+ if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x')
+ {
+ advance(ctx, 2);
+ base = 16;
+ }
+
+ lexem->type = LEX_NUMBER;
+ lexem->num = 0;
+ while(!eof(ctx) && isxdigit(cur_char(ctx)))
+ {
+ if(base == 10 && !isdigit(cur_char(ctx)))
+ break;
+ byte v;
+ if(convxdigit(cur_char(ctx), &v))
+ break;
+ lexem->num = base * lexem->num + v;
+ advance(ctx, 1);
+ }
+}
+
+static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem)
+{
+ locate_lexem(lexem, ctx);
+ /* remember position */
+ char *old = ctx->ptr;
+ while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_'))
+ advance(ctx, 1);
+ lexem->type = LEX_IDENTIFIER;
+ int len = ctx->ptr - old;
+ lexem->str = xmalloc(len + 1);
+ lexem->str[len] = 0;
+ memcpy(lexem->str, old, len);
+}
+
+static void next_lexem(struct context_t *ctx, struct lexem_t *lexem)
+{
+ #define ret_simple(t, adv) \
+ do {locate_lexem(lexem, ctx); \
+ lexem->type = t; \
+ advance(ctx, adv); \
+ return;} while(0)
+ while(!eof(ctx))
+ {
+ char c = cur_char(ctx);
+ /* skip whitespace */
+ if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ {
+ advance(ctx, 1);
+ continue;
+ }
+ /* skip C++ style comments */
+ if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/')
+ {
+ while(!eof(ctx) && cur_char(ctx) != '\n')
+ advance(ctx, 1);
+ continue;
+ }
+ /* skip C-style comments */
+ if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*')
+ {
+ advance(ctx, 2);
+ while(true)
+ {
+ if(!next_valid(ctx, 1))
+ parse_error(ctx, "Unterminated comment");
+ if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/')
+ {
+ advance(ctx, 2);
+ break;
+ }
+ advance(ctx, 1);
+ }
+ continue;
+ }
+ break;
+ }
+ if(eof(ctx)) ret_simple(LEX_EOF, 0);
+ char c = cur_char(ctx);
+ bool nv = next_valid(ctx, 1);
+ char nc = nv ? next_char(ctx, 1) : 0;
+ if(c == '(') ret_simple(LEX_LPAREN, 1);
+ if(c == ')') ret_simple(LEX_RPAREN, 1);
+ if(c == '{') ret_simple(LEX_LBRACE, 1);
+ if(c == '}') ret_simple(LEX_RBRACE, 1);
+ if(c == '>') ret_simple(LEX_RANGLE, 1);
+ if(c == '=') ret_simple(LEX_EQUAL, 1);
+ if(c == ';') ret_simple(LEX_SEMICOLON, 1);
+ if(c == ',') ret_simple(LEX_COLON, 1);
+ if(c == '|') ret_simple(LEX_OR, 1);
+ if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2);
+ if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2);
+ if(c == '"') return parse_string(ctx, lexem);
+ if(c == '\'') return parse_ascii_number(ctx, lexem);
+ if(isdigit(c)) return parse_number(ctx, lexem);
+ if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem);
+ parse_error(ctx, "Unexpected character '%c'\n", c);
+ #undef ret_simple
+}
+
+#if 0
+static void log_lexem(struct lexem_t *lexem)
+{
+ switch(lexem->type)
+ {
+ case LEX_EOF: printf("<eof>"); break;
+ case LEX_EQUAL: printf("="); break;
+ case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break;
+ case LEX_LPAREN: printf("("); break;
+ case LEX_RPAREN: printf(")"); break;
+ case LEX_LBRACE: printf("{"); break;
+ case LEX_RBRACE: printf("}"); break;
+ case LEX_SEMICOLON: printf(";"); break;
+ case LEX_NUMBER: printf("num(%d)", lexem->num); break;
+ case LEX_STRING: printf("str(%s)", lexem->str); break;
+ case LEX_OR: printf("|"); break;
+ case LEX_LSHIFT: printf("<<"); break;
+ default: printf("<unk>");
+ }
+}
+#endif
+
+struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id)
+{
+ struct cmd_source_t *src = cmd_file->source_list;
+ while(src)
+ {
+ if(strcmp(src->identifier, id) == 0)
+ return src;
+ src = src->next;
+ }
+ return NULL;
+}
+
+struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name)
+{
+ while(opt)
+ {
+ if(strcmp(opt->name, name) == 0)
+ return opt;
+ opt = opt->next;
+ }
+ return NULL;
+}
+
+#define INVALID_SB_SUBVERSION 0xffff
+
+static uint16_t parse_sb_subversion(char *str)
+{
+ int len = strlen(str);
+ uint16_t n = 0;
+ if(len == 0 || len > 4)
+ return INVALID_SB_SUBVERSION;
+ for(int i = 0; i < len; i++)
+ {
+ if(!isdigit(str[i]))
+ return INVALID_SB_SUBVERSION;
+ n = n << 4 | (str[i] - '0');
+ }
+ return n;
+}
+
+bool db_parse_sb_version(struct sb_version_t *ver, char *str)
+{
+ int len = strlen(str);
+ int cnt = 0;
+ int pos[2];
+
+ for(int i = 0; i < len; i++)
+ {
+ if(str[i] != '.')
+ continue;
+ if(cnt == 2)
+ return false;
+ pos[cnt++] = i + 1;
+ str[i] = 0;
+ }
+ if(cnt != 2)
+ return false;
+ ver->major = parse_sb_subversion(str);
+ ver->minor = parse_sb_subversion(str + pos[0]);
+ ver->revision = parse_sb_subversion(str + pos[1]);
+ return ver->major != INVALID_SB_SUBVERSION &&
+ ver->minor != INVALID_SB_SUBVERSION &&
+ ver->revision != INVALID_SB_SUBVERSION;
+}
+
+#undef parse_error
+#define parse_error(lexem, ...) \
+ do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \
+ fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
+
+struct lex_ctx_t
+{
+ struct context_t ctx;
+ struct lexem_t lexem;
+};
+
+/* When lexems hold strings (like identifier), it might be useful to steal
+ * the pointer and don't clean the lexem but in other case, one don't want
+ * to keep the pointer to the string and just want to release the memory.
+ * Thus clean_lexem should be true except when one keeps a pointer */
+static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
+{
+ if(clean_lexem)
+ free(ctx->lexem.str);
+ memset(&ctx->lexem, 0, sizeof(struct lexem_t));
+ next_lexem(&ctx->ctx, &ctx->lexem);
+}
+
+static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
+{
+ uint32_t ret = 0;
+ if(ctx->lexem.type == LEX_NUMBER)
+ ret = ctx->lexem.num;
+ else if(ctx->lexem.type == LEX_IDENTIFIER)
+ {
+ struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str);
+ if(c == NULL)
+ parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str);
+ if(c->is_string)
+ parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str);
+ ret = c->val;
+ }
+ else
+ parse_error(ctx->lexem, "Number or constant identifier expected\n");
+ next(ctx, true);
+ return ret;
+}
+
+static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
+{
+ uint32_t v = parse_term_expr(ctx, const_list);
+ while(ctx->lexem.type == LEX_LSHIFT)
+ {
+ next(ctx, true);
+ v <<= parse_term_expr(ctx, const_list);
+ }
+ return v;
+}
+
+static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
+{
+ uint32_t v = parse_shift_expr(ctx, const_list);
+ while(ctx->lexem.type == LEX_OR)
+ {
+ next(ctx, true);
+ v |= parse_shift_expr(ctx, const_list);
+ }
+ return v;
+}
+
+static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
+{
+ return parse_or_expr(ctx, const_list);
+}
+
+#define NR_INITIAL_CONSTANTS 4
+static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"};
+static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0};
+
+struct cmd_file_t *db_parse_file(const char *file)
+{
+ size_t size;
+ FILE *f = fopen(file, "r");
+ if(f == NULL)
+ bugp("Cannot open file '%s'", file);
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ char *buf = xmalloc(size);
+ if(fread(buf, size, 1, f) != 1)
+ bugp("Cannot read file '%s'", file);
+ fclose(f);
+
+ if(g_debug)
+ printf("Parsing db file '%s'\n", file);
+ struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t));
+ memset(cmd_file, 0, sizeof(struct cmd_file_t));
+
+ /* add initial constants */
+ for(int i = 0; i < NR_INITIAL_CONSTANTS; i++)
+ {
+ struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
+ memset(opt, 0, sizeof(struct cmd_option_t));
+ opt->name = strdup(init_const_name[i]);
+ opt->is_string = false;
+ opt->val = init_const_value[i];
+ opt->next = cmd_file->constant_list;
+ cmd_file->constant_list = opt;
+ }
+
+ struct lex_ctx_t lctx;
+ lctx.ctx.file = file;
+ lctx.ctx.line = 1;
+ lctx.ctx.begin = buf;
+ lctx.ctx.ptr = buf;
+ lctx.ctx.end = buf + size;
+ #define next(clean_lexem) next(&lctx, clean_lexem)
+ #define lexem lctx.lexem
+ /* init lexer */
+ next(false); /* don't clean init lexem because it doesn't exist */
+ /* constants ? */
+ if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
+ {
+ next(true);
+ if(lexem.type != LEX_LBRACE)
+ parse_error(lexem, "'{' expected after 'constants'\n");
+
+ while(true)
+ {
+ struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
+ memset(opt, 0, sizeof(struct cmd_option_t));
+ next(true);
+ if(lexem.type == LEX_RBRACE)
+ break;
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "Identifier expected in constants\n");
+ opt->name = lexem.str;
+ next(false); /* lexem string is kept as option name */
+ if(lexem.type != LEX_EQUAL)
+ parse_error(lexem, "'=' expected after identifier\n");
+ next(true);
+ opt->is_string = false;
+ opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
+ opt->next = cmd_file->constant_list;
+ cmd_file->constant_list = opt;
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "';' expected after string\n");
+ }
+ next(true);
+ }
+ /* options ? */
+ if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
+ {
+ next(true);
+ if(lexem.type != LEX_LBRACE)
+ parse_error(lexem, "'{' expected after 'options'\n");
+
+ while(true)
+ {
+ next(true);
+ if(lexem.type == LEX_RBRACE)
+ break;
+ struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
+ memset(opt, 0, sizeof(struct cmd_option_t));
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "Identifier expected in options\n");
+ opt->name = lexem.str;
+ next(false); /* lexem string is kept as option name */
+ if(lexem.type != LEX_EQUAL)
+ parse_error(lexem, "'=' expected after identifier\n");
+ next(true);
+ if(lexem.type == LEX_STRING)
+ {
+ opt->is_string = true;
+ opt->str = lexem.str;
+ next(false); /* lexem string is kept as option name */
+ }
+ else
+ {
+ opt->is_string = false;
+ opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
+ }
+ opt->next = cmd_file->opt_list;
+ cmd_file->opt_list = opt;
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "';' expected after string\n");
+ }
+ next(true);
+ }
+ /* sources */
+ if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
+ parse_error(lexem, "'sources' expected\n");
+ next(true);
+ if(lexem.type != LEX_LBRACE)
+ parse_error(lexem, "'{' expected after 'sources'\n");
+
+ while(true)
+ {
+ next(true);
+ if(lexem.type == LEX_RBRACE)
+ break;
+ struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
+ memset(src, 0, sizeof(struct cmd_source_t));
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "identifier expected in sources\n");
+ src->identifier = lexem.str;
+ next(false); /* lexem string is kept as source name */
+ if(lexem.type != LEX_EQUAL)
+ parse_error(lexem, "'=' expected after identifier\n");
+ next(true);
+ if(lexem.type == LEX_STRING)
+ {
+ src->is_extern = false;
+ src->filename = lexem.str;
+ next(false); /* lexem string is kept as file name */
+ }
+ else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
+ {
+ src->is_extern = true;
+ src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
+ next(true);
+ if(lexem.type != LEX_LPAREN)
+ parse_error(lexem, "'(' expected after 'extern'\n");
+ next(true);
+ src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
+ if(lexem.type != LEX_RPAREN)
+ parse_error(lexem, "')' expected\n");
+ next(true);
+ }
+ else
+ parse_error(lexem, "String or 'extern' expected after '='\n");
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "';' expected\n");
+ if(db_find_source_by_id(cmd_file, src->identifier) != NULL)
+ parse_error(lexem, "Duplicate source identifier\n");
+ /* type filled later */
+ src->type = CMD_SRC_UNK;
+ src->next = cmd_file->source_list;
+ cmd_file->source_list = src;
+ }
+
+ /* sections */
+ struct cmd_section_t *end_sec = NULL;
+ while(true)
+ {
+ next(true);
+ if(lexem.type == LEX_EOF)
+ break;
+ struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
+ struct cmd_inst_t *end_list = NULL;
+ memset(sec, 0, sizeof(struct cmd_section_t));
+ if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
+ parse_error(lexem, "'section' expected\n");
+ next(true);
+ if(lexem.type != LEX_LPAREN)
+ parse_error(lexem, "'(' expected after 'section'\n");
+ next(true);
+ /* can be any number */
+ sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
+ /* options ? */
+ if(lexem.type == LEX_SEMICOLON)
+ {
+ do
+ {
+ next(true);
+ struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
+ memset(opt, 0, sizeof(struct cmd_option_t));
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "Identifier expected for section option\n");
+ opt->name = lexem.str;
+ next(false); /* lexem string is kept as option name */
+ if(lexem.type != LEX_EQUAL)
+ parse_error(lexem, "'=' expected after option identifier\n");
+ next(true);
+ if(lexem.type == LEX_STRING)
+ {
+ opt->is_string = true;
+ opt->str = lexem.str;
+ next(false); /* lexem string is kept as option string */
+ }
+ else
+ {
+ opt->is_string = false;
+ opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
+ }
+ opt->next = sec->opt_list;
+ sec->opt_list = opt;
+ }while(lexem.type == LEX_COLON);
+ }
+ if(lexem.type != LEX_RPAREN)
+ parse_error(lexem, "')' expected after section identifier\n");
+ next(true);
+ if(lexem.type == LEX_LBRACE)
+ {
+ sec->is_data = false;
+ /* commands */
+ while(true)
+ {
+ next(true);
+ if(lexem.type == LEX_RBRACE)
+ break;
+ struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
+ memset(inst, 0, sizeof(struct cmd_inst_t));
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "Instruction expected in section\n");
+ if(strcmp(lexem.str, "load") == 0)
+ inst->type = CMD_LOAD;
+ else if(strcmp(lexem.str, "call") == 0)
+ inst->type = CMD_CALL;
+ else if(strcmp(lexem.str, "jump") == 0)
+ inst->type = CMD_JUMP;
+ else if(strcmp(lexem.str, "mode") == 0)
+ inst->type = CMD_MODE;
+ else
+ parse_error(lexem, "Instruction expected in section\n");
+ next(true);
+
+ if(inst->type == CMD_LOAD)
+ {
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "Identifier expected after instruction\n");
+ inst->identifier = lexem.str;
+ if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
+ parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
+ next(false); /* lexem string kept as identifier */
+ if(lexem.type == LEX_RANGLE)
+ {
+ // load at
+ inst->type = CMD_LOAD_AT;
+ next(true);
+ inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
+ }
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "';' expected after command\n");
+ }
+ else if(inst->type == CMD_CALL || inst->type == CMD_JUMP)
+ {
+ if(lexem.type == LEX_IDENTIFIER)
+ {
+ inst->identifier = lexem.str;
+ if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
+ parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
+ next(false); /* lexem string kept as identifier */
+ }
+ else
+ {
+ inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT;
+ inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
+ }
+
+ if(lexem.type == LEX_LPAREN)
+ {
+ next(true);
+ inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
+ if(lexem.type != LEX_RPAREN)
+ parse_error(lexem, "Expected closing brace\n");
+ next(true);
+ }
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "';' expected after command\n");
+ }
+ else if(inst->type == CMD_MODE)
+ {
+ inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "Expected ';' after command\n");
+ }
+ else
+ parse_error(lexem, "Internal error");
+ if(end_list == NULL)
+ {
+ sec->inst_list = inst;
+ end_list = inst;
+ }
+ else
+ {
+ end_list->next = inst;
+ end_list = inst;
+ }
+ }
+ }
+ else if(lexem.type == LEX_LE)
+ {
+ sec->is_data = true;
+ next(true);
+ if(lexem.type != LEX_IDENTIFIER)
+ parse_error(lexem, "Identifier expected after '<='\n");
+ sec->source_id = lexem.str;
+ next(false); /* lexem string is kept as source id */
+ if(lexem.type != LEX_SEMICOLON)
+ parse_error(lexem, "';' expected after identifier\n");
+ }
+ else
+ parse_error(lexem, "'{' or '<=' expected after section directive\n");
+
+ if(end_sec == NULL)
+ {
+ cmd_file->section_list = sec;
+ end_sec = sec;
+ }
+ else
+ {
+ end_sec->next = sec;
+ end_sec = sec;
+ }
+ }
+ #undef lexem
+ #undef next
+
+ free(buf);
+ return cmd_file;
+}
+
+void db_generate_default_sb_version(struct sb_version_t *ver)
+{
+ ver->major = ver->minor = ver->revision = 0x999;
+}
+
+void db_free_option_list(struct cmd_option_t *opt_list)
+{
+ while(opt_list)
+ {
+ struct cmd_option_t *next = opt_list->next;
+ fflush(stdout);
+ free(opt_list->name);
+ free(opt_list->str);
+ free(opt_list);
+ opt_list = next;
+ }
+}
+
+void db_free(struct cmd_file_t *file)
+{
+ db_free_option_list(file->opt_list);
+ db_free_option_list(file->constant_list);
+ struct cmd_source_t *src = file->source_list;
+ while(src)
+ {
+ struct cmd_source_t *next = src->next;
+ free(src->identifier);
+ fflush(stdout);
+ free(src->filename);
+ if(src->loaded)
+ {
+ if(src->type == CMD_SRC_BIN)
+ free(src->bin.data);
+ if(src->type == CMD_SRC_ELF)
+ elf_release(&src->elf);
+ }
+ free(src);
+ src = next;
+ }
+ struct cmd_section_t *sec = file->section_list;
+ while(sec)
+ {
+ struct cmd_section_t *next = sec->next;
+ db_free_option_list(sec->opt_list);
+ free(sec->source_id);
+ struct cmd_inst_t *inst = sec->inst_list;
+ while(inst)
+ {
+ struct cmd_inst_t *next = inst->next;
+ free(inst->identifier);
+ free(inst);
+ inst = next;
+ }
+ free(sec);
+ sec = next;
+ }
+ free(file);
+}
diff --git a/utils/imxtools/dbparser.h b/utils/imxtools/dbparser.h
new file mode 100644
index 0000000000..4a36861583
--- /dev/null
+++ b/utils/imxtools/dbparser.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __DBPARSER__
+#define __DBPARSER__
+
+/**
+ * Command file parsing
+ */
+#include "sb.h"
+#include "elf.h"
+
+enum cmd_source_type_t
+{
+ CMD_SRC_UNK,
+ CMD_SRC_ELF,
+ CMD_SRC_BIN
+};
+
+struct bin_param_t
+{
+ uint32_t size;
+ void *data;
+};
+
+struct cmd_source_t
+{
+ char *identifier;
+ bool is_extern;
+ // <union>
+ int extern_nr;
+ char *filename;
+ // </union>
+ struct cmd_source_t *next;
+ /* for later use */
+ enum cmd_source_type_t type;
+ bool loaded;
+ struct elf_params_t elf;
+ struct bin_param_t bin;
+};
+
+enum cmd_inst_type_t
+{
+ CMD_LOAD, /* load image */
+ CMD_JUMP, /* jump at image */
+ CMD_CALL, /* call image */
+ CMD_LOAD_AT, /* load binary at */
+ CMD_CALL_AT, /* call at address */
+ CMD_JUMP_AT, /* jump at address */
+ CMD_MODE, /* change boot mode */
+};
+
+struct cmd_inst_t
+{
+ enum cmd_inst_type_t type;
+ char *identifier;
+ uint32_t argument; // for jump, call, mode
+ uint32_t addr; // for 'at'
+ struct cmd_inst_t *next;
+};
+
+struct cmd_option_t
+{
+ char *name;
+ bool is_string;
+ /* <union> */
+ uint32_t val;
+ char *str;
+ /* </union> */
+ struct cmd_option_t *next;
+};
+
+struct cmd_section_t
+{
+ uint32_t identifier;
+ bool is_data;
+ // <union>
+ struct cmd_inst_t *inst_list;
+ char *source_id;
+ // </union>
+ struct cmd_section_t *next;
+ struct cmd_option_t *opt_list;
+};
+
+struct cmd_file_t
+{
+ struct cmd_option_t *opt_list;
+ struct cmd_option_t *constant_list; /* constant are always integers */
+ struct cmd_source_t *source_list;
+ struct cmd_section_t *section_list;
+};
+
+struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id);
+struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name);
+bool db_parse_sb_version(struct sb_version_t *ver, char *str);
+void db_generate_default_sb_version(struct sb_version_t *ver);
+struct cmd_file_t *db_parse_file(const char *file);
+void db_free_option_list(struct cmd_option_t *opt_list);
+void db_free(struct cmd_file_t *file);
+
+#endif /* __DBPARSER__ */
diff --git a/utils/imxtools/elf.c b/utils/imxtools/elf.c
new file mode 100644
index 0000000000..481ab98dd6
--- /dev/null
+++ b/utils/imxtools/elf.c
@@ -0,0 +1,575 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "elf.h"
+#include "misc.h"
+
+/**
+ * Definitions
+ * taken from elf.h linux header
+ * based on ELF specification
+ * based on ARM ELF specification
+ */
+typedef uint16_t Elf32_Half;
+
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Addr;
+typedef uint32_t Elf32_Off;
+typedef uint16_t Elf32_Section;
+
+#define EI_NIDENT 16
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+}Elf32_Ehdr;
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7f /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASS32 1 /* 32-bit objects */
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+
+#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */
+
+#define EI_OSABI 7 /* OS ABI identification */
+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
+#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
+#define ELFOSABI_ARM 97 /* ARM */
+
+#define EI_ABIVERSION 8 /* ABI version */
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+#define ET_EXEC 2 /* Executable file */
+
+#define EM_ARM 40 /* ARM */
+
+#define EV_CURRENT 1 /* Current version */
+
+#define EF_ARM_HASENTRY 0x00000002
+
+#define SHN_UNDEF 0 /* Undefined section */
+
+typedef struct
+{
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+}Elf32_Shdr;
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Dynamic linking information */
+#define SHT_NOTE 7 /* Notes */
+#define SHT_NOBITS 8 /* Program space with no data (bss) */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY 14 /* Array of constructors */
+#define SHT_FINI_ARRAY 15 /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
+#define SHT_GROUP 17 /* Section group */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+#define SHT_NUM 19 /* Number of defined types. */
+
+#define SHF_WRITE (1 << 0) /* Writable */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_MERGE (1 << 4) /* Might be merged */
+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+}Elf32_Phdr;
+
+#define PT_LOAD 1 /* Loadable program segment */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+
+void elf_init(struct elf_params_t *params)
+{
+ memset(params, 0, sizeof(struct elf_params_t));
+}
+
+extern void *xmalloc(size_t s);
+
+static struct elf_section_t *elf_add_section(struct elf_params_t *params)
+{
+ struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t));
+ if(params->first_section == NULL)
+ params->first_section = params->last_section = sec;
+ else
+ {
+ params->last_section->next = sec;
+ params->last_section = sec;
+ }
+ sec->next = NULL;
+
+ return sec;
+}
+
+static struct elf_segment_t *elf_add_segment(struct elf_params_t *params)
+{
+ struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t));
+ if(params->first_segment == NULL)
+ params->first_segment = params->last_segment = seg;
+ else
+ {
+ params->last_segment->next = seg;
+ params->last_segment = seg;
+ }
+ seg->next = NULL;
+
+ return seg;
+}
+
+void elf_add_load_section(struct elf_params_t *params,
+ uint32_t load_addr, uint32_t size, const void *section)
+{
+ struct elf_section_t *sec = elf_add_section(params);
+
+ sec->type = EST_LOAD;
+ sec->addr = load_addr;
+ sec->size = size;
+ sec->section = xmalloc(size);
+ memcpy(sec->section, section, size);
+}
+
+void elf_add_fill_section(struct elf_params_t *params,
+ uint32_t fill_addr, uint32_t size, uint32_t pattern)
+{
+ if(pattern != 0x00)
+ {
+ printf("oops, non-zero filling, ignore fill section\n");
+ return;
+ }
+
+ struct elf_section_t *sec = elf_add_section(params);
+
+ sec->type = EST_FILL;
+ sec->addr = fill_addr;
+ sec->size = size;
+ sec->pattern = pattern;
+}
+
+void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
+ elf_printf_fn_t printf, void *user)
+{
+ (void) printf;
+
+ Elf32_Ehdr ehdr;
+ uint32_t phnum = 0;
+ struct elf_section_t *sec = params->first_section;
+ uint32_t offset = 0;
+ Elf32_Phdr phdr;
+ Elf32_Shdr shdr;
+ memset(&ehdr, 0, EI_NIDENT);
+
+ while(sec)
+ {
+ if(sec->type == EST_LOAD)
+ {
+ sec->offset = offset;
+ offset += sec->size;
+ }
+ else
+ {
+ sec->offset = 0;
+ }
+
+ phnum++;
+ sec = sec->next;
+ }
+
+ uint32_t strtbl_offset = offset;
+
+ ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+ ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE;
+ ehdr.e_ident[EI_ABIVERSION] = 0;
+ ehdr.e_type = ET_EXEC;
+ ehdr.e_machine = EM_ARM;
+ ehdr.e_version = EV_CURRENT;
+ ehdr.e_entry = params->start_addr;
+ ehdr.e_flags = 0;
+ if(params->has_start_addr)
+ ehdr.e_flags |= EF_ARM_HASENTRY;
+ ehdr.e_ehsize = sizeof ehdr;
+ ehdr.e_phentsize = sizeof phdr;
+ ehdr.e_phnum = phnum;
+ ehdr.e_shentsize = sizeof shdr;
+ ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */
+ ehdr.e_shstrndx = ehdr.e_shnum - 1;
+ ehdr.e_phoff = ehdr.e_ehsize;
+ ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize;
+
+ write(user, 0, &ehdr, sizeof ehdr);
+
+ /* allocate enough size to hold any combinaison of .text/.bss in the string table:
+ * - one empty name ("\0")
+ * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0"
+ * - one name ".shstrtab\0" */
+ char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 +
+ phnum * (strlen(".textXXXX") + 1));
+
+ strtbl_content[0] = '\0';
+ strcpy(&strtbl_content[1], ".shstrtab");
+ uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1;
+
+ uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize +
+ ehdr.e_shnum * ehdr.e_shentsize;
+
+ sec = params->first_section;
+ offset = ehdr.e_phoff;
+ while(sec)
+ {
+ sec->offset += data_offset;
+
+ phdr.p_type = PT_LOAD;
+ if(sec->type == EST_LOAD)
+ phdr.p_offset = sec->offset;
+ else
+ phdr.p_offset = 0;
+ phdr.p_paddr = sec->addr;
+ phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */
+ phdr.p_memsz = sec->size;
+ if(sec->type == EST_LOAD)
+ phdr.p_filesz = phdr.p_memsz;
+ else
+ phdr.p_filesz = 0;
+ phdr.p_flags = PF_X | PF_W | PF_R;
+ phdr.p_align = 0;
+
+ write(user, offset, &phdr, sizeof phdr);
+
+ offset += sizeof(Elf32_Phdr);
+ sec = sec->next;
+ }
+
+ sec = params->first_section;
+ offset = ehdr.e_shoff;
+
+ {
+ shdr.sh_name = 0;
+ shdr.sh_type = SHT_NULL;
+ shdr.sh_flags = 0;
+ shdr.sh_addr = 0;
+ shdr.sh_offset = 0;
+ shdr.sh_size = 0;
+ shdr.sh_link = SHN_UNDEF;
+ shdr.sh_info = 0;
+ shdr.sh_addralign = 0;
+ shdr.sh_entsize = 0;
+
+ write(user, offset, &shdr, sizeof shdr);
+
+ offset += sizeof(Elf32_Shdr);
+ }
+
+ uint32_t text_idx = 0;
+ uint32_t bss_idx = 0;
+ while(sec)
+ {
+ shdr.sh_name = strtbl_index;
+ if(sec->type == EST_LOAD)
+ {
+ strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++);
+ shdr.sh_type = SHT_PROGBITS;
+ }
+ else
+ {
+ strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++);
+ shdr.sh_type = SHT_NOBITS;
+ }
+ shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
+ shdr.sh_addr = sec->addr;
+ shdr.sh_offset = sec->offset;
+ shdr.sh_size = sec->size;
+ shdr.sh_link = SHN_UNDEF;
+ shdr.sh_info = 0;
+ shdr.sh_addralign = 1;
+ shdr.sh_entsize = 0;
+
+ write(user, offset, &shdr, sizeof shdr);
+
+ offset += sizeof(Elf32_Shdr);
+ sec = sec->next;
+ }
+
+ {
+ shdr.sh_name = 1;
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_flags = 0;
+ shdr.sh_addr = 0;
+ shdr.sh_offset = strtbl_offset + data_offset;
+ shdr.sh_size = strtbl_index;
+ shdr.sh_link = SHN_UNDEF;
+ shdr.sh_info = 0;
+ shdr.sh_addralign = 1;
+ shdr.sh_entsize = 0;
+
+ write(user, offset, &shdr, sizeof shdr);
+
+ offset += sizeof(Elf32_Shdr);
+ }
+
+ sec = params->first_section;
+ while(sec)
+ {
+ if(sec->type == EST_LOAD)
+ write(user, sec->offset, sec->section, sec->size);
+ sec = sec->next;
+ }
+
+ write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index);
+ free(strtbl_content);
+}
+
+bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
+ elf_printf_fn_t printf, void *user)
+{
+ #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
+
+ /* read header */
+ Elf32_Ehdr ehdr;
+ if(!read(user, 0, &ehdr, sizeof(ehdr)))
+ {
+ printf(user, true, "error reading elf header\n");
+ return false;
+ }
+ /* basic checks */
+ if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3)
+ error_printf("invalid elf header\n");
+ if(ehdr.e_ident[EI_CLASS] != ELFCLASS32)
+ error_printf("invalid elf class: must be a 32-bit object\n");
+ if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
+ error_printf("invalid elf data encoding: must be 32-bit lsb\n");
+ if(ehdr.e_ident[EI_VERSION] != EV_CURRENT)
+ error_printf("invalid elf version\n");
+ if(ehdr.e_type != ET_EXEC)
+ error_printf("invalid elf file: must be an executable file\n");
+ if(ehdr.e_machine != EM_ARM)
+ error_printf("invalid elf file: must target an arm machine\n");
+ if(ehdr.e_ehsize != sizeof(ehdr))
+ error_printf("invalid elf file: size header mismatch\n");
+ if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr))
+ error_printf("invalid elf file: program header size mismatch\n");
+ if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr))
+ error_printf("invalid elf file: section header size mismatch\n");
+ elf_set_start_addr(params, ehdr.e_entry);
+
+ char *strtab = NULL;
+ if(ehdr.e_shstrndx != SHN_UNDEF)
+ {
+ Elf32_Shdr shstrtab;
+ if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize,
+ &shstrtab, sizeof(shstrtab)))
+ {
+ strtab = xmalloc(shstrtab.sh_size);
+ if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size))
+ {
+ free(strtab);
+ strtab = NULL;
+ }
+ }
+ }
+ /* run through sections */
+ printf(user, false, "ELF file:\n");
+ for(int i = 1; i < ehdr.e_shnum; i++)
+ {
+ uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize;
+ Elf32_Shdr shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ if(!read(user, off, &shdr, sizeof(shdr)))
+ error_printf("error reading elf section header");
+
+ if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC)
+ {
+ void *data = xmalloc(shdr.sh_size);
+ if(!read(user, shdr.sh_offset, data, shdr.sh_size))
+ error_printf("error read self section data\n");
+ elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
+ free(data);
+
+ if(strtab)
+ printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]);
+ }
+ else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC)
+ {
+ elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0);
+ if(strtab)
+ printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]);
+ }
+ else
+ {
+ if(strtab)
+ printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type);
+ }
+
+ }
+ free(strtab);
+ /* run through segments */
+ for(int i = 1; i < ehdr.e_phnum; i++)
+ {
+ uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize;
+ Elf32_Phdr phdr;
+ memset(&phdr, 0, sizeof(phdr));
+ if(!read(user, off, &phdr, sizeof(phdr)))
+ error_printf("error reading elf segment header");
+ if(phdr.p_type != PT_LOAD)
+ continue;
+ struct elf_segment_t *seg = elf_add_segment(params);
+ seg->vaddr = phdr.p_vaddr;
+ seg->paddr = phdr.p_paddr;
+ seg->vsize = phdr.p_memsz;
+ seg->psize = phdr.p_filesz;
+ printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n",
+ seg->vaddr, seg->vsize, seg->paddr, seg->psize);
+ }
+
+ return true;
+}
+
+uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr)
+{
+ struct elf_segment_t *seg = params->first_segment;
+ while(seg)
+ {
+ if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize)
+ return addr - seg->vaddr + seg->paddr;
+ seg = seg->next;
+ }
+ return addr;
+}
+
+void elf_translate_addresses(struct elf_params_t *params)
+{
+ struct elf_section_t *sec = params->first_section;
+ while(sec)
+ {
+ sec->addr = elf_translate_virtual_address(params, sec->addr);
+ sec = sec->next;
+ }
+ params->start_addr = elf_translate_virtual_address(params, params->start_addr);
+}
+
+bool elf_is_empty(struct elf_params_t *params)
+{
+ return params->first_section == NULL;
+}
+
+void elf_set_start_addr(struct elf_params_t *params, uint32_t addr)
+{
+ params->has_start_addr = true;
+ params->start_addr = addr;
+}
+
+bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr)
+{
+ if(params->has_start_addr && addr != NULL)
+ *addr = params->start_addr;
+ return params->has_start_addr;
+}
+
+int elf_get_nr_sections(struct elf_params_t *params)
+{
+ int nr = 0;
+ struct elf_section_t *sec = params->first_section;
+ while(sec)
+ {
+ nr++;
+ sec = sec->next;
+ }
+ return nr;
+}
+
+void elf_release(struct elf_params_t *params)
+{
+ struct elf_section_t *sec = params->first_section;
+ while(sec)
+ {
+ struct elf_section_t *next_sec = sec->next;
+ if(sec->type == EST_LOAD)
+ free(sec->section);
+ free(sec);
+ sec = next_sec;
+ }
+ struct elf_segment_t *seg = params->first_segment;
+ while(seg)
+ {
+ struct elf_segment_t *next_seg = seg->next;
+ free(seg);
+ seg = next_seg;
+ }
+}
diff --git a/utils/imxtools/elf.h b/utils/imxtools/elf.h
new file mode 100644
index 0000000000..2166833276
--- /dev/null
+++ b/utils/imxtools/elf.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __ELF_H__
+#define __ELF_H__
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * API
+ */
+enum elf_section_type_t
+{
+ EST_LOAD,
+ EST_FILL
+};
+
+struct elf_section_t
+{
+ uint32_t addr; /* virtual address */
+ uint32_t size; /* virtual size */
+ enum elf_section_type_t type;
+ /* <union> */
+ void *section; /* data */
+ uint32_t pattern; /* fill pattern */
+ /* </union> */
+ struct elf_section_t *next;
+ /* Internal to elf_write_file */
+ uint32_t offset;
+};
+
+struct elf_segment_t
+{
+ uint32_t vaddr; /* virtual address */
+ uint32_t paddr; /* physical address */
+ uint32_t vsize; /* virtual size */
+ uint32_t psize; /* physical size */
+ struct elf_segment_t *next;
+};
+
+struct elf_params_t
+{
+ bool has_start_addr;
+ uint32_t start_addr;
+ struct elf_section_t *first_section;
+ struct elf_section_t *last_section;
+ struct elf_segment_t *first_segment;
+ struct elf_segment_t *last_segment;
+};
+
+typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count);
+/* write function manages it's own error state */
+typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count);
+typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...);
+
+void elf_init(struct elf_params_t *params);
+void elf_add_load_section(struct elf_params_t *params,
+ uint32_t load_addr, uint32_t size, const void *section);
+void elf_add_fill_section(struct elf_params_t *params,
+ uint32_t fill_addr, uint32_t size, uint32_t pattern);
+uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr);
+void elf_translate_addresses(struct elf_params_t *params);
+void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user);
+bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf,
+ void *user);
+bool elf_is_empty(struct elf_params_t *params);
+void elf_set_start_addr(struct elf_params_t *params, uint32_t addr);
+bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr);
+int elf_get_nr_sections(struct elf_params_t *params);
+void elf_release(struct elf_params_t *params);
+
+#endif /* __ELF_H__ */
diff --git a/utils/imxtools/elftosb.c b/utils/imxtools/elftosb.c
new file mode 100644
index 0000000000..2f8700551f
--- /dev/null
+++ b/utils/imxtools/elftosb.c
@@ -0,0 +1,461 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#define _ISOC99_SOURCE
+#define _POSIX_C_SOURCE 200809L /* for strdup */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <getopt.h>
+
+#include "crypto.h"
+#include "elf.h"
+#include "sb.h"
+#include "dbparser.h"
+#include "misc.h"
+#include "sb.h"
+
+char **g_extern;
+int g_extern_count;
+
+#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
+
+#define crypto_cbc(...) \
+ do { int ret = crypto_cbc(__VA_ARGS__); \
+ if(ret != CRYPTO_ERROR_SUCCESS) \
+ bug("crypto_cbc error: %d\n", ret); \
+ }while(0)
+
+/**
+ * command file to sb conversion
+ */
+
+static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
+{
+ if(fseek((FILE *)user, addr, SEEK_SET) == -1)
+ return false;
+ return fread(buf, 1, count, (FILE *)user) == count;
+}
+
+static void elf_printf(void *user, bool error, const char *fmt, ...)
+{
+ if(!g_debug && !error)
+ return;
+ (void) user;
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+static void resolve_extern(struct cmd_source_t *src)
+{
+ if(!src->is_extern)
+ return;
+ src->is_extern = false;
+ if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
+ bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
+ /* first free the old src->filename content */
+ free(src->filename);
+ src->filename = strdup(g_extern[src->extern_nr]);
+}
+
+static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
+{
+ struct cmd_source_t *src = db_find_source_by_id(cmd_file, id);
+ if(src == NULL)
+ bug("undefined reference to source '%s'\n", id);
+ /* avoid reloading */
+ if(src->type == CMD_SRC_ELF && src->loaded)
+ return;
+ if(src->type != CMD_SRC_UNK)
+ bug("source '%s' seen both as elf and binary file\n", id);
+ /* resolve potential extern file */
+ resolve_extern(src);
+ /* load it */
+ src->type = CMD_SRC_ELF;
+ FILE *fd = fopen(src->filename, "rb");
+ if(fd == NULL)
+ bug("cannot open '%s' (id '%s')\n", src->filename, id);
+ if(g_debug)
+ printf("Loading ELF file '%s'...\n", src->filename);
+ elf_init(&src->elf);
+ src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd);
+ fclose(fd);
+ if(!src->loaded)
+ bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
+ elf_translate_addresses(&src->elf);
+}
+
+static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id)
+{
+ struct cmd_source_t *src = db_find_source_by_id(cmd_file, id);
+ if(src == NULL)
+ bug("undefined reference to source '%s'\n", id);
+ /* avoid reloading */
+ if(src->type == CMD_SRC_BIN && src->loaded)
+ return;
+ if(src->type != CMD_SRC_UNK)
+ bug("source '%s' seen both as elf and binary file\n", id);
+ /* resolve potential extern file */
+ resolve_extern(src);
+ /* load it */
+ src->type = CMD_SRC_BIN;
+ FILE *fd = fopen(src->filename, "rb");
+ if(fd == NULL)
+ bug("cannot open '%s' (id '%s')\n", src->filename, id);
+ if(g_debug)
+ printf("Loading BIN file '%s'...\n", src->filename);
+ fseek(fd, 0, SEEK_END);
+ src->bin.size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ src->bin.data = xmalloc(src->bin.size);
+ fread(src->bin.data, 1, src->bin.size, fd);
+ fclose(fd);
+ src->loaded = true;
+}
+
+static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
+{
+ struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t));
+ memset(sb, 0, sizeof(struct sb_file_t));
+
+ db_generate_default_sb_version(&sb->product_ver);
+ db_generate_default_sb_version(&sb->component_ver);
+
+ if(g_debug)
+ printf("Applying command file...\n");
+ /* count sections */
+ struct cmd_section_t *csec = cmd_file->section_list;
+ while(csec)
+ {
+ sb->nr_sections++;
+ csec = csec->next;
+ }
+
+ sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t));
+ memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t));
+ /* flatten sections */
+ csec = cmd_file->section_list;
+ for(int i = 0; i < sb->nr_sections; i++, csec = csec->next)
+ {
+ struct sb_section_t *sec = &sb->sections[i];
+ sec->identifier = csec->identifier;
+
+ /* options */
+ do
+ {
+ /* cleartext */
+ struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext");
+ if(opt != NULL)
+ {
+ if(opt->is_string)
+ bug("Cleartext section attribute must be an integer\n");
+ if(opt->val != 0 && opt->val != 1)
+ bug("Cleartext section attribute must be 0 or 1\n");
+ sec->is_cleartext = opt->val;
+ }
+ /* alignment */
+ opt = db_find_option_by_id(csec->opt_list, "alignment");
+ if(opt != NULL)
+ {
+ if(opt->is_string)
+ bug("Cleartext section attribute must be an integer\n");
+ // n is a power of 2 iff n & (n - 1) = 0
+ // alignement cannot be lower than block size
+ if((opt->val & (opt->val - 1)) != 0)
+ bug("Cleartext section attribute must be a power of two\n");
+ if(opt->val < BLOCK_SIZE)
+ sec->alignment = BLOCK_SIZE;
+ else
+ sec->alignment = opt->val;
+ }
+ else
+ sec->alignment = BLOCK_SIZE;
+ }while(0);
+
+ if(csec->is_data)
+ {
+ sec->is_data = true;
+ sec->nr_insts = 1;
+ sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t));
+ memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t));
+
+ load_bin_by_id(cmd_file, csec->source_id);
+ struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin;
+
+ sec->insts[0].inst = SB_INST_DATA;
+ sec->insts[0].size = bin->size;
+ sec->insts[0].data = memdup(bin->data, bin->size);
+ }
+ else
+ {
+ sec->is_data = false;
+ /* count instructions and loads things */
+ struct cmd_inst_t *cinst = csec->inst_list;
+ while(cinst)
+ {
+ if(cinst->type == CMD_LOAD)
+ {
+ load_elf_by_id(cmd_file, cinst->identifier);
+ struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
+ sec->nr_insts += elf_get_nr_sections(elf);
+ }
+ else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
+ {
+ load_elf_by_id(cmd_file, cinst->identifier);
+ struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
+ if(!elf_get_start_addr(elf, NULL))
+ bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier);
+ sec->nr_insts++;
+ }
+ else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT)
+ {
+ sec->nr_insts++;
+ }
+ else if(cinst->type == CMD_LOAD_AT)
+ {
+ load_bin_by_id(cmd_file, cinst->identifier);
+ sec->nr_insts++;
+ }
+ else if(cinst->type == CMD_MODE)
+ {
+ sec->nr_insts++;
+ }
+ else
+ bug("die\n");
+
+ cinst = cinst->next;
+ }
+
+ sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t));
+ memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t));
+ /* flatten */
+ int idx = 0;
+ cinst = csec->inst_list;
+ while(cinst)
+ {
+ if(cinst->type == CMD_LOAD)
+ {
+ struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
+ struct elf_section_t *esec = elf->first_section;
+ while(esec)
+ {
+ if(esec->type == EST_LOAD)
+ {
+ sec->insts[idx].inst = SB_INST_LOAD;
+ sec->insts[idx].addr = esec->addr;
+ sec->insts[idx].size = esec->size;
+ sec->insts[idx++].data = memdup(esec->section, esec->size);
+ }
+ else if(esec->type == EST_FILL)
+ {
+ sec->insts[idx].inst = SB_INST_FILL;
+ sec->insts[idx].addr = esec->addr;
+ sec->insts[idx].size = esec->size;
+ sec->insts[idx++].pattern = esec->pattern;
+ }
+ esec = esec->next;
+ }
+ }
+ else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
+ {
+ struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
+ sec->insts[idx].argument = cinst->argument;
+ sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL;
+ sec->insts[idx++].addr = elf->start_addr;
+ }
+ else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT)
+ {
+ sec->insts[idx].argument = cinst->argument;
+ sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL;
+ sec->insts[idx++].addr = cinst->addr;
+ }
+ else if(cinst->type == CMD_LOAD_AT)
+ {
+ struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
+ sec->insts[idx].inst = SB_INST_LOAD;
+ sec->insts[idx].addr = cinst->addr;
+ sec->insts[idx].data = memdup(bin->data, bin->size);
+ sec->insts[idx++].size = bin->size;
+ }
+ else if(cinst->type == CMD_MODE)
+ {
+ sec->insts[idx].inst = SB_INST_MODE;
+ sec->insts[idx++].addr = cinst->argument;
+ }
+ else
+ bug("die\n");
+
+ cinst = cinst->next;
+ }
+ }
+ }
+
+ return sb;
+}
+
+void usage(void)
+{
+ printf("Usage: elftosb [options | file]...\n");
+ printf("Options:\n");
+ printf(" -?/--help\tDisplay this message\n");
+ printf(" -o <file>\tSet output file\n");
+ printf(" -c <file>\tSet command file\n");
+ printf(" -d/--debug\tEnable debug output\n");
+ printf(" -k <file>\tAdd key file\n");
+ printf(" -z\t\tAdd zero key\n");
+ printf(" --add-key <key>\tAdd single key (hex or usbotp)\n");
+ printf(" --real-key <key>\tOverride real key\n");
+ printf(" --crypto-iv <iv>\tOverride crypto IV\n");
+ exit(1);
+}
+
+static struct crypto_key_t g_zero_key =
+{
+ .method = CRYPTO_KEY,
+ .u.key = {0}
+};
+
+int main(int argc, char **argv)
+{
+ char *cmd_filename = NULL;
+ char *output_filename = NULL;
+ struct crypto_key_t real_key;
+ struct crypto_key_t crypto_iv;
+ real_key.method = CRYPTO_NONE;
+ crypto_iv.method = CRYPTO_NONE;
+
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"debug", no_argument, 0, 'd'},
+ {"add-key", required_argument, 0, 'a'},
+ {"real-key", required_argument, 0, 'r'},
+ {"crypto-iv", required_argument, 0, 'i'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?do:c:k:za:", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case 'd':
+ g_debug = true;
+ break;
+ case '?':
+ usage();
+ break;
+ case 'o':
+ output_filename = optarg;
+ break;
+ case 'c':
+ cmd_filename = optarg;
+ break;
+ case 'k':
+ {
+ add_keys_from_file(optarg);
+ break;
+ }
+ case 'z':
+ {
+ add_keys(&g_zero_key, 1);
+ break;
+ }
+ case 'a':
+ case 'r':
+ case 'i':
+ {
+ struct crypto_key_t key;
+ char *s = optarg;
+ if(!parse_key(&s, &key))
+ bug("Invalid key/iv specified as argument");
+ if(*s != 0)
+ bug("Trailing characters after key/iv specified as argument");
+ if(c == 'r')
+ memcpy(&real_key, &key, sizeof(key));
+ else if(c == 'i')
+ memcpy(&crypto_iv, &key, sizeof(key));
+ else
+ add_keys(&key, 1);
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+
+ if(!cmd_filename)
+ bug("You must specify a command file\n");
+ if(!output_filename)
+ bug("You must specify an output file\n");
+
+ g_extern = &argv[optind];
+ g_extern_count = argc - optind;
+
+ if(g_debug)
+ {
+ printf("key: %d\n", g_nr_keys);
+ for(int i = 0; i < g_nr_keys; i++)
+ {
+ printf(" ");
+ print_key(&g_key_array[i], true);
+ }
+
+ for(int i = 0; i < g_extern_count; i++)
+ printf("extern(%d)=%s\n", i, g_extern[i]);
+ }
+
+ struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
+ struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
+ db_free(cmd_file);
+
+ if(real_key.method == CRYPTO_KEY)
+ {
+ sb_file->override_real_key = true;
+ memcpy(sb_file->real_key, real_key.u.key, 16);
+ }
+ if(crypto_iv.method == CRYPTO_KEY)
+ {
+ sb_file->override_crypto_iv = true;
+ memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16);
+ }
+
+ /* fill with default parameters since there is no command file support for them */
+ sb_file->drive_tag = 0;
+ sb_file->first_boot_sec_id = sb_file->sections[0].identifier;
+ sb_file->flags = 0;
+ sb_file->minor_version = 1;
+
+ sb_write_file(sb_file, output_filename);
+ sb_free(sb_file);
+ clear_keys();
+
+ return 0;
+}
diff --git a/utils/imxtools/fuze+_key_file.txt b/utils/imxtools/fuze+_key_file.txt
new file mode 100644
index 0000000000..a965e715f7
--- /dev/null
+++ b/utils/imxtools/fuze+_key_file.txt
@@ -0,0 +1 @@
+00000000000000000000000000000000
diff --git a/utils/imxtools/misc.c b/utils/imxtools/misc.c
new file mode 100644
index 0000000000..8d7cea89d7
--- /dev/null
+++ b/utils/imxtools/misc.c
@@ -0,0 +1,248 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#include "misc.h"
+
+bool g_debug = false;
+
+/**
+ * Misc
+ */
+
+void *memdup(void *p, size_t len)
+{
+ void *cpy = xmalloc(len);
+ memcpy(cpy, p, len);
+ return cpy;
+}
+
+void generate_random_data(void *buf, size_t sz)
+{
+ FILE *rand_fd = fopen("/dev/urandom", "rb");
+ if(rand_fd == NULL)
+ bugp("failed to open /dev/urandom");
+ if(fread(buf, 1, sz, rand_fd) != sz)
+ bugp("failed to read /dev/urandom");
+ fclose(rand_fd);
+}
+
+void *xmalloc(size_t s)
+{
+ void * r = malloc(s);
+ if(!r) bugp("malloc");
+ return r;
+}
+
+int convxdigit(char digit, byte *val)
+{
+ if(digit >= '0' && digit <= '9')
+ {
+ *val = digit - '0';
+ return 0;
+ }
+ else if(digit >= 'A' && digit <= 'F')
+ {
+ *val = digit - 'A' + 10;
+ return 0;
+ }
+ else if(digit >= 'a' && digit <= 'f')
+ {
+ *val = digit - 'a' + 10;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+/* helper function to augment an array, free old array */
+void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt)
+{
+ void *p = xmalloc(elem_sz * (cnt + aug_cnt));
+ memcpy(p, arr, elem_sz * cnt);
+ memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt);
+ free(arr);
+ return p;
+}
+
+/**
+ * Key file parsing
+ */
+int g_nr_keys;
+key_array_t g_key_array;
+
+bool parse_key(char **pstr, struct crypto_key_t *key)
+{
+ char *str = *pstr;
+ /* ignore spaces */
+ while(isspace(*str))
+ str++;
+ /* CRYPTO_KEY: 32 hex characters
+ * CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers */
+ if(isxdigit(str[0]))
+ {
+ if(strlen(str) < 32)
+ return false;
+ for(int j = 0; j < 16; j++)
+ {
+ byte a, b;
+ if(convxdigit(str[2 * j], &a) || convxdigit(str[2 * j + 1], &b))
+ return false;
+ key->u.key[j] = (a << 4) | b;
+ }
+ /* skip key */
+ *pstr = str + 32;
+ key->method = CRYPTO_KEY;
+ return true;
+ }
+ else
+ {
+ const char *prefix = "usbotp(";
+ if(strlen(str) < strlen(prefix))
+ return false;
+ if(strncmp(str, prefix, strlen(prefix)) != 0)
+ return false;
+ str += strlen(prefix);
+ /* vid */
+ long vid = strtol(str, &str, 16);
+ if(vid < 0 || vid > 0xffff)
+ return false;
+ if(*str++ != ':')
+ return false;
+ /* pid */
+ long pid = strtol(str, &str, 16);
+ if(pid < 0 || pid > 0xffff)
+ return false;
+ if(*str++ != ')')
+ return false;
+ *pstr = str;
+ key->method = CRYPTO_USBOTP;
+ key->u.vid_pid = vid << 16 | pid;
+ return true;
+ }
+}
+
+void add_keys(key_array_t ka, int kac)
+{
+ key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t));
+ memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t));
+ memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t));
+ free(g_key_array);
+ g_key_array = new_ka;
+ g_nr_keys += kac;
+}
+
+void clear_keys()
+{
+ free(g_key_array);
+ g_nr_keys = 0;
+}
+
+void add_keys_from_file(const char *key_file)
+{
+ int size;
+ FILE *fd = fopen(key_file, "r");
+ if(fd == NULL)
+ bug("opening key file failed");
+ fseek(fd, 0, SEEK_END);
+ size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ char *buf = xmalloc(size + 1);
+ if(fread(buf, 1, size, fd) != (size_t)size)
+ bug("reading key file");
+ buf[size] = 0;
+ fclose(fd);
+
+ if(g_debug)
+ printf("Parsing key file '%s'...\n", key_file);
+ char *p = buf;
+ while(1)
+ {
+ struct crypto_key_t k;
+ /* parse key */
+ if(!parse_key(&p, &k))
+ bug("invalid key file");
+ if(g_debug)
+ {
+ printf("Add key: ");
+ print_key(&k, true);
+ }
+ add_keys(&k, 1);
+ /* request at least one space character before next key, or end of file */
+ if(*p != 0 && !isspace(*p))
+ bug("invalid key file");
+ /* skip whitespace */
+ while(isspace(*p))
+ p++;
+ if(*p == 0)
+ break;
+ }
+ free(buf);
+}
+
+void print_hex(byte *data, int len, bool newline)
+{
+ for(int i = 0; i < len; i++)
+ printf("%02X ", data[i]);
+ if(newline)
+ printf("\n");
+}
+
+void print_key(struct crypto_key_t *key, bool newline)
+{
+ switch(key->method)
+ {
+ case CRYPTO_KEY:
+ print_hex(key->u.key, 16, false);
+ break;
+ case CRYPTO_USBOTP:
+ printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff);
+ break;
+ case CRYPTO_NONE:
+ printf("none");
+ break;
+ }
+ if(newline)
+ printf("\n");
+}
+
+char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
+
+char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
+char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
+char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
+char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
+char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
+
+static bool g_color_enable = true;
+
+void enable_color(bool enable)
+{
+ g_color_enable = enable;
+}
+
+void color(color_t c)
+{
+ if(g_color_enable)
+ printf("%s", (char *)c);
+}
diff --git a/utils/imxtools/misc.h b/utils/imxtools/misc.h
new file mode 100644
index 0000000000..b0b7dfeba6
--- /dev/null
+++ b/utils/imxtools/misc.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __MISC_H__
+#define __MISC_H__
+
+#include <stdbool.h>
+#include "crypto.h"
+
+#define _STR(a) #a
+#define STR(a) _STR(a)
+
+#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
+#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0)
+
+#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
+
+extern bool g_debug;
+
+typedef struct crypto_key_t *key_array_t;
+int g_nr_keys;
+key_array_t g_key_array;
+
+void *memdup(void *p, size_t len);
+void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
+void generate_random_data(void *buf, size_t sz);
+void *xmalloc(size_t s);
+int convxdigit(char digit, byte *val);
+void print_hex(byte *data, int len, bool newline);
+void add_keys(key_array_t ka, int kac);
+bool parse_key(char **str, struct crypto_key_t *key);
+void add_keys_from_file(const char *key_file);
+void print_key(struct crypto_key_t *key, bool newline);
+void clear_keys();
+
+typedef char color_t[];
+
+extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE;
+void color(color_t c);
+void enable_color(bool enable);
+
+#endif /* __MISC_H__ */
diff --git a/utils/imxtools/sb.c b/utils/imxtools/sb.c
new file mode 100644
index 0000000000..44db56b7d1
--- /dev/null
+++ b/utils/imxtools/sb.c
@@ -0,0 +1,1181 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "misc.h"
+#include "crypto.h"
+#include "sb.h"
+
+static void fill_gaps(struct sb_file_t *sb)
+{
+ for(int i = 0; i < sb->nr_sections; i++)
+ {
+ struct sb_section_t *sec = &sb->sections[i];
+ for(int j = 0; j < sec->nr_insts; j++)
+ {
+ struct sb_inst_t *inst = &sec->insts[j];
+ if(inst->inst != SB_INST_LOAD)
+ continue;
+ inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
+ /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
+ inst->padding = xmalloc(15);
+ generate_random_data(inst->padding, 15);
+ }
+ }
+}
+
+static void compute_sb_offsets(struct sb_file_t *sb)
+{
+ sb->image_size = 0;
+ /* sb header */
+ sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE;
+ /* sections headers */
+ sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE;
+ /* key dictionary */
+ sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE;
+ /* sections */
+ for(int i = 0; i < sb->nr_sections; i++)
+ {
+ /* each section has a preliminary TAG command */
+ sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE;
+ /* we might need to pad the section so compute next alignment */
+ uint32_t alignment = BLOCK_SIZE;
+ if((i + 1) < sb->nr_sections)
+ alignment = sb->sections[i + 1].alignment;
+ alignment /= BLOCK_SIZE; /* alignment in block sizes */
+
+ struct sb_section_t *sec = &sb->sections[i];
+ sec->sec_size = 0;
+
+ if(g_debug)
+ {
+ printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot",
+ sec->identifier);
+ if(sec->is_cleartext)
+ printf(" (cleartext)");
+ printf("\n");
+ }
+
+ sec->file_offset = sb->image_size;
+ for(int j = 0; j < sec->nr_insts; j++)
+ {
+ struct sb_inst_t *inst = &sec->insts[j];
+ if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP)
+ {
+ if(g_debug)
+ printf(" %s | addr=0x%08x | arg=0x%08x\n",
+ inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument);
+ sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
+ sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
+ }
+ else if(inst->inst == SB_INST_FILL)
+ {
+ if(g_debug)
+ printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
+ inst->addr, inst->size, inst->pattern);
+ sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
+ sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
+ }
+ else if(inst->inst == SB_INST_LOAD)
+ {
+ if(g_debug)
+ printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
+ /* load header */
+ sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
+ sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
+ /* data + alignment */
+ sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
+ sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
+ }
+ else if(inst->inst == SB_INST_MODE)
+ {
+ if(g_debug)
+ printf(" MODE | mod=0x%08x", inst->addr);
+ sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
+ sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
+ }
+ else if(inst->inst == SB_INST_DATA)
+ {
+ if(g_debug)
+ printf(" DATA | size=0x%08x\n", inst->size);
+ sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
+ sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
+ }
+ else
+ bug("die on inst %d\n", inst->inst);
+ }
+ /* we need to make sure next section starts on the right alignment.
+ * Since each section starts with a boot tag, we thus need to ensure
+ * that this sections ends at adress X such that X+BLOCK_SIZE is
+ * a multiple of the alignment.
+ * For data sections, we just add random data, otherwise we add nops */
+ uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment);
+ if(missing_sz != alignment)
+ {
+ struct sb_inst_t *aug_insts;
+ int nr_aug_insts = 0;
+
+ if(sb->sections[i].is_data)
+ {
+ nr_aug_insts = 1;
+ aug_insts = xmalloc(sizeof(struct sb_inst_t));
+ memset(aug_insts, 0, sizeof(struct sb_inst_t));
+ aug_insts[0].inst = SB_INST_DATA;
+ aug_insts[0].size = missing_sz * BLOCK_SIZE;
+ aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE);
+ generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE);
+ if(g_debug)
+ printf(" DATA | size=0x%08x\n", aug_insts[0].size);
+ }
+ else
+ {
+ nr_aug_insts = missing_sz;
+ aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
+ memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
+ for(int j = 0; j < nr_aug_insts; j++)
+ {
+ aug_insts[j].inst = SB_INST_NOP;
+ if(g_debug)
+ printf(" NOOP\n");
+ }
+ }
+
+ sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
+ sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
+ sb->sections[i].nr_insts += nr_aug_insts;
+ free(aug_insts);
+
+ /* augment image and section size */
+ sb->image_size += missing_sz;
+ sec->sec_size += missing_sz;
+ }
+ }
+ /* final signature */
+ sb->image_size += 2;
+}
+
+static uint64_t generate_timestamp()
+{
+ struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
+ time_t t = time(NULL) - mktime(&tm_base);
+ return (uint64_t)t * 1000000L;
+}
+
+static uint16_t swap16(uint16_t t)
+{
+ return (t << 8) | (t >> 8);
+}
+
+static void fix_version(struct sb_version_t *ver)
+{
+ ver->major = swap16(ver->major);
+ ver->minor = swap16(ver->minor);
+ ver->revision = swap16(ver->revision);
+}
+
+static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
+{
+ struct sha_1_params_t sha_1_params;
+
+ sb_hdr->signature[0] = 'S';
+ sb_hdr->signature[1] = 'T';
+ sb_hdr->signature[2] = 'M';
+ sb_hdr->signature[3] = 'P';
+ sb_hdr->major_ver = IMAGE_MAJOR_VERSION;
+ sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
+ sb_hdr->flags = 0;
+ sb_hdr->image_size = sb->image_size;
+ sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
+ sb_hdr->first_boot_sec_id = sb->first_boot_sec_id;
+ sb_hdr->nr_keys = g_nr_keys;
+ sb_hdr->nr_sections = sb->nr_sections;
+ sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
+ sb_hdr->key_dict_off = sb_hdr->header_size +
+ sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
+ sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
+ sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE;
+ generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0));
+ generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
+ /* Version 1.0 has 6 bytes of random padding,
+ * Version 1.1 requires the last 4 bytes to be 'sgtl' */
+ if(sb->minor_version >= 1)
+ memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4);
+
+ sb_hdr->timestamp = generate_timestamp();
+ sb_hdr->product_ver = sb->product_ver;
+ fix_version(&sb_hdr->product_ver);
+ sb_hdr->component_ver = sb->component_ver;
+ fix_version(&sb_hdr->component_ver);
+ sb_hdr->drive_tag = sb->drive_tag;
+
+ sha_1_init(&sha_1_params);
+ sha_1_update(&sha_1_params, &sb_hdr->signature[0],
+ sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
+ sha_1_finish(&sha_1_params);
+ sha_1_output(&sha_1_params, sb_hdr->sha1_header);
+}
+
+static void produce_sb_section_header(struct sb_section_t *sec,
+ struct sb_section_header_t *sec_hdr)
+{
+ sec_hdr->identifier = sec->identifier;
+ sec_hdr->offset = sec->file_offset;
+ sec_hdr->size = sec->sec_size;
+ sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
+ | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
+}
+
+static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
+{
+ uint8_t sum = 90;
+ byte *ptr = (byte *)hdr;
+ for(int i = 1; i < 16; i++)
+ sum += ptr[i];
+ return sum;
+}
+
+static void produce_section_tag_cmd(struct sb_section_t *sec,
+ struct sb_instruction_tag_t *tag, bool is_last)
+{
+ tag->hdr.opcode = SB_INST_TAG;
+ tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
+ tag->identifier = sec->identifier;
+ tag->len = sec->sec_size;
+ tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
+ | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
+ tag->hdr.checksum = instruction_checksum(&tag->hdr);
+}
+
+void produce_sb_instruction(struct sb_inst_t *inst,
+ struct sb_instruction_common_t *cmd)
+{
+ memset(cmd, 0, sizeof(struct sb_instruction_common_t));
+ cmd->hdr.opcode = inst->inst;
+ switch(inst->inst)
+ {
+ case SB_INST_CALL:
+ case SB_INST_JUMP:
+ cmd->addr = inst->addr;
+ cmd->data = inst->argument;
+ break;
+ case SB_INST_FILL:
+ cmd->addr = inst->addr;
+ cmd->len = inst->size;
+ cmd->data = inst->pattern;
+ break;
+ case SB_INST_LOAD:
+ cmd->addr = inst->addr;
+ cmd->len = inst->size;
+ cmd->data = crc_continue(crc(inst->data, inst->size),
+ inst->padding, inst->padding_size);
+ break;
+ case SB_INST_MODE:
+ cmd->data = inst->addr;
+ break;
+ case SB_INST_NOP:
+ break;
+ default:
+ bug("die\n");
+ }
+ cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
+}
+
+enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
+{
+ struct crypto_key_t real_key;
+ real_key.method = CRYPTO_KEY;
+ byte crypto_iv[16];
+ byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
+ /* init CBC-MACs */
+ for(int i = 0; i < g_nr_keys; i++)
+ memset(cbc_macs[i], 0, 16);
+
+ fill_gaps(sb);
+ compute_sb_offsets(sb);
+
+ generate_random_data(real_key.u.key, 16);
+
+ /* global SHA-1 */
+ struct sha_1_params_t file_sha1;
+ sha_1_init(&file_sha1);
+ /* produce and write header */
+ struct sb_header_t sb_hdr;
+ produce_sb_header(sb, &sb_hdr);
+ /* allocate image */
+ byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
+ byte *buf_p = buf;
+ #define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
+
+ sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
+ write(&sb_hdr, sizeof(sb_hdr));
+
+ memcpy(crypto_iv, &sb_hdr, 16);
+
+ /* update CBC-MACs */
+ for(int i = 0; i < g_nr_keys; i++)
+ crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
+ cbc_macs[i], &cbc_macs[i], 1);
+
+ /* produce and write section headers */
+ for(int i = 0; i < sb_hdr.nr_sections; i++)
+ {
+ struct sb_section_header_t sb_sec_hdr;
+ produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
+ sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
+ write(&sb_sec_hdr, sizeof(sb_sec_hdr));
+ /* update CBC-MACs */
+ for(int j = 0; j < g_nr_keys; j++)
+ crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
+ &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
+ }
+ /* produce key dictionary */
+ for(int i = 0; i < g_nr_keys; i++)
+ {
+ struct sb_key_dictionary_entry_t entry;
+ memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
+ crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
+ crypto_iv, NULL, 1);
+
+ write(&entry, sizeof(entry));
+ sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
+ }
+
+ free(cbc_macs);
+
+ /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
+ /* Image crafting, don't use it unless you understand what you do */
+ if(sb->override_real_key)
+ memcpy(real_key.u.key, sb->real_key, 16);
+ if(sb->override_crypto_iv)
+ memcpy(crypto_iv, sb->crypto_iv, 16);
+ /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
+ if(g_debug)
+ {
+ printf("Real key: ");
+ for(int j = 0; j < 16; j++)
+ printf("%02x", real_key.u.key[j]);
+ printf("\n");
+ printf("IV : ");
+ for(int j = 0; j < 16; j++)
+ printf("%02x", crypto_iv[j]);
+ printf("\n");
+ }
+ /* produce sections data */
+ for(int i = 0; i< sb_hdr.nr_sections; i++)
+ {
+ /* produce tag command */
+ struct sb_instruction_tag_t tag_cmd;
+ produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
+ if(g_nr_keys > 0)
+ crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
+ &real_key, crypto_iv, NULL, 1);
+ sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
+ write(&tag_cmd, sizeof(tag_cmd));
+ /* produce other commands */
+ byte cur_cbc_mac[16];
+ memcpy(cur_cbc_mac, crypto_iv, 16);
+ for(int j = 0; j < sb->sections[i].nr_insts; j++)
+ {
+ struct sb_inst_t *inst = &sb->sections[i].insts[j];
+ /* command */
+ if(inst->inst != SB_INST_DATA)
+ {
+ struct sb_instruction_common_t cmd;
+ produce_sb_instruction(inst, &cmd);
+ if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
+ crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
+ &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
+ sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
+ write(&cmd, sizeof(cmd));
+ }
+ /* data */
+ if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
+ {
+ uint32_t sz = inst->size + inst->padding_size;
+ byte *data = xmalloc(sz);
+ memcpy(data, inst->data, inst->size);
+ memcpy(data + inst->size, inst->padding, inst->padding_size);
+ if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
+ crypto_cbc(data, data, sz / BLOCK_SIZE,
+ &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
+ sha_1_update(&file_sha1, data, sz);
+ write(data, sz);
+ free(data);
+ }
+ }
+ }
+ /* write file SHA-1 */
+ byte final_sig[32];
+ sha_1_finish(&file_sha1);
+ sha_1_output(&file_sha1, final_sig);
+ generate_random_data(final_sig + 20, 12);
+ if(g_nr_keys > 0)
+ crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
+ write(final_sig, 32);
+
+ if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
+ bug("SB image buffer was not entirely filled !");
+
+ FILE *fd = fopen(filename, "wb");
+ if(fd == NULL)
+ return SB_OPEN_ERROR;
+ if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
+ {
+ free(buf);
+ return SB_WRITE_ERROR;
+ }
+ fclose(fd);
+ free(buf);
+
+ return SB_SUCCESS;
+}
+
+static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
+ int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
+{
+ #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
+ #define fatal(e, ...) \
+ do { if(err) *err = e; \
+ cprintf(u, true, GREY, __VA_ARGS__); \
+ sb_free_section(*sec); \
+ free(sec); \
+ return NULL; } while(0)
+
+ struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
+ memset(sec, 0, sizeof(struct sb_section_t));
+ sec->identifier = id;
+ sec->is_data = data_sec;
+ sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE;
+
+ if(data_sec)
+ {
+ sec->nr_insts = 1;
+ sec->insts = xmalloc(sizeof(struct sb_inst_t));
+ memset(sec->insts, 0, sizeof(struct sb_inst_t));
+ sec->insts->inst = SB_INST_DATA;
+ sec->insts->size = size;
+ sec->insts->data = memdup(buf, size);
+ return sec;
+ }
+
+ /* Pretty print the content */
+ int pos = 0;
+ while(pos < size)
+ {
+ struct sb_inst_t inst;
+ memset(&inst, 0, sizeof(inst));
+
+ struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos];
+ inst.inst = hdr->opcode;
+
+ printf(OFF, "%s", indent);
+ uint8_t checksum = instruction_checksum(hdr);
+ if(checksum != hdr->checksum)
+ fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
+ if(hdr->flags != 0)
+ {
+ printf(GREY, "[");
+ printf(BLUE, "f=%x", hdr->flags);
+ printf(GREY, "] ");
+ }
+ if(hdr->opcode == SB_INST_LOAD)
+ {
+ struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos];
+ inst.size = load->len;
+ inst.addr = load->addr;
+ inst.data = memdup(load + 1, load->len);
+
+ printf(RED, "LOAD");
+ printf(OFF, " | ");
+ printf(BLUE, "addr=0x%08x", load->addr);
+ printf(OFF, " | ");
+ printf(GREEN, "len=0x%08x", load->len);
+ printf(OFF, " | ");
+ printf(YELLOW, "crc=0x%08x", load->crc);
+ /* data is padded to 16-byte boundary with random data and crc'ed with it */
+ uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)],
+ ROUND_UP(load->len, 16));
+ if(load->crc == computed_crc)
+ printf(RED, " Ok\n");
+ else
+ {
+ printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
+ fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
+ }
+
+ pos += load->len + sizeof(struct sb_instruction_load_t);
+ }
+ else if(hdr->opcode == SB_INST_FILL)
+ {
+ struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos];
+ inst.pattern = fill->pattern;
+ inst.size = fill->len;
+ inst.addr = fill->addr;
+
+ printf(RED, "FILL");
+ printf(OFF, " | ");
+ printf(BLUE, "addr=0x%08x", fill->addr);
+ printf(OFF, " | ");
+ printf(GREEN, "len=0x%08x", fill->len);
+ printf(OFF, " | ");
+ printf(YELLOW, "pattern=0x%08x\n", fill->pattern);
+
+ pos += sizeof(struct sb_instruction_fill_t);
+ }
+ else if(hdr->opcode == SB_INST_CALL ||
+ hdr->opcode == SB_INST_JUMP)
+ {
+ int is_call = (hdr->opcode == SB_INST_CALL);
+ struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos];
+ inst.addr = call->addr;
+ inst.argument = call->arg;
+
+ if(is_call)
+ printf(RED, "CALL");
+ else
+ printf(RED, "JUMP");
+ printf(OFF, " | ");
+ printf(BLUE, "addr=0x%08x", call->addr);
+ printf(OFF, " | ");
+ printf(GREEN, "arg=0x%08x\n", call->arg);
+
+ pos += sizeof(struct sb_instruction_call_t);
+ }
+ else if(hdr->opcode == SB_INST_MODE)
+ {
+ struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr;
+ inst.argument = mode->mode;
+
+ printf(RED, "MODE");
+ printf(OFF, " | ");
+ printf(BLUE, "mod=0x%08x\n", mode->mode);
+
+ pos += sizeof(struct sb_instruction_mode_t);
+ }
+ else if(hdr->opcode == SB_INST_NOP)
+ {
+ printf(RED, "NOOP\n");
+ pos += sizeof(struct sb_instruction_mode_t);
+ }
+ else
+ {
+ fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
+ break;
+ }
+
+ sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1);
+ pos = ROUND_UP(pos, BLOCK_SIZE);
+ }
+
+ return sec;
+ #undef printf
+ #undef fatal
+}
+
+void sb_fill_section_name(char name[5], uint32_t identifier)
+{
+ name[0] = (identifier >> 24) & 0xff;
+ name[1] = (identifier >> 16) & 0xff;
+ name[2] = (identifier >> 8) & 0xff;
+ name[3] = identifier & 0xff;
+ for(int i = 0; i < 4; i++)
+ if(!isprint(name[i]))
+ name[i] = '_';
+ name[4] = 0;
+}
+
+static uint32_t guess_alignment(uint32_t off)
+{
+ /* find greatest power of two which divides the offset */
+ if(off == 0)
+ return 1;
+ uint32_t a = 1;
+ while(off % (2 * a) == 0)
+ a *= 2;
+ return a;
+}
+
+struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
+ sb_color_printf cprintf, enum sb_error_t *err)
+{
+ uint8_t *buf = NULL;
+ struct sb_file_t *sb_file = NULL;
+
+ #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
+ #define fatal(e, ...) \
+ do { if(err) *err = e; \
+ cprintf(u, true, GREY, __VA_ARGS__); \
+ free(buf); \
+ sb_free(sb_file); \
+ return NULL; } while(0)
+ #define print_hex(c, p, len, nl) \
+ do { printf(c, ""); print_hex(p, len, nl); } while(0)
+
+ FILE *f = fopen(filename, "rb");
+ if(f == NULL)
+ fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
+ fseek(f, 0, SEEK_END);
+ long filesize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buf = xmalloc(filesize);
+ if(fread(buf, filesize, 1, f) != 1)
+ {
+ fclose(f);
+ fatal(SB_READ_ERROR, "Cannot read file\n");
+ }
+ fclose(f);
+
+ struct sha_1_params_t sha_1_params;
+ sb_file = xmalloc(sizeof(struct sb_file_t));
+ memset(sb_file, 0, sizeof(struct sb_file_t));
+ struct sb_header_t *sb_header = (struct sb_header_t *)buf;
+
+ sb_file->image_size = sb_header->image_size;
+ sb_file->minor_version = sb_header->minor_ver;
+ sb_file->flags = sb_header->flags;
+ sb_file->drive_tag = sb_header->drive_tag;
+ sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
+
+ if(memcmp(sb_header->signature, "STMP", 4) != 0)
+ fatal(SB_FORMAT_ERROR, "Bad signature\n");
+ if(sb_header->image_size * BLOCK_SIZE > filesize)
+ fatal(SB_FORMAT_ERROR, "File too small");
+ if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
+ fatal(SB_FORMAT_ERROR, "Bad header size");
+ if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
+ fatal(SB_FORMAT_ERROR, "Bad section header size");
+
+ if(filesize > sb_header->image_size * BLOCK_SIZE)
+ {
+ printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize,
+ sb_header->image_size * BLOCK_SIZE);
+ filesize = sb_header->image_size * BLOCK_SIZE;
+ }
+
+ printf(BLUE, "Basic info:\n");
+ printf(GREEN, " SB version: ");
+ printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver);
+ printf(GREEN, " Header SHA-1: ");
+ byte *hdr_sha1 = sb_header->sha1_header;
+ print_hex(YELLOW, hdr_sha1, 20, false);
+ /* Check SHA1 sum */
+ byte computed_sha1[20];
+ sha_1_init(&sha_1_params);
+ sha_1_update(&sha_1_params, &sb_header->signature[0],
+ sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
+ sha_1_finish(&sha_1_params);
+ sha_1_output(&sha_1_params, computed_sha1);
+ if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
+ printf(RED, " Ok\n");
+ else
+ printf(RED, " Failed\n");
+ printf(GREEN, " Flags: ");
+ printf(YELLOW, "%x\n", sb_header->flags);
+ printf(GREEN, " Total file size : ");
+ printf(YELLOW, "%ld\n", filesize);
+
+ /* Sizes and offsets */
+ printf(BLUE, "Sizes and offsets:\n");
+ printf(GREEN, " # of encryption keys = ");
+ printf(YELLOW, "%d\n", sb_header->nr_keys);
+ printf(GREEN, " # of sections = ");
+ printf(YELLOW, "%d\n", sb_header->nr_sections);
+
+ /* Versions */
+ printf(BLUE, "Versions\n");
+
+ printf(GREEN, " Random 1: ");
+ print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
+ printf(GREEN, " Random 2: ");
+ print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
+
+ uint64_t micros = sb_header->timestamp;
+ time_t seconds = (micros / (uint64_t)1000000L);
+ struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
+ seconds += mktime(&tm_base);
+ struct tm *time = gmtime(&seconds);
+ printf(GREEN, " Creation date/time = ");
+ printf(YELLOW, "%s", asctime(time));
+
+ struct sb_version_t product_ver = sb_header->product_ver;
+ fix_version(&product_ver);
+ struct sb_version_t component_ver = sb_header->component_ver;
+ fix_version(&component_ver);
+
+ memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver));
+ memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver));
+
+ printf(GREEN, " Product version = ");
+ printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
+ printf(GREEN, " Component version = ");
+ printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
+
+ printf(GREEN, " Drive tag = ");
+ printf(YELLOW, "%x\n", sb_header->drive_tag);
+ printf(GREEN, " First boot tag offset = ");
+ printf(YELLOW, "%x\n", sb_header->first_boot_tag_off);
+ printf(GREEN, " First boot section ID = ");
+ printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id);
+
+ /* encryption cbc-mac */
+ byte real_key[16];
+ bool valid_key = false; /* false until a matching key was found */
+
+ if(sb_header->nr_keys > 0)
+ {
+ byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
+ printf(BLUE, "Encryption keys\n");
+ for(int i = 0; i < g_nr_keys; i++)
+ {
+ printf(RED, " Key %d: ", i);
+ printf(YELLOW, "");
+ print_key(&g_key_array[i], true);
+ printf(GREEN, " CBC-MAC: ");
+ /* check it */
+ byte zero[16];
+ memset(zero, 0, 16);
+ int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
+ &g_key_array[i], zero, &cbcmacs[i], 1);
+ if(ret != CRYPTO_ERROR_SUCCESS)
+ {
+ free(cbcmacs);
+ fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
+ }
+ print_hex(YELLOW, cbcmacs[i], 16, true);
+ }
+
+ printf(BLUE, "DEK\n");
+ for(int i = 0; i < sb_header->nr_keys; i++)
+ {
+ printf(RED, " Entry %d\n", i);
+ uint32_t ofs = sizeof(struct sb_header_t)
+ + sizeof(struct sb_section_header_t) * sb_header->nr_sections
+ + sizeof(struct sb_key_dictionary_entry_t) * i;
+ struct sb_key_dictionary_entry_t *dict_entry =
+ (struct sb_key_dictionary_entry_t *)&buf[ofs];
+ /* cbc mac */
+ printf(GREEN, " Encrypted key: ");
+ print_hex(YELLOW, dict_entry->key, 16, true);
+ printf(GREEN, " CBC-MAC : ");
+ print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
+ /* check it */
+ int idx = 0;
+ while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
+ idx++;
+ if(idx != g_nr_keys)
+ {
+ printf(RED, " Match\n");
+ /* decrypt */
+ byte decrypted_key[16];
+ byte iv[16];
+ memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
+ int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
+ if(ret != CRYPTO_ERROR_SUCCESS)
+ {
+ free(cbcmacs);
+ fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
+ }
+ printf(GREEN, " Decrypted key: ");
+ print_hex(YELLOW, decrypted_key, 16, false);
+ if(valid_key)
+ {
+ if(memcmp(real_key, decrypted_key, 16) == 0)
+ printf(RED, " Cross-Check Ok");
+ else
+ printf(RED, " Cross-Check Failed");
+ }
+ else
+ {
+ memcpy(real_key, decrypted_key, 16);
+ valid_key = true;
+ }
+ printf(OFF, "\n");
+ }
+ else
+ printf(RED, " Don't Match\n");
+ }
+
+ free(cbcmacs);
+
+ if(!valid_key)
+ fatal(SB_NO_VALID_KEY, "No valid key found\n");
+
+ if(getenv("SB_REAL_KEY") != 0)
+ {
+ struct crypto_key_t k;
+ char *env = getenv("SB_REAL_KEY");
+ if(!parse_key(&env, &k) || *env)
+ bug("Invalid SB_REAL_KEY\n");
+ memcpy(real_key, k.u.key, 16);
+ }
+
+ printf(RED, " Summary:\n");
+ printf(GREEN, " Real key: ");
+ print_hex(YELLOW, real_key, 16, true);
+ printf(GREEN, " IV : ");
+ print_hex(YELLOW, buf, 16, true);
+
+ sb_file->override_real_key = true;
+ memcpy(sb_file->real_key, real_key, 16);
+ sb_file->override_crypto_iv = true;
+ memcpy(sb_file->crypto_iv, buf, 16);
+ }
+
+ /* sections */
+ if(!raw_mode)
+ {
+ sb_file->nr_sections = sb_header->nr_sections;
+ sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t));
+ memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t));
+ printf(BLUE, "Sections\n");
+ for(int i = 0; i < sb_header->nr_sections; i++)
+ {
+ uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
+ struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs];
+
+ char name[5];
+ sb_fill_section_name(name, sec_hdr->identifier);
+ int pos = sec_hdr->offset * BLOCK_SIZE;
+ int size = sec_hdr->size * BLOCK_SIZE;
+ int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
+ int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
+
+ printf(GREEN, " Section ");
+ printf(YELLOW, "'%s'\n", name);
+ printf(GREEN, " pos = ");
+ printf(YELLOW, "%8x - %8x\n", pos, pos+size);
+ printf(GREEN, " len = ");
+ printf(YELLOW, "%8x\n", size);
+ printf(GREEN, " flags = ");
+ printf(YELLOW, "%8x", sec_hdr->flags);
+ if(data_sec)
+ printf(RED, " Data Section");
+ else
+ printf(RED, " Boot Section");
+ if(encrypted)
+ printf(RED, " (Encrypted)");
+ printf(OFF, "\n");
+
+ /* save it */
+ byte *sec = xmalloc(size);
+ if(encrypted)
+ cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
+ else
+ memcpy(sec, buf + pos, size);
+
+ struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
+ sec, size, " ", u, cprintf, err);
+ if(s)
+ {
+ s->is_cleartext = !encrypted;
+ s->alignment = guess_alignment(pos);
+ memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
+ free(s);
+ }
+ else
+ fatal(*err, "Error reading section\n");
+
+ free(sec);
+ }
+ }
+ else
+ {
+ /* advanced raw mode */
+ printf(BLUE, "Commands\n");
+ uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
+ byte iv[16];
+ const char *indent = " ";
+ while(true)
+ {
+ /* restart with IV */
+ memcpy(iv, buf, 16);
+ byte cmd[BLOCK_SIZE];
+ if(sb_header->nr_keys > 0)
+ cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0);
+ else
+ memcpy(cmd, buf + offset, BLOCK_SIZE);
+ struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
+ printf(OFF, "%s", indent);
+ uint8_t checksum = instruction_checksum(hdr);
+ if(checksum != hdr->checksum)
+ printf(GREY, "[Bad checksum']");
+
+ if(hdr->opcode == SB_INST_NOP)
+ {
+ printf(RED, "NOOP\n");
+ offset += BLOCK_SIZE;
+ }
+ else if(hdr->opcode == SB_INST_TAG)
+ {
+ struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
+ printf(RED, "BTAG");
+ printf(OFF, " | ");
+ printf(BLUE, "sec=0x%08x", tag->identifier);
+ printf(OFF, " | ");
+ printf(GREEN, "cnt=0x%08x", tag->len);
+ printf(OFF, " | ");
+ printf(YELLOW, "flg=0x%08x", tag->flags);
+ if(tag->hdr.flags & SB_INST_LAST_TAG)
+ {
+ printf(OFF, " | ");
+ printf(RED, " Last section");
+ }
+ printf(OFF, "\n");
+ offset += sizeof(struct sb_instruction_tag_t);
+
+ char name[5];
+ sb_fill_section_name(name, tag->identifier);
+ int pos = offset;
+ int size = tag->len * BLOCK_SIZE;
+ int data_sec = !(tag->flags & SECTION_BOOTABLE);
+ int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
+
+ printf(GREEN, "%sSection ", indent);
+ printf(YELLOW, "'%s'\n", name);
+ printf(GREEN, "%s pos = ", indent);
+ printf(YELLOW, "%8x - %8x\n", pos, pos+size);
+ printf(GREEN, "%s len = ", indent);
+ printf(YELLOW, "%8x\n", size);
+ printf(GREEN, "%s flags = ", indent);
+ printf(YELLOW, "%8x", tag->flags);
+ if(data_sec)
+ printf(RED, " Data Section");
+ else
+ printf(RED, " Boot Section");
+ if(encrypted)
+ printf(RED, " (Encrypted)");
+ printf(OFF, "\n");
+
+ /* save it */
+ byte *sec = xmalloc(size);
+ if(encrypted)
+ cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
+ else
+ memcpy(sec, buf + pos, size);
+
+ struct sb_section_t *s = read_section(data_sec, tag->identifier,
+ sec, size, " ", u, cprintf, err);
+ if(s)
+ {
+ s->is_cleartext = !encrypted;
+ s->alignment = guess_alignment(pos);
+ sb_file->sections = augment_array(sb_file->sections,
+ sizeof(struct sb_section_t), sb_file->nr_sections++,
+ s, 1);
+ free(s);
+ }
+ else
+ fatal(*err, "Error reading section\n");
+ free(sec);
+
+ /* last one ? */
+ if(tag->hdr.flags & SB_INST_LAST_TAG)
+ break;
+ offset += size;
+ }
+ else
+ {
+ fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
+ break;
+ }
+ }
+ }
+
+ /* final signature */
+ printf(BLUE, "Final signature:\n");
+ byte decrypted_block[32];
+ if(sb_header->nr_keys > 0)
+ {
+ printf(GREEN, " Encrypted SHA-1:\n");
+ byte *encrypted_block = &buf[filesize - 32];
+ printf(OFF, " ");
+ print_hex(YELLOW, encrypted_block, 16, true);
+ printf(OFF, " ");
+ print_hex(YELLOW, encrypted_block + 16, 16, true);
+ /* decrypt it */
+ cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0);
+ }
+ else
+ memcpy(decrypted_block, &buf[filesize - 32], 32);
+ printf(GREEN, " File SHA-1:\n ");
+ print_hex(YELLOW, decrypted_block, 20, false);
+ /* check it */
+ sha_1_init(&sha_1_params);
+ sha_1_update(&sha_1_params, buf, filesize - 32);
+ sha_1_finish(&sha_1_params);
+ sha_1_output(&sha_1_params, computed_sha1);
+ if(memcmp(decrypted_block, computed_sha1, 20) == 0)
+ printf(RED, " Ok\n");
+ else
+ {
+ printf(RED, " Failed\n");
+ fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
+ }
+ free(buf);
+
+ return sb_file;
+ #undef printf
+ #undef fatal
+ #undef print_hex
+}
+
+void sb_free_section(struct sb_section_t sec)
+{
+ for(int j = 0; j < sec.nr_insts; j++)
+ {
+ free(sec.insts[j].padding);
+ free(sec.insts[j].data);
+ }
+ free(sec.insts);
+}
+
+void sb_free(struct sb_file_t *file)
+{
+ if(!file) return;
+
+ for(int i = 0; i < file->nr_sections; i++)
+ sb_free_section(file->sections[i]);
+
+ free(file->sections);
+ free(file);
+}
+
+void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
+{
+ #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
+ #define print_hex(c, p, len, nl) \
+ do { printf(c, ""); print_hex(p, len, nl); } while(0)
+
+ #define TREE RED
+ #define HEADER GREEN
+ #define TEXT YELLOW
+ #define TEXT2 BLUE
+ #define SEP OFF
+
+ printf(HEADER, "SB File\n");
+ printf(TREE, "+-");
+ printf(HEADER, "Version: ");
+ printf(TEXT, "1.%d\n", file->minor_version);
+ printf(TREE, "+-");
+ printf(HEADER, "Flags: ");
+ printf(TEXT, "%x\n", file->flags);
+ printf(TREE, "+-");
+ printf(HEADER, "Drive Tag: ");
+ printf(TEXT, "%x\n", file->drive_tag);
+ printf(TREE, "+-");
+ printf(HEADER, "First Boot Section ID: ");
+ char name[5];
+ sb_fill_section_name(name, file->first_boot_sec_id);
+ printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
+
+ if(file->override_real_key)
+ {
+ printf(TREE, "+-");
+ printf(HEADER, "Real key: ");
+ print_hex(TEXT, file->real_key, 16, true);
+ }
+ if(file->override_crypto_iv)
+ {
+ printf(TREE, "+-");
+ printf(HEADER, "IV : ");
+ print_hex(TEXT, file->crypto_iv, 16, true);
+ }
+ printf(TREE, "+-");
+ printf(HEADER, "Product Version: ");
+ printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor,
+ file->product_ver.revision);
+ printf(TREE, "+-");
+ printf(HEADER, "Component Version: ");
+ printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor,
+ file->component_ver.revision);
+
+ for(int i = 0; i < file->nr_sections; i++)
+ {
+ struct sb_section_t *sec = &file->sections[i];
+ printf(TREE, "+-");
+ printf(HEADER, "Section\n");
+ printf(TREE,"| +-");
+ printf(HEADER, "Identifier: ");
+ sb_fill_section_name(name, sec->identifier);
+ printf(TEXT, "%08x (%s)\n", sec->identifier, name);
+ printf(TREE, "| +-");
+ printf(HEADER, "Type: ");
+ printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section",
+ sec->is_cleartext ? "Cleartext" : "Encrypted");
+ printf(TREE, "| +-");
+ printf(HEADER, "Alignment: ");
+ printf(TEXT, "%d (bytes)\n", sec->alignment);
+ printf(TREE, "| +-");
+ printf(HEADER, "Instructions\n");
+ for(int j = 0; j < sec->nr_insts; j++)
+ {
+ struct sb_inst_t *inst = &sec->insts[j];
+ printf(TREE, "| | +-");
+ switch(inst->inst)
+ {
+ case SB_INST_DATA:
+ printf(HEADER, "DATA");
+ printf(SEP, " | ");
+ printf(TEXT, "size=0x%08x\n", inst->size);
+ break;
+ case SB_INST_CALL:
+ case SB_INST_JUMP:
+ printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP");
+ printf(SEP, " | ");
+ printf(TEXT, "addr=0x%08x", inst->addr);
+ printf(SEP, " | ");
+ printf(TEXT2, "arg=0x%08x\n", inst->argument);
+ break;
+ case SB_INST_LOAD:
+ printf(HEADER, "LOAD");
+ printf(SEP, " | ");
+ printf(TEXT, "addr=0x%08x", inst->addr);
+ printf(SEP, " | ");
+ printf(TEXT2, "len=0x%08x\n", inst->size);
+ break;
+ case SB_INST_FILL:
+ printf(HEADER, "FILL");
+ printf(SEP, " | ");
+ printf(TEXT, "addr=0x%08x", inst->addr);
+ printf(SEP, " | ");
+ printf(TEXT2, "len=0x%08x", inst->size);
+ printf(SEP, " | ");
+ printf(TEXT2, "pattern=0x%08x\n", inst->pattern);
+ break;
+ case SB_INST_MODE:
+ printf(HEADER, "MODE");
+ printf(SEP, " | ");
+ printf(TEXT, "mod=0x%08x\n", inst->addr);
+ break;
+ case SB_INST_NOP:
+ printf(HEADER, "NOOP\n");
+ break;
+ default:
+ printf(GREY, "[Unknown instruction %x]\n", inst->inst);
+ }
+ }
+ }
+
+ #undef printf
+ #undef print_hex
+}
diff --git a/utils/imxtools/sb.h b/utils/imxtools/sb.h
new file mode 100644
index 0000000000..ced6481a80
--- /dev/null
+++ b/utils/imxtools/sb.h
@@ -0,0 +1,237 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2011 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __SB_H__
+#define __SB_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "misc.h"
+
+#define BLOCK_SIZE 16
+
+/* All fields are in big-endian BCD */
+struct sb_version_t
+{
+ uint16_t major;
+ uint16_t pad0;
+ uint16_t minor;
+ uint16_t pad1;
+ uint16_t revision;
+ uint16_t pad2;
+};
+
+struct sb_header_t
+{
+ uint8_t sha1_header[20]; /* SHA-1 of the rest of the header */
+ uint8_t signature[4]; /* Signature "STMP" */
+ uint8_t major_ver; /* Should be 1 */
+ uint8_t minor_ver; /* Should be 1 */
+ uint16_t flags;
+ uint32_t image_size; /* In blocks (=16bytes) */
+ uint32_t first_boot_tag_off; /* Offset in blocks */
+ uint32_t first_boot_sec_id; /* First bootable section ID */
+ uint16_t nr_keys; /* Number of encryption keys */
+ uint16_t key_dict_off; /* Offset to key dictionary (in blocks) */
+ uint16_t header_size; /* In blocks */
+ uint16_t nr_sections; /* Number of sections */
+ uint16_t sec_hdr_size; /* Section header size (in blocks) */
+ uint8_t rand_pad0[6]; /* Random padding */
+ uint64_t timestamp; /* In microseconds since 2000/1/1 00:00:00 */
+ struct sb_version_t product_ver;
+ struct sb_version_t component_ver;
+ uint16_t drive_tag; /* first tag to boot ? */
+ uint8_t rand_pad1[6]; /* Random padding */
+} __attribute__((packed));
+
+struct sb_section_header_t
+{
+ uint32_t identifier;
+ uint32_t offset; /* In blocks */
+ uint32_t size; /* In blocks */
+ uint32_t flags;
+} __attribute__((packed));
+
+struct sb_key_dictionary_entry_t
+{
+ uint8_t hdr_cbc_mac[16]; /* CBC-MAC of the header */
+ uint8_t key[16]; /* Actual AES Key (encrypted by the global key) */
+} __attribute__((packed));
+
+#define IMAGE_MAJOR_VERSION 1
+#define IMAGE_MINOR_VERSION 1
+
+#define SECTION_BOOTABLE (1 << 0)
+#define SECTION_CLEARTEXT (1 << 1)
+
+#define SB_INST_NOP 0x0
+#define SB_INST_TAG 0x1
+#define SB_INST_LOAD 0x2
+#define SB_INST_FILL 0x3
+#define SB_INST_JUMP 0x4
+#define SB_INST_CALL 0x5
+#define SB_INST_MODE 0x6
+
+/* flags */
+#define SB_INST_LAST_TAG 1 /* for TAG */
+#define SB_INST_LOAD_DCD 1 /* for LOAD */
+#define SB_INST_FILL_BYTE 0 /* for FILL */
+#define SB_INST_FILL_HWORD 1 /* for FILL */
+#define SB_INST_FILL_WORD 2 /* for FILL */
+#define SB_INST_HAB_EXEC 1 /* for JUMP/CALL */
+
+struct sb_instruction_header_t
+{
+ uint8_t checksum;
+ uint8_t opcode;
+ uint16_t flags;
+} __attribute__((packed));
+
+struct sb_instruction_common_t
+{
+ struct sb_instruction_header_t hdr;
+ uint32_t addr;
+ uint32_t len;
+ uint32_t data;
+} __attribute__((packed));
+
+struct sb_instruction_load_t
+{
+ struct sb_instruction_header_t hdr;
+ uint32_t addr;
+ uint32_t len;
+ uint32_t crc;
+} __attribute__((packed));
+
+struct sb_instruction_fill_t
+{
+ struct sb_instruction_header_t hdr;
+ uint32_t addr;
+ uint32_t len;
+ uint32_t pattern;
+} __attribute__((packed));
+
+struct sb_instruction_mode_t
+{
+ struct sb_instruction_header_t hdr;
+ uint32_t zero1;
+ uint32_t zero2;
+ uint32_t mode;
+} __attribute__((packed));
+
+struct sb_instruction_call_t
+{
+ struct sb_instruction_header_t hdr;
+ uint32_t addr;
+ uint32_t zero;
+ uint32_t arg;
+} __attribute__((packed));
+
+struct sb_instruction_tag_t
+{
+ struct sb_instruction_header_t hdr;
+ uint32_t identifier; /* section identifier */
+ uint32_t len; /* length of the section */
+ uint32_t flags; /* section flags */
+} __attribute__((packed));
+
+/*******
+ * API *
+ *******/
+
+#define SB_INST_DATA 0xff
+
+struct sb_inst_t
+{
+ uint8_t inst; /* SB_INST_* */
+ uint32_t size;
+ uint32_t addr;
+ // <union>
+ void *data;
+ uint32_t pattern;
+ // </union>
+ uint32_t argument; // for call, jump and mode
+ /* for production use */
+ uint32_t padding_size;
+ uint8_t *padding;
+};
+
+struct sb_section_t
+{
+ uint32_t identifier;
+ bool is_data;
+ bool is_cleartext;
+ uint32_t alignment;
+ // data sections are handled as one or more SB_INST_DATA virtual instruction
+ int nr_insts;
+ struct sb_inst_t *insts;
+ /* for production use */
+ uint32_t file_offset; /* in blocks */
+ uint32_t sec_size; /* in blocks */
+};
+
+struct sb_file_t
+{
+ /* override real, otherwise it is randomly generated */
+ bool override_real_key;
+ uint8_t real_key[16];
+ /* override crypto IV, use with caution ! Use NULL to generate it */
+ bool override_crypto_iv;
+ uint8_t crypto_iv[16];
+
+ int nr_sections;
+ uint16_t drive_tag;
+ uint32_t first_boot_sec_id;
+ uint16_t flags;
+ uint8_t minor_version;
+ struct sb_section_t *sections;
+ struct sb_version_t product_ver;
+ struct sb_version_t component_ver;
+ /* for production use */
+ uint32_t image_size; /* in blocks */
+};
+
+enum sb_error_t
+{
+ SB_SUCCESS = 0,
+ SB_ERROR = -1,
+ SB_OPEN_ERROR = -2,
+ SB_READ_ERROR = -3,
+ SB_WRITE_ERROR = -4,
+ SB_FORMAT_ERROR = -5,
+ SB_CHECKSUM_ERROR = -6,
+ SB_NO_VALID_KEY = -7,
+ SB_FIRST_CRYPTO_ERROR = -8,
+ SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
+};
+
+enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename);
+
+typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
+struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
+ sb_color_printf printf, enum sb_error_t *err);
+
+void sb_fill_section_name(char name[5], uint32_t identifier);
+void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf);
+void sb_free_section(struct sb_section_t file);
+void sb_free(struct sb_file_t *file);
+
+#endif /* __SB_H__ */
diff --git a/utils/imxtools/sbloader.c b/utils/imxtools/sbloader.c
new file mode 100644
index 0000000000..ba4645f8ab
--- /dev/null
+++ b/utils/imxtools/sbloader.c
@@ -0,0 +1,174 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+#include <stdint.h>
+
+void put32le(uint8_t *buf, uint32_t i)
+{
+ *buf++ = i & 0xff;
+ *buf++ = (i >> 8) & 0xff;
+ *buf++ = (i >> 16) & 0xff;
+ *buf++ = (i >> 24) & 0xff;
+}
+
+void put32be(uint8_t *buf, uint32_t i)
+{
+ *buf++ = (i >> 24) & 0xff;
+ *buf++ = (i >> 16) & 0xff;
+ *buf++ = (i >> 8) & 0xff;
+ *buf++ = i & 0xff;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ uint8_t msg[0x20];
+ uint8_t *p;
+ FILE *f;
+ int i, xfer_size, nr_xfers, recv_size;
+
+ if(argc != 3)
+ {
+ printf("usage: %s <xfer size> <file>\n", argv[0]);
+ return 1;
+ }
+
+ char *end;
+ xfer_size = strtol(argv[1], &end, 0);
+ if(end != (argv[1] + strlen(argv[1])))
+ {
+ printf("Invalid transfer size !\n");
+ return 1;
+ }
+
+ libusb_device_handle *dev;
+
+ libusb_init(NULL);
+
+ libusb_set_debug(NULL, 3);
+
+ /* MX23 */
+ dev = libusb_open_device_with_vid_pid(NULL, 0x066F, 0x3780);
+ if(dev == NULL)
+ /* MX28 */
+ dev = libusb_open_device_with_vid_pid(NULL, 0x15A2, 0x004F);
+ if(dev == NULL)
+ {
+ printf("Cannot open device\n");
+ return 1;
+ }
+
+ libusb_detach_kernel_driver(dev, 0);
+ libusb_detach_kernel_driver(dev, 4);
+
+ libusb_claim_interface (dev, 0);
+ libusb_claim_interface (dev, 4);
+
+ if (!dev)
+ {
+ printf("No dev\n");
+ exit(1);
+ }
+
+ f = fopen(argv[2], "r");
+ if(f == NULL)
+ {
+ perror("cannot open file");
+ return 1;
+ }
+ fseek(f, 0, SEEK_END);
+ size_t size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ printf("Transfer size: %d\n", xfer_size);
+ nr_xfers = (size + xfer_size - 1) / xfer_size;
+ uint8_t *file_buf = malloc(nr_xfers * xfer_size);
+ memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff
+ if(fread(file_buf, size, 1, f) != 1)
+ {
+ perror("read error");
+ fclose(f);
+ return 1;
+ }
+ fclose(f);
+
+ memset(msg, 0, 0x20);
+
+ p = msg;
+
+ *p++ = 0x01; // Init upload command
+ *p++ = 'B'; // Signature
+ *p++ = 'L';
+ *p++ = 'T';
+ *p++ = 'C';
+ put32le(p, 0x1); // I guess version or sub-command
+ p += 4;
+ put32le(p, size); // Payload size
+
+ // The second command starts at 0x20
+
+ p = &msg[0x10];
+
+ *p++ = 0x02; // Start upload
+ put32be(p, size); // Payload size, again
+
+ ret = libusb_control_transfer(dev,
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0,
+ msg, 0x20, 1000);
+ if(ret < 0)
+ {
+ printf("transfer error at init step\n");
+ return 1;
+ }
+
+ uint8_t *xfer_buf = malloc(1 + xfer_size);
+
+ for(i = 0; i < nr_xfers; i++)
+ {
+ xfer_buf[0] = 0x2;
+ memcpy(&xfer_buf[1], &file_buf[i * xfer_size], xfer_size);
+
+ ret = libusb_control_transfer(dev,
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ 0x9, 0x202, 0, xfer_buf, xfer_size + 1, 1000);
+ if(ret < 0)
+ {
+ printf("transfer error at send step %d\n", i);
+ return 1;
+ }
+ }
+
+ ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, &recv_size,
+ 1000);
+ if(ret < 0)
+ {
+ printf("transfer error at final stage\n");
+ return 1;
+ }
+
+ printf("ret %i\n", ret);
+
+ return 0;
+}
+
diff --git a/utils/imxtools/sbtoelf.c b/utils/imxtools/sbtoelf.c
new file mode 100644
index 0000000000..fda70b1180
--- /dev/null
+++ b/utils/imxtools/sbtoelf.c
@@ -0,0 +1,302 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+ * .sb file parser and chunk extractor
+ *
+ * Based on amsinfo, which is
+ * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com>
+ */
+
+#define _ISOC99_SOURCE /* snprintf() */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <getopt.h>
+
+#include "crypto.h"
+#include "elf.h"
+#include "sb.h"
+#include "misc.h"
+
+/* all blocks are sized as a multiple of 0x1ff */
+#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
+
+/* If you find a firmware that breaks the known format ^^ */
+#define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
+
+#define crypto_cbc(...) \
+ do { int ret = crypto_cbc(__VA_ARGS__); \
+ if(ret != CRYPTO_ERROR_SUCCESS) \
+ bug("crypto_cbc error: %d\n", ret); \
+ }while(0)
+
+/* globals */
+
+char *g_out_prefix;
+
+static void elf_printf(void *user, bool error, const char *fmt, ...)
+{
+ if(!g_debug && !error)
+ return;
+ (void) user;
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+static void elf_write(void *user, uint32_t addr, const void *buf, size_t count)
+{
+ FILE *f = user;
+ fseek(f, addr, SEEK_SET);
+ fwrite(buf, count, 1, f);
+}
+
+static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id)
+{
+ char name[5];
+ char *filename = xmalloc(strlen(g_out_prefix) + 32);
+ sb_fill_section_name(name, id);
+ sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count);
+ if(g_debug)
+ printf("Write boot section %s to %s\n", name, filename);
+
+ FILE *fd = fopen(filename, "wb");
+ free(filename);
+
+ if(fd == NULL)
+ return ;
+ elf_write_file(elf, elf_write, elf_printf, fd);
+ fclose(fd);
+}
+
+static void extract_sb_section(struct sb_section_t *sec)
+{
+ if(sec->is_data)
+ {
+ char sec_name[5];
+ char *filename = xmalloc(strlen(g_out_prefix) + 32);
+ sb_fill_section_name(sec_name, sec->identifier);
+ sprintf(filename, "%s%s.bin", g_out_prefix, sec_name);
+ FILE *fd = fopen(filename, "wb");
+ if(fd == NULL)
+ bugp("Cannot open %s for writing\n", filename);
+ if(g_debug)
+ printf("Write data section %s to %s\n", sec_name, filename);
+ free(filename);
+
+ for(int j = 0; j < sec->nr_insts; j++)
+ {
+ assert(sec->insts[j].inst == SB_INST_DATA);
+ fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd);
+ }
+ fclose(fd);
+ }
+
+ int elf_count = 0;
+ struct elf_params_t elf;
+ elf_init(&elf);
+
+ for(int i = 0; i < sec->nr_insts; i++)
+ {
+ struct sb_inst_t *inst = &sec->insts[i];
+ switch(inst->inst)
+ {
+ case SB_INST_LOAD:
+ elf_add_load_section(&elf, inst->addr, inst->size, inst->data);
+ break;
+ case SB_INST_FILL:
+ elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern);
+ break;
+ case SB_INST_CALL:
+ case SB_INST_JUMP:
+ elf_set_start_addr(&elf, inst->addr);
+ extract_elf_section(&elf, elf_count++, sec->identifier);
+ elf_release(&elf);
+ elf_init(&elf);
+ break;
+ default:
+ /* ignore mode and nop */
+ break;
+ }
+ }
+
+ if(!elf_is_empty(&elf))
+ extract_elf_section(&elf, elf_count, sec->identifier);
+ elf_release(&elf);
+}
+
+static void extract_sb_file(struct sb_file_t *file)
+{
+ for(int i = 0; i < file->nr_sections; i++)
+ extract_sb_section(&file->sections[i]);
+}
+
+static void usage(void)
+{
+ printf("Usage: sbtoelf [options] sb-file\n");
+ printf("Options:\n");
+ printf(" -?/--help\tDisplay this message\n");
+ printf(" -o <prefix>\tEnable output and set prefix\n");
+ printf(" -d/--debug\tEnable debug output*\n");
+ printf(" -k <file>\tAdd key file\n");
+ printf(" -z\t\tAdd zero key\n");
+ printf(" -r\t\tUse raw command mode\n");
+ printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n");
+ printf(" -n/--no-color\tDisable output colors\n");
+ printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n");
+ printf("Options marked with a * are for debug purpose only\n");
+ exit(1);
+}
+
+static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...)
+{
+ (void) user;
+ (void) error;
+ va_list args;
+ va_start(args, fmt);
+ color(c);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+static struct crypto_key_t g_zero_key =
+{
+ .method = CRYPTO_KEY,
+ .u.key = {0}
+};
+
+int main(int argc, char **argv)
+{
+ bool raw_mode = false;
+ const char *loopback = NULL;
+
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"debug", no_argument, 0, 'd'},
+ {"add-key", required_argument, 0, 'a'},
+ {"no-color", no_argument, 0, 'n'},
+ {"loopback", required_argument, 0, 'l'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case -1:
+ break;
+ case 'l':
+ if(loopback)
+ bug("Only one loopback file can be specified !\n");
+ loopback = optarg;
+ break;
+ case 'n':
+ enable_color(false);
+ break;
+ case 'd':
+ g_debug = true;
+ break;
+ case '?':
+ usage();
+ break;
+ case 'o':
+ g_out_prefix = optarg;
+ break;
+ case 'k':
+ {
+ add_keys_from_file(optarg);
+ break;
+ }
+ case 'z':
+ {
+ add_keys(&g_zero_key, 1);
+ break;
+ }
+ case 'r':
+ raw_mode = true;
+ break;
+ case 'a':
+ {
+ struct crypto_key_t key;
+ char *s = optarg;
+ if(!parse_key(&s, &key))
+ bug("Invalid key specified as argument");
+ if(*s != 0)
+ bug("Trailing characters after key specified as argument");
+ add_keys(&key, 1);
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+
+ if(argc - optind != 1)
+ {
+ usage();
+ return 1;
+ }
+
+ const char *sb_filename = argv[optind];
+
+ enum sb_error_t err;
+ struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
+ if(file == NULL)
+ {
+ color(OFF);
+ printf("SB read failed: %d\n", err);
+ return 1;
+ }
+
+ color(OFF);
+ if(g_out_prefix)
+ extract_sb_file(file);
+ if(g_debug)
+ {
+ color(GREY);
+ printf("[Debug output]\n");
+ sb_dump(file, NULL, sb_printf);
+ }
+ if(loopback)
+ {
+ /* sb_read_file will fill real key and IV but we don't want to override
+ * them when looping back otherwise the output will be inconsistent and
+ * garbage */
+ file->override_real_key = false;
+ file->override_crypto_iv = false;
+ sb_write_file(file, loopback);
+ }
+ sb_free(file);
+ clear_keys();
+
+ return 0;
+}
diff --git a/utils/imxtools/sha1.c b/utils/imxtools/sha1.c
new file mode 100644
index 0000000000..0ad05bb5cd
--- /dev/null
+++ b/utils/imxtools/sha1.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+/* Based on http://en.wikipedia.org/wiki/SHA-1 */
+#include "crypto.h"
+
+static uint32_t rot_left(uint32_t val, int rot)
+{
+ return (val << rot) | (val >> (32 - rot));
+}
+
+static inline void byte_swapxx(byte *ptr, int size)
+{
+ for(int i = 0; i < size / 2; i++)
+ {
+ byte c = ptr[i];
+ ptr[i] = ptr[size - i - 1];
+ ptr[size - i - 1] = c;
+ }
+}
+
+static void byte_swap32(uint32_t *v)
+{
+ byte_swapxx((byte *)v, 4);
+}
+
+void sha_1_init(struct sha_1_params_t *params)
+{
+ params->hash[0] = 0x67452301;
+ params->hash[1] = 0xEFCDAB89;
+ params->hash[2] = 0x98BADCFE;
+ params->hash[3] = 0x10325476;
+ params->hash[4] = 0xC3D2E1F0;
+ params->buffer_nr_bits = 0;
+}
+
+void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size)
+{
+ int buffer_nr_bytes = (params->buffer_nr_bits / 8) % 64;
+ params->buffer_nr_bits += 8 * size;
+ int pos = 0;
+ if(buffer_nr_bytes + size >= 64)
+ {
+ pos = 64 - buffer_nr_bytes;
+ memcpy((byte *)(params->w) + buffer_nr_bytes, buffer, 64 - buffer_nr_bytes);
+ sha_1_block(params, params->hash, (byte *)params->w);
+ for(; pos + 64 <= size; pos += 64)
+ sha_1_block(params, params->hash, buffer + pos);
+ buffer_nr_bytes = 0;
+ }
+ memcpy((byte *)(params->w) + buffer_nr_bytes, buffer + pos, size - pos);
+}
+
+void sha_1_finish(struct sha_1_params_t *params)
+{
+ /* length (in bits) in big endian BEFORE preprocessing */
+ byte length_big_endian[8];
+ memcpy(length_big_endian, &params->buffer_nr_bits, 8);
+ byte_swapxx(length_big_endian, 8);
+ /* append '1' and then '0's to the message to get 448 bit length for the last block */
+ byte b = 0x80;
+ sha_1_update(params, &b, 1);
+ b = 0;
+ while((params->buffer_nr_bits % 512) != 448)
+ sha_1_update(params, &b, 1);
+ /* append length */
+ sha_1_update(params, length_big_endian, 8);
+ /* go back to big endian */
+ for(int i = 0; i < 5; i++)
+ byte_swap32(&params->hash[i]);
+}
+
+void sha_1_output(struct sha_1_params_t *params, byte *out)
+{
+ memcpy(out, params->hash, 20);
+}
+
+void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data)
+{
+ uint32_t a, b, c, d, e;
+ a = cur_hash[0];
+ b = cur_hash[1];
+ c = cur_hash[2];
+ d = cur_hash[3];
+ e = cur_hash[4];
+
+ #define w params->w
+
+ memmove(w, data, 64);
+ for(int i = 0; i < 16; i++)
+ byte_swap32(&w[i]);
+
+ for(int i = 16; i <= 79; i++)
+ w[i] = rot_left(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
+
+ for(int i = 0; i<= 79; i++)
+ {
+ uint32_t f, k;
+ if(i <= 19)
+ {
+ f = (b & c) | ((~b) & d);
+ k = 0x5A827999;
+ }
+ else if(i <= 39)
+ {
+ f = b ^ c ^ d;
+ k = 0x6ED9EBA1;
+ }
+ else if(i <= 59)
+ {
+ f = (b & c) | (b & d) | (c & d);
+ k = 0x8F1BBCDC;
+ }
+ else
+ {
+ f = b ^ c ^ d;
+ k = 0xCA62C1D6;
+ }
+ uint32_t temp = rot_left(a, 5) + f + e + k + w[i];
+ e = d;
+ d = c;
+ c = rot_left(b, 30);
+ b = a;
+ a = temp;
+ }
+ #undef w
+
+ cur_hash[0] += a;
+ cur_hash[1] += b;
+ cur_hash[2] += c;
+ cur_hash[3] += d;
+ cur_hash[4] += e;
+}