forked from len0rd/rockbox
		
	git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23470 a1c6a512-1295-4272-9138-f99709370657
		
			
				
	
	
		
			182 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***************************************************************************
 | |
|  *             __________               __   ___.
 | |
|  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 | |
|  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 | |
|  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 | |
|  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 | |
|  *                     \/            \/     \/    \/            \/
 | |
|  * $Id$
 | |
|  *
 | |
|  * Telechips firmware checksum support for scramble
 | |
|  *
 | |
|  * Copyright (C) 2007 Dave Chapman
 | |
|  *
 | |
|  * Thanks to Hein-Pieter van Braam for his work in identifying the
 | |
|  * CRC algorithm used.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 | |
|  * KIND, either express or implied.
 | |
|  *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <stdint.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| static uint32_t crctable[256];
 | |
| 
 | |
| /* Simple implementation of a function to reverse the bottom n bits in x */
 | |
| static uint32_t bitreverse(uint32_t x,int n)
 | |
| {
 | |
|     int i;
 | |
|     uint32_t mask = 1<<(n-1);
 | |
|     uint32_t res = 0;
 | |
| 
 | |
|     for (i=0; i<n; i++)
 | |
|     {
 | |
|         if (x & 1)
 | |
|             res |=  mask;
 | |
| 
 | |
|         x >>= 1;
 | |
|         mask >>= 1;
 | |
|     }
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| /* Generate a lookup table for a reverse CRC32 */
 | |
| static void gentable(uint32_t poly)
 | |
| {
 | |
|     int i;
 | |
|     uint32_t r;
 | |
|     uint32_t idx;
 | |
| 
 | |
|     for (idx = 0; idx < 256; idx++)
 | |
|     {
 | |
|         r = bitreverse(idx,8) << 24;
 | |
|         for (i=0; i<8; i++)
 | |
|         {
 | |
|             if (r & (1 << 31))
 | |
|                 r = (r << 1) ^ poly;
 | |
|             else
 | |
|                 r<<=1;
 | |
|         }
 | |
|         crctable[idx] = bitreverse(r,32);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Perform a reverse CRC32 */
 | |
| static uint32_t calc_crc(unsigned char *message, int size)
 | |
| {
 | |
|     uint32_t crc = 0;
 | |
|     int i;
 | |
| 
 | |
|     for (i=0; i < size; i++){
 | |
|         if ((i < 0x10) || (i >= 0x18)) {
 | |
|             crc = crctable[((crc ^ (message[i])) & 0xff)] ^ (crc >> 8);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return crc;
 | |
| }
 | |
| 
 | |
| /* Endian-safe functions to read/write a 32-bit little-endian integer */
 | |
| 
 | |
| static uint32_t get_uint32le(unsigned char* p)
 | |
| {
 | |
|     return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
 | |
| }
 | |
| 
 | |
| static void put_uint32le(unsigned char* p, uint32_t x)
 | |
| {
 | |
|     p[0] = x & 0xff;
 | |
|     p[1] = (x >> 8) & 0xff;
 | |
|     p[2] = (x >> 16) & 0xff;
 | |
|     p[3] = (x >> 24) & 0xff;
 | |
| }
 | |
| 
 | |
| /* A simple checksum - seems to be used by the TCC76x firmwares */
 | |
| void telechips_encode_sum(unsigned char* buf, int length)
 | |
| {
 | |
|     uint32_t sum;
 | |
|     int i;
 | |
| 
 | |
|     /* Set checksum field to 0 */
 | |
|     put_uint32le(buf + 0x10, 0);
 | |
| 
 | |
|     /* Perform a simple sum, treating the file as a series of 32-bit
 | |
|        little-endian integers */
 | |
|     sum = 0;
 | |
|     for (i=0; i < length; i+=4) {
 | |
|         sum += get_uint32le(buf + i);
 | |
|     }
 | |
|     /* Negate the sum - this means that the sum of the whole file
 | |
|        (including this value) will be equal to zero */
 | |
|     sum = -sum;
 | |
| 
 | |
|     /* Set the checksum field */
 | |
|     put_uint32le(buf + 0x10, sum);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Two reverse CRC32 checksums - seems to be used by the TCC77x firmwares */
 | |
| void telechips_encode_crc(unsigned char* buf, int length)
 | |
| {
 | |
|     uint32_t crc1,crc2;
 | |
| 
 | |
|     /* Generate the CRC table */
 | |
|     gentable(0x8001801BL);
 | |
| 
 | |
|     /* Clear the existing CRC values */
 | |
|     put_uint32le(buf+0x10, 0);
 | |
|     put_uint32le(buf+0x18, 0);
 | |
| 
 | |
|     /* Write the length */
 | |
|     put_uint32le(buf+0x1c, length);
 | |
| 
 | |
|     /* Calculate the first CRC - over the entire file */
 | |
|     crc1 = calc_crc(buf, length);
 | |
| 
 | |
|     /* What happens next depends on the filesize */
 | |
|     if (length >= 128*1024)
 | |
|     {
 | |
|         put_uint32le(buf+0x18, crc1);
 | |
| 
 | |
|         crc2 = calc_crc(buf, 128*1024);
 | |
|         put_uint32le(buf+0x10, crc2);
 | |
|     } else {
 | |
|         put_uint32le(buf+0x10, crc1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| int telechips_test_crc(unsigned char* buf, int length)
 | |
| {
 | |
|     uint32_t crc1, crc2, test_crc1, test_crc2;
 | |
|     unsigned char *test_buf;
 | |
| 
 | |
|     crc1 = get_uint32le(buf + 0x10);
 | |
|     crc2 = get_uint32le(buf + 0x18);
 | |
| 
 | |
|     test_buf = malloc(length);
 | |
|     if (!test_buf)
 | |
|         return 1;
 | |
| 
 | |
|     memcpy(test_buf, buf, length);
 | |
|     telechips_encode_crc(test_buf, length);
 | |
| 
 | |
|     test_crc1 = get_uint32le(test_buf + 0x10);
 | |
|     test_crc2 = get_uint32le(test_buf + 0x18);
 | |
| 
 | |
|     free(test_buf);
 | |
| 
 | |
|     return (crc1 == test_crc1 && crc2 == test_crc2) ? 0 : 2;
 | |
| }
 |