FS#10728 - Cowon D2: Add support for D2 in rbutil
[kugel-rb.git] / rbutil / mktccboot / mktccboot.c
blob2c6b08890e6012643196a5d3814c21a5303cbf14
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <inttypes.h>
31 #include "telechips.h"
35 Append a Rockbox bootloader to a Telechips original firmware file.
37 The first instruction in a TCC firmware file is always of the form:
39 ldr pc, [pc, #xxx]
41 where [pc, #xxx] is the entry point of the firmware - e.g. 0x20000020
43 mktccboot appends the Rockbox bootloader to the end of the original
44 firmware image and replaces the contents of [pc, #xxx] with the entry
45 point of our bootloader - i.e. the length of the original firmware plus
46 0x20000000.
48 It then stores the original entry point from [pc, #xxx] in a fixed
49 offset in the Rockbox boootloader, which is used by the bootloader to
50 dual-boot.
52 Finally, mktccboot corrects the length and CRCs in the main firmware
53 header, creating a new legal firmware file which can be installed on
54 the device.
58 /* win32 compatibility */
60 #ifndef O_BINARY
61 #define O_BINARY 0
62 #endif
64 static void put_uint32le(uint32_t x, unsigned char* p)
66 p[0] = x & 0xff;
67 p[1] = (x >> 8) & 0xff;
68 p[2] = (x >> 16) & 0xff;
69 p[3] = (x >> 24) & 0xff;
72 static uint32_t get_uint32le(unsigned char* p)
74 return (p[3] << 24) | (p[2] << 16) | (p[1]<<8) | p[0];
77 void usage(void)
79 printf("Usage: mktccboot <firmware file> <boot file> <output file>\n");
81 exit(1);
84 static off_t filesize(int fd) {
85 struct stat buf;
87 if (fstat(fd,&buf) < 0) {
88 perror("[ERR] Checking filesize of input file");
89 return -1;
90 } else {
91 return(buf.st_size);
95 #define DRAMORIG 0x20000000
96 /* Injects a bootloader into a Telechips 77X/78X firmware file */
97 unsigned char *patch_firmware_tcc(unsigned char *of_buf, int of_size,
98 unsigned char *boot_buf, int boot_size, int *patched_size)
100 unsigned char *patched_buf;
101 uint32_t ldr, old_ep_offset, new_ep_offset;
102 int of_offset;
104 patched_buf = malloc(of_size + boot_size);
105 if (!patched_buf)
106 return NULL;
108 memcpy(patched_buf, of_buf, of_size);
109 memcpy(patched_buf + of_size, boot_buf, boot_size);
111 ldr = get_uint32le(patched_buf);
113 /* TODO: Verify it's a LDR instruction */
114 of_offset = (ldr & 0xfff) + 8;
115 old_ep_offset = get_uint32le(patched_buf + of_offset);
116 new_ep_offset = DRAMORIG + of_size;
118 printf("OF entry point: 0x%08x\n", old_ep_offset);
119 printf("New entry point: 0x%08x\n", new_ep_offset + 8);
121 /* Save the OF entry point at the start of the bootloader image */
122 put_uint32le(old_ep_offset, patched_buf + of_size);
123 put_uint32le(new_ep_offset, patched_buf + of_size + 4);
125 /* Change the OF entry point to the third word in our bootloader */
126 put_uint32le(new_ep_offset + 8, patched_buf + of_offset);
128 telechips_encode_crc(patched_buf, of_size + boot_size);
129 *patched_size = of_size + boot_size;
131 return patched_buf;
134 unsigned char *file_read(char *filename, int *size)
136 unsigned char *buf = NULL;
137 int n, fd = -1;
139 /* Open file for reading */
140 fd = open(filename, O_RDONLY|O_BINARY);
141 if (fd < 0)
143 printf("[ERR] Could open file for reading, aborting\n");
144 perror(filename);
145 goto error;
148 /* Get file size, and allocate a buffer of that size */
149 *size = filesize(fd);
150 buf = malloc(*size);
151 if (buf == NULL)
153 printf("[ERR] Could not allocate memory, aborting\n");
154 goto error;
157 /* Read the file's content to the buffer */
158 n = read(fd, buf, *size);
159 if (n != *size)
161 printf("[ERR] Could not read from %s\n", filename);
162 goto error;
165 return buf;
167 error:
168 if (fd >= 0)
169 close(fd);
171 if (buf)
172 free(buf);
174 return NULL;
177 #ifndef LIB
178 int main(int argc, char *argv[])
180 char *infile, *bootfile, *outfile;
181 int fdout = -1;
182 int n, of_size, boot_size, patched_size;
183 unsigned char *of_buf;
184 unsigned char *boot_buf = NULL;
185 unsigned char* image = NULL;
186 int ret = 0;
188 if(argc < 3) {
189 usage();
192 infile = argv[1];
193 bootfile = argv[2];
194 outfile = argv[3];
196 /* Read OF and boot files */
197 of_buf = file_read(infile, &of_size);
198 if (!of_buf)
200 ret = 1;
201 goto error_exit;
204 boot_buf = file_read(bootfile, &boot_size);
205 if (!boot_buf)
207 ret = 3;
208 goto error_exit;
211 /* Allocate buffer for patched firmware */
212 image = malloc(of_size + boot_size);
213 if (image == NULL)
215 printf("[ERR] Could not allocate memory, aborting\n");
216 ret = 4;
217 goto error_exit;
220 /* Create the patched firmware */
221 image = patch_firmware_tcc(of_buf, of_size, boot_buf, boot_size,
222 &patched_size);
223 if (!image)
225 printf("[ERR] Error creating patched firmware, aborting\n");
226 ret = 5;
227 goto error_exit;
230 fdout = open(outfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
231 if (fdout < 0)
233 perror(outfile);
234 ret = 6;
235 goto error_exit;
238 n = write(fdout, image, patched_size);
239 if (n != patched_size)
241 printf("[ERR] Could not write output file %s\n",outfile);
242 ret = 7;
243 goto error_exit;
246 error_exit:
248 if (fdout >= 0)
249 close(fdout);
251 if (of_buf)
252 free(of_buf);
254 if (boot_buf)
255 free(boot_buf);
257 if (image)
258 free(image);
260 return ret;
262 #endif