diff options
Diffstat (limited to 'tools/creative.c')
-rw-r--r-- | tools/creative.c | 144 |
1 files changed, 77 insertions, 67 deletions
diff --git a/tools/creative.c b/tools/creative.c index 287df03a7c..7748f56611 100644 --- a/tools/creative.c +++ b/tools/creative.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
22 | #include <stdlib.h> | 22 | #include <stdlib.h> |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <elf.h> | ||
24 | 25 | ||
25 | #include "creative.h" | 26 | #include "creative.h" |
26 | #include "hmac-sha1.h" | 27 | #include "hmac-sha1.h" |
@@ -30,36 +31,19 @@ static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP."; | |||
30 | static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP."; | 31 | static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP."; |
31 | static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP."; | 32 | static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP."; |
32 | 33 | ||
33 | static const unsigned char bootloader_v1[] = | ||
34 | { | ||
35 | 0xD3, 0xF0, 0x29, 0xE3, /* MSR CPSR_cf, #0xD3 */ | ||
36 | 0x09, 0xF6, 0xA0, 0xE3 /* MOV PC, #0x900000 */ | ||
37 | }; | ||
38 | |||
39 | static const unsigned char bootloader_v2[] = | ||
40 | { | ||
41 | 0xD3, 0xF0, 0x29, 0xE3, /* MSR CPSR_cf, #0xD3 */ | ||
42 | 0x09, 0xF6, 0xA0, 0xE3 /* MOV PC, #0x40000000 */ | ||
43 | }; | ||
44 | |||
45 | static const unsigned char bootloader_v3[] = | ||
46 | { | ||
47 | 0 /* Unknown */ | ||
48 | }; | ||
49 | |||
50 | static const struct device_info devices[] = | 34 | static const struct device_info devices[] = |
51 | { | 35 | { |
52 | /* Creative Zen Vision:M */ | 36 | /* Creative Zen Vision:M */ |
53 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", 42, null_key_v2, bootloader_v1, sizeof(bootloader_v1), 0x00900000}, | 37 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", 42, null_key_v2}, |
54 | /* Creative Zen Vision:M Go! */ | 38 | /* Creative Zen Vision:M Go! */ |
55 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", 50, null_key_v2, bootloader_v1, sizeof(bootloader_v1), 0x00900000}, | 39 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", 50, null_key_v2}, |
56 | /* Creative Zen Vision © TL */ | 40 | /* Creative Zen Vision © TL */ |
57 | /* The "©" should be ANSI encoded or the device won't accept the firmware package. */ | 41 | /* The "©" should be ANSI encoded or the device won't accept the firmware package. */ |
58 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0©\0T\0L", 46, null_key_v2, bootloader_v1, sizeof(bootloader_v1), 0x00900000}, | 42 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0©\0T\0L", 46, null_key_v2}, |
59 | /* Creative ZEN V */ | 43 | /* Creative ZEN V */ |
60 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4, bootloader_v3, sizeof(bootloader_v3), 0x00000000}, | 44 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4}, |
61 | /* Creative ZEN */ | 45 | /* Creative ZEN */ |
62 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N", 48, null_key_v3, bootloader_v2, sizeof(bootloader_v2), 0x40000000} | 46 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N", 48, null_key_v3} |
63 | }; | 47 | }; |
64 | 48 | ||
65 | /* | 49 | /* |
@@ -69,7 +53,7 @@ extern void int2le(unsigned int val, unsigned char* addr); | |||
69 | extern unsigned int le2int(unsigned char* buf); | 53 | extern unsigned int le2int(unsigned char* buf); |
70 | 54 | ||
71 | 55 | ||
72 | static int make_ciff_file(unsigned char *inbuf, unsigned int length, | 56 | static int make_ciff_file(const unsigned char *inbuf, unsigned int length, |
73 | unsigned char *outbuf, int device) | 57 | unsigned char *outbuf, int device) |
74 | { | 58 | { |
75 | unsigned char key[20]; | 59 | unsigned char key[20]; |
@@ -83,7 +67,8 @@ static int make_ciff_file(unsigned char *inbuf, unsigned int length, | |||
83 | memcpy(&outbuf[0x70], "ATAD", 4); | 67 | memcpy(&outbuf[0x70], "ATAD", 4); |
84 | int2le(length+32, &outbuf[0x74]); | 68 | int2le(length+32, &outbuf[0x74]); |
85 | memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m", | 69 | memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m", |
86 | 32); /*Unicode encoded*/ | 70 | 25); /*Unicode encoded*/ |
71 | memset(&outbuf[0x78+25], 0, 32); | ||
87 | memcpy(&outbuf[0x98], inbuf, length); | 72 | memcpy(&outbuf[0x98], inbuf, length); |
88 | memcpy(&outbuf[0x98+length], "LLUN", 4); | 73 | memcpy(&outbuf[0x98+length], "LLUN", 4); |
89 | int2le(20, &outbuf[0x98+length+4]); | 74 | int2le(20, &outbuf[0x98+length+4]); |
@@ -94,57 +79,76 @@ static int make_ciff_file(unsigned char *inbuf, unsigned int length, | |||
94 | return length+0x90+0x1C+8; | 79 | return length+0x90+0x1C+8; |
95 | } | 80 | } |
96 | 81 | ||
97 | static int make_jrm_file(unsigned char *inbuf, unsigned int length, | 82 | static int elf_convert(const unsigned char *inbuf, unsigned char *outbuf) |
98 | unsigned char *outbuf, int device) | ||
99 | { | 83 | { |
100 | unsigned int i; | 84 | Elf32_Ehdr *main_header; |
101 | unsigned int sum = 0; | 85 | Elf32_Shdr *section_header; |
86 | unsigned int i, j, sum, startaddr; | ||
87 | |||
88 | main_header = (Elf32_Ehdr*)inbuf; | ||
89 | if( !( main_header->e_ident[0] == ELFMAG0 && main_header->e_ident[1] == ELFMAG1 | ||
90 | && main_header->e_ident[2] == ELFMAG2 && main_header->e_ident[3] == ELFMAG3 ) ) | ||
91 | { | ||
92 | printf("Invalid ELF header!\n"); | ||
93 | return -1; | ||
94 | } | ||
95 | |||
96 | startaddr = (unsigned int)outbuf; | ||
97 | |||
98 | for(i = 0; i < main_header->e_shnum; i++) | ||
99 | { | ||
100 | section_header = (Elf32_Shdr*)(inbuf+main_header->e_shoff+i*sizeof(Elf32_Shdr)); | ||
101 | |||
102 | if( (section_header->sh_flags & SHF_WRITE || section_header->sh_flags & SHF_ALLOC | ||
103 | || section_header->sh_flags & SHF_EXECINSTR) && section_header->sh_size > 0 | ||
104 | && section_header->sh_type != SHT_NOBITS ) | ||
105 | { | ||
106 | /* Address */ | ||
107 | int2le(section_header->sh_addr, outbuf); | ||
108 | outbuf += 4; | ||
109 | /* Size */ | ||
110 | int2le(section_header->sh_size, outbuf); | ||
111 | outbuf += 4; | ||
112 | /* Checksum */ | ||
113 | sum = 0; | ||
114 | for(j=0; j<section_header->sh_size; j+= 4) | ||
115 | sum += le2int((unsigned char*)(inbuf+section_header->sh_offset+j)) + (le2int((unsigned char*)(inbuf+section_header->sh_offset+j))>>16); | ||
116 | int2le(sum, outbuf); | ||
117 | outbuf += 2; | ||
118 | memset(outbuf, 0, 2); | ||
119 | outbuf += 2; | ||
120 | /* Data */ | ||
121 | memcpy(outbuf, inbuf+section_header->sh_offset, section_header->sh_size); | ||
122 | outbuf += section_header->sh_size; | ||
123 | } | ||
124 | } | ||
125 | return (unsigned int)(outbuf - startaddr); | ||
126 | } | ||
127 | |||
128 | static int make_jrm_file(const unsigned char *inbuf, unsigned char *outbuf) | ||
129 | { | ||
130 | int length; | ||
102 | 131 | ||
103 | /* Clear the header area to zero */ | 132 | /* Clear the header area to zero */ |
104 | memset(outbuf, 0, 0x18); | 133 | memset(outbuf, 0, 0x18); |
105 | 134 | ||
106 | /* Header (EDOC) */ | 135 | /* Header (EDOC) */ |
107 | memcpy(outbuf, "EDOC", 4); | 136 | memcpy(outbuf, "EDOC", 4); |
108 | /* Total Size */ | 137 | /* Total Size: temporarily set to 0 */ |
109 | #define SIZEOF_BOOTLOADER_CODE devices[device].bootloader_size | 138 | memset(&outbuf[0x4], 0, 4); |
110 | int2le(4+0xC+SIZEOF_BOOTLOADER_CODE+0xC+length, &outbuf[0x4]); | ||
111 | /* 4 bytes of zero */ | 139 | /* 4 bytes of zero */ |
112 | memset(&outbuf[0x8], 0, 0x4); | 140 | memset(&outbuf[0x8], 0, 4); |
113 | 141 | ||
114 | /* First block starts here ... */ | 142 | length = elf_convert(inbuf, &outbuf[0xC]); |
115 | /* Address = 0x0 */ | 143 | if(length < 0) |
116 | memset(&outbuf[0xC], 0, 0x4); | 144 | return -1; |
117 | /* Size */ | 145 | /* Now set the actual Total Size */ |
118 | int2le(SIZEOF_BOOTLOADER_CODE, &outbuf[0x10]); | 146 | int2le(4+length, &outbuf[0x4]); |
119 | /* Checksum */ | 147 | |
120 | for(i=0; i<SIZEOF_BOOTLOADER_CODE; i+= 4) | 148 | return 0xC+length; |
121 | sum += le2int((unsigned char*)&devices[device].bootloader[i]) + (le2int((unsigned char*)&devices[device].bootloader[i])>>16); | ||
122 | int2le(sum, &outbuf[0x14]); | ||
123 | outbuf[0x16] = 0; | ||
124 | outbuf[0x17] = 0; | ||
125 | /*Data */ | ||
126 | memcpy(&outbuf[0x18], devices[device].bootloader, SIZEOF_BOOTLOADER_CODE); | ||
127 | |||
128 | /* Second block starts here ... */ | ||
129 | /* Address = depends on target */ | ||
130 | #define SB_START (0x18+SIZEOF_BOOTLOADER_CODE) | ||
131 | int2le(devices[device].memory_address, &outbuf[SB_START]); | ||
132 | /* Size */ | ||
133 | int2le(length, &outbuf[SB_START+0x4]); | ||
134 | /* Checksum */ | ||
135 | sum = 0; | ||
136 | for(i=0; i<length; i+= 4) | ||
137 | sum += le2int(&inbuf[i]) + (le2int(&inbuf[i])>>16); | ||
138 | int2le(sum, &outbuf[SB_START+0x8]); | ||
139 | outbuf[SB_START+0xA] = 0; | ||
140 | outbuf[SB_START+0xB] = 0; | ||
141 | /* Data */ | ||
142 | memcpy(&outbuf[SB_START+0xC], inbuf, length); | ||
143 | |||
144 | return SB_START+0xC+length; | ||
145 | } | 149 | } |
146 | 150 | ||
147 | int zvm_encode(char *iname, char *oname, int device) | 151 | int zvm_encode(const char *iname, const char *oname, int device) |
148 | { | 152 | { |
149 | size_t len; | 153 | size_t len; |
150 | int length; | 154 | int length; |
@@ -164,7 +168,7 @@ int zvm_encode(char *iname, char *oname, int device) | |||
164 | 168 | ||
165 | buf = (unsigned char*)malloc(length); | 169 | buf = (unsigned char*)malloc(length); |
166 | if ( !buf ) { | 170 | if ( !buf ) { |
167 | printf("out of memory!\n"); | 171 | printf("Out of memory!\n"); |
168 | return -1; | 172 | return -1; |
169 | } | 173 | } |
170 | 174 | ||
@@ -178,11 +182,17 @@ int zvm_encode(char *iname, char *oname, int device) | |||
178 | outbuf = (unsigned char*)malloc(length+0x300); | 182 | outbuf = (unsigned char*)malloc(length+0x300); |
179 | if ( !outbuf ) { | 183 | if ( !outbuf ) { |
180 | free(buf); | 184 | free(buf); |
181 | printf("out of memory!\n"); | 185 | printf("Out of memory!\n"); |
182 | return -1; | 186 | return -1; |
183 | } | 187 | } |
184 | length = make_jrm_file(buf, len, outbuf, device); | 188 | length = make_jrm_file(buf, outbuf); |
185 | free(buf); | 189 | free(buf); |
190 | if(length < 0) | ||
191 | { | ||
192 | free(outbuf); | ||
193 | printf("Error in making JRM file!\n"); | ||
194 | return -1; | ||
195 | } | ||
186 | buf = (unsigned char*)malloc(length+0x200); | 196 | buf = (unsigned char*)malloc(length+0x200); |
187 | memset(buf, 0, length+0x200); | 197 | memset(buf, 0, length+0x200); |
188 | length = make_ciff_file(outbuf, length, buf, device); | 198 | length = make_ciff_file(outbuf, length, buf, device); |