diff options
Diffstat (limited to 'utils/imxtools')
-rw-r--r-- | utils/imxtools/Makefile | 26 | ||||
-rw-r--r-- | utils/imxtools/README | 32 | ||||
-rw-r--r-- | utils/imxtools/aes128.c | 284 | ||||
-rw-r--r-- | utils/imxtools/crc.c | 83 | ||||
-rw-r--r-- | utils/imxtools/crypto.c | 188 | ||||
-rw-r--r-- | utils/imxtools/crypto.h | 115 | ||||
-rw-r--r-- | utils/imxtools/dbparser.c | 849 | ||||
-rw-r--r-- | utils/imxtools/dbparser.h | 118 | ||||
-rw-r--r-- | utils/imxtools/elf.c | 575 | ||||
-rw-r--r-- | utils/imxtools/elf.h | 94 | ||||
-rw-r--r-- | utils/imxtools/elftosb.c | 461 | ||||
-rw-r--r-- | utils/imxtools/fuze+_key_file.txt | 1 | ||||
-rw-r--r-- | utils/imxtools/misc.c | 248 | ||||
-rw-r--r-- | utils/imxtools/misc.h | 59 | ||||
-rw-r--r-- | utils/imxtools/sb.c | 1181 | ||||
-rw-r--r-- | utils/imxtools/sb.h | 237 | ||||
-rw-r--r-- | utils/imxtools/sbloader.c | 174 | ||||
-rw-r--r-- | utils/imxtools/sbtoelf.c | 302 | ||||
-rw-r--r-- | utils/imxtools/sha1.c | 150 |
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 @@ | |||
1 | DEFINES=-DCRYPTO_LIBUSB | ||
2 | CC=gcc | ||
3 | LD=gcc | ||
4 | CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES) | ||
5 | LDFLAGS=`pkg-config --libs libusb-1.0` | ||
6 | BINS=elftosb sbtoelf sbloader | ||
7 | |||
8 | all: $(BINS) | ||
9 | |||
10 | %.o: %.c | ||
11 | $(CC) $(CFLAGS) -c -o $@ $< | ||
12 | |||
13 | sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o | ||
14 | $(LD) -o $@ $^ $(LDFLAGS) | ||
15 | |||
16 | elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o | ||
17 | $(LD) -o $@ $^ $(LDFLAGS) | ||
18 | |||
19 | sbloader: sbloader.o | ||
20 | $(LD) -o $@ $^ $(LDFLAGS) | ||
21 | |||
22 | clean: | ||
23 | rm -fr *.o | ||
24 | |||
25 | veryclean: | ||
26 | 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 @@ | |||
1 | This file document the format of the command file used by the elftosb tool. | ||
2 | By no way our tools tries to be compatible with Freescale's elftosb2. | ||
3 | However, our format is more subset of the general one. | ||
4 | |||
5 | The parse supports a limited form of comments: comments starting with // and ending at the end of the line. | ||
6 | |||
7 | A file first contains the list of sources: | ||
8 | |||
9 | sources | ||
10 | { | ||
11 | hw_init = "sdram_init.elf"; | ||
12 | rockbox = "rockbox.elf"; | ||
13 | } | ||
14 | |||
15 | It can then contain an arbitrary number of section. A section is identified by a number. | ||
16 | Within a section, three commands are supported: "load", "jump" and "call": | ||
17 | |||
18 | section(0x626f6f74) // hex for 'boot' | ||
19 | { | ||
20 | load hw_init; | ||
21 | call hw_init; | ||
22 | load rockbox; | ||
23 | jump rockbox; | ||
24 | } | ||
25 | |||
26 | Finally, both elftosb and sbtoelf tools use key files. A key file is a list of keys. | ||
27 | Each key consist is 128-bit long and is written in hexadecimal: | ||
28 | |||
29 | 00000000000000000000000000000000 | ||
30 | |||
31 | The parser does not handle blank line and only allows a final newline at the end of the file. | ||
32 | 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 @@ | |||
1 | // Simple, thoroughly commented implementation of 128-bit AES / Rijndael using C | ||
2 | // Chris Hulbert - chris.hulbert@gmail.com - http://splinter.com.au/blog | ||
3 | // References: | ||
4 | // http://en.wikipedia.org/wiki/Advanced_Encryption_Standard | ||
5 | // http://en.wikipedia.org/wiki/Rijndael_key_schedule | ||
6 | // http://en.wikipeia.org/wiki/Rijndael_mix_columns | ||
7 | // http://en.wikipedia.org/wiki/Rijndael_S-box | ||
8 | // This code is public domain, or any OSI-approved license, your choice. No warranty. | ||
9 | #include "crypto.h" | ||
10 | |||
11 | // Here are all the lookup tables for the row shifts, rcon, s-boxes, and galois field multiplications | ||
12 | byte shift_rows_table[] = {0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11}; | ||
13 | byte shift_rows_table_inv[] = {0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3}; | ||
14 | byte lookup_rcon[]={0x8d,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a}; | ||
15 | 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}; | ||
16 | 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}; | ||
17 | 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}; | ||
18 | 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}; | ||
19 | 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}; | ||
20 | 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}; | ||
21 | 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}; | ||
22 | 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}; | ||
23 | |||
24 | // Xor's all elements in a n byte array a by b | ||
25 | void xor_(byte *a, byte *b, int n) { | ||
26 | int i; | ||
27 | for (i=0;i<n;i++) | ||
28 | a[i] ^= b[i]; | ||
29 | } | ||
30 | |||
31 | // Xor the current cipher state by a specific round key | ||
32 | static void xor_round_key(byte *state, byte *keys, int round) { | ||
33 | xor_(state,keys+round*16,16); | ||
34 | } | ||
35 | |||
36 | // Apply and reverse the rijndael s-box to all elements in an array | ||
37 | // http://en.wikipedia.org/wiki/Rijndael_S-box | ||
38 | static void sub_bytes(byte *a,int n) { | ||
39 | int i; | ||
40 | for (i=0;i<n;i++) | ||
41 | a[i] = lookup_sbox[a[i]]; | ||
42 | } | ||
43 | static void sub_bytes_inv(byte *a,int n) { | ||
44 | int i; | ||
45 | for (i=0;i<n;i++) | ||
46 | a[i] = lookup_sbox_inv[a[i]]; | ||
47 | } | ||
48 | |||
49 | // Perform the core key schedule transform on 4 bytes, as part of the key expansion process | ||
50 | // http://en.wikipedia.org/wiki/Rijndael_key_schedule#Key_schedule_core | ||
51 | static void key_schedule_core(byte *a, int i) { | ||
52 | byte temp = a[0]; // Rotate the output eight bits to the left | ||
53 | a[0]=a[1]; | ||
54 | a[1]=a[2]; | ||
55 | a[2]=a[3]; | ||
56 | a[3]=temp; | ||
57 | sub_bytes(a,4); // Apply Rijndael's S-box on all four individual bytes in the output word | ||
58 | a[0]^=lookup_rcon[i]; // On just the first (leftmost) byte of the output word, perform the rcon operation with i | ||
59 | // as the input, and exclusive or the rcon output with the first byte of the output word | ||
60 | } | ||
61 | |||
62 | // Expand the 16-byte key to 11 round keys (176 bytes) | ||
63 | // http://en.wikipedia.org/wiki/Rijndael_key_schedule#The_key_schedule | ||
64 | static void expand_key(byte *key, byte *keys) { | ||
65 | int bytes=16; // The count of how many bytes we've created so far | ||
66 | int i=1; // The rcon iteration value i is set to 1 | ||
67 | int j; // For repeating the second stage 3 times | ||
68 | byte t[4]; // Temporary working area known as 't' in the Wiki article | ||
69 | memcpy(keys,key,16); // The first 16 bytes of the expanded key are simply the encryption key | ||
70 | |||
71 | while (bytes<176) { // Until we have 176 bytes of expanded key, we do the following: | ||
72 | memcpy(t,keys+bytes-4,4); // We assign the value of the previous four bytes in the expanded key to t | ||
73 | key_schedule_core(t, i); // We perform the key schedule core on t, with i as the rcon iteration value | ||
74 | i++; // We increment i by 1 | ||
75 | xor_(t,keys+bytes-16,4); // We exclusive-or t with the four-byte block 16 bytes before the new expanded key. | ||
76 | memcpy(keys+bytes,t,4); // This becomes the next 4 bytes in the expanded key | ||
77 | bytes+=4; // Keep track of how many expanded key bytes we've added | ||
78 | |||
79 | // We then do the following three times to create the next twelve bytes | ||
80 | for (j=0;j<3;j++) { | ||
81 | memcpy(t,keys+bytes-4,4); // We assign the value of the previous 4 bytes in the expanded key to t | ||
82 | xor_(t,keys+bytes-16,4); // We exclusive-or t with the four-byte block n bytes before | ||
83 | memcpy(keys+bytes,t,4); // This becomes the next 4 bytes in the expanded key | ||
84 | bytes+=4; // Keep track of how many expanded key bytes we've added | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // Apply / reverse the shift rows step on the 16 byte cipher state | ||
90 | // http://en.wikipedia.org/wiki/Advanced_Encryption_Standard#The_ShiftRows_step | ||
91 | static void shift_rows(byte *state) { | ||
92 | int i; | ||
93 | byte temp[16]; | ||
94 | memcpy(temp,state,16); | ||
95 | for (i=0;i<16;i++) | ||
96 | state[i]=temp[shift_rows_table[i]]; | ||
97 | } | ||
98 | static void shift_rows_inv(byte *state) { | ||
99 | int i; | ||
100 | byte temp[16]; | ||
101 | memcpy(temp,state,16); | ||
102 | for (i=0;i<16;i++) | ||
103 | state[i]=temp[shift_rows_table_inv[i]]; | ||
104 | } | ||
105 | |||
106 | // Perform the mix columns matrix on one column of 4 bytes | ||
107 | // http://en.wikipedia.org/wiki/Rijndael_mix_columns | ||
108 | static void mix_col (byte *state) { | ||
109 | byte a0 = state[0]; | ||
110 | byte a1 = state[1]; | ||
111 | byte a2 = state[2]; | ||
112 | byte a3 = state[3]; | ||
113 | state[0] = lookup_g2[a0] ^ lookup_g3[a1] ^ a2 ^ a3; | ||
114 | state[1] = lookup_g2[a1] ^ lookup_g3[a2] ^ a3 ^ a0; | ||
115 | state[2] = lookup_g2[a2] ^ lookup_g3[a3] ^ a0 ^ a1; | ||
116 | state[3] = lookup_g2[a3] ^ lookup_g3[a0] ^ a1 ^ a2; | ||
117 | } | ||
118 | |||
119 | // Perform the mix columns matrix on each column of the 16 bytes | ||
120 | static void mix_cols (byte *state) { | ||
121 | mix_col(state); | ||
122 | mix_col(state+4); | ||
123 | mix_col(state+8); | ||
124 | mix_col(state+12); | ||
125 | } | ||
126 | |||
127 | // Perform the inverse mix columns matrix on one column of 4 bytes | ||
128 | // http://en.wikipedia.org/wiki/Rijndael_mix_columns | ||
129 | static void mix_col_inv (byte *state) { | ||
130 | byte a0 = state[0]; | ||
131 | byte a1 = state[1]; | ||
132 | byte a2 = state[2]; | ||
133 | byte a3 = state[3]; | ||
134 | state[0] = lookup_g14[a0] ^ lookup_g9[a3] ^ lookup_g13[a2] ^ lookup_g11[a1]; | ||
135 | state[1] = lookup_g14[a1] ^ lookup_g9[a0] ^ lookup_g13[a3] ^ lookup_g11[a2]; | ||
136 | state[2] = lookup_g14[a2] ^ lookup_g9[a1] ^ lookup_g13[a0] ^ lookup_g11[a3]; | ||
137 | state[3] = lookup_g14[a3] ^ lookup_g9[a2] ^ lookup_g13[a1] ^ lookup_g11[a0]; | ||
138 | } | ||
139 | |||
140 | // Perform the inverse mix columns matrix on each column of the 16 bytes | ||
141 | static void mix_cols_inv (byte *state) { | ||
142 | mix_col_inv(state); | ||
143 | mix_col_inv(state+4); | ||
144 | mix_col_inv(state+8); | ||
145 | mix_col_inv(state+12); | ||
146 | } | ||
147 | |||
148 | // Encrypt a single 128 bit block by a 128 bit key using AES | ||
149 | // http://en.wikipedia.org/wiki/Advanced_Encryption_Standard | ||
150 | void EncryptAES(byte *msg, byte *key, byte *c) { | ||
151 | int i; // To count the rounds | ||
152 | |||
153 | // Key expansion | ||
154 | byte keys[176]; | ||
155 | expand_key(key,keys); | ||
156 | |||
157 | // First Round | ||
158 | memmove(c, msg, 16); | ||
159 | xor_round_key(c,keys,0); | ||
160 | |||
161 | // Middle rounds | ||
162 | for(i=0; i<9; i++) { | ||
163 | sub_bytes(c,16); | ||
164 | shift_rows(c); | ||
165 | mix_cols(c); | ||
166 | xor_round_key(c, keys, i+1); | ||
167 | } | ||
168 | |||
169 | // Final Round | ||
170 | sub_bytes(c,16); | ||
171 | shift_rows(c); | ||
172 | xor_round_key(c, keys, 10); | ||
173 | } | ||
174 | |||
175 | // Decrypt a single 128 bit block by a 128 bit key using AES | ||
176 | // http://en.wikipedia.org/wiki/Advanced_Encryption_Standard | ||
177 | void DecryptAES(byte *c, byte *key, byte *m) { | ||
178 | int i; // To count the rounds | ||
179 | |||
180 | // Key expansion | ||
181 | byte keys[176]; | ||
182 | expand_key(key,keys); | ||
183 | |||
184 | // Reverse the final Round | ||
185 | memcpy(m,c,16); | ||
186 | xor_round_key(m,keys,10); | ||
187 | shift_rows_inv(m); | ||
188 | sub_bytes_inv(m, 16); | ||
189 | |||
190 | // Reverse the middle rounds | ||
191 | for (i=0; i<9; i++) { | ||
192 | xor_round_key(m,keys,9-i); | ||
193 | mix_cols_inv(m); | ||
194 | shift_rows_inv(m); | ||
195 | sub_bytes_inv(m, 16); | ||
196 | } | ||
197 | |||
198 | // Reverse the first Round | ||
199 | xor_round_key(m, keys, 0); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | // Pretty-print a key (or any smallish buffer) onto screen as hex | ||
204 | void Pretty(byte* b,int len,const char* label) | ||
205 | { | ||
206 | char out[100]; | ||
207 | int i; | ||
208 | for (i=0;i<len;i++) | ||
209 | sprintf(out+i*2,"%02x",b[i]); | ||
210 | |||
211 | printf("%s%s",label, out); | ||
212 | } | ||
213 | */ | ||
214 | |||
215 | /* | ||
216 | // Test AES | ||
217 | int main(void) | ||
218 | { | ||
219 | byte key[] = {0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12}; | ||
220 | byte msg[] = {0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab}; | ||
221 | byte encrypted[16], decrypted[16]; | ||
222 | |||
223 | printf("Test AES\r\n\n"); | ||
224 | Pretty(key,16,"Key: "); | ||
225 | Pretty(msg,16,"Original: "); | ||
226 | |||
227 | EncryptAES(msg,key,encrypted); | ||
228 | printf("Encrypted should be: 85E5A3D7356A61E29A8AFA559AD67102\r\n"); | ||
229 | Pretty(encrypted,16,"Encrypted: "); | ||
230 | |||
231 | DecryptAES(encrypted,key,decrypted); | ||
232 | Pretty(decrypted,16,"Decrypted: "); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | */ | ||
237 | |||
238 | void cbc_mac( | ||
239 | byte *in_data, /* Input data */ | ||
240 | byte *out_data, /* Output data (or NULL) */ | ||
241 | int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */ | ||
242 | byte key[16], /* Key */ | ||
243 | byte iv[16], /* Initialisation Vector */ | ||
244 | byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ | ||
245 | int encrypt /* 1 to encrypt, 0 to decrypt */ | ||
246 | ) | ||
247 | { | ||
248 | byte feedback[16]; | ||
249 | memcpy(feedback, iv, 16); | ||
250 | |||
251 | if(encrypt) | ||
252 | { | ||
253 | /* for each block */ | ||
254 | for(int i = 0; i < nr_blocks; i++) | ||
255 | { | ||
256 | /* xor it with feedback */ | ||
257 | xor_(feedback, &in_data[i * 16], 16); | ||
258 | /* encrypt it using aes */ | ||
259 | EncryptAES(feedback, key, feedback); | ||
260 | /* write cipher to output */ | ||
261 | if(out_data) | ||
262 | memcpy(&out_data[i * 16], feedback, 16); | ||
263 | } | ||
264 | if(out_cbc_mac) | ||
265 | memcpy(out_cbc_mac, feedback, 16); | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | /* nothing to do ? */ | ||
270 | if(out_data == NULL) | ||
271 | return; | ||
272 | |||
273 | /* for each block */ | ||
274 | for(int i = 0; i < nr_blocks; i++) | ||
275 | { | ||
276 | /* decrypt it using aes */ | ||
277 | DecryptAES(&in_data[i * 16], key, &out_data[i * 16]); | ||
278 | /* xor it with iv */ | ||
279 | xor_(&out_data[i * 16], feedback, 16); | ||
280 | /* copy cipher to iv */ | ||
281 | memcpy(feedback, &in_data[i * 16], 16); | ||
282 | } | ||
283 | } | ||
284 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "crypto.h" | ||
22 | |||
23 | /* Table extracted from firmware, don't know if this is regular CRC32 */ | ||
24 | |||
25 | static uint32_t crc_table[256] = { | ||
26 | 0x0, 0x4C11DB7, 0x9823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, | ||
27 | 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, | ||
28 | 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, | ||
29 | 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, | ||
30 | 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, | ||
31 | 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, | ||
32 | 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0x0BE2B5B58, 0x0BAEA46EF, 0x0B7A96036, | ||
33 | 0x0B3687D81, 0x0AD2F2D84, 0x0A9EE3033, 0x0A4AD16EA, 0x0A06C0B5D, 0x0D4326D90, | ||
34 | 0x0D0F37027, 0x0DDB056FE, 0x0D9714B49, 0x0C7361B4C, 0x0C3F706FB, 0x0CEB42022, | ||
35 | 0x0CA753D95, 0x0F23A8028, 0x0F6FB9D9F, 0x0FBB8BB46, 0x0FF79A6F1, 0x0E13EF6F4, | ||
36 | 0x0E5FFEB43, 0x0E8BCCD9A, 0x0EC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19, | ||
37 | 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF, | ||
38 | 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x18AEB13, 0x54BF6A4, 0x808D07D, | ||
39 | 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, | ||
40 | 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, | ||
41 | 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0x0ACA5C697, | ||
42 | 0x0A864DB20, 0x0A527FDF9, 0x0A1E6E04E, 0x0BFA1B04B, 0x0BB60ADFC, 0x0B6238B25, | ||
43 | 0x0B2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, | ||
44 | 0x9D684044, 0x902B669D, 0x94EA7B2A, 0x0E0B41DE7, 0x0E4750050, 0x0E9362689, | ||
45 | 0x0EDF73B3E, 0x0F3B06B3B, 0x0F771768C, 0x0FA325055, 0x0FEF34DE2, 0x0C6BCF05F, | ||
46 | 0x0C27DEDE8, 0x0CF3ECB31, 0x0CBFFD686, 0x0D5B88683, 0x0D1799B34, 0x0DC3ABDED, | ||
47 | 0x0D8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, | ||
48 | 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, | ||
49 | 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, | ||
50 | 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, | ||
51 | 0x3B5A6B9B, 0x315D626, 0x7D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, | ||
52 | 0x14D0BD4D, 0x19939B94, 0x1D528623, 0x0F12F560E, 0x0F5EE4BB9, 0x0F8AD6D60, | ||
53 | 0x0FC6C70D7, 0x0E22B20D2, 0x0E6EA3D65, 0x0EBA91BBC, 0x0EF68060B, 0x0D727BBB6, | ||
54 | 0x0D3E6A601, 0x0DEA580D8, 0x0DA649D6F, 0x0C423CD6A, 0x0C0E2D0DD, 0x0CDA1F604, | ||
55 | 0x0C960EBB3, 0x0BD3E8D7E, 0x0B9FF90C9, 0x0B4BCB610, 0x0B07DABA7, 0x0AE3AFBA2, | ||
56 | 0x0AAFBE615, 0x0A7B8C0CC, 0x0A379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, | ||
57 | 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099, | ||
58 | 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, | ||
59 | 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, | ||
60 | 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087, | ||
61 | 0x1CD86D30, 0x29F3D35, 0x65E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651, | ||
62 | 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, | ||
63 | 0x29D4F654, 0x0C5A92679, 0x0C1683BCE, 0x0CC2B1D17, 0x0C8EA00A0, 0x0D6AD50A5, | ||
64 | 0x0D26C4D12, 0x0DF2F6BCB, 0x0DBEE767C, 0x0E3A1CBC1, 0x0E760D676, 0x0EA23F0AF, | ||
65 | 0x0EEE2ED18, 0x0F0A5BD1D, 0x0F464A0AA, 0x0F9278673, 0x0FDE69BC4, 0x89B8FD09, | ||
66 | 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, | ||
67 | 0x97FFAD0C, 0x0AFB010B1, 0x0AB710D06, 0x0A6322BDF, 0x0A2F33668, 0x0BCB4666D, | ||
68 | 0x0B8757BDA, 0x0B5365D03, 0x0B1F740B4 | ||
69 | }; | ||
70 | |||
71 | uint32_t crc(byte *data, int size) | ||
72 | { | ||
73 | return crc_continue(0xffffffff, data, size); | ||
74 | } | ||
75 | |||
76 | uint32_t crc_continue(uint32_t previous_crc, byte *data, int size) | ||
77 | { | ||
78 | uint32_t c = previous_crc; | ||
79 | /* normal CRC */ | ||
80 | for(int i = 0; i < size; i++) | ||
81 | c = crc_table[data[i] ^ (c >> 24)] ^ (c << 8); | ||
82 | return c; | ||
83 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "crypto.h" | ||
22 | #include <stdio.h> | ||
23 | #include <stdbool.h> | ||
24 | #ifdef CRYPTO_LIBUSB | ||
25 | #include "libusb.h" | ||
26 | #endif | ||
27 | #include "misc.h" | ||
28 | |||
29 | static enum crypto_method_t cur_method = CRYPTO_NONE; | ||
30 | static byte key[16]; | ||
31 | static uint16_t usb_vid, usb_pid; | ||
32 | |||
33 | void crypto_setup(enum crypto_method_t method, void *param) | ||
34 | { | ||
35 | cur_method = method; | ||
36 | switch(method) | ||
37 | { | ||
38 | case CRYPTO_KEY: | ||
39 | memcpy(key, param, sizeof(key)); | ||
40 | break; | ||
41 | case CRYPTO_USBOTP: | ||
42 | { | ||
43 | uint32_t value = *(uint32_t *)param; | ||
44 | usb_vid = value >> 16; | ||
45 | usb_pid = value & 0xffff; | ||
46 | break; | ||
47 | } | ||
48 | default: | ||
49 | break; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | int crypto_apply( | ||
54 | byte *in_data, /* Input data */ | ||
55 | byte *out_data, /* Output data (or NULL) */ | ||
56 | int nr_blocks, /* Number of blocks (one block=16 bytes) */ | ||
57 | byte iv[16], /* Key */ | ||
58 | byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ | ||
59 | int encrypt) | ||
60 | { | ||
61 | if(cur_method == CRYPTO_KEY) | ||
62 | { | ||
63 | cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt); | ||
64 | return CRYPTO_ERROR_SUCCESS; | ||
65 | } | ||
66 | #ifdef CRYPTO_LIBUSB | ||
67 | else if(cur_method == CRYPTO_USBOTP) | ||
68 | { | ||
69 | if(out_cbc_mac && !encrypt) | ||
70 | memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16); | ||
71 | |||
72 | libusb_device_handle *handle = NULL; | ||
73 | libusb_context *ctx; | ||
74 | /* init library */ | ||
75 | libusb_init(&ctx); | ||
76 | libusb_set_debug(NULL,3); | ||
77 | /* open device */ | ||
78 | handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid); | ||
79 | if(handle == NULL) | ||
80 | { | ||
81 | printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid); | ||
82 | return CRYPTO_ERROR_NODEVICE; | ||
83 | } | ||
84 | /* get device pointer */ | ||
85 | libusb_device *mydev = libusb_get_device(handle); | ||
86 | if(g_debug) | ||
87 | printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev), | ||
88 | libusb_get_device_address(mydev)); | ||
89 | int config_id; | ||
90 | /* explore configuration */ | ||
91 | libusb_get_configuration(handle, &config_id); | ||
92 | struct libusb_config_descriptor *config; | ||
93 | libusb_get_active_config_descriptor(mydev, &config); | ||
94 | |||
95 | if(g_debug) | ||
96 | { | ||
97 | printf("usbotp: configuration: %d\n", config_id); | ||
98 | printf("usbotp: interfaces: %d\n", config->bNumInterfaces); | ||
99 | } | ||
100 | |||
101 | const struct libusb_endpoint_descriptor *endp = NULL; | ||
102 | int intf, intf_alt; | ||
103 | for(intf = 0; intf < config->bNumInterfaces; intf++) | ||
104 | for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++) | ||
105 | for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++) | ||
106 | { | ||
107 | endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep]; | ||
108 | if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT && | ||
109 | (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) | ||
110 | goto Lfound; | ||
111 | } | ||
112 | libusb_close(handle); | ||
113 | printf("usbotp: No suitable endpoint found\n"); | ||
114 | return CRYPTO_ERROR_BADENDP; | ||
115 | |||
116 | if(g_debug) | ||
117 | { | ||
118 | printf("usbotp: use interface %d, alt %d\n", intf, intf_alt); | ||
119 | printf("usbotp: use endpoint %d\n", endp->bEndpointAddress); | ||
120 | } | ||
121 | Lfound: | ||
122 | if(libusb_claim_interface(handle, intf) != 0) | ||
123 | { | ||
124 | if(g_debug) | ||
125 | printf("usbotp: claim error\n"); | ||
126 | return CRYPTO_ERROR_CLAIMFAIL; | ||
127 | } | ||
128 | |||
129 | int buffer_size = 16 + 16 * nr_blocks; | ||
130 | unsigned char *buffer = xmalloc(buffer_size); | ||
131 | memcpy(buffer, iv, 16); | ||
132 | memcpy(buffer + 16, in_data, 16 * nr_blocks); | ||
133 | int ret = libusb_control_transfer(handle, | ||
134 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, | ||
135 | 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000); | ||
136 | if(ret < 0) | ||
137 | { | ||
138 | if(g_debug) | ||
139 | printf("usbotp: control transfer failed: %d\n", ret); | ||
140 | libusb_release_interface(handle, intf); | ||
141 | libusb_close(handle); | ||
142 | return CRYPTO_ERROR_DEVREJECT; | ||
143 | } | ||
144 | |||
145 | int recv_size; | ||
146 | ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer, | ||
147 | buffer_size, &recv_size, 1000); | ||
148 | libusb_release_interface(handle, intf); | ||
149 | libusb_close(handle); | ||
150 | |||
151 | if(ret < 0) | ||
152 | { | ||
153 | if(g_debug) | ||
154 | printf("usbotp: interrupt transfer failed: %d\n", ret); | ||
155 | return CRYPTO_ERROR_DEVSILENT; | ||
156 | } | ||
157 | if(recv_size != buffer_size) | ||
158 | { | ||
159 | if(g_debug) | ||
160 | printf("usbotp: device returned %d bytes, expected %d\n", recv_size, | ||
161 | buffer_size); | ||
162 | return CRYPTO_ERROR_DEVERR; | ||
163 | } | ||
164 | |||
165 | if(out_data) | ||
166 | memcpy(out_data, buffer + 16, 16 * nr_blocks); | ||
167 | if(out_cbc_mac && encrypt) | ||
168 | memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16); | ||
169 | |||
170 | return CRYPTO_ERROR_SUCCESS; | ||
171 | } | ||
172 | #endif | ||
173 | else | ||
174 | return CRYPTO_ERROR_BADSETUP; | ||
175 | } | ||
176 | |||
177 | int crypto_cbc( | ||
178 | byte *in_data, /* Input data */ | ||
179 | byte *out_data, /* Output data (or NULL) */ | ||
180 | int nr_blocks, /* Number of blocks (one block=16 bytes) */ | ||
181 | struct crypto_key_t *key, /* Key */ | ||
182 | byte iv[16], /* IV */ | ||
183 | byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ | ||
184 | int encrypt) | ||
185 | { | ||
186 | crypto_setup(key->method, (void *)key->u.param); | ||
187 | return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt); | ||
188 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __CRYPTO_H__ | ||
22 | #define __CRYPTO_H__ | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <stdint.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | typedef uint8_t byte; | ||
29 | |||
30 | /* aes128.c */ | ||
31 | void xor_(byte *a, byte *b, int n); | ||
32 | void EncryptAES(byte *msg, byte *key, byte *c); | ||
33 | void DecryptAES(byte *c, byte *key, byte *m); | ||
34 | void Pretty(byte* b,int len,const char* label); | ||
35 | void cbc_mac( | ||
36 | byte *in_data, /* Input data */ | ||
37 | byte *out_data, /* Output data (or NULL) */ | ||
38 | int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */ | ||
39 | byte key[16], /* Key */ | ||
40 | byte iv[16], /* Initialisation Vector */ | ||
41 | byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ | ||
42 | int encrypt /* 1 to encrypt, 0 to decrypt */ | ||
43 | ); | ||
44 | |||
45 | /* crypto.c */ | ||
46 | enum crypto_method_t | ||
47 | { | ||
48 | CRYPTO_NONE, /* disable */ | ||
49 | CRYPTO_KEY, /* key */ | ||
50 | CRYPTO_USBOTP, /* use usbotp device */ | ||
51 | }; | ||
52 | |||
53 | /* parameter can be: | ||
54 | * - CRYPTO_KEY: array of 16-bytes (the key) | ||
55 | * - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */ | ||
56 | void crypto_setup(enum crypto_method_t method, void *param); | ||
57 | |||
58 | #define CRYPTO_ERROR_SUCCESS 0 | ||
59 | #define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */ | ||
60 | #define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */ | ||
61 | #define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */ | ||
62 | #define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */ | ||
63 | #define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */ | ||
64 | #define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */ | ||
65 | #define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */ | ||
66 | #define CRYPTO_NUM_ERRORS 8 | ||
67 | /* return 0 on success, <0 on error */ | ||
68 | int crypto_apply( | ||
69 | byte *in_data, /* Input data */ | ||
70 | byte *out_data, /* Output data (or NULL) */ | ||
71 | int nr_blocks, /* Number of blocks (one block=16 bytes) */ | ||
72 | byte iv[16], /* IV */ | ||
73 | byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ | ||
74 | int encrypt); | ||
75 | |||
76 | /* all-in-one function */ | ||
77 | struct crypto_key_t | ||
78 | { | ||
79 | enum crypto_method_t method; | ||
80 | union | ||
81 | { | ||
82 | byte key[16]; | ||
83 | uint32_t vid_pid; | ||
84 | byte param[0]; | ||
85 | }u; | ||
86 | }; | ||
87 | |||
88 | int crypto_cbc( | ||
89 | byte *in_data, /* Input data */ | ||
90 | byte *out_data, /* Output data (or NULL) */ | ||
91 | int nr_blocks, /* Number of blocks (one block=16 bytes) */ | ||
92 | struct crypto_key_t *key, /* Key */ | ||
93 | byte iv[16], /* IV */ | ||
94 | byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ | ||
95 | int encrypt); | ||
96 | |||
97 | /* crc.c */ | ||
98 | uint32_t crc(byte *data, int size); | ||
99 | uint32_t crc_continue(uint32_t previous_crc, byte *data, int size); | ||
100 | |||
101 | /* sha1.c */ | ||
102 | struct sha_1_params_t | ||
103 | { | ||
104 | uint32_t hash[5]; | ||
105 | uint64_t buffer_nr_bits; | ||
106 | uint32_t w[80]; | ||
107 | }; | ||
108 | |||
109 | void sha_1_init(struct sha_1_params_t *params); | ||
110 | void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data); | ||
111 | void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size); | ||
112 | void sha_1_finish(struct sha_1_params_t *params); | ||
113 | void sha_1_output(struct sha_1_params_t *params, byte *out); | ||
114 | |||
115 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #define _POSIX_C_SOURCE 200809L /* for strdup */ | ||
23 | #include <stdio.h> | ||
24 | #include <ctype.h> | ||
25 | #include <stdint.h> | ||
26 | #include <string.h> | ||
27 | #include "dbparser.h" | ||
28 | #include "misc.h" | ||
29 | |||
30 | enum lexem_type_t | ||
31 | { | ||
32 | LEX_IDENTIFIER, | ||
33 | LEX_LPAREN, | ||
34 | LEX_RPAREN, | ||
35 | LEX_NUMBER, | ||
36 | LEX_STRING, /* double-quoted string */ | ||
37 | LEX_EQUAL, | ||
38 | LEX_SEMICOLON, | ||
39 | LEX_LBRACE, | ||
40 | LEX_RBRACE, | ||
41 | LEX_RANGLE, | ||
42 | LEX_OR, | ||
43 | LEX_LSHIFT, | ||
44 | LEX_COLON, | ||
45 | LEX_LE, | ||
46 | LEX_EOF | ||
47 | }; | ||
48 | |||
49 | struct lexem_t | ||
50 | { | ||
51 | enum lexem_type_t type; | ||
52 | /* if str is not NULL, it must be a malloc'd pointer */ | ||
53 | char *str; | ||
54 | uint32_t num; | ||
55 | int line; | ||
56 | const char *file; | ||
57 | }; | ||
58 | |||
59 | struct context_t | ||
60 | { | ||
61 | const char *file; | ||
62 | char *begin; | ||
63 | char *end; | ||
64 | char *ptr; | ||
65 | int line; | ||
66 | }; | ||
67 | |||
68 | #define parse_error(ctx, ...) \ | ||
69 | do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \ | ||
70 | fprintf(stderr, __VA_ARGS__); exit(2); } while(0) | ||
71 | |||
72 | static void advance(struct context_t *ctx, int nr_chars) | ||
73 | { | ||
74 | while(nr_chars--) | ||
75 | { | ||
76 | if(*(ctx->ptr++) == '\n') | ||
77 | ctx->line++; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static inline bool eof(struct context_t *ctx) | ||
82 | { | ||
83 | return ctx->ptr == ctx->end; | ||
84 | } | ||
85 | |||
86 | static inline bool next_valid(struct context_t *ctx, int nr) | ||
87 | { | ||
88 | return ctx->ptr + nr < ctx->end; | ||
89 | } | ||
90 | |||
91 | static inline char cur_char(struct context_t *ctx) | ||
92 | { | ||
93 | return *ctx->ptr; | ||
94 | } | ||
95 | |||
96 | static inline char next_char(struct context_t *ctx, int nr) | ||
97 | { | ||
98 | return ctx->ptr[nr]; | ||
99 | } | ||
100 | |||
101 | static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx) | ||
102 | { | ||
103 | lex->file = ctx->file; | ||
104 | lex->line = ctx->line; | ||
105 | } | ||
106 | |||
107 | static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c)) | ||
108 | { | ||
109 | while(!eof(ctx)) | ||
110 | { | ||
111 | if(cur_char(ctx) == '"') | ||
112 | break; | ||
113 | else if(cur_char(ctx) == '\\') | ||
114 | { | ||
115 | advance(ctx, 1); | ||
116 | if(eof(ctx)) | ||
117 | parse_error(ctx, "Unfinished string\n"); | ||
118 | if(cur_char(ctx) == '\\') emit_fn(user, '\\'); | ||
119 | else if(cur_char(ctx) == '\'') emit_fn(user, '\''); | ||
120 | else if(cur_char(ctx) == '\"') emit_fn(user, '\"'); | ||
121 | else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx)); | ||
122 | advance(ctx, 1); | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | emit_fn(user, cur_char(ctx)); | ||
127 | advance(ctx, 1); | ||
128 | } | ||
129 | } | ||
130 | if(eof(ctx) || cur_char(ctx) != '"') | ||
131 | parse_error(ctx, "Unfinished string\n"); | ||
132 | advance(ctx, 1); | ||
133 | } | ||
134 | |||
135 | static void __parse_string_emit(void *user, char c) | ||
136 | { | ||
137 | char **pstr = (char **)user; | ||
138 | *(*pstr)++ = c; | ||
139 | } | ||
140 | |||
141 | static void __parse_string_count(void *user, char c) | ||
142 | { | ||
143 | (void) c; | ||
144 | (*(int *)user)++; | ||
145 | } | ||
146 | |||
147 | static void parse_string(struct context_t *ctx, struct lexem_t *lexem) | ||
148 | { | ||
149 | locate_lexem(lexem, ctx); | ||
150 | /* skip " */ | ||
151 | advance(ctx, 1); | ||
152 | /* compute length */ | ||
153 | struct context_t cpy_ctx = *ctx; | ||
154 | int length = 0; | ||
155 | __parse_string(&cpy_ctx, (void *)&length, __parse_string_count); | ||
156 | /* parse again */ | ||
157 | lexem->type = LEX_STRING; | ||
158 | lexem->str = xmalloc(length + 1); | ||
159 | lexem->str[length] = 0; | ||
160 | char *pstr = lexem->str; | ||
161 | __parse_string(ctx, (void *)&pstr, __parse_string_emit); | ||
162 | } | ||
163 | |||
164 | static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem) | ||
165 | { | ||
166 | locate_lexem(lexem, ctx); | ||
167 | /* skip ' */ | ||
168 | advance(ctx, 1); | ||
169 | /* we expect n<=4 character and then ' */ | ||
170 | int len = 0; | ||
171 | uint32_t value = 0; | ||
172 | while(!eof(ctx)) | ||
173 | { | ||
174 | if(cur_char(ctx) != '\'') | ||
175 | { | ||
176 | value = value << 8 | cur_char(ctx); | ||
177 | len++; | ||
178 | advance(ctx, 1); | ||
179 | } | ||
180 | else | ||
181 | break; | ||
182 | } | ||
183 | if(eof(ctx) || cur_char(ctx) != '\'') | ||
184 | parse_error(ctx, "Unterminated ascii number literal\n"); | ||
185 | if(len == 0 || len > 4) | ||
186 | parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n"); | ||
187 | /* skip ' */ | ||
188 | advance(ctx, 1); | ||
189 | lexem->type = LEX_NUMBER; | ||
190 | lexem->num = value; | ||
191 | } | ||
192 | |||
193 | static void parse_number(struct context_t *ctx, struct lexem_t *lexem) | ||
194 | { | ||
195 | locate_lexem(lexem, ctx); | ||
196 | /* check base */ | ||
197 | int base = 10; | ||
198 | if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x') | ||
199 | { | ||
200 | advance(ctx, 2); | ||
201 | base = 16; | ||
202 | } | ||
203 | |||
204 | lexem->type = LEX_NUMBER; | ||
205 | lexem->num = 0; | ||
206 | while(!eof(ctx) && isxdigit(cur_char(ctx))) | ||
207 | { | ||
208 | if(base == 10 && !isdigit(cur_char(ctx))) | ||
209 | break; | ||
210 | byte v; | ||
211 | if(convxdigit(cur_char(ctx), &v)) | ||
212 | break; | ||
213 | lexem->num = base * lexem->num + v; | ||
214 | advance(ctx, 1); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem) | ||
219 | { | ||
220 | locate_lexem(lexem, ctx); | ||
221 | /* remember position */ | ||
222 | char *old = ctx->ptr; | ||
223 | while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_')) | ||
224 | advance(ctx, 1); | ||
225 | lexem->type = LEX_IDENTIFIER; | ||
226 | int len = ctx->ptr - old; | ||
227 | lexem->str = xmalloc(len + 1); | ||
228 | lexem->str[len] = 0; | ||
229 | memcpy(lexem->str, old, len); | ||
230 | } | ||
231 | |||
232 | static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) | ||
233 | { | ||
234 | #define ret_simple(t, adv) \ | ||
235 | do {locate_lexem(lexem, ctx); \ | ||
236 | lexem->type = t; \ | ||
237 | advance(ctx, adv); \ | ||
238 | return;} while(0) | ||
239 | while(!eof(ctx)) | ||
240 | { | ||
241 | char c = cur_char(ctx); | ||
242 | /* skip whitespace */ | ||
243 | if(c == ' ' || c == '\t' || c == '\n' || c == '\r') | ||
244 | { | ||
245 | advance(ctx, 1); | ||
246 | continue; | ||
247 | } | ||
248 | /* skip C++ style comments */ | ||
249 | if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/') | ||
250 | { | ||
251 | while(!eof(ctx) && cur_char(ctx) != '\n') | ||
252 | advance(ctx, 1); | ||
253 | continue; | ||
254 | } | ||
255 | /* skip C-style comments */ | ||
256 | if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*') | ||
257 | { | ||
258 | advance(ctx, 2); | ||
259 | while(true) | ||
260 | { | ||
261 | if(!next_valid(ctx, 1)) | ||
262 | parse_error(ctx, "Unterminated comment"); | ||
263 | if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/') | ||
264 | { | ||
265 | advance(ctx, 2); | ||
266 | break; | ||
267 | } | ||
268 | advance(ctx, 1); | ||
269 | } | ||
270 | continue; | ||
271 | } | ||
272 | break; | ||
273 | } | ||
274 | if(eof(ctx)) ret_simple(LEX_EOF, 0); | ||
275 | char c = cur_char(ctx); | ||
276 | bool nv = next_valid(ctx, 1); | ||
277 | char nc = nv ? next_char(ctx, 1) : 0; | ||
278 | if(c == '(') ret_simple(LEX_LPAREN, 1); | ||
279 | if(c == ')') ret_simple(LEX_RPAREN, 1); | ||
280 | if(c == '{') ret_simple(LEX_LBRACE, 1); | ||
281 | if(c == '}') ret_simple(LEX_RBRACE, 1); | ||
282 | if(c == '>') ret_simple(LEX_RANGLE, 1); | ||
283 | if(c == '=') ret_simple(LEX_EQUAL, 1); | ||
284 | if(c == ';') ret_simple(LEX_SEMICOLON, 1); | ||
285 | if(c == ',') ret_simple(LEX_COLON, 1); | ||
286 | if(c == '|') ret_simple(LEX_OR, 1); | ||
287 | if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2); | ||
288 | if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2); | ||
289 | if(c == '"') return parse_string(ctx, lexem); | ||
290 | if(c == '\'') return parse_ascii_number(ctx, lexem); | ||
291 | if(isdigit(c)) return parse_number(ctx, lexem); | ||
292 | if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem); | ||
293 | parse_error(ctx, "Unexpected character '%c'\n", c); | ||
294 | #undef ret_simple | ||
295 | } | ||
296 | |||
297 | #if 0 | ||
298 | static void log_lexem(struct lexem_t *lexem) | ||
299 | { | ||
300 | switch(lexem->type) | ||
301 | { | ||
302 | case LEX_EOF: printf("<eof>"); break; | ||
303 | case LEX_EQUAL: printf("="); break; | ||
304 | case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break; | ||
305 | case LEX_LPAREN: printf("("); break; | ||
306 | case LEX_RPAREN: printf(")"); break; | ||
307 | case LEX_LBRACE: printf("{"); break; | ||
308 | case LEX_RBRACE: printf("}"); break; | ||
309 | case LEX_SEMICOLON: printf(";"); break; | ||
310 | case LEX_NUMBER: printf("num(%d)", lexem->num); break; | ||
311 | case LEX_STRING: printf("str(%s)", lexem->str); break; | ||
312 | case LEX_OR: printf("|"); break; | ||
313 | case LEX_LSHIFT: printf("<<"); break; | ||
314 | default: printf("<unk>"); | ||
315 | } | ||
316 | } | ||
317 | #endif | ||
318 | |||
319 | struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
320 | { | ||
321 | struct cmd_source_t *src = cmd_file->source_list; | ||
322 | while(src) | ||
323 | { | ||
324 | if(strcmp(src->identifier, id) == 0) | ||
325 | return src; | ||
326 | src = src->next; | ||
327 | } | ||
328 | return NULL; | ||
329 | } | ||
330 | |||
331 | struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name) | ||
332 | { | ||
333 | while(opt) | ||
334 | { | ||
335 | if(strcmp(opt->name, name) == 0) | ||
336 | return opt; | ||
337 | opt = opt->next; | ||
338 | } | ||
339 | return NULL; | ||
340 | } | ||
341 | |||
342 | #define INVALID_SB_SUBVERSION 0xffff | ||
343 | |||
344 | static uint16_t parse_sb_subversion(char *str) | ||
345 | { | ||
346 | int len = strlen(str); | ||
347 | uint16_t n = 0; | ||
348 | if(len == 0 || len > 4) | ||
349 | return INVALID_SB_SUBVERSION; | ||
350 | for(int i = 0; i < len; i++) | ||
351 | { | ||
352 | if(!isdigit(str[i])) | ||
353 | return INVALID_SB_SUBVERSION; | ||
354 | n = n << 4 | (str[i] - '0'); | ||
355 | } | ||
356 | return n; | ||
357 | } | ||
358 | |||
359 | bool db_parse_sb_version(struct sb_version_t *ver, char *str) | ||
360 | { | ||
361 | int len = strlen(str); | ||
362 | int cnt = 0; | ||
363 | int pos[2]; | ||
364 | |||
365 | for(int i = 0; i < len; i++) | ||
366 | { | ||
367 | if(str[i] != '.') | ||
368 | continue; | ||
369 | if(cnt == 2) | ||
370 | return false; | ||
371 | pos[cnt++] = i + 1; | ||
372 | str[i] = 0; | ||
373 | } | ||
374 | if(cnt != 2) | ||
375 | return false; | ||
376 | ver->major = parse_sb_subversion(str); | ||
377 | ver->minor = parse_sb_subversion(str + pos[0]); | ||
378 | ver->revision = parse_sb_subversion(str + pos[1]); | ||
379 | return ver->major != INVALID_SB_SUBVERSION && | ||
380 | ver->minor != INVALID_SB_SUBVERSION && | ||
381 | ver->revision != INVALID_SB_SUBVERSION; | ||
382 | } | ||
383 | |||
384 | #undef parse_error | ||
385 | #define parse_error(lexem, ...) \ | ||
386 | do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ | ||
387 | fprintf(stderr, __VA_ARGS__); exit(2); } while(0) | ||
388 | |||
389 | struct lex_ctx_t | ||
390 | { | ||
391 | struct context_t ctx; | ||
392 | struct lexem_t lexem; | ||
393 | }; | ||
394 | |||
395 | /* When lexems hold strings (like identifier), it might be useful to steal | ||
396 | * the pointer and don't clean the lexem but in other case, one don't want | ||
397 | * to keep the pointer to the string and just want to release the memory. | ||
398 | * Thus clean_lexem should be true except when one keeps a pointer */ | ||
399 | static inline void next(struct lex_ctx_t *ctx, bool clean_lexem) | ||
400 | { | ||
401 | if(clean_lexem) | ||
402 | free(ctx->lexem.str); | ||
403 | memset(&ctx->lexem, 0, sizeof(struct lexem_t)); | ||
404 | next_lexem(&ctx->ctx, &ctx->lexem); | ||
405 | } | ||
406 | |||
407 | static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
408 | { | ||
409 | uint32_t ret = 0; | ||
410 | if(ctx->lexem.type == LEX_NUMBER) | ||
411 | ret = ctx->lexem.num; | ||
412 | else if(ctx->lexem.type == LEX_IDENTIFIER) | ||
413 | { | ||
414 | struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str); | ||
415 | if(c == NULL) | ||
416 | parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str); | ||
417 | if(c->is_string) | ||
418 | parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str); | ||
419 | ret = c->val; | ||
420 | } | ||
421 | else | ||
422 | parse_error(ctx->lexem, "Number or constant identifier expected\n"); | ||
423 | next(ctx, true); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
428 | { | ||
429 | uint32_t v = parse_term_expr(ctx, const_list); | ||
430 | while(ctx->lexem.type == LEX_LSHIFT) | ||
431 | { | ||
432 | next(ctx, true); | ||
433 | v <<= parse_term_expr(ctx, const_list); | ||
434 | } | ||
435 | return v; | ||
436 | } | ||
437 | |||
438 | static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
439 | { | ||
440 | uint32_t v = parse_shift_expr(ctx, const_list); | ||
441 | while(ctx->lexem.type == LEX_OR) | ||
442 | { | ||
443 | next(ctx, true); | ||
444 | v |= parse_shift_expr(ctx, const_list); | ||
445 | } | ||
446 | return v; | ||
447 | } | ||
448 | |||
449 | static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) | ||
450 | { | ||
451 | return parse_or_expr(ctx, const_list); | ||
452 | } | ||
453 | |||
454 | #define NR_INITIAL_CONSTANTS 4 | ||
455 | static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"}; | ||
456 | static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0}; | ||
457 | |||
458 | struct cmd_file_t *db_parse_file(const char *file) | ||
459 | { | ||
460 | size_t size; | ||
461 | FILE *f = fopen(file, "r"); | ||
462 | if(f == NULL) | ||
463 | bugp("Cannot open file '%s'", file); | ||
464 | fseek(f, 0, SEEK_END); | ||
465 | size = ftell(f); | ||
466 | fseek(f, 0, SEEK_SET); | ||
467 | char *buf = xmalloc(size); | ||
468 | if(fread(buf, size, 1, f) != 1) | ||
469 | bugp("Cannot read file '%s'", file); | ||
470 | fclose(f); | ||
471 | |||
472 | if(g_debug) | ||
473 | printf("Parsing db file '%s'\n", file); | ||
474 | struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); | ||
475 | memset(cmd_file, 0, sizeof(struct cmd_file_t)); | ||
476 | |||
477 | /* add initial constants */ | ||
478 | for(int i = 0; i < NR_INITIAL_CONSTANTS; i++) | ||
479 | { | ||
480 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
481 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
482 | opt->name = strdup(init_const_name[i]); | ||
483 | opt->is_string = false; | ||
484 | opt->val = init_const_value[i]; | ||
485 | opt->next = cmd_file->constant_list; | ||
486 | cmd_file->constant_list = opt; | ||
487 | } | ||
488 | |||
489 | struct lex_ctx_t lctx; | ||
490 | lctx.ctx.file = file; | ||
491 | lctx.ctx.line = 1; | ||
492 | lctx.ctx.begin = buf; | ||
493 | lctx.ctx.ptr = buf; | ||
494 | lctx.ctx.end = buf + size; | ||
495 | #define next(clean_lexem) next(&lctx, clean_lexem) | ||
496 | #define lexem lctx.lexem | ||
497 | /* init lexer */ | ||
498 | next(false); /* don't clean init lexem because it doesn't exist */ | ||
499 | /* constants ? */ | ||
500 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants")) | ||
501 | { | ||
502 | next(true); | ||
503 | if(lexem.type != LEX_LBRACE) | ||
504 | parse_error(lexem, "'{' expected after 'constants'\n"); | ||
505 | |||
506 | while(true) | ||
507 | { | ||
508 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
509 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
510 | next(true); | ||
511 | if(lexem.type == LEX_RBRACE) | ||
512 | break; | ||
513 | if(lexem.type != LEX_IDENTIFIER) | ||
514 | parse_error(lexem, "Identifier expected in constants\n"); | ||
515 | opt->name = lexem.str; | ||
516 | next(false); /* lexem string is kept as option name */ | ||
517 | if(lexem.type != LEX_EQUAL) | ||
518 | parse_error(lexem, "'=' expected after identifier\n"); | ||
519 | next(true); | ||
520 | opt->is_string = false; | ||
521 | opt->val = parse_intexpr(&lctx, cmd_file->constant_list); | ||
522 | opt->next = cmd_file->constant_list; | ||
523 | cmd_file->constant_list = opt; | ||
524 | if(lexem.type != LEX_SEMICOLON) | ||
525 | parse_error(lexem, "';' expected after string\n"); | ||
526 | } | ||
527 | next(true); | ||
528 | } | ||
529 | /* options ? */ | ||
530 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) | ||
531 | { | ||
532 | next(true); | ||
533 | if(lexem.type != LEX_LBRACE) | ||
534 | parse_error(lexem, "'{' expected after 'options'\n"); | ||
535 | |||
536 | while(true) | ||
537 | { | ||
538 | next(true); | ||
539 | if(lexem.type == LEX_RBRACE) | ||
540 | break; | ||
541 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
542 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
543 | if(lexem.type != LEX_IDENTIFIER) | ||
544 | parse_error(lexem, "Identifier expected in options\n"); | ||
545 | opt->name = lexem.str; | ||
546 | next(false); /* lexem string is kept as option name */ | ||
547 | if(lexem.type != LEX_EQUAL) | ||
548 | parse_error(lexem, "'=' expected after identifier\n"); | ||
549 | next(true); | ||
550 | if(lexem.type == LEX_STRING) | ||
551 | { | ||
552 | opt->is_string = true; | ||
553 | opt->str = lexem.str; | ||
554 | next(false); /* lexem string is kept as option name */ | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | opt->is_string = false; | ||
559 | opt->val = parse_intexpr(&lctx, cmd_file->constant_list); | ||
560 | } | ||
561 | opt->next = cmd_file->opt_list; | ||
562 | cmd_file->opt_list = opt; | ||
563 | if(lexem.type != LEX_SEMICOLON) | ||
564 | parse_error(lexem, "';' expected after string\n"); | ||
565 | } | ||
566 | next(true); | ||
567 | } | ||
568 | /* sources */ | ||
569 | if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources")) | ||
570 | parse_error(lexem, "'sources' expected\n"); | ||
571 | next(true); | ||
572 | if(lexem.type != LEX_LBRACE) | ||
573 | parse_error(lexem, "'{' expected after 'sources'\n"); | ||
574 | |||
575 | while(true) | ||
576 | { | ||
577 | next(true); | ||
578 | if(lexem.type == LEX_RBRACE) | ||
579 | break; | ||
580 | struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); | ||
581 | memset(src, 0, sizeof(struct cmd_source_t)); | ||
582 | if(lexem.type != LEX_IDENTIFIER) | ||
583 | parse_error(lexem, "identifier expected in sources\n"); | ||
584 | src->identifier = lexem.str; | ||
585 | next(false); /* lexem string is kept as source name */ | ||
586 | if(lexem.type != LEX_EQUAL) | ||
587 | parse_error(lexem, "'=' expected after identifier\n"); | ||
588 | next(true); | ||
589 | if(lexem.type == LEX_STRING) | ||
590 | { | ||
591 | src->is_extern = false; | ||
592 | src->filename = lexem.str; | ||
593 | next(false); /* lexem string is kept as file name */ | ||
594 | } | ||
595 | else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern")) | ||
596 | { | ||
597 | src->is_extern = true; | ||
598 | src->filename = strdup("<extern>"); /* duplicate because it will be free'd */ | ||
599 | next(true); | ||
600 | if(lexem.type != LEX_LPAREN) | ||
601 | parse_error(lexem, "'(' expected after 'extern'\n"); | ||
602 | next(true); | ||
603 | src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list); | ||
604 | if(lexem.type != LEX_RPAREN) | ||
605 | parse_error(lexem, "')' expected\n"); | ||
606 | next(true); | ||
607 | } | ||
608 | else | ||
609 | parse_error(lexem, "String or 'extern' expected after '='\n"); | ||
610 | if(lexem.type != LEX_SEMICOLON) | ||
611 | parse_error(lexem, "';' expected\n"); | ||
612 | if(db_find_source_by_id(cmd_file, src->identifier) != NULL) | ||
613 | parse_error(lexem, "Duplicate source identifier\n"); | ||
614 | /* type filled later */ | ||
615 | src->type = CMD_SRC_UNK; | ||
616 | src->next = cmd_file->source_list; | ||
617 | cmd_file->source_list = src; | ||
618 | } | ||
619 | |||
620 | /* sections */ | ||
621 | struct cmd_section_t *end_sec = NULL; | ||
622 | while(true) | ||
623 | { | ||
624 | next(true); | ||
625 | if(lexem.type == LEX_EOF) | ||
626 | break; | ||
627 | struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); | ||
628 | struct cmd_inst_t *end_list = NULL; | ||
629 | memset(sec, 0, sizeof(struct cmd_section_t)); | ||
630 | if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0) | ||
631 | parse_error(lexem, "'section' expected\n"); | ||
632 | next(true); | ||
633 | if(lexem.type != LEX_LPAREN) | ||
634 | parse_error(lexem, "'(' expected after 'section'\n"); | ||
635 | next(true); | ||
636 | /* can be any number */ | ||
637 | sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list); | ||
638 | /* options ? */ | ||
639 | if(lexem.type == LEX_SEMICOLON) | ||
640 | { | ||
641 | do | ||
642 | { | ||
643 | next(true); | ||
644 | struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); | ||
645 | memset(opt, 0, sizeof(struct cmd_option_t)); | ||
646 | if(lexem.type != LEX_IDENTIFIER) | ||
647 | parse_error(lexem, "Identifier expected for section option\n"); | ||
648 | opt->name = lexem.str; | ||
649 | next(false); /* lexem string is kept as option name */ | ||
650 | if(lexem.type != LEX_EQUAL) | ||
651 | parse_error(lexem, "'=' expected after option identifier\n"); | ||
652 | next(true); | ||
653 | if(lexem.type == LEX_STRING) | ||
654 | { | ||
655 | opt->is_string = true; | ||
656 | opt->str = lexem.str; | ||
657 | next(false); /* lexem string is kept as option string */ | ||
658 | } | ||
659 | else | ||
660 | { | ||
661 | opt->is_string = false; | ||
662 | opt->val = parse_intexpr(&lctx, cmd_file->constant_list); | ||
663 | } | ||
664 | opt->next = sec->opt_list; | ||
665 | sec->opt_list = opt; | ||
666 | }while(lexem.type == LEX_COLON); | ||
667 | } | ||
668 | if(lexem.type != LEX_RPAREN) | ||
669 | parse_error(lexem, "')' expected after section identifier\n"); | ||
670 | next(true); | ||
671 | if(lexem.type == LEX_LBRACE) | ||
672 | { | ||
673 | sec->is_data = false; | ||
674 | /* commands */ | ||
675 | while(true) | ||
676 | { | ||
677 | next(true); | ||
678 | if(lexem.type == LEX_RBRACE) | ||
679 | break; | ||
680 | struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); | ||
681 | memset(inst, 0, sizeof(struct cmd_inst_t)); | ||
682 | if(lexem.type != LEX_IDENTIFIER) | ||
683 | parse_error(lexem, "Instruction expected in section\n"); | ||
684 | if(strcmp(lexem.str, "load") == 0) | ||
685 | inst->type = CMD_LOAD; | ||
686 | else if(strcmp(lexem.str, "call") == 0) | ||
687 | inst->type = CMD_CALL; | ||
688 | else if(strcmp(lexem.str, "jump") == 0) | ||
689 | inst->type = CMD_JUMP; | ||
690 | else if(strcmp(lexem.str, "mode") == 0) | ||
691 | inst->type = CMD_MODE; | ||
692 | else | ||
693 | parse_error(lexem, "Instruction expected in section\n"); | ||
694 | next(true); | ||
695 | |||
696 | if(inst->type == CMD_LOAD) | ||
697 | { | ||
698 | if(lexem.type != LEX_IDENTIFIER) | ||
699 | parse_error(lexem, "Identifier expected after instruction\n"); | ||
700 | inst->identifier = lexem.str; | ||
701 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
702 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | ||
703 | next(false); /* lexem string kept as identifier */ | ||
704 | if(lexem.type == LEX_RANGLE) | ||
705 | { | ||
706 | // load at | ||
707 | inst->type = CMD_LOAD_AT; | ||
708 | next(true); | ||
709 | inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); | ||
710 | } | ||
711 | if(lexem.type != LEX_SEMICOLON) | ||
712 | parse_error(lexem, "';' expected after command\n"); | ||
713 | } | ||
714 | else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) | ||
715 | { | ||
716 | if(lexem.type == LEX_IDENTIFIER) | ||
717 | { | ||
718 | inst->identifier = lexem.str; | ||
719 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
720 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | ||
721 | next(false); /* lexem string kept as identifier */ | ||
722 | } | ||
723 | else | ||
724 | { | ||
725 | inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; | ||
726 | inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); | ||
727 | } | ||
728 | |||
729 | if(lexem.type == LEX_LPAREN) | ||
730 | { | ||
731 | next(true); | ||
732 | inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); | ||
733 | if(lexem.type != LEX_RPAREN) | ||
734 | parse_error(lexem, "Expected closing brace\n"); | ||
735 | next(true); | ||
736 | } | ||
737 | if(lexem.type != LEX_SEMICOLON) | ||
738 | parse_error(lexem, "';' expected after command\n"); | ||
739 | } | ||
740 | else if(inst->type == CMD_MODE) | ||
741 | { | ||
742 | inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); | ||
743 | if(lexem.type != LEX_SEMICOLON) | ||
744 | parse_error(lexem, "Expected ';' after command\n"); | ||
745 | } | ||
746 | else | ||
747 | parse_error(lexem, "Internal error"); | ||
748 | if(end_list == NULL) | ||
749 | { | ||
750 | sec->inst_list = inst; | ||
751 | end_list = inst; | ||
752 | } | ||
753 | else | ||
754 | { | ||
755 | end_list->next = inst; | ||
756 | end_list = inst; | ||
757 | } | ||
758 | } | ||
759 | } | ||
760 | else if(lexem.type == LEX_LE) | ||
761 | { | ||
762 | sec->is_data = true; | ||
763 | next(true); | ||
764 | if(lexem.type != LEX_IDENTIFIER) | ||
765 | parse_error(lexem, "Identifier expected after '<='\n"); | ||
766 | sec->source_id = lexem.str; | ||
767 | next(false); /* lexem string is kept as source id */ | ||
768 | if(lexem.type != LEX_SEMICOLON) | ||
769 | parse_error(lexem, "';' expected after identifier\n"); | ||
770 | } | ||
771 | else | ||
772 | parse_error(lexem, "'{' or '<=' expected after section directive\n"); | ||
773 | |||
774 | if(end_sec == NULL) | ||
775 | { | ||
776 | cmd_file->section_list = sec; | ||
777 | end_sec = sec; | ||
778 | } | ||
779 | else | ||
780 | { | ||
781 | end_sec->next = sec; | ||
782 | end_sec = sec; | ||
783 | } | ||
784 | } | ||
785 | #undef lexem | ||
786 | #undef next | ||
787 | |||
788 | free(buf); | ||
789 | return cmd_file; | ||
790 | } | ||
791 | |||
792 | void db_generate_default_sb_version(struct sb_version_t *ver) | ||
793 | { | ||
794 | ver->major = ver->minor = ver->revision = 0x999; | ||
795 | } | ||
796 | |||
797 | void db_free_option_list(struct cmd_option_t *opt_list) | ||
798 | { | ||
799 | while(opt_list) | ||
800 | { | ||
801 | struct cmd_option_t *next = opt_list->next; | ||
802 | fflush(stdout); | ||
803 | free(opt_list->name); | ||
804 | free(opt_list->str); | ||
805 | free(opt_list); | ||
806 | opt_list = next; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | void db_free(struct cmd_file_t *file) | ||
811 | { | ||
812 | db_free_option_list(file->opt_list); | ||
813 | db_free_option_list(file->constant_list); | ||
814 | struct cmd_source_t *src = file->source_list; | ||
815 | while(src) | ||
816 | { | ||
817 | struct cmd_source_t *next = src->next; | ||
818 | free(src->identifier); | ||
819 | fflush(stdout); | ||
820 | free(src->filename); | ||
821 | if(src->loaded) | ||
822 | { | ||
823 | if(src->type == CMD_SRC_BIN) | ||
824 | free(src->bin.data); | ||
825 | if(src->type == CMD_SRC_ELF) | ||
826 | elf_release(&src->elf); | ||
827 | } | ||
828 | free(src); | ||
829 | src = next; | ||
830 | } | ||
831 | struct cmd_section_t *sec = file->section_list; | ||
832 | while(sec) | ||
833 | { | ||
834 | struct cmd_section_t *next = sec->next; | ||
835 | db_free_option_list(sec->opt_list); | ||
836 | free(sec->source_id); | ||
837 | struct cmd_inst_t *inst = sec->inst_list; | ||
838 | while(inst) | ||
839 | { | ||
840 | struct cmd_inst_t *next = inst->next; | ||
841 | free(inst->identifier); | ||
842 | free(inst); | ||
843 | inst = next; | ||
844 | } | ||
845 | free(sec); | ||
846 | sec = next; | ||
847 | } | ||
848 | free(file); | ||
849 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __DBPARSER__ | ||
22 | #define __DBPARSER__ | ||
23 | |||
24 | /** | ||
25 | * Command file parsing | ||
26 | */ | ||
27 | #include "sb.h" | ||
28 | #include "elf.h" | ||
29 | |||
30 | enum cmd_source_type_t | ||
31 | { | ||
32 | CMD_SRC_UNK, | ||
33 | CMD_SRC_ELF, | ||
34 | CMD_SRC_BIN | ||
35 | }; | ||
36 | |||
37 | struct bin_param_t | ||
38 | { | ||
39 | uint32_t size; | ||
40 | void *data; | ||
41 | }; | ||
42 | |||
43 | struct cmd_source_t | ||
44 | { | ||
45 | char *identifier; | ||
46 | bool is_extern; | ||
47 | // <union> | ||
48 | int extern_nr; | ||
49 | char *filename; | ||
50 | // </union> | ||
51 | struct cmd_source_t *next; | ||
52 | /* for later use */ | ||
53 | enum cmd_source_type_t type; | ||
54 | bool loaded; | ||
55 | struct elf_params_t elf; | ||
56 | struct bin_param_t bin; | ||
57 | }; | ||
58 | |||
59 | enum cmd_inst_type_t | ||
60 | { | ||
61 | CMD_LOAD, /* load image */ | ||
62 | CMD_JUMP, /* jump at image */ | ||
63 | CMD_CALL, /* call image */ | ||
64 | CMD_LOAD_AT, /* load binary at */ | ||
65 | CMD_CALL_AT, /* call at address */ | ||
66 | CMD_JUMP_AT, /* jump at address */ | ||
67 | CMD_MODE, /* change boot mode */ | ||
68 | }; | ||
69 | |||
70 | struct cmd_inst_t | ||
71 | { | ||
72 | enum cmd_inst_type_t type; | ||
73 | char *identifier; | ||
74 | uint32_t argument; // for jump, call, mode | ||
75 | uint32_t addr; // for 'at' | ||
76 | struct cmd_inst_t *next; | ||
77 | }; | ||
78 | |||
79 | struct cmd_option_t | ||
80 | { | ||
81 | char *name; | ||
82 | bool is_string; | ||
83 | /* <union> */ | ||
84 | uint32_t val; | ||
85 | char *str; | ||
86 | /* </union> */ | ||
87 | struct cmd_option_t *next; | ||
88 | }; | ||
89 | |||
90 | struct cmd_section_t | ||
91 | { | ||
92 | uint32_t identifier; | ||
93 | bool is_data; | ||
94 | // <union> | ||
95 | struct cmd_inst_t *inst_list; | ||
96 | char *source_id; | ||
97 | // </union> | ||
98 | struct cmd_section_t *next; | ||
99 | struct cmd_option_t *opt_list; | ||
100 | }; | ||
101 | |||
102 | struct cmd_file_t | ||
103 | { | ||
104 | struct cmd_option_t *opt_list; | ||
105 | struct cmd_option_t *constant_list; /* constant are always integers */ | ||
106 | struct cmd_source_t *source_list; | ||
107 | struct cmd_section_t *section_list; | ||
108 | }; | ||
109 | |||
110 | struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); | ||
111 | struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name); | ||
112 | bool db_parse_sb_version(struct sb_version_t *ver, char *str); | ||
113 | void db_generate_default_sb_version(struct sb_version_t *ver); | ||
114 | struct cmd_file_t *db_parse_file(const char *file); | ||
115 | void db_free_option_list(struct cmd_option_t *opt_list); | ||
116 | void db_free(struct cmd_file_t *file); | ||
117 | |||
118 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "elf.h" | ||
22 | #include "misc.h" | ||
23 | |||
24 | /** | ||
25 | * Definitions | ||
26 | * taken from elf.h linux header | ||
27 | * based on ELF specification | ||
28 | * based on ARM ELF specification | ||
29 | */ | ||
30 | typedef uint16_t Elf32_Half; | ||
31 | |||
32 | typedef uint32_t Elf32_Word; | ||
33 | typedef int32_t Elf32_Sword; | ||
34 | typedef uint32_t Elf32_Addr; | ||
35 | typedef uint32_t Elf32_Off; | ||
36 | typedef uint16_t Elf32_Section; | ||
37 | |||
38 | #define EI_NIDENT 16 | ||
39 | |||
40 | typedef struct | ||
41 | { | ||
42 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ | ||
43 | Elf32_Half e_type; /* Object file type */ | ||
44 | Elf32_Half e_machine; /* Architecture */ | ||
45 | Elf32_Word e_version; /* Object file version */ | ||
46 | Elf32_Addr e_entry; /* Entry point virtual address */ | ||
47 | Elf32_Off e_phoff; /* Program header table file offset */ | ||
48 | Elf32_Off e_shoff; /* Section header table file offset */ | ||
49 | Elf32_Word e_flags; /* Processor-specific flags */ | ||
50 | Elf32_Half e_ehsize; /* ELF header size in bytes */ | ||
51 | Elf32_Half e_phentsize; /* Program header table entry size */ | ||
52 | Elf32_Half e_phnum; /* Program header table entry count */ | ||
53 | Elf32_Half e_shentsize; /* Section header table entry size */ | ||
54 | Elf32_Half e_shnum; /* Section header table entry count */ | ||
55 | Elf32_Half e_shstrndx; /* Section header string table index */ | ||
56 | }Elf32_Ehdr; | ||
57 | |||
58 | #define EI_MAG0 0 /* File identification byte 0 index */ | ||
59 | #define ELFMAG0 0x7f /* Magic number byte 0 */ | ||
60 | |||
61 | #define EI_MAG1 1 /* File identification byte 1 index */ | ||
62 | #define ELFMAG1 'E' /* Magic number byte 1 */ | ||
63 | |||
64 | #define EI_MAG2 2 /* File identification byte 2 index */ | ||
65 | #define ELFMAG2 'L' /* Magic number byte 2 */ | ||
66 | |||
67 | #define EI_MAG3 3 /* File identification byte 3 index */ | ||
68 | #define ELFMAG3 'F' /* Magic number byte 3 */ | ||
69 | |||
70 | #define EI_CLASS 4 /* File class byte index */ | ||
71 | #define ELFCLASS32 1 /* 32-bit objects */ | ||
72 | |||
73 | #define EI_DATA 5 /* Data encoding byte index */ | ||
74 | #define ELFDATA2LSB 1 /* 2's complement, little endian */ | ||
75 | |||
76 | #define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ | ||
77 | |||
78 | #define EI_OSABI 7 /* OS ABI identification */ | ||
79 | #define ELFOSABI_NONE 0 /* UNIX System V ABI */ | ||
80 | #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ | ||
81 | #define ELFOSABI_ARM 97 /* ARM */ | ||
82 | |||
83 | #define EI_ABIVERSION 8 /* ABI version */ | ||
84 | |||
85 | #define EI_PAD 9 /* Byte index of padding bytes */ | ||
86 | |||
87 | #define ET_EXEC 2 /* Executable file */ | ||
88 | |||
89 | #define EM_ARM 40 /* ARM */ | ||
90 | |||
91 | #define EV_CURRENT 1 /* Current version */ | ||
92 | |||
93 | #define EF_ARM_HASENTRY 0x00000002 | ||
94 | |||
95 | #define SHN_UNDEF 0 /* Undefined section */ | ||
96 | |||
97 | typedef struct | ||
98 | { | ||
99 | Elf32_Word sh_name; /* Section name (string tbl index) */ | ||
100 | Elf32_Word sh_type; /* Section type */ | ||
101 | Elf32_Word sh_flags; /* Section flags */ | ||
102 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ | ||
103 | Elf32_Off sh_offset; /* Section file offset */ | ||
104 | Elf32_Word sh_size; /* Section size in bytes */ | ||
105 | Elf32_Word sh_link; /* Link to another section */ | ||
106 | Elf32_Word sh_info; /* Additional section information */ | ||
107 | Elf32_Word sh_addralign; /* Section alignment */ | ||
108 | Elf32_Word sh_entsize; /* Entry size if section holds table */ | ||
109 | }Elf32_Shdr; | ||
110 | |||
111 | #define SHT_NULL 0 /* Section header table entry unused */ | ||
112 | #define SHT_PROGBITS 1 /* Program data */ | ||
113 | #define SHT_SYMTAB 2 /* Symbol table */ | ||
114 | #define SHT_STRTAB 3 /* String table */ | ||
115 | #define SHT_RELA 4 /* Relocation entries with addends */ | ||
116 | #define SHT_HASH 5 /* Symbol hash table */ | ||
117 | #define SHT_DYNAMIC 6 /* Dynamic linking information */ | ||
118 | #define SHT_NOTE 7 /* Notes */ | ||
119 | #define SHT_NOBITS 8 /* Program space with no data (bss) */ | ||
120 | #define SHT_REL 9 /* Relocation entries, no addends */ | ||
121 | #define SHT_SHLIB 10 /* Reserved */ | ||
122 | #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ | ||
123 | #define SHT_INIT_ARRAY 14 /* Array of constructors */ | ||
124 | #define SHT_FINI_ARRAY 15 /* Array of destructors */ | ||
125 | #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ | ||
126 | #define SHT_GROUP 17 /* Section group */ | ||
127 | #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ | ||
128 | #define SHT_NUM 19 /* Number of defined types. */ | ||
129 | |||
130 | #define SHF_WRITE (1 << 0) /* Writable */ | ||
131 | #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ | ||
132 | #define SHF_EXECINSTR (1 << 2) /* Executable */ | ||
133 | #define SHF_MERGE (1 << 4) /* Might be merged */ | ||
134 | #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ | ||
135 | |||
136 | typedef struct | ||
137 | { | ||
138 | Elf32_Word p_type; /* Segment type */ | ||
139 | Elf32_Off p_offset; /* Segment file offset */ | ||
140 | Elf32_Addr p_vaddr; /* Segment virtual address */ | ||
141 | Elf32_Addr p_paddr; /* Segment physical address */ | ||
142 | Elf32_Word p_filesz; /* Segment size in file */ | ||
143 | Elf32_Word p_memsz; /* Segment size in memory */ | ||
144 | Elf32_Word p_flags; /* Segment flags */ | ||
145 | Elf32_Word p_align; /* Segment alignment */ | ||
146 | }Elf32_Phdr; | ||
147 | |||
148 | #define PT_LOAD 1 /* Loadable program segment */ | ||
149 | |||
150 | #define PF_X (1 << 0) /* Segment is executable */ | ||
151 | #define PF_W (1 << 1) /* Segment is writable */ | ||
152 | #define PF_R (1 << 2) /* Segment is readable */ | ||
153 | |||
154 | void elf_init(struct elf_params_t *params) | ||
155 | { | ||
156 | memset(params, 0, sizeof(struct elf_params_t)); | ||
157 | } | ||
158 | |||
159 | extern void *xmalloc(size_t s); | ||
160 | |||
161 | static struct elf_section_t *elf_add_section(struct elf_params_t *params) | ||
162 | { | ||
163 | struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); | ||
164 | if(params->first_section == NULL) | ||
165 | params->first_section = params->last_section = sec; | ||
166 | else | ||
167 | { | ||
168 | params->last_section->next = sec; | ||
169 | params->last_section = sec; | ||
170 | } | ||
171 | sec->next = NULL; | ||
172 | |||
173 | return sec; | ||
174 | } | ||
175 | |||
176 | static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) | ||
177 | { | ||
178 | struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t)); | ||
179 | if(params->first_segment == NULL) | ||
180 | params->first_segment = params->last_segment = seg; | ||
181 | else | ||
182 | { | ||
183 | params->last_segment->next = seg; | ||
184 | params->last_segment = seg; | ||
185 | } | ||
186 | seg->next = NULL; | ||
187 | |||
188 | return seg; | ||
189 | } | ||
190 | |||
191 | void elf_add_load_section(struct elf_params_t *params, | ||
192 | uint32_t load_addr, uint32_t size, const void *section) | ||
193 | { | ||
194 | struct elf_section_t *sec = elf_add_section(params); | ||
195 | |||
196 | sec->type = EST_LOAD; | ||
197 | sec->addr = load_addr; | ||
198 | sec->size = size; | ||
199 | sec->section = xmalloc(size); | ||
200 | memcpy(sec->section, section, size); | ||
201 | } | ||
202 | |||
203 | void elf_add_fill_section(struct elf_params_t *params, | ||
204 | uint32_t fill_addr, uint32_t size, uint32_t pattern) | ||
205 | { | ||
206 | if(pattern != 0x00) | ||
207 | { | ||
208 | printf("oops, non-zero filling, ignore fill section\n"); | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | struct elf_section_t *sec = elf_add_section(params); | ||
213 | |||
214 | sec->type = EST_FILL; | ||
215 | sec->addr = fill_addr; | ||
216 | sec->size = size; | ||
217 | sec->pattern = pattern; | ||
218 | } | ||
219 | |||
220 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | ||
221 | elf_printf_fn_t printf, void *user) | ||
222 | { | ||
223 | (void) printf; | ||
224 | |||
225 | Elf32_Ehdr ehdr; | ||
226 | uint32_t phnum = 0; | ||
227 | struct elf_section_t *sec = params->first_section; | ||
228 | uint32_t offset = 0; | ||
229 | Elf32_Phdr phdr; | ||
230 | Elf32_Shdr shdr; | ||
231 | memset(&ehdr, 0, EI_NIDENT); | ||
232 | |||
233 | while(sec) | ||
234 | { | ||
235 | if(sec->type == EST_LOAD) | ||
236 | { | ||
237 | sec->offset = offset; | ||
238 | offset += sec->size; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | sec->offset = 0; | ||
243 | } | ||
244 | |||
245 | phnum++; | ||
246 | sec = sec->next; | ||
247 | } | ||
248 | |||
249 | uint32_t strtbl_offset = offset; | ||
250 | |||
251 | ehdr.e_ident[EI_MAG0] = ELFMAG0; | ||
252 | ehdr.e_ident[EI_MAG1] = ELFMAG1; | ||
253 | ehdr.e_ident[EI_MAG2] = ELFMAG2; | ||
254 | ehdr.e_ident[EI_MAG3] = ELFMAG3; | ||
255 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; | ||
256 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB; | ||
257 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; | ||
258 | ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; | ||
259 | ehdr.e_ident[EI_ABIVERSION] = 0; | ||
260 | ehdr.e_type = ET_EXEC; | ||
261 | ehdr.e_machine = EM_ARM; | ||
262 | ehdr.e_version = EV_CURRENT; | ||
263 | ehdr.e_entry = params->start_addr; | ||
264 | ehdr.e_flags = 0; | ||
265 | if(params->has_start_addr) | ||
266 | ehdr.e_flags |= EF_ARM_HASENTRY; | ||
267 | ehdr.e_ehsize = sizeof ehdr; | ||
268 | ehdr.e_phentsize = sizeof phdr; | ||
269 | ehdr.e_phnum = phnum; | ||
270 | ehdr.e_shentsize = sizeof shdr; | ||
271 | ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */ | ||
272 | ehdr.e_shstrndx = ehdr.e_shnum - 1; | ||
273 | ehdr.e_phoff = ehdr.e_ehsize; | ||
274 | ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize; | ||
275 | |||
276 | write(user, 0, &ehdr, sizeof ehdr); | ||
277 | |||
278 | /* allocate enough size to hold any combinaison of .text/.bss in the string table: | ||
279 | * - one empty name ("\0") | ||
280 | * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" | ||
281 | * - one name ".shstrtab\0" */ | ||
282 | char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + | ||
283 | phnum * (strlen(".textXXXX") + 1)); | ||
284 | |||
285 | strtbl_content[0] = '\0'; | ||
286 | strcpy(&strtbl_content[1], ".shstrtab"); | ||
287 | uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; | ||
288 | |||
289 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + | ||
290 | ehdr.e_shnum * ehdr.e_shentsize; | ||
291 | |||
292 | sec = params->first_section; | ||
293 | offset = ehdr.e_phoff; | ||
294 | while(sec) | ||
295 | { | ||
296 | sec->offset += data_offset; | ||
297 | |||
298 | phdr.p_type = PT_LOAD; | ||
299 | if(sec->type == EST_LOAD) | ||
300 | phdr.p_offset = sec->offset; | ||
301 | else | ||
302 | phdr.p_offset = 0; | ||
303 | phdr.p_paddr = sec->addr; | ||
304 | phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ | ||
305 | phdr.p_memsz = sec->size; | ||
306 | if(sec->type == EST_LOAD) | ||
307 | phdr.p_filesz = phdr.p_memsz; | ||
308 | else | ||
309 | phdr.p_filesz = 0; | ||
310 | phdr.p_flags = PF_X | PF_W | PF_R; | ||
311 | phdr.p_align = 0; | ||
312 | |||
313 | write(user, offset, &phdr, sizeof phdr); | ||
314 | |||
315 | offset += sizeof(Elf32_Phdr); | ||
316 | sec = sec->next; | ||
317 | } | ||
318 | |||
319 | sec = params->first_section; | ||
320 | offset = ehdr.e_shoff; | ||
321 | |||
322 | { | ||
323 | shdr.sh_name = 0; | ||
324 | shdr.sh_type = SHT_NULL; | ||
325 | shdr.sh_flags = 0; | ||
326 | shdr.sh_addr = 0; | ||
327 | shdr.sh_offset = 0; | ||
328 | shdr.sh_size = 0; | ||
329 | shdr.sh_link = SHN_UNDEF; | ||
330 | shdr.sh_info = 0; | ||
331 | shdr.sh_addralign = 0; | ||
332 | shdr.sh_entsize = 0; | ||
333 | |||
334 | write(user, offset, &shdr, sizeof shdr); | ||
335 | |||
336 | offset += sizeof(Elf32_Shdr); | ||
337 | } | ||
338 | |||
339 | uint32_t text_idx = 0; | ||
340 | uint32_t bss_idx = 0; | ||
341 | while(sec) | ||
342 | { | ||
343 | shdr.sh_name = strtbl_index; | ||
344 | if(sec->type == EST_LOAD) | ||
345 | { | ||
346 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); | ||
347 | shdr.sh_type = SHT_PROGBITS; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); | ||
352 | shdr.sh_type = SHT_NOBITS; | ||
353 | } | ||
354 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; | ||
355 | shdr.sh_addr = sec->addr; | ||
356 | shdr.sh_offset = sec->offset; | ||
357 | shdr.sh_size = sec->size; | ||
358 | shdr.sh_link = SHN_UNDEF; | ||
359 | shdr.sh_info = 0; | ||
360 | shdr.sh_addralign = 1; | ||
361 | shdr.sh_entsize = 0; | ||
362 | |||
363 | write(user, offset, &shdr, sizeof shdr); | ||
364 | |||
365 | offset += sizeof(Elf32_Shdr); | ||
366 | sec = sec->next; | ||
367 | } | ||
368 | |||
369 | { | ||
370 | shdr.sh_name = 1; | ||
371 | shdr.sh_type = SHT_STRTAB; | ||
372 | shdr.sh_flags = 0; | ||
373 | shdr.sh_addr = 0; | ||
374 | shdr.sh_offset = strtbl_offset + data_offset; | ||
375 | shdr.sh_size = strtbl_index; | ||
376 | shdr.sh_link = SHN_UNDEF; | ||
377 | shdr.sh_info = 0; | ||
378 | shdr.sh_addralign = 1; | ||
379 | shdr.sh_entsize = 0; | ||
380 | |||
381 | write(user, offset, &shdr, sizeof shdr); | ||
382 | |||
383 | offset += sizeof(Elf32_Shdr); | ||
384 | } | ||
385 | |||
386 | sec = params->first_section; | ||
387 | while(sec) | ||
388 | { | ||
389 | if(sec->type == EST_LOAD) | ||
390 | write(user, sec->offset, sec->section, sec->size); | ||
391 | sec = sec->next; | ||
392 | } | ||
393 | |||
394 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); | ||
395 | free(strtbl_content); | ||
396 | } | ||
397 | |||
398 | bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | ||
399 | elf_printf_fn_t printf, void *user) | ||
400 | { | ||
401 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) | ||
402 | |||
403 | /* read header */ | ||
404 | Elf32_Ehdr ehdr; | ||
405 | if(!read(user, 0, &ehdr, sizeof(ehdr))) | ||
406 | { | ||
407 | printf(user, true, "error reading elf header\n"); | ||
408 | return false; | ||
409 | } | ||
410 | /* basic checks */ | ||
411 | if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || | ||
412 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) | ||
413 | error_printf("invalid elf header\n"); | ||
414 | if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) | ||
415 | error_printf("invalid elf class: must be a 32-bit object\n"); | ||
416 | if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) | ||
417 | error_printf("invalid elf data encoding: must be 32-bit lsb\n"); | ||
418 | if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) | ||
419 | error_printf("invalid elf version\n"); | ||
420 | if(ehdr.e_type != ET_EXEC) | ||
421 | error_printf("invalid elf file: must be an executable file\n"); | ||
422 | if(ehdr.e_machine != EM_ARM) | ||
423 | error_printf("invalid elf file: must target an arm machine\n"); | ||
424 | if(ehdr.e_ehsize != sizeof(ehdr)) | ||
425 | error_printf("invalid elf file: size header mismatch\n"); | ||
426 | if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr)) | ||
427 | error_printf("invalid elf file: program header size mismatch\n"); | ||
428 | if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr)) | ||
429 | error_printf("invalid elf file: section header size mismatch\n"); | ||
430 | elf_set_start_addr(params, ehdr.e_entry); | ||
431 | |||
432 | char *strtab = NULL; | ||
433 | if(ehdr.e_shstrndx != SHN_UNDEF) | ||
434 | { | ||
435 | Elf32_Shdr shstrtab; | ||
436 | if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, | ||
437 | &shstrtab, sizeof(shstrtab))) | ||
438 | { | ||
439 | strtab = xmalloc(shstrtab.sh_size); | ||
440 | if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) | ||
441 | { | ||
442 | free(strtab); | ||
443 | strtab = NULL; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | /* run through sections */ | ||
448 | printf(user, false, "ELF file:\n"); | ||
449 | for(int i = 1; i < ehdr.e_shnum; i++) | ||
450 | { | ||
451 | uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; | ||
452 | Elf32_Shdr shdr; | ||
453 | memset(&shdr, 0, sizeof(shdr)); | ||
454 | if(!read(user, off, &shdr, sizeof(shdr))) | ||
455 | error_printf("error reading elf section header"); | ||
456 | |||
457 | if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) | ||
458 | { | ||
459 | void *data = xmalloc(shdr.sh_size); | ||
460 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) | ||
461 | error_printf("error read self section data\n"); | ||
462 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); | ||
463 | free(data); | ||
464 | |||
465 | if(strtab) | ||
466 | printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); | ||
467 | } | ||
468 | else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) | ||
469 | { | ||
470 | elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); | ||
471 | if(strtab) | ||
472 | printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | if(strtab) | ||
477 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); | ||
478 | } | ||
479 | |||
480 | } | ||
481 | free(strtab); | ||
482 | /* run through segments */ | ||
483 | for(int i = 1; i < ehdr.e_phnum; i++) | ||
484 | { | ||
485 | uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize; | ||
486 | Elf32_Phdr phdr; | ||
487 | memset(&phdr, 0, sizeof(phdr)); | ||
488 | if(!read(user, off, &phdr, sizeof(phdr))) | ||
489 | error_printf("error reading elf segment header"); | ||
490 | if(phdr.p_type != PT_LOAD) | ||
491 | continue; | ||
492 | struct elf_segment_t *seg = elf_add_segment(params); | ||
493 | seg->vaddr = phdr.p_vaddr; | ||
494 | seg->paddr = phdr.p_paddr; | ||
495 | seg->vsize = phdr.p_memsz; | ||
496 | seg->psize = phdr.p_filesz; | ||
497 | printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n", | ||
498 | seg->vaddr, seg->vsize, seg->paddr, seg->psize); | ||
499 | } | ||
500 | |||
501 | return true; | ||
502 | } | ||
503 | |||
504 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr) | ||
505 | { | ||
506 | struct elf_segment_t *seg = params->first_segment; | ||
507 | while(seg) | ||
508 | { | ||
509 | if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize) | ||
510 | return addr - seg->vaddr + seg->paddr; | ||
511 | seg = seg->next; | ||
512 | } | ||
513 | return addr; | ||
514 | } | ||
515 | |||
516 | void elf_translate_addresses(struct elf_params_t *params) | ||
517 | { | ||
518 | struct elf_section_t *sec = params->first_section; | ||
519 | while(sec) | ||
520 | { | ||
521 | sec->addr = elf_translate_virtual_address(params, sec->addr); | ||
522 | sec = sec->next; | ||
523 | } | ||
524 | params->start_addr = elf_translate_virtual_address(params, params->start_addr); | ||
525 | } | ||
526 | |||
527 | bool elf_is_empty(struct elf_params_t *params) | ||
528 | { | ||
529 | return params->first_section == NULL; | ||
530 | } | ||
531 | |||
532 | void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) | ||
533 | { | ||
534 | params->has_start_addr = true; | ||
535 | params->start_addr = addr; | ||
536 | } | ||
537 | |||
538 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) | ||
539 | { | ||
540 | if(params->has_start_addr && addr != NULL) | ||
541 | *addr = params->start_addr; | ||
542 | return params->has_start_addr; | ||
543 | } | ||
544 | |||
545 | int elf_get_nr_sections(struct elf_params_t *params) | ||
546 | { | ||
547 | int nr = 0; | ||
548 | struct elf_section_t *sec = params->first_section; | ||
549 | while(sec) | ||
550 | { | ||
551 | nr++; | ||
552 | sec = sec->next; | ||
553 | } | ||
554 | return nr; | ||
555 | } | ||
556 | |||
557 | void elf_release(struct elf_params_t *params) | ||
558 | { | ||
559 | struct elf_section_t *sec = params->first_section; | ||
560 | while(sec) | ||
561 | { | ||
562 | struct elf_section_t *next_sec = sec->next; | ||
563 | if(sec->type == EST_LOAD) | ||
564 | free(sec->section); | ||
565 | free(sec); | ||
566 | sec = next_sec; | ||
567 | } | ||
568 | struct elf_segment_t *seg = params->first_segment; | ||
569 | while(seg) | ||
570 | { | ||
571 | struct elf_segment_t *next_seg = seg->next; | ||
572 | free(seg); | ||
573 | seg = next_seg; | ||
574 | } | ||
575 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __ELF_H__ | ||
22 | #define __ELF_H__ | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <stdint.h> | ||
26 | #include <string.h> | ||
27 | #include <stdbool.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <unistd.h> | ||
30 | |||
31 | /** | ||
32 | * API | ||
33 | */ | ||
34 | enum elf_section_type_t | ||
35 | { | ||
36 | EST_LOAD, | ||
37 | EST_FILL | ||
38 | }; | ||
39 | |||
40 | struct elf_section_t | ||
41 | { | ||
42 | uint32_t addr; /* virtual address */ | ||
43 | uint32_t size; /* virtual size */ | ||
44 | enum elf_section_type_t type; | ||
45 | /* <union> */ | ||
46 | void *section; /* data */ | ||
47 | uint32_t pattern; /* fill pattern */ | ||
48 | /* </union> */ | ||
49 | struct elf_section_t *next; | ||
50 | /* Internal to elf_write_file */ | ||
51 | uint32_t offset; | ||
52 | }; | ||
53 | |||
54 | struct elf_segment_t | ||
55 | { | ||
56 | uint32_t vaddr; /* virtual address */ | ||
57 | uint32_t paddr; /* physical address */ | ||
58 | uint32_t vsize; /* virtual size */ | ||
59 | uint32_t psize; /* physical size */ | ||
60 | struct elf_segment_t *next; | ||
61 | }; | ||
62 | |||
63 | struct elf_params_t | ||
64 | { | ||
65 | bool has_start_addr; | ||
66 | uint32_t start_addr; | ||
67 | struct elf_section_t *first_section; | ||
68 | struct elf_section_t *last_section; | ||
69 | struct elf_segment_t *first_segment; | ||
70 | struct elf_segment_t *last_segment; | ||
71 | }; | ||
72 | |||
73 | typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); | ||
74 | /* write function manages it's own error state */ | ||
75 | typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count); | ||
76 | typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...); | ||
77 | |||
78 | void elf_init(struct elf_params_t *params); | ||
79 | void elf_add_load_section(struct elf_params_t *params, | ||
80 | uint32_t load_addr, uint32_t size, const void *section); | ||
81 | void elf_add_fill_section(struct elf_params_t *params, | ||
82 | uint32_t fill_addr, uint32_t size, uint32_t pattern); | ||
83 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); | ||
84 | void elf_translate_addresses(struct elf_params_t *params); | ||
85 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user); | ||
86 | bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf, | ||
87 | void *user); | ||
88 | bool elf_is_empty(struct elf_params_t *params); | ||
89 | void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); | ||
90 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); | ||
91 | int elf_get_nr_sections(struct elf_params_t *params); | ||
92 | void elf_release(struct elf_params_t *params); | ||
93 | |||
94 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #define _ISOC99_SOURCE | ||
23 | #define _POSIX_C_SOURCE 200809L /* for strdup */ | ||
24 | #include <stdio.h> | ||
25 | #include <errno.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | #include <ctype.h> | ||
29 | #include <time.h> | ||
30 | #include <stdarg.h> | ||
31 | #include <strings.h> | ||
32 | #include <getopt.h> | ||
33 | |||
34 | #include "crypto.h" | ||
35 | #include "elf.h" | ||
36 | #include "sb.h" | ||
37 | #include "dbparser.h" | ||
38 | #include "misc.h" | ||
39 | #include "sb.h" | ||
40 | |||
41 | char **g_extern; | ||
42 | int g_extern_count; | ||
43 | |||
44 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | ||
45 | |||
46 | #define crypto_cbc(...) \ | ||
47 | do { int ret = crypto_cbc(__VA_ARGS__); \ | ||
48 | if(ret != CRYPTO_ERROR_SUCCESS) \ | ||
49 | bug("crypto_cbc error: %d\n", ret); \ | ||
50 | }while(0) | ||
51 | |||
52 | /** | ||
53 | * command file to sb conversion | ||
54 | */ | ||
55 | |||
56 | static bool elf_read(void *user, uint32_t addr, void *buf, size_t count) | ||
57 | { | ||
58 | if(fseek((FILE *)user, addr, SEEK_SET) == -1) | ||
59 | return false; | ||
60 | return fread(buf, 1, count, (FILE *)user) == count; | ||
61 | } | ||
62 | |||
63 | static void elf_printf(void *user, bool error, const char *fmt, ...) | ||
64 | { | ||
65 | if(!g_debug && !error) | ||
66 | return; | ||
67 | (void) user; | ||
68 | va_list args; | ||
69 | va_start(args, fmt); | ||
70 | vprintf(fmt, args); | ||
71 | va_end(args); | ||
72 | } | ||
73 | |||
74 | static void resolve_extern(struct cmd_source_t *src) | ||
75 | { | ||
76 | if(!src->is_extern) | ||
77 | return; | ||
78 | src->is_extern = false; | ||
79 | if(src->extern_nr < 0 || src->extern_nr >= g_extern_count) | ||
80 | bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr); | ||
81 | /* first free the old src->filename content */ | ||
82 | free(src->filename); | ||
83 | src->filename = strdup(g_extern[src->extern_nr]); | ||
84 | } | ||
85 | |||
86 | static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
87 | { | ||
88 | struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); | ||
89 | if(src == NULL) | ||
90 | bug("undefined reference to source '%s'\n", id); | ||
91 | /* avoid reloading */ | ||
92 | if(src->type == CMD_SRC_ELF && src->loaded) | ||
93 | return; | ||
94 | if(src->type != CMD_SRC_UNK) | ||
95 | bug("source '%s' seen both as elf and binary file\n", id); | ||
96 | /* resolve potential extern file */ | ||
97 | resolve_extern(src); | ||
98 | /* load it */ | ||
99 | src->type = CMD_SRC_ELF; | ||
100 | FILE *fd = fopen(src->filename, "rb"); | ||
101 | if(fd == NULL) | ||
102 | bug("cannot open '%s' (id '%s')\n", src->filename, id); | ||
103 | if(g_debug) | ||
104 | printf("Loading ELF file '%s'...\n", src->filename); | ||
105 | elf_init(&src->elf); | ||
106 | src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd); | ||
107 | fclose(fd); | ||
108 | if(!src->loaded) | ||
109 | bug("error loading elf file '%s' (id '%s')\n", src->filename, id); | ||
110 | elf_translate_addresses(&src->elf); | ||
111 | } | ||
112 | |||
113 | static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
114 | { | ||
115 | struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); | ||
116 | if(src == NULL) | ||
117 | bug("undefined reference to source '%s'\n", id); | ||
118 | /* avoid reloading */ | ||
119 | if(src->type == CMD_SRC_BIN && src->loaded) | ||
120 | return; | ||
121 | if(src->type != CMD_SRC_UNK) | ||
122 | bug("source '%s' seen both as elf and binary file\n", id); | ||
123 | /* resolve potential extern file */ | ||
124 | resolve_extern(src); | ||
125 | /* load it */ | ||
126 | src->type = CMD_SRC_BIN; | ||
127 | FILE *fd = fopen(src->filename, "rb"); | ||
128 | if(fd == NULL) | ||
129 | bug("cannot open '%s' (id '%s')\n", src->filename, id); | ||
130 | if(g_debug) | ||
131 | printf("Loading BIN file '%s'...\n", src->filename); | ||
132 | fseek(fd, 0, SEEK_END); | ||
133 | src->bin.size = ftell(fd); | ||
134 | fseek(fd, 0, SEEK_SET); | ||
135 | src->bin.data = xmalloc(src->bin.size); | ||
136 | fread(src->bin.data, 1, src->bin.size, fd); | ||
137 | fclose(fd); | ||
138 | src->loaded = true; | ||
139 | } | ||
140 | |||
141 | static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | ||
142 | { | ||
143 | struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); | ||
144 | memset(sb, 0, sizeof(struct sb_file_t)); | ||
145 | |||
146 | db_generate_default_sb_version(&sb->product_ver); | ||
147 | db_generate_default_sb_version(&sb->component_ver); | ||
148 | |||
149 | if(g_debug) | ||
150 | printf("Applying command file...\n"); | ||
151 | /* count sections */ | ||
152 | struct cmd_section_t *csec = cmd_file->section_list; | ||
153 | while(csec) | ||
154 | { | ||
155 | sb->nr_sections++; | ||
156 | csec = csec->next; | ||
157 | } | ||
158 | |||
159 | sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t)); | ||
160 | memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t)); | ||
161 | /* flatten sections */ | ||
162 | csec = cmd_file->section_list; | ||
163 | for(int i = 0; i < sb->nr_sections; i++, csec = csec->next) | ||
164 | { | ||
165 | struct sb_section_t *sec = &sb->sections[i]; | ||
166 | sec->identifier = csec->identifier; | ||
167 | |||
168 | /* options */ | ||
169 | do | ||
170 | { | ||
171 | /* cleartext */ | ||
172 | struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext"); | ||
173 | if(opt != NULL) | ||
174 | { | ||
175 | if(opt->is_string) | ||
176 | bug("Cleartext section attribute must be an integer\n"); | ||
177 | if(opt->val != 0 && opt->val != 1) | ||
178 | bug("Cleartext section attribute must be 0 or 1\n"); | ||
179 | sec->is_cleartext = opt->val; | ||
180 | } | ||
181 | /* alignment */ | ||
182 | opt = db_find_option_by_id(csec->opt_list, "alignment"); | ||
183 | if(opt != NULL) | ||
184 | { | ||
185 | if(opt->is_string) | ||
186 | bug("Cleartext section attribute must be an integer\n"); | ||
187 | // n is a power of 2 iff n & (n - 1) = 0 | ||
188 | // alignement cannot be lower than block size | ||
189 | if((opt->val & (opt->val - 1)) != 0) | ||
190 | bug("Cleartext section attribute must be a power of two\n"); | ||
191 | if(opt->val < BLOCK_SIZE) | ||
192 | sec->alignment = BLOCK_SIZE; | ||
193 | else | ||
194 | sec->alignment = opt->val; | ||
195 | } | ||
196 | else | ||
197 | sec->alignment = BLOCK_SIZE; | ||
198 | }while(0); | ||
199 | |||
200 | if(csec->is_data) | ||
201 | { | ||
202 | sec->is_data = true; | ||
203 | sec->nr_insts = 1; | ||
204 | sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); | ||
205 | memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); | ||
206 | |||
207 | load_bin_by_id(cmd_file, csec->source_id); | ||
208 | struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin; | ||
209 | |||
210 | sec->insts[0].inst = SB_INST_DATA; | ||
211 | sec->insts[0].size = bin->size; | ||
212 | sec->insts[0].data = memdup(bin->data, bin->size); | ||
213 | } | ||
214 | else | ||
215 | { | ||
216 | sec->is_data = false; | ||
217 | /* count instructions and loads things */ | ||
218 | struct cmd_inst_t *cinst = csec->inst_list; | ||
219 | while(cinst) | ||
220 | { | ||
221 | if(cinst->type == CMD_LOAD) | ||
222 | { | ||
223 | load_elf_by_id(cmd_file, cinst->identifier); | ||
224 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
225 | sec->nr_insts += elf_get_nr_sections(elf); | ||
226 | } | ||
227 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | ||
228 | { | ||
229 | load_elf_by_id(cmd_file, cinst->identifier); | ||
230 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
231 | if(!elf_get_start_addr(elf, NULL)) | ||
232 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); | ||
233 | sec->nr_insts++; | ||
234 | } | ||
235 | else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) | ||
236 | { | ||
237 | sec->nr_insts++; | ||
238 | } | ||
239 | else if(cinst->type == CMD_LOAD_AT) | ||
240 | { | ||
241 | load_bin_by_id(cmd_file, cinst->identifier); | ||
242 | sec->nr_insts++; | ||
243 | } | ||
244 | else if(cinst->type == CMD_MODE) | ||
245 | { | ||
246 | sec->nr_insts++; | ||
247 | } | ||
248 | else | ||
249 | bug("die\n"); | ||
250 | |||
251 | cinst = cinst->next; | ||
252 | } | ||
253 | |||
254 | sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); | ||
255 | memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); | ||
256 | /* flatten */ | ||
257 | int idx = 0; | ||
258 | cinst = csec->inst_list; | ||
259 | while(cinst) | ||
260 | { | ||
261 | if(cinst->type == CMD_LOAD) | ||
262 | { | ||
263 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
264 | struct elf_section_t *esec = elf->first_section; | ||
265 | while(esec) | ||
266 | { | ||
267 | if(esec->type == EST_LOAD) | ||
268 | { | ||
269 | sec->insts[idx].inst = SB_INST_LOAD; | ||
270 | sec->insts[idx].addr = esec->addr; | ||
271 | sec->insts[idx].size = esec->size; | ||
272 | sec->insts[idx++].data = memdup(esec->section, esec->size); | ||
273 | } | ||
274 | else if(esec->type == EST_FILL) | ||
275 | { | ||
276 | sec->insts[idx].inst = SB_INST_FILL; | ||
277 | sec->insts[idx].addr = esec->addr; | ||
278 | sec->insts[idx].size = esec->size; | ||
279 | sec->insts[idx++].pattern = esec->pattern; | ||
280 | } | ||
281 | esec = esec->next; | ||
282 | } | ||
283 | } | ||
284 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | ||
285 | { | ||
286 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
287 | sec->insts[idx].argument = cinst->argument; | ||
288 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; | ||
289 | sec->insts[idx++].addr = elf->start_addr; | ||
290 | } | ||
291 | else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) | ||
292 | { | ||
293 | sec->insts[idx].argument = cinst->argument; | ||
294 | sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; | ||
295 | sec->insts[idx++].addr = cinst->addr; | ||
296 | } | ||
297 | else if(cinst->type == CMD_LOAD_AT) | ||
298 | { | ||
299 | struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; | ||
300 | sec->insts[idx].inst = SB_INST_LOAD; | ||
301 | sec->insts[idx].addr = cinst->addr; | ||
302 | sec->insts[idx].data = memdup(bin->data, bin->size); | ||
303 | sec->insts[idx++].size = bin->size; | ||
304 | } | ||
305 | else if(cinst->type == CMD_MODE) | ||
306 | { | ||
307 | sec->insts[idx].inst = SB_INST_MODE; | ||
308 | sec->insts[idx++].addr = cinst->argument; | ||
309 | } | ||
310 | else | ||
311 | bug("die\n"); | ||
312 | |||
313 | cinst = cinst->next; | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
318 | return sb; | ||
319 | } | ||
320 | |||
321 | void usage(void) | ||
322 | { | ||
323 | printf("Usage: elftosb [options | file]...\n"); | ||
324 | printf("Options:\n"); | ||
325 | printf(" -?/--help\tDisplay this message\n"); | ||
326 | printf(" -o <file>\tSet output file\n"); | ||
327 | printf(" -c <file>\tSet command file\n"); | ||
328 | printf(" -d/--debug\tEnable debug output\n"); | ||
329 | printf(" -k <file>\tAdd key file\n"); | ||
330 | printf(" -z\t\tAdd zero key\n"); | ||
331 | printf(" --add-key <key>\tAdd single key (hex or usbotp)\n"); | ||
332 | printf(" --real-key <key>\tOverride real key\n"); | ||
333 | printf(" --crypto-iv <iv>\tOverride crypto IV\n"); | ||
334 | exit(1); | ||
335 | } | ||
336 | |||
337 | static struct crypto_key_t g_zero_key = | ||
338 | { | ||
339 | .method = CRYPTO_KEY, | ||
340 | .u.key = {0} | ||
341 | }; | ||
342 | |||
343 | int main(int argc, char **argv) | ||
344 | { | ||
345 | char *cmd_filename = NULL; | ||
346 | char *output_filename = NULL; | ||
347 | struct crypto_key_t real_key; | ||
348 | struct crypto_key_t crypto_iv; | ||
349 | real_key.method = CRYPTO_NONE; | ||
350 | crypto_iv.method = CRYPTO_NONE; | ||
351 | |||
352 | while(1) | ||
353 | { | ||
354 | static struct option long_options[] = | ||
355 | { | ||
356 | {"help", no_argument, 0, '?'}, | ||
357 | {"debug", no_argument, 0, 'd'}, | ||
358 | {"add-key", required_argument, 0, 'a'}, | ||
359 | {"real-key", required_argument, 0, 'r'}, | ||
360 | {"crypto-iv", required_argument, 0, 'i'}, | ||
361 | {0, 0, 0, 0} | ||
362 | }; | ||
363 | |||
364 | int c = getopt_long(argc, argv, "?do:c:k:za:", long_options, NULL); | ||
365 | if(c == -1) | ||
366 | break; | ||
367 | switch(c) | ||
368 | { | ||
369 | case 'd': | ||
370 | g_debug = true; | ||
371 | break; | ||
372 | case '?': | ||
373 | usage(); | ||
374 | break; | ||
375 | case 'o': | ||
376 | output_filename = optarg; | ||
377 | break; | ||
378 | case 'c': | ||
379 | cmd_filename = optarg; | ||
380 | break; | ||
381 | case 'k': | ||
382 | { | ||
383 | add_keys_from_file(optarg); | ||
384 | break; | ||
385 | } | ||
386 | case 'z': | ||
387 | { | ||
388 | add_keys(&g_zero_key, 1); | ||
389 | break; | ||
390 | } | ||
391 | case 'a': | ||
392 | case 'r': | ||
393 | case 'i': | ||
394 | { | ||
395 | struct crypto_key_t key; | ||
396 | char *s = optarg; | ||
397 | if(!parse_key(&s, &key)) | ||
398 | bug("Invalid key/iv specified as argument"); | ||
399 | if(*s != 0) | ||
400 | bug("Trailing characters after key/iv specified as argument"); | ||
401 | if(c == 'r') | ||
402 | memcpy(&real_key, &key, sizeof(key)); | ||
403 | else if(c == 'i') | ||
404 | memcpy(&crypto_iv, &key, sizeof(key)); | ||
405 | else | ||
406 | add_keys(&key, 1); | ||
407 | break; | ||
408 | } | ||
409 | default: | ||
410 | abort(); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | if(!cmd_filename) | ||
415 | bug("You must specify a command file\n"); | ||
416 | if(!output_filename) | ||
417 | bug("You must specify an output file\n"); | ||
418 | |||
419 | g_extern = &argv[optind]; | ||
420 | g_extern_count = argc - optind; | ||
421 | |||
422 | if(g_debug) | ||
423 | { | ||
424 | printf("key: %d\n", g_nr_keys); | ||
425 | for(int i = 0; i < g_nr_keys; i++) | ||
426 | { | ||
427 | printf(" "); | ||
428 | print_key(&g_key_array[i], true); | ||
429 | } | ||
430 | |||
431 | for(int i = 0; i < g_extern_count; i++) | ||
432 | printf("extern(%d)=%s\n", i, g_extern[i]); | ||
433 | } | ||
434 | |||
435 | struct cmd_file_t *cmd_file = db_parse_file(cmd_filename); | ||
436 | struct sb_file_t *sb_file = apply_cmd_file(cmd_file); | ||
437 | db_free(cmd_file); | ||
438 | |||
439 | if(real_key.method == CRYPTO_KEY) | ||
440 | { | ||
441 | sb_file->override_real_key = true; | ||
442 | memcpy(sb_file->real_key, real_key.u.key, 16); | ||
443 | } | ||
444 | if(crypto_iv.method == CRYPTO_KEY) | ||
445 | { | ||
446 | sb_file->override_crypto_iv = true; | ||
447 | memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16); | ||
448 | } | ||
449 | |||
450 | /* fill with default parameters since there is no command file support for them */ | ||
451 | sb_file->drive_tag = 0; | ||
452 | sb_file->first_boot_sec_id = sb_file->sections[0].identifier; | ||
453 | sb_file->flags = 0; | ||
454 | sb_file->minor_version = 1; | ||
455 | |||
456 | sb_write_file(sb_file, output_filename); | ||
457 | sb_free(sb_file); | ||
458 | clear_keys(); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdlib.h> | ||
22 | #include <stdio.h> | ||
23 | #include <time.h> | ||
24 | #include <ctype.h> | ||
25 | #include "misc.h" | ||
26 | |||
27 | bool g_debug = false; | ||
28 | |||
29 | /** | ||
30 | * Misc | ||
31 | */ | ||
32 | |||
33 | void *memdup(void *p, size_t len) | ||
34 | { | ||
35 | void *cpy = xmalloc(len); | ||
36 | memcpy(cpy, p, len); | ||
37 | return cpy; | ||
38 | } | ||
39 | |||
40 | void generate_random_data(void *buf, size_t sz) | ||
41 | { | ||
42 | FILE *rand_fd = fopen("/dev/urandom", "rb"); | ||
43 | if(rand_fd == NULL) | ||
44 | bugp("failed to open /dev/urandom"); | ||
45 | if(fread(buf, 1, sz, rand_fd) != sz) | ||
46 | bugp("failed to read /dev/urandom"); | ||
47 | fclose(rand_fd); | ||
48 | } | ||
49 | |||
50 | void *xmalloc(size_t s) | ||
51 | { | ||
52 | void * r = malloc(s); | ||
53 | if(!r) bugp("malloc"); | ||
54 | return r; | ||
55 | } | ||
56 | |||
57 | int convxdigit(char digit, byte *val) | ||
58 | { | ||
59 | if(digit >= '0' && digit <= '9') | ||
60 | { | ||
61 | *val = digit - '0'; | ||
62 | return 0; | ||
63 | } | ||
64 | else if(digit >= 'A' && digit <= 'F') | ||
65 | { | ||
66 | *val = digit - 'A' + 10; | ||
67 | return 0; | ||
68 | } | ||
69 | else if(digit >= 'a' && digit <= 'f') | ||
70 | { | ||
71 | *val = digit - 'a' + 10; | ||
72 | return 0; | ||
73 | } | ||
74 | else | ||
75 | return 1; | ||
76 | } | ||
77 | |||
78 | /* helper function to augment an array, free old array */ | ||
79 | void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt) | ||
80 | { | ||
81 | void *p = xmalloc(elem_sz * (cnt + aug_cnt)); | ||
82 | memcpy(p, arr, elem_sz * cnt); | ||
83 | memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt); | ||
84 | free(arr); | ||
85 | return p; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * Key file parsing | ||
90 | */ | ||
91 | int g_nr_keys; | ||
92 | key_array_t g_key_array; | ||
93 | |||
94 | bool parse_key(char **pstr, struct crypto_key_t *key) | ||
95 | { | ||
96 | char *str = *pstr; | ||
97 | /* ignore spaces */ | ||
98 | while(isspace(*str)) | ||
99 | str++; | ||
100 | /* CRYPTO_KEY: 32 hex characters | ||
101 | * CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers */ | ||
102 | if(isxdigit(str[0])) | ||
103 | { | ||
104 | if(strlen(str) < 32) | ||
105 | return false; | ||
106 | for(int j = 0; j < 16; j++) | ||
107 | { | ||
108 | byte a, b; | ||
109 | if(convxdigit(str[2 * j], &a) || convxdigit(str[2 * j + 1], &b)) | ||
110 | return false; | ||
111 | key->u.key[j] = (a << 4) | b; | ||
112 | } | ||
113 | /* skip key */ | ||
114 | *pstr = str + 32; | ||
115 | key->method = CRYPTO_KEY; | ||
116 | return true; | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | const char *prefix = "usbotp("; | ||
121 | if(strlen(str) < strlen(prefix)) | ||
122 | return false; | ||
123 | if(strncmp(str, prefix, strlen(prefix)) != 0) | ||
124 | return false; | ||
125 | str += strlen(prefix); | ||
126 | /* vid */ | ||
127 | long vid = strtol(str, &str, 16); | ||
128 | if(vid < 0 || vid > 0xffff) | ||
129 | return false; | ||
130 | if(*str++ != ':') | ||
131 | return false; | ||
132 | /* pid */ | ||
133 | long pid = strtol(str, &str, 16); | ||
134 | if(pid < 0 || pid > 0xffff) | ||
135 | return false; | ||
136 | if(*str++ != ')') | ||
137 | return false; | ||
138 | *pstr = str; | ||
139 | key->method = CRYPTO_USBOTP; | ||
140 | key->u.vid_pid = vid << 16 | pid; | ||
141 | return true; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void add_keys(key_array_t ka, int kac) | ||
146 | { | ||
147 | key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t)); | ||
148 | memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t)); | ||
149 | memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t)); | ||
150 | free(g_key_array); | ||
151 | g_key_array = new_ka; | ||
152 | g_nr_keys += kac; | ||
153 | } | ||
154 | |||
155 | void clear_keys() | ||
156 | { | ||
157 | free(g_key_array); | ||
158 | g_nr_keys = 0; | ||
159 | } | ||
160 | |||
161 | void add_keys_from_file(const char *key_file) | ||
162 | { | ||
163 | int size; | ||
164 | FILE *fd = fopen(key_file, "r"); | ||
165 | if(fd == NULL) | ||
166 | bug("opening key file failed"); | ||
167 | fseek(fd, 0, SEEK_END); | ||
168 | size = ftell(fd); | ||
169 | fseek(fd, 0, SEEK_SET); | ||
170 | char *buf = xmalloc(size + 1); | ||
171 | if(fread(buf, 1, size, fd) != (size_t)size) | ||
172 | bug("reading key file"); | ||
173 | buf[size] = 0; | ||
174 | fclose(fd); | ||
175 | |||
176 | if(g_debug) | ||
177 | printf("Parsing key file '%s'...\n", key_file); | ||
178 | char *p = buf; | ||
179 | while(1) | ||
180 | { | ||
181 | struct crypto_key_t k; | ||
182 | /* parse key */ | ||
183 | if(!parse_key(&p, &k)) | ||
184 | bug("invalid key file"); | ||
185 | if(g_debug) | ||
186 | { | ||
187 | printf("Add key: "); | ||
188 | print_key(&k, true); | ||
189 | } | ||
190 | add_keys(&k, 1); | ||
191 | /* request at least one space character before next key, or end of file */ | ||
192 | if(*p != 0 && !isspace(*p)) | ||
193 | bug("invalid key file"); | ||
194 | /* skip whitespace */ | ||
195 | while(isspace(*p)) | ||
196 | p++; | ||
197 | if(*p == 0) | ||
198 | break; | ||
199 | } | ||
200 | free(buf); | ||
201 | } | ||
202 | |||
203 | void print_hex(byte *data, int len, bool newline) | ||
204 | { | ||
205 | for(int i = 0; i < len; i++) | ||
206 | printf("%02X ", data[i]); | ||
207 | if(newline) | ||
208 | printf("\n"); | ||
209 | } | ||
210 | |||
211 | void print_key(struct crypto_key_t *key, bool newline) | ||
212 | { | ||
213 | switch(key->method) | ||
214 | { | ||
215 | case CRYPTO_KEY: | ||
216 | print_hex(key->u.key, 16, false); | ||
217 | break; | ||
218 | case CRYPTO_USBOTP: | ||
219 | printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff); | ||
220 | break; | ||
221 | case CRYPTO_NONE: | ||
222 | printf("none"); | ||
223 | break; | ||
224 | } | ||
225 | if(newline) | ||
226 | printf("\n"); | ||
227 | } | ||
228 | |||
229 | char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; | ||
230 | |||
231 | char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; | ||
232 | char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; | ||
233 | char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; | ||
234 | char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; | ||
235 | char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; | ||
236 | |||
237 | static bool g_color_enable = true; | ||
238 | |||
239 | void enable_color(bool enable) | ||
240 | { | ||
241 | g_color_enable = enable; | ||
242 | } | ||
243 | |||
244 | void color(color_t c) | ||
245 | { | ||
246 | if(g_color_enable) | ||
247 | printf("%s", (char *)c); | ||
248 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __MISC_H__ | ||
22 | #define __MISC_H__ | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | #include "crypto.h" | ||
26 | |||
27 | #define _STR(a) #a | ||
28 | #define STR(a) _STR(a) | ||
29 | |||
30 | #define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) | ||
31 | #define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) | ||
32 | |||
33 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | ||
34 | |||
35 | extern bool g_debug; | ||
36 | |||
37 | typedef struct crypto_key_t *key_array_t; | ||
38 | int g_nr_keys; | ||
39 | key_array_t g_key_array; | ||
40 | |||
41 | void *memdup(void *p, size_t len); | ||
42 | void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt); | ||
43 | void generate_random_data(void *buf, size_t sz); | ||
44 | void *xmalloc(size_t s); | ||
45 | int convxdigit(char digit, byte *val); | ||
46 | void print_hex(byte *data, int len, bool newline); | ||
47 | void add_keys(key_array_t ka, int kac); | ||
48 | bool parse_key(char **str, struct crypto_key_t *key); | ||
49 | void add_keys_from_file(const char *key_file); | ||
50 | void print_key(struct crypto_key_t *key, bool newline); | ||
51 | void clear_keys(); | ||
52 | |||
53 | typedef char color_t[]; | ||
54 | |||
55 | extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; | ||
56 | void color(color_t c); | ||
57 | void enable_color(bool enable); | ||
58 | |||
59 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdio.h> | ||
22 | #include <time.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <ctype.h> | ||
25 | #include "misc.h" | ||
26 | #include "crypto.h" | ||
27 | #include "sb.h" | ||
28 | |||
29 | static void fill_gaps(struct sb_file_t *sb) | ||
30 | { | ||
31 | for(int i = 0; i < sb->nr_sections; i++) | ||
32 | { | ||
33 | struct sb_section_t *sec = &sb->sections[i]; | ||
34 | for(int j = 0; j < sec->nr_insts; j++) | ||
35 | { | ||
36 | struct sb_inst_t *inst = &sec->insts[j]; | ||
37 | if(inst->inst != SB_INST_LOAD) | ||
38 | continue; | ||
39 | inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size; | ||
40 | /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */ | ||
41 | inst->padding = xmalloc(15); | ||
42 | generate_random_data(inst->padding, 15); | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | |||
47 | static void compute_sb_offsets(struct sb_file_t *sb) | ||
48 | { | ||
49 | sb->image_size = 0; | ||
50 | /* sb header */ | ||
51 | sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE; | ||
52 | /* sections headers */ | ||
53 | sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE; | ||
54 | /* key dictionary */ | ||
55 | sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE; | ||
56 | /* sections */ | ||
57 | for(int i = 0; i < sb->nr_sections; i++) | ||
58 | { | ||
59 | /* each section has a preliminary TAG command */ | ||
60 | sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE; | ||
61 | /* we might need to pad the section so compute next alignment */ | ||
62 | uint32_t alignment = BLOCK_SIZE; | ||
63 | if((i + 1) < sb->nr_sections) | ||
64 | alignment = sb->sections[i + 1].alignment; | ||
65 | alignment /= BLOCK_SIZE; /* alignment in block sizes */ | ||
66 | |||
67 | struct sb_section_t *sec = &sb->sections[i]; | ||
68 | sec->sec_size = 0; | ||
69 | |||
70 | if(g_debug) | ||
71 | { | ||
72 | printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot", | ||
73 | sec->identifier); | ||
74 | if(sec->is_cleartext) | ||
75 | printf(" (cleartext)"); | ||
76 | printf("\n"); | ||
77 | } | ||
78 | |||
79 | sec->file_offset = sb->image_size; | ||
80 | for(int j = 0; j < sec->nr_insts; j++) | ||
81 | { | ||
82 | struct sb_inst_t *inst = &sec->insts[j]; | ||
83 | if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP) | ||
84 | { | ||
85 | if(g_debug) | ||
86 | printf(" %s | addr=0x%08x | arg=0x%08x\n", | ||
87 | inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument); | ||
88 | sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; | ||
89 | sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; | ||
90 | } | ||
91 | else if(inst->inst == SB_INST_FILL) | ||
92 | { | ||
93 | if(g_debug) | ||
94 | printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n", | ||
95 | inst->addr, inst->size, inst->pattern); | ||
96 | sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; | ||
97 | sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; | ||
98 | } | ||
99 | else if(inst->inst == SB_INST_LOAD) | ||
100 | { | ||
101 | if(g_debug) | ||
102 | printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size); | ||
103 | /* load header */ | ||
104 | sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; | ||
105 | sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; | ||
106 | /* data + alignment */ | ||
107 | sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE; | ||
108 | sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE; | ||
109 | } | ||
110 | else if(inst->inst == SB_INST_MODE) | ||
111 | { | ||
112 | if(g_debug) | ||
113 | printf(" MODE | mod=0x%08x", inst->addr); | ||
114 | sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; | ||
115 | sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; | ||
116 | } | ||
117 | else if(inst->inst == SB_INST_DATA) | ||
118 | { | ||
119 | if(g_debug) | ||
120 | printf(" DATA | size=0x%08x\n", inst->size); | ||
121 | sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; | ||
122 | sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; | ||
123 | } | ||
124 | else | ||
125 | bug("die on inst %d\n", inst->inst); | ||
126 | } | ||
127 | /* we need to make sure next section starts on the right alignment. | ||
128 | * Since each section starts with a boot tag, we thus need to ensure | ||
129 | * that this sections ends at adress X such that X+BLOCK_SIZE is | ||
130 | * a multiple of the alignment. | ||
131 | * For data sections, we just add random data, otherwise we add nops */ | ||
132 | uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment); | ||
133 | if(missing_sz != alignment) | ||
134 | { | ||
135 | struct sb_inst_t *aug_insts; | ||
136 | int nr_aug_insts = 0; | ||
137 | |||
138 | if(sb->sections[i].is_data) | ||
139 | { | ||
140 | nr_aug_insts = 1; | ||
141 | aug_insts = xmalloc(sizeof(struct sb_inst_t)); | ||
142 | memset(aug_insts, 0, sizeof(struct sb_inst_t)); | ||
143 | aug_insts[0].inst = SB_INST_DATA; | ||
144 | aug_insts[0].size = missing_sz * BLOCK_SIZE; | ||
145 | aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE); | ||
146 | generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE); | ||
147 | if(g_debug) | ||
148 | printf(" DATA | size=0x%08x\n", aug_insts[0].size); | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | nr_aug_insts = missing_sz; | ||
153 | aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts); | ||
154 | memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts); | ||
155 | for(int j = 0; j < nr_aug_insts; j++) | ||
156 | { | ||
157 | aug_insts[j].inst = SB_INST_NOP; | ||
158 | if(g_debug) | ||
159 | printf(" NOOP\n"); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t), | ||
164 | sb->sections[i].nr_insts, aug_insts, nr_aug_insts); | ||
165 | sb->sections[i].nr_insts += nr_aug_insts; | ||
166 | free(aug_insts); | ||
167 | |||
168 | /* augment image and section size */ | ||
169 | sb->image_size += missing_sz; | ||
170 | sec->sec_size += missing_sz; | ||
171 | } | ||
172 | } | ||
173 | /* final signature */ | ||
174 | sb->image_size += 2; | ||
175 | } | ||
176 | |||
177 | static uint64_t generate_timestamp() | ||
178 | { | ||
179 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
180 | time_t t = time(NULL) - mktime(&tm_base); | ||
181 | return (uint64_t)t * 1000000L; | ||
182 | } | ||
183 | |||
184 | static uint16_t swap16(uint16_t t) | ||
185 | { | ||
186 | return (t << 8) | (t >> 8); | ||
187 | } | ||
188 | |||
189 | static void fix_version(struct sb_version_t *ver) | ||
190 | { | ||
191 | ver->major = swap16(ver->major); | ||
192 | ver->minor = swap16(ver->minor); | ||
193 | ver->revision = swap16(ver->revision); | ||
194 | } | ||
195 | |||
196 | static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) | ||
197 | { | ||
198 | struct sha_1_params_t sha_1_params; | ||
199 | |||
200 | sb_hdr->signature[0] = 'S'; | ||
201 | sb_hdr->signature[1] = 'T'; | ||
202 | sb_hdr->signature[2] = 'M'; | ||
203 | sb_hdr->signature[3] = 'P'; | ||
204 | sb_hdr->major_ver = IMAGE_MAJOR_VERSION; | ||
205 | sb_hdr->minor_ver = IMAGE_MINOR_VERSION; | ||
206 | sb_hdr->flags = 0; | ||
207 | sb_hdr->image_size = sb->image_size; | ||
208 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; | ||
209 | sb_hdr->first_boot_sec_id = sb->first_boot_sec_id; | ||
210 | sb_hdr->nr_keys = g_nr_keys; | ||
211 | sb_hdr->nr_sections = sb->nr_sections; | ||
212 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; | ||
213 | sb_hdr->key_dict_off = sb_hdr->header_size + | ||
214 | sb_hdr->sec_hdr_size * sb_hdr->nr_sections; | ||
215 | sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off + | ||
216 | sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; | ||
217 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); | ||
218 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); | ||
219 | /* Version 1.0 has 6 bytes of random padding, | ||
220 | * Version 1.1 requires the last 4 bytes to be 'sgtl' */ | ||
221 | if(sb->minor_version >= 1) | ||
222 | memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4); | ||
223 | |||
224 | sb_hdr->timestamp = generate_timestamp(); | ||
225 | sb_hdr->product_ver = sb->product_ver; | ||
226 | fix_version(&sb_hdr->product_ver); | ||
227 | sb_hdr->component_ver = sb->component_ver; | ||
228 | fix_version(&sb_hdr->component_ver); | ||
229 | sb_hdr->drive_tag = sb->drive_tag; | ||
230 | |||
231 | sha_1_init(&sha_1_params); | ||
232 | sha_1_update(&sha_1_params, &sb_hdr->signature[0], | ||
233 | sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header)); | ||
234 | sha_1_finish(&sha_1_params); | ||
235 | sha_1_output(&sha_1_params, sb_hdr->sha1_header); | ||
236 | } | ||
237 | |||
238 | static void produce_sb_section_header(struct sb_section_t *sec, | ||
239 | struct sb_section_header_t *sec_hdr) | ||
240 | { | ||
241 | sec_hdr->identifier = sec->identifier; | ||
242 | sec_hdr->offset = sec->file_offset; | ||
243 | sec_hdr->size = sec->sec_size; | ||
244 | sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) | ||
245 | | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); | ||
246 | } | ||
247 | |||
248 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) | ||
249 | { | ||
250 | uint8_t sum = 90; | ||
251 | byte *ptr = (byte *)hdr; | ||
252 | for(int i = 1; i < 16; i++) | ||
253 | sum += ptr[i]; | ||
254 | return sum; | ||
255 | } | ||
256 | |||
257 | static void produce_section_tag_cmd(struct sb_section_t *sec, | ||
258 | struct sb_instruction_tag_t *tag, bool is_last) | ||
259 | { | ||
260 | tag->hdr.opcode = SB_INST_TAG; | ||
261 | tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0; | ||
262 | tag->identifier = sec->identifier; | ||
263 | tag->len = sec->sec_size; | ||
264 | tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) | ||
265 | | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); | ||
266 | tag->hdr.checksum = instruction_checksum(&tag->hdr); | ||
267 | } | ||
268 | |||
269 | void produce_sb_instruction(struct sb_inst_t *inst, | ||
270 | struct sb_instruction_common_t *cmd) | ||
271 | { | ||
272 | memset(cmd, 0, sizeof(struct sb_instruction_common_t)); | ||
273 | cmd->hdr.opcode = inst->inst; | ||
274 | switch(inst->inst) | ||
275 | { | ||
276 | case SB_INST_CALL: | ||
277 | case SB_INST_JUMP: | ||
278 | cmd->addr = inst->addr; | ||
279 | cmd->data = inst->argument; | ||
280 | break; | ||
281 | case SB_INST_FILL: | ||
282 | cmd->addr = inst->addr; | ||
283 | cmd->len = inst->size; | ||
284 | cmd->data = inst->pattern; | ||
285 | break; | ||
286 | case SB_INST_LOAD: | ||
287 | cmd->addr = inst->addr; | ||
288 | cmd->len = inst->size; | ||
289 | cmd->data = crc_continue(crc(inst->data, inst->size), | ||
290 | inst->padding, inst->padding_size); | ||
291 | break; | ||
292 | case SB_INST_MODE: | ||
293 | cmd->data = inst->addr; | ||
294 | break; | ||
295 | case SB_INST_NOP: | ||
296 | break; | ||
297 | default: | ||
298 | bug("die\n"); | ||
299 | } | ||
300 | cmd->hdr.checksum = instruction_checksum(&cmd->hdr); | ||
301 | } | ||
302 | |||
303 | enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename) | ||
304 | { | ||
305 | struct crypto_key_t real_key; | ||
306 | real_key.method = CRYPTO_KEY; | ||
307 | byte crypto_iv[16]; | ||
308 | byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys); | ||
309 | /* init CBC-MACs */ | ||
310 | for(int i = 0; i < g_nr_keys; i++) | ||
311 | memset(cbc_macs[i], 0, 16); | ||
312 | |||
313 | fill_gaps(sb); | ||
314 | compute_sb_offsets(sb); | ||
315 | |||
316 | generate_random_data(real_key.u.key, 16); | ||
317 | |||
318 | /* global SHA-1 */ | ||
319 | struct sha_1_params_t file_sha1; | ||
320 | sha_1_init(&file_sha1); | ||
321 | /* produce and write header */ | ||
322 | struct sb_header_t sb_hdr; | ||
323 | produce_sb_header(sb, &sb_hdr); | ||
324 | /* allocate image */ | ||
325 | byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE); | ||
326 | byte *buf_p = buf; | ||
327 | #define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0) | ||
328 | |||
329 | sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr)); | ||
330 | write(&sb_hdr, sizeof(sb_hdr)); | ||
331 | |||
332 | memcpy(crypto_iv, &sb_hdr, 16); | ||
333 | |||
334 | /* update CBC-MACs */ | ||
335 | for(int i = 0; i < g_nr_keys; i++) | ||
336 | crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i], | ||
337 | cbc_macs[i], &cbc_macs[i], 1); | ||
338 | |||
339 | /* produce and write section headers */ | ||
340 | for(int i = 0; i < sb_hdr.nr_sections; i++) | ||
341 | { | ||
342 | struct sb_section_header_t sb_sec_hdr; | ||
343 | produce_sb_section_header(&sb->sections[i], &sb_sec_hdr); | ||
344 | sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr)); | ||
345 | write(&sb_sec_hdr, sizeof(sb_sec_hdr)); | ||
346 | /* update CBC-MACs */ | ||
347 | for(int j = 0; j < g_nr_keys; j++) | ||
348 | crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE, | ||
349 | &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1); | ||
350 | } | ||
351 | /* produce key dictionary */ | ||
352 | for(int i = 0; i < g_nr_keys; i++) | ||
353 | { | ||
354 | struct sb_key_dictionary_entry_t entry; | ||
355 | memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16); | ||
356 | crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i], | ||
357 | crypto_iv, NULL, 1); | ||
358 | |||
359 | write(&entry, sizeof(entry)); | ||
360 | sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry)); | ||
361 | } | ||
362 | |||
363 | free(cbc_macs); | ||
364 | |||
365 | /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */ | ||
366 | /* Image crafting, don't use it unless you understand what you do */ | ||
367 | if(sb->override_real_key) | ||
368 | memcpy(real_key.u.key, sb->real_key, 16); | ||
369 | if(sb->override_crypto_iv) | ||
370 | memcpy(crypto_iv, sb->crypto_iv, 16); | ||
371 | /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */ | ||
372 | if(g_debug) | ||
373 | { | ||
374 | printf("Real key: "); | ||
375 | for(int j = 0; j < 16; j++) | ||
376 | printf("%02x", real_key.u.key[j]); | ||
377 | printf("\n"); | ||
378 | printf("IV : "); | ||
379 | for(int j = 0; j < 16; j++) | ||
380 | printf("%02x", crypto_iv[j]); | ||
381 | printf("\n"); | ||
382 | } | ||
383 | /* produce sections data */ | ||
384 | for(int i = 0; i< sb_hdr.nr_sections; i++) | ||
385 | { | ||
386 | /* produce tag command */ | ||
387 | struct sb_instruction_tag_t tag_cmd; | ||
388 | produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections); | ||
389 | if(g_nr_keys > 0) | ||
390 | crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE, | ||
391 | &real_key, crypto_iv, NULL, 1); | ||
392 | sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); | ||
393 | write(&tag_cmd, sizeof(tag_cmd)); | ||
394 | /* produce other commands */ | ||
395 | byte cur_cbc_mac[16]; | ||
396 | memcpy(cur_cbc_mac, crypto_iv, 16); | ||
397 | for(int j = 0; j < sb->sections[i].nr_insts; j++) | ||
398 | { | ||
399 | struct sb_inst_t *inst = &sb->sections[i].insts[j]; | ||
400 | /* command */ | ||
401 | if(inst->inst != SB_INST_DATA) | ||
402 | { | ||
403 | struct sb_instruction_common_t cmd; | ||
404 | produce_sb_instruction(inst, &cmd); | ||
405 | if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) | ||
406 | crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, | ||
407 | &real_key, cur_cbc_mac, &cur_cbc_mac, 1); | ||
408 | sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); | ||
409 | write(&cmd, sizeof(cmd)); | ||
410 | } | ||
411 | /* data */ | ||
412 | if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA) | ||
413 | { | ||
414 | uint32_t sz = inst->size + inst->padding_size; | ||
415 | byte *data = xmalloc(sz); | ||
416 | memcpy(data, inst->data, inst->size); | ||
417 | memcpy(data + inst->size, inst->padding, inst->padding_size); | ||
418 | if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) | ||
419 | crypto_cbc(data, data, sz / BLOCK_SIZE, | ||
420 | &real_key, cur_cbc_mac, &cur_cbc_mac, 1); | ||
421 | sha_1_update(&file_sha1, data, sz); | ||
422 | write(data, sz); | ||
423 | free(data); | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | /* write file SHA-1 */ | ||
428 | byte final_sig[32]; | ||
429 | sha_1_finish(&file_sha1); | ||
430 | sha_1_output(&file_sha1, final_sig); | ||
431 | generate_random_data(final_sig + 20, 12); | ||
432 | if(g_nr_keys > 0) | ||
433 | crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1); | ||
434 | write(final_sig, 32); | ||
435 | |||
436 | if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE) | ||
437 | bug("SB image buffer was not entirely filled !"); | ||
438 | |||
439 | FILE *fd = fopen(filename, "wb"); | ||
440 | if(fd == NULL) | ||
441 | return SB_OPEN_ERROR; | ||
442 | if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1) | ||
443 | { | ||
444 | free(buf); | ||
445 | return SB_WRITE_ERROR; | ||
446 | } | ||
447 | fclose(fd); | ||
448 | free(buf); | ||
449 | |||
450 | return SB_SUCCESS; | ||
451 | } | ||
452 | |||
453 | static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf, | ||
454 | int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err) | ||
455 | { | ||
456 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
457 | #define fatal(e, ...) \ | ||
458 | do { if(err) *err = e; \ | ||
459 | cprintf(u, true, GREY, __VA_ARGS__); \ | ||
460 | sb_free_section(*sec); \ | ||
461 | free(sec); \ | ||
462 | return NULL; } while(0) | ||
463 | |||
464 | struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t)); | ||
465 | memset(sec, 0, sizeof(struct sb_section_t)); | ||
466 | sec->identifier = id; | ||
467 | sec->is_data = data_sec; | ||
468 | sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE; | ||
469 | |||
470 | if(data_sec) | ||
471 | { | ||
472 | sec->nr_insts = 1; | ||
473 | sec->insts = xmalloc(sizeof(struct sb_inst_t)); | ||
474 | memset(sec->insts, 0, sizeof(struct sb_inst_t)); | ||
475 | sec->insts->inst = SB_INST_DATA; | ||
476 | sec->insts->size = size; | ||
477 | sec->insts->data = memdup(buf, size); | ||
478 | return sec; | ||
479 | } | ||
480 | |||
481 | /* Pretty print the content */ | ||
482 | int pos = 0; | ||
483 | while(pos < size) | ||
484 | { | ||
485 | struct sb_inst_t inst; | ||
486 | memset(&inst, 0, sizeof(inst)); | ||
487 | |||
488 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; | ||
489 | inst.inst = hdr->opcode; | ||
490 | |||
491 | printf(OFF, "%s", indent); | ||
492 | uint8_t checksum = instruction_checksum(hdr); | ||
493 | if(checksum != hdr->checksum) | ||
494 | fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum"); | ||
495 | if(hdr->flags != 0) | ||
496 | { | ||
497 | printf(GREY, "["); | ||
498 | printf(BLUE, "f=%x", hdr->flags); | ||
499 | printf(GREY, "] "); | ||
500 | } | ||
501 | if(hdr->opcode == SB_INST_LOAD) | ||
502 | { | ||
503 | struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; | ||
504 | inst.size = load->len; | ||
505 | inst.addr = load->addr; | ||
506 | inst.data = memdup(load + 1, load->len); | ||
507 | |||
508 | printf(RED, "LOAD"); | ||
509 | printf(OFF, " | "); | ||
510 | printf(BLUE, "addr=0x%08x", load->addr); | ||
511 | printf(OFF, " | "); | ||
512 | printf(GREEN, "len=0x%08x", load->len); | ||
513 | printf(OFF, " | "); | ||
514 | printf(YELLOW, "crc=0x%08x", load->crc); | ||
515 | /* data is padded to 16-byte boundary with random data and crc'ed with it */ | ||
516 | uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], | ||
517 | ROUND_UP(load->len, 16)); | ||
518 | if(load->crc == computed_crc) | ||
519 | printf(RED, " Ok\n"); | ||
520 | else | ||
521 | { | ||
522 | printf(RED, " Failed (crc=0x%08x)\n", computed_crc); | ||
523 | fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n"); | ||
524 | } | ||
525 | |||
526 | pos += load->len + sizeof(struct sb_instruction_load_t); | ||
527 | } | ||
528 | else if(hdr->opcode == SB_INST_FILL) | ||
529 | { | ||
530 | struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; | ||
531 | inst.pattern = fill->pattern; | ||
532 | inst.size = fill->len; | ||
533 | inst.addr = fill->addr; | ||
534 | |||
535 | printf(RED, "FILL"); | ||
536 | printf(OFF, " | "); | ||
537 | printf(BLUE, "addr=0x%08x", fill->addr); | ||
538 | printf(OFF, " | "); | ||
539 | printf(GREEN, "len=0x%08x", fill->len); | ||
540 | printf(OFF, " | "); | ||
541 | printf(YELLOW, "pattern=0x%08x\n", fill->pattern); | ||
542 | |||
543 | pos += sizeof(struct sb_instruction_fill_t); | ||
544 | } | ||
545 | else if(hdr->opcode == SB_INST_CALL || | ||
546 | hdr->opcode == SB_INST_JUMP) | ||
547 | { | ||
548 | int is_call = (hdr->opcode == SB_INST_CALL); | ||
549 | struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; | ||
550 | inst.addr = call->addr; | ||
551 | inst.argument = call->arg; | ||
552 | |||
553 | if(is_call) | ||
554 | printf(RED, "CALL"); | ||
555 | else | ||
556 | printf(RED, "JUMP"); | ||
557 | printf(OFF, " | "); | ||
558 | printf(BLUE, "addr=0x%08x", call->addr); | ||
559 | printf(OFF, " | "); | ||
560 | printf(GREEN, "arg=0x%08x\n", call->arg); | ||
561 | |||
562 | pos += sizeof(struct sb_instruction_call_t); | ||
563 | } | ||
564 | else if(hdr->opcode == SB_INST_MODE) | ||
565 | { | ||
566 | struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; | ||
567 | inst.argument = mode->mode; | ||
568 | |||
569 | printf(RED, "MODE"); | ||
570 | printf(OFF, " | "); | ||
571 | printf(BLUE, "mod=0x%08x\n", mode->mode); | ||
572 | |||
573 | pos += sizeof(struct sb_instruction_mode_t); | ||
574 | } | ||
575 | else if(hdr->opcode == SB_INST_NOP) | ||
576 | { | ||
577 | printf(RED, "NOOP\n"); | ||
578 | pos += sizeof(struct sb_instruction_mode_t); | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); | ||
583 | break; | ||
584 | } | ||
585 | |||
586 | sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1); | ||
587 | pos = ROUND_UP(pos, BLOCK_SIZE); | ||
588 | } | ||
589 | |||
590 | return sec; | ||
591 | #undef printf | ||
592 | #undef fatal | ||
593 | } | ||
594 | |||
595 | void sb_fill_section_name(char name[5], uint32_t identifier) | ||
596 | { | ||
597 | name[0] = (identifier >> 24) & 0xff; | ||
598 | name[1] = (identifier >> 16) & 0xff; | ||
599 | name[2] = (identifier >> 8) & 0xff; | ||
600 | name[3] = identifier & 0xff; | ||
601 | for(int i = 0; i < 4; i++) | ||
602 | if(!isprint(name[i])) | ||
603 | name[i] = '_'; | ||
604 | name[4] = 0; | ||
605 | } | ||
606 | |||
607 | static uint32_t guess_alignment(uint32_t off) | ||
608 | { | ||
609 | /* find greatest power of two which divides the offset */ | ||
610 | if(off == 0) | ||
611 | return 1; | ||
612 | uint32_t a = 1; | ||
613 | while(off % (2 * a) == 0) | ||
614 | a *= 2; | ||
615 | return a; | ||
616 | } | ||
617 | |||
618 | struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, | ||
619 | sb_color_printf cprintf, enum sb_error_t *err) | ||
620 | { | ||
621 | uint8_t *buf = NULL; | ||
622 | struct sb_file_t *sb_file = NULL; | ||
623 | |||
624 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
625 | #define fatal(e, ...) \ | ||
626 | do { if(err) *err = e; \ | ||
627 | cprintf(u, true, GREY, __VA_ARGS__); \ | ||
628 | free(buf); \ | ||
629 | sb_free(sb_file); \ | ||
630 | return NULL; } while(0) | ||
631 | #define print_hex(c, p, len, nl) \ | ||
632 | do { printf(c, ""); print_hex(p, len, nl); } while(0) | ||
633 | |||
634 | FILE *f = fopen(filename, "rb"); | ||
635 | if(f == NULL) | ||
636 | fatal(SB_OPEN_ERROR, "Cannot open file for reading\n"); | ||
637 | fseek(f, 0, SEEK_END); | ||
638 | long filesize = ftell(f); | ||
639 | fseek(f, 0, SEEK_SET); | ||
640 | buf = xmalloc(filesize); | ||
641 | if(fread(buf, filesize, 1, f) != 1) | ||
642 | { | ||
643 | fclose(f); | ||
644 | fatal(SB_READ_ERROR, "Cannot read file\n"); | ||
645 | } | ||
646 | fclose(f); | ||
647 | |||
648 | struct sha_1_params_t sha_1_params; | ||
649 | sb_file = xmalloc(sizeof(struct sb_file_t)); | ||
650 | memset(sb_file, 0, sizeof(struct sb_file_t)); | ||
651 | struct sb_header_t *sb_header = (struct sb_header_t *)buf; | ||
652 | |||
653 | sb_file->image_size = sb_header->image_size; | ||
654 | sb_file->minor_version = sb_header->minor_ver; | ||
655 | sb_file->flags = sb_header->flags; | ||
656 | sb_file->drive_tag = sb_header->drive_tag; | ||
657 | sb_file->first_boot_sec_id = sb_header->first_boot_sec_id; | ||
658 | |||
659 | if(memcmp(sb_header->signature, "STMP", 4) != 0) | ||
660 | fatal(SB_FORMAT_ERROR, "Bad signature\n"); | ||
661 | if(sb_header->image_size * BLOCK_SIZE > filesize) | ||
662 | fatal(SB_FORMAT_ERROR, "File too small"); | ||
663 | if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) | ||
664 | fatal(SB_FORMAT_ERROR, "Bad header size"); | ||
665 | if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) | ||
666 | fatal(SB_FORMAT_ERROR, "Bad section header size"); | ||
667 | |||
668 | if(filesize > sb_header->image_size * BLOCK_SIZE) | ||
669 | { | ||
670 | printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize, | ||
671 | sb_header->image_size * BLOCK_SIZE); | ||
672 | filesize = sb_header->image_size * BLOCK_SIZE; | ||
673 | } | ||
674 | |||
675 | printf(BLUE, "Basic info:\n"); | ||
676 | printf(GREEN, " SB version: "); | ||
677 | printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver); | ||
678 | printf(GREEN, " Header SHA-1: "); | ||
679 | byte *hdr_sha1 = sb_header->sha1_header; | ||
680 | print_hex(YELLOW, hdr_sha1, 20, false); | ||
681 | /* Check SHA1 sum */ | ||
682 | byte computed_sha1[20]; | ||
683 | sha_1_init(&sha_1_params); | ||
684 | sha_1_update(&sha_1_params, &sb_header->signature[0], | ||
685 | sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); | ||
686 | sha_1_finish(&sha_1_params); | ||
687 | sha_1_output(&sha_1_params, computed_sha1); | ||
688 | if(memcmp(hdr_sha1, computed_sha1, 20) == 0) | ||
689 | printf(RED, " Ok\n"); | ||
690 | else | ||
691 | printf(RED, " Failed\n"); | ||
692 | printf(GREEN, " Flags: "); | ||
693 | printf(YELLOW, "%x\n", sb_header->flags); | ||
694 | printf(GREEN, " Total file size : "); | ||
695 | printf(YELLOW, "%ld\n", filesize); | ||
696 | |||
697 | /* Sizes and offsets */ | ||
698 | printf(BLUE, "Sizes and offsets:\n"); | ||
699 | printf(GREEN, " # of encryption keys = "); | ||
700 | printf(YELLOW, "%d\n", sb_header->nr_keys); | ||
701 | printf(GREEN, " # of sections = "); | ||
702 | printf(YELLOW, "%d\n", sb_header->nr_sections); | ||
703 | |||
704 | /* Versions */ | ||
705 | printf(BLUE, "Versions\n"); | ||
706 | |||
707 | printf(GREEN, " Random 1: "); | ||
708 | print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); | ||
709 | printf(GREEN, " Random 2: "); | ||
710 | print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); | ||
711 | |||
712 | uint64_t micros = sb_header->timestamp; | ||
713 | time_t seconds = (micros / (uint64_t)1000000L); | ||
714 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
715 | seconds += mktime(&tm_base); | ||
716 | struct tm *time = gmtime(&seconds); | ||
717 | printf(GREEN, " Creation date/time = "); | ||
718 | printf(YELLOW, "%s", asctime(time)); | ||
719 | |||
720 | struct sb_version_t product_ver = sb_header->product_ver; | ||
721 | fix_version(&product_ver); | ||
722 | struct sb_version_t component_ver = sb_header->component_ver; | ||
723 | fix_version(&component_ver); | ||
724 | |||
725 | memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver)); | ||
726 | memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver)); | ||
727 | |||
728 | printf(GREEN, " Product version = "); | ||
729 | printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); | ||
730 | printf(GREEN, " Component version = "); | ||
731 | printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); | ||
732 | |||
733 | printf(GREEN, " Drive tag = "); | ||
734 | printf(YELLOW, "%x\n", sb_header->drive_tag); | ||
735 | printf(GREEN, " First boot tag offset = "); | ||
736 | printf(YELLOW, "%x\n", sb_header->first_boot_tag_off); | ||
737 | printf(GREEN, " First boot section ID = "); | ||
738 | printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id); | ||
739 | |||
740 | /* encryption cbc-mac */ | ||
741 | byte real_key[16]; | ||
742 | bool valid_key = false; /* false until a matching key was found */ | ||
743 | |||
744 | if(sb_header->nr_keys > 0) | ||
745 | { | ||
746 | byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys); | ||
747 | printf(BLUE, "Encryption keys\n"); | ||
748 | for(int i = 0; i < g_nr_keys; i++) | ||
749 | { | ||
750 | printf(RED, " Key %d: ", i); | ||
751 | printf(YELLOW, ""); | ||
752 | print_key(&g_key_array[i], true); | ||
753 | printf(GREEN, " CBC-MAC: "); | ||
754 | /* check it */ | ||
755 | byte zero[16]; | ||
756 | memset(zero, 0, 16); | ||
757 | int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections, | ||
758 | &g_key_array[i], zero, &cbcmacs[i], 1); | ||
759 | if(ret != CRYPTO_ERROR_SUCCESS) | ||
760 | { | ||
761 | free(cbcmacs); | ||
762 | fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret); | ||
763 | } | ||
764 | print_hex(YELLOW, cbcmacs[i], 16, true); | ||
765 | } | ||
766 | |||
767 | printf(BLUE, "DEK\n"); | ||
768 | for(int i = 0; i < sb_header->nr_keys; i++) | ||
769 | { | ||
770 | printf(RED, " Entry %d\n", i); | ||
771 | uint32_t ofs = sizeof(struct sb_header_t) | ||
772 | + sizeof(struct sb_section_header_t) * sb_header->nr_sections | ||
773 | + sizeof(struct sb_key_dictionary_entry_t) * i; | ||
774 | struct sb_key_dictionary_entry_t *dict_entry = | ||
775 | (struct sb_key_dictionary_entry_t *)&buf[ofs]; | ||
776 | /* cbc mac */ | ||
777 | printf(GREEN, " Encrypted key: "); | ||
778 | print_hex(YELLOW, dict_entry->key, 16, true); | ||
779 | printf(GREEN, " CBC-MAC : "); | ||
780 | print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false); | ||
781 | /* check it */ | ||
782 | int idx = 0; | ||
783 | while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0) | ||
784 | idx++; | ||
785 | if(idx != g_nr_keys) | ||
786 | { | ||
787 | printf(RED, " Match\n"); | ||
788 | /* decrypt */ | ||
789 | byte decrypted_key[16]; | ||
790 | byte iv[16]; | ||
791 | memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ | ||
792 | int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0); | ||
793 | if(ret != CRYPTO_ERROR_SUCCESS) | ||
794 | { | ||
795 | free(cbcmacs); | ||
796 | fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret); | ||
797 | } | ||
798 | printf(GREEN, " Decrypted key: "); | ||
799 | print_hex(YELLOW, decrypted_key, 16, false); | ||
800 | if(valid_key) | ||
801 | { | ||
802 | if(memcmp(real_key, decrypted_key, 16) == 0) | ||
803 | printf(RED, " Cross-Check Ok"); | ||
804 | else | ||
805 | printf(RED, " Cross-Check Failed"); | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | memcpy(real_key, decrypted_key, 16); | ||
810 | valid_key = true; | ||
811 | } | ||
812 | printf(OFF, "\n"); | ||
813 | } | ||
814 | else | ||
815 | printf(RED, " Don't Match\n"); | ||
816 | } | ||
817 | |||
818 | free(cbcmacs); | ||
819 | |||
820 | if(!valid_key) | ||
821 | fatal(SB_NO_VALID_KEY, "No valid key found\n"); | ||
822 | |||
823 | if(getenv("SB_REAL_KEY") != 0) | ||
824 | { | ||
825 | struct crypto_key_t k; | ||
826 | char *env = getenv("SB_REAL_KEY"); | ||
827 | if(!parse_key(&env, &k) || *env) | ||
828 | bug("Invalid SB_REAL_KEY\n"); | ||
829 | memcpy(real_key, k.u.key, 16); | ||
830 | } | ||
831 | |||
832 | printf(RED, " Summary:\n"); | ||
833 | printf(GREEN, " Real key: "); | ||
834 | print_hex(YELLOW, real_key, 16, true); | ||
835 | printf(GREEN, " IV : "); | ||
836 | print_hex(YELLOW, buf, 16, true); | ||
837 | |||
838 | sb_file->override_real_key = true; | ||
839 | memcpy(sb_file->real_key, real_key, 16); | ||
840 | sb_file->override_crypto_iv = true; | ||
841 | memcpy(sb_file->crypto_iv, buf, 16); | ||
842 | } | ||
843 | |||
844 | /* sections */ | ||
845 | if(!raw_mode) | ||
846 | { | ||
847 | sb_file->nr_sections = sb_header->nr_sections; | ||
848 | sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t)); | ||
849 | memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t)); | ||
850 | printf(BLUE, "Sections\n"); | ||
851 | for(int i = 0; i < sb_header->nr_sections; i++) | ||
852 | { | ||
853 | uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); | ||
854 | struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs]; | ||
855 | |||
856 | char name[5]; | ||
857 | sb_fill_section_name(name, sec_hdr->identifier); | ||
858 | int pos = sec_hdr->offset * BLOCK_SIZE; | ||
859 | int size = sec_hdr->size * BLOCK_SIZE; | ||
860 | int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); | ||
861 | int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
862 | |||
863 | printf(GREEN, " Section "); | ||
864 | printf(YELLOW, "'%s'\n", name); | ||
865 | printf(GREEN, " pos = "); | ||
866 | printf(YELLOW, "%8x - %8x\n", pos, pos+size); | ||
867 | printf(GREEN, " len = "); | ||
868 | printf(YELLOW, "%8x\n", size); | ||
869 | printf(GREEN, " flags = "); | ||
870 | printf(YELLOW, "%8x", sec_hdr->flags); | ||
871 | if(data_sec) | ||
872 | printf(RED, " Data Section"); | ||
873 | else | ||
874 | printf(RED, " Boot Section"); | ||
875 | if(encrypted) | ||
876 | printf(RED, " (Encrypted)"); | ||
877 | printf(OFF, "\n"); | ||
878 | |||
879 | /* save it */ | ||
880 | byte *sec = xmalloc(size); | ||
881 | if(encrypted) | ||
882 | cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); | ||
883 | else | ||
884 | memcpy(sec, buf + pos, size); | ||
885 | |||
886 | struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier, | ||
887 | sec, size, " ", u, cprintf, err); | ||
888 | if(s) | ||
889 | { | ||
890 | s->is_cleartext = !encrypted; | ||
891 | s->alignment = guess_alignment(pos); | ||
892 | memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t)); | ||
893 | free(s); | ||
894 | } | ||
895 | else | ||
896 | fatal(*err, "Error reading section\n"); | ||
897 | |||
898 | free(sec); | ||
899 | } | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | /* advanced raw mode */ | ||
904 | printf(BLUE, "Commands\n"); | ||
905 | uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; | ||
906 | byte iv[16]; | ||
907 | const char *indent = " "; | ||
908 | while(true) | ||
909 | { | ||
910 | /* restart with IV */ | ||
911 | memcpy(iv, buf, 16); | ||
912 | byte cmd[BLOCK_SIZE]; | ||
913 | if(sb_header->nr_keys > 0) | ||
914 | cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0); | ||
915 | else | ||
916 | memcpy(cmd, buf + offset, BLOCK_SIZE); | ||
917 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; | ||
918 | printf(OFF, "%s", indent); | ||
919 | uint8_t checksum = instruction_checksum(hdr); | ||
920 | if(checksum != hdr->checksum) | ||
921 | printf(GREY, "[Bad checksum']"); | ||
922 | |||
923 | if(hdr->opcode == SB_INST_NOP) | ||
924 | { | ||
925 | printf(RED, "NOOP\n"); | ||
926 | offset += BLOCK_SIZE; | ||
927 | } | ||
928 | else if(hdr->opcode == SB_INST_TAG) | ||
929 | { | ||
930 | struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; | ||
931 | printf(RED, "BTAG"); | ||
932 | printf(OFF, " | "); | ||
933 | printf(BLUE, "sec=0x%08x", tag->identifier); | ||
934 | printf(OFF, " | "); | ||
935 | printf(GREEN, "cnt=0x%08x", tag->len); | ||
936 | printf(OFF, " | "); | ||
937 | printf(YELLOW, "flg=0x%08x", tag->flags); | ||
938 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
939 | { | ||
940 | printf(OFF, " | "); | ||
941 | printf(RED, " Last section"); | ||
942 | } | ||
943 | printf(OFF, "\n"); | ||
944 | offset += sizeof(struct sb_instruction_tag_t); | ||
945 | |||
946 | char name[5]; | ||
947 | sb_fill_section_name(name, tag->identifier); | ||
948 | int pos = offset; | ||
949 | int size = tag->len * BLOCK_SIZE; | ||
950 | int data_sec = !(tag->flags & SECTION_BOOTABLE); | ||
951 | int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
952 | |||
953 | printf(GREEN, "%sSection ", indent); | ||
954 | printf(YELLOW, "'%s'\n", name); | ||
955 | printf(GREEN, "%s pos = ", indent); | ||
956 | printf(YELLOW, "%8x - %8x\n", pos, pos+size); | ||
957 | printf(GREEN, "%s len = ", indent); | ||
958 | printf(YELLOW, "%8x\n", size); | ||
959 | printf(GREEN, "%s flags = ", indent); | ||
960 | printf(YELLOW, "%8x", tag->flags); | ||
961 | if(data_sec) | ||
962 | printf(RED, " Data Section"); | ||
963 | else | ||
964 | printf(RED, " Boot Section"); | ||
965 | if(encrypted) | ||
966 | printf(RED, " (Encrypted)"); | ||
967 | printf(OFF, "\n"); | ||
968 | |||
969 | /* save it */ | ||
970 | byte *sec = xmalloc(size); | ||
971 | if(encrypted) | ||
972 | cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); | ||
973 | else | ||
974 | memcpy(sec, buf + pos, size); | ||
975 | |||
976 | struct sb_section_t *s = read_section(data_sec, tag->identifier, | ||
977 | sec, size, " ", u, cprintf, err); | ||
978 | if(s) | ||
979 | { | ||
980 | s->is_cleartext = !encrypted; | ||
981 | s->alignment = guess_alignment(pos); | ||
982 | sb_file->sections = augment_array(sb_file->sections, | ||
983 | sizeof(struct sb_section_t), sb_file->nr_sections++, | ||
984 | s, 1); | ||
985 | free(s); | ||
986 | } | ||
987 | else | ||
988 | fatal(*err, "Error reading section\n"); | ||
989 | free(sec); | ||
990 | |||
991 | /* last one ? */ | ||
992 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
993 | break; | ||
994 | offset += size; | ||
995 | } | ||
996 | else | ||
997 | { | ||
998 | fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); | ||
999 | break; | ||
1000 | } | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | /* final signature */ | ||
1005 | printf(BLUE, "Final signature:\n"); | ||
1006 | byte decrypted_block[32]; | ||
1007 | if(sb_header->nr_keys > 0) | ||
1008 | { | ||
1009 | printf(GREEN, " Encrypted SHA-1:\n"); | ||
1010 | byte *encrypted_block = &buf[filesize - 32]; | ||
1011 | printf(OFF, " "); | ||
1012 | print_hex(YELLOW, encrypted_block, 16, true); | ||
1013 | printf(OFF, " "); | ||
1014 | print_hex(YELLOW, encrypted_block + 16, 16, true); | ||
1015 | /* decrypt it */ | ||
1016 | cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0); | ||
1017 | } | ||
1018 | else | ||
1019 | memcpy(decrypted_block, &buf[filesize - 32], 32); | ||
1020 | printf(GREEN, " File SHA-1:\n "); | ||
1021 | print_hex(YELLOW, decrypted_block, 20, false); | ||
1022 | /* check it */ | ||
1023 | sha_1_init(&sha_1_params); | ||
1024 | sha_1_update(&sha_1_params, buf, filesize - 32); | ||
1025 | sha_1_finish(&sha_1_params); | ||
1026 | sha_1_output(&sha_1_params, computed_sha1); | ||
1027 | if(memcmp(decrypted_block, computed_sha1, 20) == 0) | ||
1028 | printf(RED, " Ok\n"); | ||
1029 | else | ||
1030 | { | ||
1031 | printf(RED, " Failed\n"); | ||
1032 | fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n"); | ||
1033 | } | ||
1034 | free(buf); | ||
1035 | |||
1036 | return sb_file; | ||
1037 | #undef printf | ||
1038 | #undef fatal | ||
1039 | #undef print_hex | ||
1040 | } | ||
1041 | |||
1042 | void sb_free_section(struct sb_section_t sec) | ||
1043 | { | ||
1044 | for(int j = 0; j < sec.nr_insts; j++) | ||
1045 | { | ||
1046 | free(sec.insts[j].padding); | ||
1047 | free(sec.insts[j].data); | ||
1048 | } | ||
1049 | free(sec.insts); | ||
1050 | } | ||
1051 | |||
1052 | void sb_free(struct sb_file_t *file) | ||
1053 | { | ||
1054 | if(!file) return; | ||
1055 | |||
1056 | for(int i = 0; i < file->nr_sections; i++) | ||
1057 | sb_free_section(file->sections[i]); | ||
1058 | |||
1059 | free(file->sections); | ||
1060 | free(file); | ||
1061 | } | ||
1062 | |||
1063 | void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf) | ||
1064 | { | ||
1065 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
1066 | #define print_hex(c, p, len, nl) \ | ||
1067 | do { printf(c, ""); print_hex(p, len, nl); } while(0) | ||
1068 | |||
1069 | #define TREE RED | ||
1070 | #define HEADER GREEN | ||
1071 | #define TEXT YELLOW | ||
1072 | #define TEXT2 BLUE | ||
1073 | #define SEP OFF | ||
1074 | |||
1075 | printf(HEADER, "SB File\n"); | ||
1076 | printf(TREE, "+-"); | ||
1077 | printf(HEADER, "Version: "); | ||
1078 | printf(TEXT, "1.%d\n", file->minor_version); | ||
1079 | printf(TREE, "+-"); | ||
1080 | printf(HEADER, "Flags: "); | ||
1081 | printf(TEXT, "%x\n", file->flags); | ||
1082 | printf(TREE, "+-"); | ||
1083 | printf(HEADER, "Drive Tag: "); | ||
1084 | printf(TEXT, "%x\n", file->drive_tag); | ||
1085 | printf(TREE, "+-"); | ||
1086 | printf(HEADER, "First Boot Section ID: "); | ||
1087 | char name[5]; | ||
1088 | sb_fill_section_name(name, file->first_boot_sec_id); | ||
1089 | printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); | ||
1090 | |||
1091 | if(file->override_real_key) | ||
1092 | { | ||
1093 | printf(TREE, "+-"); | ||
1094 | printf(HEADER, "Real key: "); | ||
1095 | print_hex(TEXT, file->real_key, 16, true); | ||
1096 | } | ||
1097 | if(file->override_crypto_iv) | ||
1098 | { | ||
1099 | printf(TREE, "+-"); | ||
1100 | printf(HEADER, "IV : "); | ||
1101 | print_hex(TEXT, file->crypto_iv, 16, true); | ||
1102 | } | ||
1103 | printf(TREE, "+-"); | ||
1104 | printf(HEADER, "Product Version: "); | ||
1105 | printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor, | ||
1106 | file->product_ver.revision); | ||
1107 | printf(TREE, "+-"); | ||
1108 | printf(HEADER, "Component Version: "); | ||
1109 | printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor, | ||
1110 | file->component_ver.revision); | ||
1111 | |||
1112 | for(int i = 0; i < file->nr_sections; i++) | ||
1113 | { | ||
1114 | struct sb_section_t *sec = &file->sections[i]; | ||
1115 | printf(TREE, "+-"); | ||
1116 | printf(HEADER, "Section\n"); | ||
1117 | printf(TREE,"| +-"); | ||
1118 | printf(HEADER, "Identifier: "); | ||
1119 | sb_fill_section_name(name, sec->identifier); | ||
1120 | printf(TEXT, "%08x (%s)\n", sec->identifier, name); | ||
1121 | printf(TREE, "| +-"); | ||
1122 | printf(HEADER, "Type: "); | ||
1123 | printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section", | ||
1124 | sec->is_cleartext ? "Cleartext" : "Encrypted"); | ||
1125 | printf(TREE, "| +-"); | ||
1126 | printf(HEADER, "Alignment: "); | ||
1127 | printf(TEXT, "%d (bytes)\n", sec->alignment); | ||
1128 | printf(TREE, "| +-"); | ||
1129 | printf(HEADER, "Instructions\n"); | ||
1130 | for(int j = 0; j < sec->nr_insts; j++) | ||
1131 | { | ||
1132 | struct sb_inst_t *inst = &sec->insts[j]; | ||
1133 | printf(TREE, "| | +-"); | ||
1134 | switch(inst->inst) | ||
1135 | { | ||
1136 | case SB_INST_DATA: | ||
1137 | printf(HEADER, "DATA"); | ||
1138 | printf(SEP, " | "); | ||
1139 | printf(TEXT, "size=0x%08x\n", inst->size); | ||
1140 | break; | ||
1141 | case SB_INST_CALL: | ||
1142 | case SB_INST_JUMP: | ||
1143 | printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); | ||
1144 | printf(SEP, " | "); | ||
1145 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1146 | printf(SEP, " | "); | ||
1147 | printf(TEXT2, "arg=0x%08x\n", inst->argument); | ||
1148 | break; | ||
1149 | case SB_INST_LOAD: | ||
1150 | printf(HEADER, "LOAD"); | ||
1151 | printf(SEP, " | "); | ||
1152 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1153 | printf(SEP, " | "); | ||
1154 | printf(TEXT2, "len=0x%08x\n", inst->size); | ||
1155 | break; | ||
1156 | case SB_INST_FILL: | ||
1157 | printf(HEADER, "FILL"); | ||
1158 | printf(SEP, " | "); | ||
1159 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1160 | printf(SEP, " | "); | ||
1161 | printf(TEXT2, "len=0x%08x", inst->size); | ||
1162 | printf(SEP, " | "); | ||
1163 | printf(TEXT2, "pattern=0x%08x\n", inst->pattern); | ||
1164 | break; | ||
1165 | case SB_INST_MODE: | ||
1166 | printf(HEADER, "MODE"); | ||
1167 | printf(SEP, " | "); | ||
1168 | printf(TEXT, "mod=0x%08x\n", inst->addr); | ||
1169 | break; | ||
1170 | case SB_INST_NOP: | ||
1171 | printf(HEADER, "NOOP\n"); | ||
1172 | break; | ||
1173 | default: | ||
1174 | printf(GREY, "[Unknown instruction %x]\n", inst->inst); | ||
1175 | } | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | #undef printf | ||
1180 | #undef print_hex | ||
1181 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __SB_H__ | ||
22 | #define __SB_H__ | ||
23 | |||
24 | #include <stdint.h> | ||
25 | #include <stdbool.h> | ||
26 | |||
27 | #include "misc.h" | ||
28 | |||
29 | #define BLOCK_SIZE 16 | ||
30 | |||
31 | /* All fields are in big-endian BCD */ | ||
32 | struct sb_version_t | ||
33 | { | ||
34 | uint16_t major; | ||
35 | uint16_t pad0; | ||
36 | uint16_t minor; | ||
37 | uint16_t pad1; | ||
38 | uint16_t revision; | ||
39 | uint16_t pad2; | ||
40 | }; | ||
41 | |||
42 | struct sb_header_t | ||
43 | { | ||
44 | uint8_t sha1_header[20]; /* SHA-1 of the rest of the header */ | ||
45 | uint8_t signature[4]; /* Signature "STMP" */ | ||
46 | uint8_t major_ver; /* Should be 1 */ | ||
47 | uint8_t minor_ver; /* Should be 1 */ | ||
48 | uint16_t flags; | ||
49 | uint32_t image_size; /* In blocks (=16bytes) */ | ||
50 | uint32_t first_boot_tag_off; /* Offset in blocks */ | ||
51 | uint32_t first_boot_sec_id; /* First bootable section ID */ | ||
52 | uint16_t nr_keys; /* Number of encryption keys */ | ||
53 | uint16_t key_dict_off; /* Offset to key dictionary (in blocks) */ | ||
54 | uint16_t header_size; /* In blocks */ | ||
55 | uint16_t nr_sections; /* Number of sections */ | ||
56 | uint16_t sec_hdr_size; /* Section header size (in blocks) */ | ||
57 | uint8_t rand_pad0[6]; /* Random padding */ | ||
58 | uint64_t timestamp; /* In microseconds since 2000/1/1 00:00:00 */ | ||
59 | struct sb_version_t product_ver; | ||
60 | struct sb_version_t component_ver; | ||
61 | uint16_t drive_tag; /* first tag to boot ? */ | ||
62 | uint8_t rand_pad1[6]; /* Random padding */ | ||
63 | } __attribute__((packed)); | ||
64 | |||
65 | struct sb_section_header_t | ||
66 | { | ||
67 | uint32_t identifier; | ||
68 | uint32_t offset; /* In blocks */ | ||
69 | uint32_t size; /* In blocks */ | ||
70 | uint32_t flags; | ||
71 | } __attribute__((packed)); | ||
72 | |||
73 | struct sb_key_dictionary_entry_t | ||
74 | { | ||
75 | uint8_t hdr_cbc_mac[16]; /* CBC-MAC of the header */ | ||
76 | uint8_t key[16]; /* Actual AES Key (encrypted by the global key) */ | ||
77 | } __attribute__((packed)); | ||
78 | |||
79 | #define IMAGE_MAJOR_VERSION 1 | ||
80 | #define IMAGE_MINOR_VERSION 1 | ||
81 | |||
82 | #define SECTION_BOOTABLE (1 << 0) | ||
83 | #define SECTION_CLEARTEXT (1 << 1) | ||
84 | |||
85 | #define SB_INST_NOP 0x0 | ||
86 | #define SB_INST_TAG 0x1 | ||
87 | #define SB_INST_LOAD 0x2 | ||
88 | #define SB_INST_FILL 0x3 | ||
89 | #define SB_INST_JUMP 0x4 | ||
90 | #define SB_INST_CALL 0x5 | ||
91 | #define SB_INST_MODE 0x6 | ||
92 | |||
93 | /* flags */ | ||
94 | #define SB_INST_LAST_TAG 1 /* for TAG */ | ||
95 | #define SB_INST_LOAD_DCD 1 /* for LOAD */ | ||
96 | #define SB_INST_FILL_BYTE 0 /* for FILL */ | ||
97 | #define SB_INST_FILL_HWORD 1 /* for FILL */ | ||
98 | #define SB_INST_FILL_WORD 2 /* for FILL */ | ||
99 | #define SB_INST_HAB_EXEC 1 /* for JUMP/CALL */ | ||
100 | |||
101 | struct sb_instruction_header_t | ||
102 | { | ||
103 | uint8_t checksum; | ||
104 | uint8_t opcode; | ||
105 | uint16_t flags; | ||
106 | } __attribute__((packed)); | ||
107 | |||
108 | struct sb_instruction_common_t | ||
109 | { | ||
110 | struct sb_instruction_header_t hdr; | ||
111 | uint32_t addr; | ||
112 | uint32_t len; | ||
113 | uint32_t data; | ||
114 | } __attribute__((packed)); | ||
115 | |||
116 | struct sb_instruction_load_t | ||
117 | { | ||
118 | struct sb_instruction_header_t hdr; | ||
119 | uint32_t addr; | ||
120 | uint32_t len; | ||
121 | uint32_t crc; | ||
122 | } __attribute__((packed)); | ||
123 | |||
124 | struct sb_instruction_fill_t | ||
125 | { | ||
126 | struct sb_instruction_header_t hdr; | ||
127 | uint32_t addr; | ||
128 | uint32_t len; | ||
129 | uint32_t pattern; | ||
130 | } __attribute__((packed)); | ||
131 | |||
132 | struct sb_instruction_mode_t | ||
133 | { | ||
134 | struct sb_instruction_header_t hdr; | ||
135 | uint32_t zero1; | ||
136 | uint32_t zero2; | ||
137 | uint32_t mode; | ||
138 | } __attribute__((packed)); | ||
139 | |||
140 | struct sb_instruction_call_t | ||
141 | { | ||
142 | struct sb_instruction_header_t hdr; | ||
143 | uint32_t addr; | ||
144 | uint32_t zero; | ||
145 | uint32_t arg; | ||
146 | } __attribute__((packed)); | ||
147 | |||
148 | struct sb_instruction_tag_t | ||
149 | { | ||
150 | struct sb_instruction_header_t hdr; | ||
151 | uint32_t identifier; /* section identifier */ | ||
152 | uint32_t len; /* length of the section */ | ||
153 | uint32_t flags; /* section flags */ | ||
154 | } __attribute__((packed)); | ||
155 | |||
156 | /******* | ||
157 | * API * | ||
158 | *******/ | ||
159 | |||
160 | #define SB_INST_DATA 0xff | ||
161 | |||
162 | struct sb_inst_t | ||
163 | { | ||
164 | uint8_t inst; /* SB_INST_* */ | ||
165 | uint32_t size; | ||
166 | uint32_t addr; | ||
167 | // <union> | ||
168 | void *data; | ||
169 | uint32_t pattern; | ||
170 | // </union> | ||
171 | uint32_t argument; // for call, jump and mode | ||
172 | /* for production use */ | ||
173 | uint32_t padding_size; | ||
174 | uint8_t *padding; | ||
175 | }; | ||
176 | |||
177 | struct sb_section_t | ||
178 | { | ||
179 | uint32_t identifier; | ||
180 | bool is_data; | ||
181 | bool is_cleartext; | ||
182 | uint32_t alignment; | ||
183 | // data sections are handled as one or more SB_INST_DATA virtual instruction | ||
184 | int nr_insts; | ||
185 | struct sb_inst_t *insts; | ||
186 | /* for production use */ | ||
187 | uint32_t file_offset; /* in blocks */ | ||
188 | uint32_t sec_size; /* in blocks */ | ||
189 | }; | ||
190 | |||
191 | struct sb_file_t | ||
192 | { | ||
193 | /* override real, otherwise it is randomly generated */ | ||
194 | bool override_real_key; | ||
195 | uint8_t real_key[16]; | ||
196 | /* override crypto IV, use with caution ! Use NULL to generate it */ | ||
197 | bool override_crypto_iv; | ||
198 | uint8_t crypto_iv[16]; | ||
199 | |||
200 | int nr_sections; | ||
201 | uint16_t drive_tag; | ||
202 | uint32_t first_boot_sec_id; | ||
203 | uint16_t flags; | ||
204 | uint8_t minor_version; | ||
205 | struct sb_section_t *sections; | ||
206 | struct sb_version_t product_ver; | ||
207 | struct sb_version_t component_ver; | ||
208 | /* for production use */ | ||
209 | uint32_t image_size; /* in blocks */ | ||
210 | }; | ||
211 | |||
212 | enum sb_error_t | ||
213 | { | ||
214 | SB_SUCCESS = 0, | ||
215 | SB_ERROR = -1, | ||
216 | SB_OPEN_ERROR = -2, | ||
217 | SB_READ_ERROR = -3, | ||
218 | SB_WRITE_ERROR = -4, | ||
219 | SB_FORMAT_ERROR = -5, | ||
220 | SB_CHECKSUM_ERROR = -6, | ||
221 | SB_NO_VALID_KEY = -7, | ||
222 | SB_FIRST_CRYPTO_ERROR = -8, | ||
223 | SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS, | ||
224 | }; | ||
225 | |||
226 | enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename); | ||
227 | |||
228 | typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...); | ||
229 | struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, | ||
230 | sb_color_printf printf, enum sb_error_t *err); | ||
231 | |||
232 | void sb_fill_section_name(char name[5], uint32_t identifier); | ||
233 | void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf); | ||
234 | void sb_free_section(struct sb_section_t file); | ||
235 | void sb_free(struct sb_file_t *file); | ||
236 | |||
237 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <libusb.h> | ||
25 | #include <stdint.h> | ||
26 | |||
27 | void put32le(uint8_t *buf, uint32_t i) | ||
28 | { | ||
29 | *buf++ = i & 0xff; | ||
30 | *buf++ = (i >> 8) & 0xff; | ||
31 | *buf++ = (i >> 16) & 0xff; | ||
32 | *buf++ = (i >> 24) & 0xff; | ||
33 | } | ||
34 | |||
35 | void put32be(uint8_t *buf, uint32_t i) | ||
36 | { | ||
37 | *buf++ = (i >> 24) & 0xff; | ||
38 | *buf++ = (i >> 16) & 0xff; | ||
39 | *buf++ = (i >> 8) & 0xff; | ||
40 | *buf++ = i & 0xff; | ||
41 | } | ||
42 | |||
43 | int main(int argc, char **argv) | ||
44 | { | ||
45 | int ret; | ||
46 | uint8_t msg[0x20]; | ||
47 | uint8_t *p; | ||
48 | FILE *f; | ||
49 | int i, xfer_size, nr_xfers, recv_size; | ||
50 | |||
51 | if(argc != 3) | ||
52 | { | ||
53 | printf("usage: %s <xfer size> <file>\n", argv[0]); | ||
54 | return 1; | ||
55 | } | ||
56 | |||
57 | char *end; | ||
58 | xfer_size = strtol(argv[1], &end, 0); | ||
59 | if(end != (argv[1] + strlen(argv[1]))) | ||
60 | { | ||
61 | printf("Invalid transfer size !\n"); | ||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | libusb_device_handle *dev; | ||
66 | |||
67 | libusb_init(NULL); | ||
68 | |||
69 | libusb_set_debug(NULL, 3); | ||
70 | |||
71 | /* MX23 */ | ||
72 | dev = libusb_open_device_with_vid_pid(NULL, 0x066F, 0x3780); | ||
73 | if(dev == NULL) | ||
74 | /* MX28 */ | ||
75 | dev = libusb_open_device_with_vid_pid(NULL, 0x15A2, 0x004F); | ||
76 | if(dev == NULL) | ||
77 | { | ||
78 | printf("Cannot open device\n"); | ||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | libusb_detach_kernel_driver(dev, 0); | ||
83 | libusb_detach_kernel_driver(dev, 4); | ||
84 | |||
85 | libusb_claim_interface (dev, 0); | ||
86 | libusb_claim_interface (dev, 4); | ||
87 | |||
88 | if (!dev) | ||
89 | { | ||
90 | printf("No dev\n"); | ||
91 | exit(1); | ||
92 | } | ||
93 | |||
94 | f = fopen(argv[2], "r"); | ||
95 | if(f == NULL) | ||
96 | { | ||
97 | perror("cannot open file"); | ||
98 | return 1; | ||
99 | } | ||
100 | fseek(f, 0, SEEK_END); | ||
101 | size_t size = ftell(f); | ||
102 | fseek(f, 0, SEEK_SET); | ||
103 | |||
104 | printf("Transfer size: %d\n", xfer_size); | ||
105 | nr_xfers = (size + xfer_size - 1) / xfer_size; | ||
106 | uint8_t *file_buf = malloc(nr_xfers * xfer_size); | ||
107 | memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff | ||
108 | if(fread(file_buf, size, 1, f) != 1) | ||
109 | { | ||
110 | perror("read error"); | ||
111 | fclose(f); | ||
112 | return 1; | ||
113 | } | ||
114 | fclose(f); | ||
115 | |||
116 | memset(msg, 0, 0x20); | ||
117 | |||
118 | p = msg; | ||
119 | |||
120 | *p++ = 0x01; // Init upload command | ||
121 | *p++ = 'B'; // Signature | ||
122 | *p++ = 'L'; | ||
123 | *p++ = 'T'; | ||
124 | *p++ = 'C'; | ||
125 | put32le(p, 0x1); // I guess version or sub-command | ||
126 | p += 4; | ||
127 | put32le(p, size); // Payload size | ||
128 | |||
129 | // The second command starts at 0x20 | ||
130 | |||
131 | p = &msg[0x10]; | ||
132 | |||
133 | *p++ = 0x02; // Start upload | ||
134 | put32be(p, size); // Payload size, again | ||
135 | |||
136 | ret = libusb_control_transfer(dev, | ||
137 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0, | ||
138 | msg, 0x20, 1000); | ||
139 | if(ret < 0) | ||
140 | { | ||
141 | printf("transfer error at init step\n"); | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | uint8_t *xfer_buf = malloc(1 + xfer_size); | ||
146 | |||
147 | for(i = 0; i < nr_xfers; i++) | ||
148 | { | ||
149 | xfer_buf[0] = 0x2; | ||
150 | memcpy(&xfer_buf[1], &file_buf[i * xfer_size], xfer_size); | ||
151 | |||
152 | ret = libusb_control_transfer(dev, | ||
153 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, | ||
154 | 0x9, 0x202, 0, xfer_buf, xfer_size + 1, 1000); | ||
155 | if(ret < 0) | ||
156 | { | ||
157 | printf("transfer error at send step %d\n", i); | ||
158 | return 1; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, &recv_size, | ||
163 | 1000); | ||
164 | if(ret < 0) | ||
165 | { | ||
166 | printf("transfer error at final stage\n"); | ||
167 | return 1; | ||
168 | } | ||
169 | |||
170 | printf("ret %i\n", ret); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Bertrik Sikken | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* | ||
23 | * .sb file parser and chunk extractor | ||
24 | * | ||
25 | * Based on amsinfo, which is | ||
26 | * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com> | ||
27 | */ | ||
28 | |||
29 | #define _ISOC99_SOURCE /* snprintf() */ | ||
30 | #include <stdio.h> | ||
31 | #include <errno.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <ctype.h> | ||
35 | #include <time.h> | ||
36 | #include <stdarg.h> | ||
37 | #include <strings.h> | ||
38 | #include <getopt.h> | ||
39 | |||
40 | #include "crypto.h" | ||
41 | #include "elf.h" | ||
42 | #include "sb.h" | ||
43 | #include "misc.h" | ||
44 | |||
45 | /* all blocks are sized as a multiple of 0x1ff */ | ||
46 | #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) | ||
47 | |||
48 | /* If you find a firmware that breaks the known format ^^ */ | ||
49 | #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) | ||
50 | |||
51 | #define crypto_cbc(...) \ | ||
52 | do { int ret = crypto_cbc(__VA_ARGS__); \ | ||
53 | if(ret != CRYPTO_ERROR_SUCCESS) \ | ||
54 | bug("crypto_cbc error: %d\n", ret); \ | ||
55 | }while(0) | ||
56 | |||
57 | /* globals */ | ||
58 | |||
59 | char *g_out_prefix; | ||
60 | |||
61 | static void elf_printf(void *user, bool error, const char *fmt, ...) | ||
62 | { | ||
63 | if(!g_debug && !error) | ||
64 | return; | ||
65 | (void) user; | ||
66 | va_list args; | ||
67 | va_start(args, fmt); | ||
68 | vprintf(fmt, args); | ||
69 | va_end(args); | ||
70 | } | ||
71 | |||
72 | static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) | ||
73 | { | ||
74 | FILE *f = user; | ||
75 | fseek(f, addr, SEEK_SET); | ||
76 | fwrite(buf, count, 1, f); | ||
77 | } | ||
78 | |||
79 | static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id) | ||
80 | { | ||
81 | char name[5]; | ||
82 | char *filename = xmalloc(strlen(g_out_prefix) + 32); | ||
83 | sb_fill_section_name(name, id); | ||
84 | sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count); | ||
85 | if(g_debug) | ||
86 | printf("Write boot section %s to %s\n", name, filename); | ||
87 | |||
88 | FILE *fd = fopen(filename, "wb"); | ||
89 | free(filename); | ||
90 | |||
91 | if(fd == NULL) | ||
92 | return ; | ||
93 | elf_write_file(elf, elf_write, elf_printf, fd); | ||
94 | fclose(fd); | ||
95 | } | ||
96 | |||
97 | static void extract_sb_section(struct sb_section_t *sec) | ||
98 | { | ||
99 | if(sec->is_data) | ||
100 | { | ||
101 | char sec_name[5]; | ||
102 | char *filename = xmalloc(strlen(g_out_prefix) + 32); | ||
103 | sb_fill_section_name(sec_name, sec->identifier); | ||
104 | sprintf(filename, "%s%s.bin", g_out_prefix, sec_name); | ||
105 | FILE *fd = fopen(filename, "wb"); | ||
106 | if(fd == NULL) | ||
107 | bugp("Cannot open %s for writing\n", filename); | ||
108 | if(g_debug) | ||
109 | printf("Write data section %s to %s\n", sec_name, filename); | ||
110 | free(filename); | ||
111 | |||
112 | for(int j = 0; j < sec->nr_insts; j++) | ||
113 | { | ||
114 | assert(sec->insts[j].inst == SB_INST_DATA); | ||
115 | fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd); | ||
116 | } | ||
117 | fclose(fd); | ||
118 | } | ||
119 | |||
120 | int elf_count = 0; | ||
121 | struct elf_params_t elf; | ||
122 | elf_init(&elf); | ||
123 | |||
124 | for(int i = 0; i < sec->nr_insts; i++) | ||
125 | { | ||
126 | struct sb_inst_t *inst = &sec->insts[i]; | ||
127 | switch(inst->inst) | ||
128 | { | ||
129 | case SB_INST_LOAD: | ||
130 | elf_add_load_section(&elf, inst->addr, inst->size, inst->data); | ||
131 | break; | ||
132 | case SB_INST_FILL: | ||
133 | elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern); | ||
134 | break; | ||
135 | case SB_INST_CALL: | ||
136 | case SB_INST_JUMP: | ||
137 | elf_set_start_addr(&elf, inst->addr); | ||
138 | extract_elf_section(&elf, elf_count++, sec->identifier); | ||
139 | elf_release(&elf); | ||
140 | elf_init(&elf); | ||
141 | break; | ||
142 | default: | ||
143 | /* ignore mode and nop */ | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | if(!elf_is_empty(&elf)) | ||
149 | extract_elf_section(&elf, elf_count, sec->identifier); | ||
150 | elf_release(&elf); | ||
151 | } | ||
152 | |||
153 | static void extract_sb_file(struct sb_file_t *file) | ||
154 | { | ||
155 | for(int i = 0; i < file->nr_sections; i++) | ||
156 | extract_sb_section(&file->sections[i]); | ||
157 | } | ||
158 | |||
159 | static void usage(void) | ||
160 | { | ||
161 | printf("Usage: sbtoelf [options] sb-file\n"); | ||
162 | printf("Options:\n"); | ||
163 | printf(" -?/--help\tDisplay this message\n"); | ||
164 | printf(" -o <prefix>\tEnable output and set prefix\n"); | ||
165 | printf(" -d/--debug\tEnable debug output*\n"); | ||
166 | printf(" -k <file>\tAdd key file\n"); | ||
167 | printf(" -z\t\tAdd zero key\n"); | ||
168 | printf(" -r\t\tUse raw command mode\n"); | ||
169 | printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); | ||
170 | printf(" -n/--no-color\tDisable output colors\n"); | ||
171 | printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n"); | ||
172 | printf("Options marked with a * are for debug purpose only\n"); | ||
173 | exit(1); | ||
174 | } | ||
175 | |||
176 | static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...) | ||
177 | { | ||
178 | (void) user; | ||
179 | (void) error; | ||
180 | va_list args; | ||
181 | va_start(args, fmt); | ||
182 | color(c); | ||
183 | vprintf(fmt, args); | ||
184 | va_end(args); | ||
185 | } | ||
186 | |||
187 | static struct crypto_key_t g_zero_key = | ||
188 | { | ||
189 | .method = CRYPTO_KEY, | ||
190 | .u.key = {0} | ||
191 | }; | ||
192 | |||
193 | int main(int argc, char **argv) | ||
194 | { | ||
195 | bool raw_mode = false; | ||
196 | const char *loopback = NULL; | ||
197 | |||
198 | while(1) | ||
199 | { | ||
200 | static struct option long_options[] = | ||
201 | { | ||
202 | {"help", no_argument, 0, '?'}, | ||
203 | {"debug", no_argument, 0, 'd'}, | ||
204 | {"add-key", required_argument, 0, 'a'}, | ||
205 | {"no-color", no_argument, 0, 'n'}, | ||
206 | {"loopback", required_argument, 0, 'l'}, | ||
207 | {0, 0, 0, 0} | ||
208 | }; | ||
209 | |||
210 | int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL); | ||
211 | if(c == -1) | ||
212 | break; | ||
213 | switch(c) | ||
214 | { | ||
215 | case -1: | ||
216 | break; | ||
217 | case 'l': | ||
218 | if(loopback) | ||
219 | bug("Only one loopback file can be specified !\n"); | ||
220 | loopback = optarg; | ||
221 | break; | ||
222 | case 'n': | ||
223 | enable_color(false); | ||
224 | break; | ||
225 | case 'd': | ||
226 | g_debug = true; | ||
227 | break; | ||
228 | case '?': | ||
229 | usage(); | ||
230 | break; | ||
231 | case 'o': | ||
232 | g_out_prefix = optarg; | ||
233 | break; | ||
234 | case 'k': | ||
235 | { | ||
236 | add_keys_from_file(optarg); | ||
237 | break; | ||
238 | } | ||
239 | case 'z': | ||
240 | { | ||
241 | add_keys(&g_zero_key, 1); | ||
242 | break; | ||
243 | } | ||
244 | case 'r': | ||
245 | raw_mode = true; | ||
246 | break; | ||
247 | case 'a': | ||
248 | { | ||
249 | struct crypto_key_t key; | ||
250 | char *s = optarg; | ||
251 | if(!parse_key(&s, &key)) | ||
252 | bug("Invalid key specified as argument"); | ||
253 | if(*s != 0) | ||
254 | bug("Trailing characters after key specified as argument"); | ||
255 | add_keys(&key, 1); | ||
256 | break; | ||
257 | } | ||
258 | default: | ||
259 | abort(); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if(argc - optind != 1) | ||
264 | { | ||
265 | usage(); | ||
266 | return 1; | ||
267 | } | ||
268 | |||
269 | const char *sb_filename = argv[optind]; | ||
270 | |||
271 | enum sb_error_t err; | ||
272 | struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err); | ||
273 | if(file == NULL) | ||
274 | { | ||
275 | color(OFF); | ||
276 | printf("SB read failed: %d\n", err); | ||
277 | return 1; | ||
278 | } | ||
279 | |||
280 | color(OFF); | ||
281 | if(g_out_prefix) | ||
282 | extract_sb_file(file); | ||
283 | if(g_debug) | ||
284 | { | ||
285 | color(GREY); | ||
286 | printf("[Debug output]\n"); | ||
287 | sb_dump(file, NULL, sb_printf); | ||
288 | } | ||
289 | if(loopback) | ||
290 | { | ||
291 | /* sb_read_file will fill real key and IV but we don't want to override | ||
292 | * them when looping back otherwise the output will be inconsistent and | ||
293 | * garbage */ | ||
294 | file->override_real_key = false; | ||
295 | file->override_crypto_iv = false; | ||
296 | sb_write_file(file, loopback); | ||
297 | } | ||
298 | sb_free(file); | ||
299 | clear_keys(); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | /* Based on http://en.wikipedia.org/wiki/SHA-1 */ | ||
22 | #include "crypto.h" | ||
23 | |||
24 | static uint32_t rot_left(uint32_t val, int rot) | ||
25 | { | ||
26 | return (val << rot) | (val >> (32 - rot)); | ||
27 | } | ||
28 | |||
29 | static inline void byte_swapxx(byte *ptr, int size) | ||
30 | { | ||
31 | for(int i = 0; i < size / 2; i++) | ||
32 | { | ||
33 | byte c = ptr[i]; | ||
34 | ptr[i] = ptr[size - i - 1]; | ||
35 | ptr[size - i - 1] = c; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | static void byte_swap32(uint32_t *v) | ||
40 | { | ||
41 | byte_swapxx((byte *)v, 4); | ||
42 | } | ||
43 | |||
44 | void sha_1_init(struct sha_1_params_t *params) | ||
45 | { | ||
46 | params->hash[0] = 0x67452301; | ||
47 | params->hash[1] = 0xEFCDAB89; | ||
48 | params->hash[2] = 0x98BADCFE; | ||
49 | params->hash[3] = 0x10325476; | ||
50 | params->hash[4] = 0xC3D2E1F0; | ||
51 | params->buffer_nr_bits = 0; | ||
52 | } | ||
53 | |||
54 | void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size) | ||
55 | { | ||
56 | int buffer_nr_bytes = (params->buffer_nr_bits / 8) % 64; | ||
57 | params->buffer_nr_bits += 8 * size; | ||
58 | int pos = 0; | ||
59 | if(buffer_nr_bytes + size >= 64) | ||
60 | { | ||
61 | pos = 64 - buffer_nr_bytes; | ||
62 | memcpy((byte *)(params->w) + buffer_nr_bytes, buffer, 64 - buffer_nr_bytes); | ||
63 | sha_1_block(params, params->hash, (byte *)params->w); | ||
64 | for(; pos + 64 <= size; pos += 64) | ||
65 | sha_1_block(params, params->hash, buffer + pos); | ||
66 | buffer_nr_bytes = 0; | ||
67 | } | ||
68 | memcpy((byte *)(params->w) + buffer_nr_bytes, buffer + pos, size - pos); | ||
69 | } | ||
70 | |||
71 | void sha_1_finish(struct sha_1_params_t *params) | ||
72 | { | ||
73 | /* length (in bits) in big endian BEFORE preprocessing */ | ||
74 | byte length_big_endian[8]; | ||
75 | memcpy(length_big_endian, ¶ms->buffer_nr_bits, 8); | ||
76 | byte_swapxx(length_big_endian, 8); | ||
77 | /* append '1' and then '0's to the message to get 448 bit length for the last block */ | ||
78 | byte b = 0x80; | ||
79 | sha_1_update(params, &b, 1); | ||
80 | b = 0; | ||
81 | while((params->buffer_nr_bits % 512) != 448) | ||
82 | sha_1_update(params, &b, 1); | ||
83 | /* append length */ | ||
84 | sha_1_update(params, length_big_endian, 8); | ||
85 | /* go back to big endian */ | ||
86 | for(int i = 0; i < 5; i++) | ||
87 | byte_swap32(¶ms->hash[i]); | ||
88 | } | ||
89 | |||
90 | void sha_1_output(struct sha_1_params_t *params, byte *out) | ||
91 | { | ||
92 | memcpy(out, params->hash, 20); | ||
93 | } | ||
94 | |||
95 | void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data) | ||
96 | { | ||
97 | uint32_t a, b, c, d, e; | ||
98 | a = cur_hash[0]; | ||
99 | b = cur_hash[1]; | ||
100 | c = cur_hash[2]; | ||
101 | d = cur_hash[3]; | ||
102 | e = cur_hash[4]; | ||
103 | |||
104 | #define w params->w | ||
105 | |||
106 | memmove(w, data, 64); | ||
107 | for(int i = 0; i < 16; i++) | ||
108 | byte_swap32(&w[i]); | ||
109 | |||
110 | for(int i = 16; i <= 79; i++) | ||
111 | w[i] = rot_left(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); | ||
112 | |||
113 | for(int i = 0; i<= 79; i++) | ||
114 | { | ||
115 | uint32_t f, k; | ||
116 | if(i <= 19) | ||
117 | { | ||
118 | f = (b & c) | ((~b) & d); | ||
119 | k = 0x5A827999; | ||
120 | } | ||
121 | else if(i <= 39) | ||
122 | { | ||
123 | f = b ^ c ^ d; | ||
124 | k = 0x6ED9EBA1; | ||
125 | } | ||
126 | else if(i <= 59) | ||
127 | { | ||
128 | f = (b & c) | (b & d) | (c & d); | ||
129 | k = 0x8F1BBCDC; | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | f = b ^ c ^ d; | ||
134 | k = 0xCA62C1D6; | ||
135 | } | ||
136 | uint32_t temp = rot_left(a, 5) + f + e + k + w[i]; | ||
137 | e = d; | ||
138 | d = c; | ||
139 | c = rot_left(b, 30); | ||
140 | b = a; | ||
141 | a = temp; | ||
142 | } | ||
143 | #undef w | ||
144 | |||
145 | cur_hash[0] += a; | ||
146 | cur_hash[1] += b; | ||
147 | cur_hash[2] += c; | ||
148 | cur_hash[3] += d; | ||
149 | cur_hash[4] += e; | ||
150 | } | ||