SA9200 boot: Add OF.ebn to the list of OF filenames to check.
[kugel-rb.git] / tools / telechips.c
blobacb15b8b148611ffa24d4e8d0a80915b7edc61b2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Telechips firmware checksum support for scramble
12 * Copyright (C) 2007 Dave Chapman
14 * Thanks to Hein-Pieter van Braam for his work in identifying the
15 * CRC algorithm used.
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
25 ****************************************************************************/
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
36 static uint32_t crctable[256];
38 /* Simple implementation of a function to reverse the bottom n bits in x */
39 static uint32_t bitreverse(uint32_t x,int n)
41 int i;
42 uint32_t mask = 1<<(n-1);
43 uint32_t res = 0;
45 for (i=0; i<n; i++)
47 if (x & 1)
48 res |= mask;
50 x >>= 1;
51 mask >>= 1;
53 return res;
56 /* Generate a lookup table for a reverse CRC32 */
57 static void gentable(uint32_t poly)
59 int i;
60 uint32_t r;
61 uint32_t idx;
63 for (idx = 0; idx < 256; idx++)
65 r = bitreverse(idx,8) << 24;
66 for (i=0; i<8; i++)
68 if (r & (1 << 31))
69 r = (r << 1) ^ poly;
70 else
71 r<<=1;
73 crctable[idx] = bitreverse(r,32);
77 /* Perform a reverse CRC32 */
78 static uint32_t calc_crc(unsigned char *message, int size)
80 uint32_t crc = 0;
81 int i;
83 for (i=0; i < size; i++){
84 if ((i < 0x10) || (i >= 0x18)) {
85 crc = crctable[((crc ^ (message[i])) & 0xff)] ^ (crc >> 8);
89 return crc;
92 /* Endian-safe functions to read/write a 32-bit little-endian integer */
94 static uint32_t get_uint32le(unsigned char* p)
96 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
99 static void put_uint32le(unsigned char* p, uint32_t x)
101 p[0] = x & 0xff;
102 p[1] = (x >> 8) & 0xff;
103 p[2] = (x >> 16) & 0xff;
104 p[3] = (x >> 24) & 0xff;
107 /* A simple checksum - seems to be used by the TCC76x firmwares */
108 void telechips_encode_sum(unsigned char* buf, int length)
110 uint32_t sum;
111 int i;
113 /* Set checksum field to 0 */
114 put_uint32le(buf + 0x10, 0);
116 /* Perform a simple sum, treating the file as a series of 32-bit
117 little-endian integers */
118 sum = 0;
119 for (i=0; i < length; i+=4) {
120 sum += get_uint32le(buf + i);
122 /* Negate the sum - this means that the sum of the whole file
123 (including this value) will be equal to zero */
124 sum = -sum;
126 /* Set the checksum field */
127 put_uint32le(buf + 0x10, sum);
131 /* Two reverse CRC32 checksums - seems to be used by the TCC77x firmwares */
132 void telechips_encode_crc(unsigned char* buf, int length)
134 uint32_t crc1,crc2;
136 /* Generate the CRC table */
137 gentable(0x8001801BL);
139 /* Clear the existing CRC values */
140 put_uint32le(buf+0x10, 0);
141 put_uint32le(buf+0x18, 0);
143 /* Write the length */
144 put_uint32le(buf+0x1c, length);
146 /* Calculate the first CRC - over the entire file */
147 crc1 = calc_crc(buf, length);
149 /* What happens next depends on the filesize */
150 if (length >= 128*1024)
152 put_uint32le(buf+0x18, crc1);
154 crc2 = calc_crc(buf, 128*1024);
155 put_uint32le(buf+0x10, crc2);
156 } else {
157 put_uint32le(buf+0x10, crc1);
161 int telechips_test_crc(unsigned char* buf, int length)
163 uint32_t crc1, crc2, test_crc1, test_crc2;
164 unsigned char *test_buf;
166 crc1 = get_uint32le(buf + 0x10);
167 crc2 = get_uint32le(buf + 0x18);
169 test_buf = malloc(length);
170 if (!test_buf)
171 return 1;
173 memcpy(test_buf, buf, length);
174 telechips_encode_crc(test_buf, length);
176 test_crc1 = get_uint32le(test_buf + 0x10);
177 test_crc2 = get_uint32le(test_buf + 0x18);
179 free(test_buf);
181 return (crc1 == test_crc1 && crc2 == test_crc2) ? 0 : 2;