1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Dave Chapman
12 * Based on mkboot, Copyright (C) 2005 by Linus Nielsen Feltzing
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
27 #include <sys/types.h>
31 #include "mktccboot.h"
32 #include "telechips.h"
36 Append a Rockbox bootloader to a Telechips original firmware file.
38 The first instruction in a TCC firmware file is always of the form:
42 where [pc, #xxx] is the entry point of the firmware - e.g. 0x20000020
44 mktccboot appends the Rockbox bootloader to the end of the original
45 firmware image and replaces the contents of [pc, #xxx] with the entry
46 point of our bootloader - i.e. the length of the original firmware plus
49 It then stores the original entry point from [pc, #xxx] in a fixed
50 offset in the Rockbox boootloader, which is used by the bootloader to
53 Finally, mktccboot corrects the length and CRCs in the main firmware
54 header, creating a new legal firmware file which can be installed on
59 /* win32 compatibility */
65 static void put_uint32le(uint32_t x
, unsigned char* p
)
68 p
[1] = (x
>> 8) & 0xff;
69 p
[2] = (x
>> 16) & 0xff;
70 p
[3] = (x
>> 24) & 0xff;
73 static uint32_t get_uint32le(unsigned char* p
)
75 return (p
[3] << 24) | (p
[2] << 16) | (p
[1]<<8) | p
[0];
80 printf("Usage: mktccboot <firmware file> <boot file> <output file>\n");
85 static off_t
filesize(int fd
) {
88 if (fstat(fd
,&buf
) < 0) {
89 perror("[ERR] Checking filesize of input file");
96 #define DRAMORIG 0x20000000
97 /* Injects a bootloader into a Telechips 77X/78X firmware file */
98 unsigned char *patch_firmware_tcc(unsigned char *of_buf
, int of_size
,
99 unsigned char *boot_buf
, int boot_size
, int *patched_size
)
101 unsigned char *patched_buf
;
102 uint32_t ldr
, old_ep_offset
, new_ep_offset
;
105 patched_buf
= malloc(of_size
+ boot_size
);
109 memcpy(patched_buf
, of_buf
, of_size
);
110 memcpy(patched_buf
+ of_size
, boot_buf
, boot_size
);
112 ldr
= get_uint32le(patched_buf
);
114 /* TODO: Verify it's a LDR instruction */
115 of_offset
= (ldr
& 0xfff) + 8;
116 old_ep_offset
= get_uint32le(patched_buf
+ of_offset
);
117 new_ep_offset
= DRAMORIG
+ of_size
;
119 printf("OF entry point: 0x%08x\n", old_ep_offset
);
120 printf("New entry point: 0x%08x\n", new_ep_offset
+ 8);
122 /* Save the OF entry point at the start of the bootloader image */
123 put_uint32le(old_ep_offset
, patched_buf
+ of_size
);
124 put_uint32le(new_ep_offset
, patched_buf
+ of_size
+ 4);
126 /* Change the OF entry point to the third word in our bootloader */
127 put_uint32le(new_ep_offset
+ 8, patched_buf
+ of_offset
);
129 telechips_encode_crc(patched_buf
, of_size
+ boot_size
);
130 *patched_size
= of_size
+ boot_size
;
135 unsigned char *file_read(char *filename
, int *size
)
137 unsigned char *buf
= NULL
;
140 /* Open file for reading */
141 fd
= open(filename
, O_RDONLY
|O_BINARY
);
144 printf("[ERR] Could open file for reading, aborting\n");
149 /* Get file size, and allocate a buffer of that size */
150 *size
= filesize(fd
);
154 printf("[ERR] Could not allocate memory, aborting\n");
158 /* Read the file's content to the buffer */
159 n
= read(fd
, buf
, *size
);
162 printf("[ERR] Could not read from %s\n", filename
);
179 int main(int argc
, char *argv
[])
181 char *infile
, *bootfile
, *outfile
;
183 int n
, of_size
, boot_size
, patched_size
;
184 unsigned char *of_buf
;
185 unsigned char *boot_buf
= NULL
;
186 unsigned char* image
= NULL
;
197 /* Read OF and boot files */
198 of_buf
= file_read(infile
, &of_size
);
205 boot_buf
= file_read(bootfile
, &boot_size
);
212 /* Allocate buffer for patched firmware */
213 image
= malloc(of_size
+ boot_size
);
216 printf("[ERR] Could not allocate memory, aborting\n");
221 /* Create the patched firmware */
222 image
= patch_firmware_tcc(of_buf
, of_size
, boot_buf
, boot_size
,
226 printf("[ERR] Error creating patched firmware, aborting\n");
231 fdout
= open(outfile
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0644);
239 n
= write(fdout
, image
, patched_size
);
240 if (n
!= patched_size
)
242 printf("[ERR] Could not write output file %s\n",outfile
);