summaryrefslogtreecommitdiffstats
path: root/tools/rkw.c
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2012-02-28 23:36:13 +0100
committerMarcin Bukat <marcin.bukat@gmail.com>2012-03-04 00:33:41 +0100
commitf35e300304388c30fdeb6493ec5e5e5bd52e3aab (patch)
treedb0bfba04e30c59dea9b94c902541c86e494dc3c /tools/rkw.c
parent1c565c9c3b5005ca1f1708040718e35a0cf69e88 (diff)
downloadrockbox-f35e300304388c30fdeb6493ec5e5e5bd52e3aab.tar.gz
rockbox-f35e300304388c30fdeb6493ec5e5e5bd52e3aab.tar.bz2
rockbox-f35e300304388c30fdeb6493ec5e5e5bd52e3aab.zip
scramble: add RKW firmware file format encoder
Change-Id: I8057d6186724c3e8a319a262f45c12da7afb722e
Diffstat (limited to 'tools/rkw.c')
-rw-r--r--tools/rkw.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/tools/rkw.c b/tools/rkw.c
new file mode 100644
index 0000000000..db86b4f748
--- /dev/null
+++ b/tools/rkw.c
@@ -0,0 +1,166 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2012 Marcin Bukat
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#define RKLD_MAGIC 0x4c44524b
+#define RKW_HEADER_SIZE 0x2c
+
+/* slightly modified version from crc32.c in rockbox */
+static uint32_t rkw_crc32(const void *src, uint32_t len)
+{
+ const unsigned char *buf = (const unsigned char *)src;
+
+ /* polynomial 0x04c10db7 */
+ static const uint32_t crc32_lookup[16] =
+ { /* lookup table for 4 bits at a time is affordable */
+ 0x00000000, 0x04C10DB7, 0x09821B6E, 0x0D4316D9,
+ 0x130436DC, 0x17C53B6B, 0x1A862DB2, 0x1E472005,
+ 0x26086DB8, 0x22C9600F, 0x2F8A76D6, 0x2B4B7B61,
+ 0x350C5B64, 0x31CD56D3, 0x3C8E400A, 0x384F4DBD
+ };
+
+ uint32_t crc32 = 0;
+ unsigned char byte;
+ uint32_t t;
+
+ while (len--)
+ {
+ byte = *buf++; /* get one byte of data */
+
+ /* upper nibble of our data */
+ t = crc32 >> 28; /* extract the 4 most significant bits */
+ t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
+ crc32 <<= 4; /* shift the CRC register left 4 bits */
+ crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
+
+ /* lower nibble of our data */
+ t = crc32 >> 28; /* extract the 4 most significant bits */
+ t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
+ crc32 <<= 4; /* shift the CRC register left 4 bits */
+ crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
+ }
+
+ return crc32;
+}
+
+static void int2le(unsigned int val, unsigned char* addr)
+{
+ addr[0] = val & 0xFF;
+ addr[1] = (val >> 8) & 0xff;
+ addr[2] = (val >> 16) & 0xff;
+ addr[3] = (val >> 24) & 0xff;
+}
+
+int rkw_encode(char *iname, char *oname, unsigned long modelnum)
+{
+ size_t len;
+ int length;
+ int rkwlength;
+ FILE *file;
+ uint32_t binary_crc, header_crc;
+ unsigned char *outbuf;
+
+ file = fopen(iname, "rb");
+ if (!file)
+ {
+ perror(iname);
+ return -1;
+ }
+
+ fseek(file,0,SEEK_END);
+ length = ftell(file);
+
+ fseek(file,0,SEEK_SET);
+
+ /* length of the RKW header + binary length + 4 bytes of CRC */
+ rkwlength = (length + RKW_HEADER_SIZE + 4);
+
+ outbuf = malloc(rkwlength);
+
+ if (!outbuf)
+ {
+ printf("out of memory!\n");
+ fclose(file);
+ return -1;
+ }
+
+ /* Clear the buffer to zero */
+ memset(outbuf, 0, rkwlength);
+
+ /* Build the RKW header */
+ int2le(RKLD_MAGIC, outbuf); /* magic */
+ int2le(RKW_HEADER_SIZE, outbuf+0x04); /* header size */
+ int2le(0x60000000, outbuf+0x08); /* base address */
+ int2le(0x60000000, outbuf+0x0c); /* load address */
+ int2le(0x60000000+length, outbuf+0x10); /* end address */
+ int2le(0x6035a5e4, outbuf+0x14); /* points to some unknown struct */
+ int2le(modelnum, outbuf+0x18); /* reserved (we abuse the format
+ * to store modelnum here
+ */
+ int2le(0, outbuf+0x1c); /* reserved */
+ int2le(0x60000000, outbuf+0x20); /* entry point */
+ int2le(0xe0000000, outbuf+0x24); /* flags */
+
+ header_crc = rkw_crc32(outbuf, RKW_HEADER_SIZE - 4);
+
+ int2le(header_crc, outbuf+0x28); /* header CRC */
+
+ /* Copy the binary */
+ len = fread(outbuf + RKW_HEADER_SIZE, 1, length, file);
+ if(len < (size_t)length)
+ {
+ perror(iname);
+ free(outbuf);
+ fclose(file);
+ return -2;
+ }
+ fclose(file);
+
+ /* calc binary CRC and put at the end */
+ binary_crc = rkw_crc32 (outbuf + RKW_HEADER_SIZE, length);
+ int2le(binary_crc, outbuf + rkwlength - 4);
+
+ file = fopen(oname, "wb");
+ if (!file)
+ {
+ perror(oname);
+ free(outbuf);
+ return -3;
+ }
+
+ len = fwrite(outbuf, 1, rkwlength, file);
+ if(len < (size_t)length)
+ {
+ perror(oname);
+ fclose(file);
+ free(outbuf);
+ return -4;
+ }
+
+ fclose(file);
+ free(outbuf);
+ fprintf(stderr, "File encoded successfully\n" );
+
+ return 0;
+}