summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-12-06 12:16:57 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2012-12-06 12:17:50 +0100
commitfb43a137e72d1f428efef00047a416497463edfb (patch)
tree5d933a0240418967cf85e17da48949d4ec24748b /utils
parent8666e83aaadfa7f334431da697b82963d649acc6 (diff)
downloadrockbox-fb43a137e72d1f428efef00047a416497463edfb.tar.gz
rockbox-fb43a137e72d1f428efef00047a416497463edfb.tar.bz2
rockbox-fb43a137e72d1f428efef00047a416497463edfb.zip
samsungtool: allow firmware creation
The new tool fwcrypt can create a firmware image with a specified model, version, region and so on. Change-Id: I0e90e9ab905398a3e7ae3f4fb8b8bbfb2d12d703
Diffstat (limited to 'utils')
-rw-r--r--utils/samsungtools/Makefile5
-rw-r--r--utils/samsungtools/fwcrypt.c170
-rw-r--r--utils/samsungtools/samsung.c51
-rw-r--r--utils/samsungtools/samsung.h4
4 files changed, 229 insertions, 1 deletions
diff --git a/utils/samsungtools/Makefile b/utils/samsungtools/Makefile
index 97af8bb873..1179de5243 100644
--- a/utils/samsungtools/Makefile
+++ b/utils/samsungtools/Makefile
@@ -3,7 +3,7 @@ CC=gcc
LD=gcc
CFLAGS=-g -std=c99 -W -Wall $(DEFINES) `pkg-config --cflags openssl`
LDFLAGS=`pkg-config --libs openssl`
-BINS=fwdecrypt
+BINS=fwdecrypt fwcrypt
all: $(BINS)
@@ -13,5 +13,8 @@ all: $(BINS)
fwdecrypt: fwdecrypt.o samsung.o
$(LD) -o $@ $^ $(LDFLAGS)
+fwcrypt: fwcrypt.o samsung.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
clean:
rm -fr *.o $(BINS)
diff --git a/utils/samsungtools/fwcrypt.c b/utils/samsungtools/fwcrypt.c
new file mode 100644
index 0000000000..f920406e12
--- /dev/null
+++ b/utils/samsungtools/fwcrypt.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 Amaury Pouly
+ *
+ * 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 "samsung.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <string.h>
+
+static bool g_debug = false;
+static char *g_out_prefix = NULL;
+
+static void usage(void)
+{
+ printf("Usage: fwcrypt [options] content\n");
+ printf("Options:\n");
+ printf(" -o <prefix>\tSet output file\n");
+ printf(" -m/--model <model>\tSet model\n");
+ printf(" -v/--version <ver>\tSet version\n");
+ printf(" -r/--region <region>\tSet region\n");
+ printf(" -e/--extra <extra>\tSet extra\n");
+ printf(" -?/--help\tDisplay this message\n");
+ printf(" -d/--debug\tDisplay debug messages\n");
+ exit(1);
+}
+
+static int s_write(void *user, int offset, void *buf, int size)
+{
+ FILE *f = user;
+ if(fseek(f, offset, SEEK_SET) != 0)
+ return 0;
+ return fwrite(buf, 1, size, f);
+}
+
+static void s_printf(void *user, bool error, const char *fmt, ...)
+{
+ if(!g_debug && !error)
+ return;
+ (void) user;
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+int main(int argc, char **argv)
+{
+ struct samsung_firmware_t *fw = malloc(sizeof(struct samsung_firmware_t));
+ memset(fw, 0, sizeof(struct samsung_firmware_t));
+
+ if(argc <= 1)
+ usage();
+
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"debug", no_argument, 0, 'd'},
+ {"model", required_argument, 0, 'm'},
+ {"version", required_argument, 0, 'v'},
+ {"region", required_argument, 0, 'r'},
+ {"extra", required_argument, 0, 'e'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?do:m:v:r:e:", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case -1:
+ break;
+ case 'd':
+ g_debug = true;
+ break;
+ case '?':
+ usage();
+ break;
+ case 'o':
+ g_out_prefix = optarg;
+ break;
+ case 'm':
+ strncpy(fw->model, optarg, sizeof(fw->model));
+ if(strlen(optarg) > sizeof(fw->model))
+ printf("Warning: truncate model string\n");
+ break;
+ case 'r':
+ strncpy(fw->region, optarg, sizeof(fw->region));
+ if(strlen(optarg) > sizeof(fw->region))
+ printf("Warning: truncate region string\n");
+ break;
+ case 'v':
+ strncpy(fw->version, optarg, sizeof(fw->version));
+ if(strlen(optarg) > sizeof(fw->version))
+ printf("Warning: truncate vesion string\n");
+ break;
+ case 'e':
+ strncpy(fw->extra, optarg, sizeof(fw->extra));
+ if(strlen(optarg) > sizeof(fw->extra))
+ printf("Warning: truncate extra string\n");
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if(optind != argc - 1)
+ usage();
+
+ FILE *fin = fopen(argv[optind], "rb");
+ if(fin == NULL)
+ {
+ printf("Cannot open file for reading: %m\n");
+ samsung_free(fw);
+ return 1;
+ }
+ fseek(fin, 0, SEEK_END);
+ fw->data_size = ftell(fin);
+ fseek(fin, 0, SEEK_SET);
+ fw->data = malloc(fw->data_size);
+ if((int)fread(fw->data, 1, fw->data_size, fin) != fw->data_size)
+ {
+ printf("Cannot read input file: %m\n");
+ samsung_free(fw);
+ return 2;
+ }
+ fclose(fin);
+
+ if(g_out_prefix)
+ {
+ FILE *f = fopen(g_out_prefix, "wb");
+ if(f == NULL)
+ {
+ printf("Cannot open file for writing: %m\n");
+ samsung_free(fw);
+ return 1;
+ }
+
+ enum samsung_error_t err = samsung_write(s_write, s_printf, f, fw);
+ if(err != SAMSUNG_SUCCESS)
+ {
+ printf("Error writing firmware: %d\n", err);
+ samsung_free(fw);
+ return 3;
+ }
+ fclose(f);
+ }
+ samsung_free(fw);
+
+ return 0;
+}
diff --git a/utils/samsungtools/samsung.c b/utils/samsungtools/samsung.c
index decf34f208..2d45b6f068 100644
--- a/utils/samsungtools/samsung.c
+++ b/utils/samsungtools/samsung.c
@@ -117,6 +117,57 @@ struct samsung_firmware_t *samsung_read(samsung_read_t read,
return fw;
}
+enum samsung_error_t samsung_write(samsung_write_t write, samsung_printf_t printf,
+ void *user, struct samsung_firmware_t *fw)
+{
+ struct yp_header_t yp_hdr;
+ struct yp_md5_t yp_md5;
+
+ // write header
+ strncpy(yp_hdr.signature, YP_SIGNATURE, sizeof(yp_hdr.signature));
+ strncpy(yp_hdr.version, fw->version, sizeof(yp_hdr.version));
+ strncpy(yp_hdr.region, fw->region, sizeof(yp_hdr.region));
+ strncpy(yp_hdr.extra, fw->extra, sizeof(yp_hdr.extra));
+ strncpy(yp_hdr.model, fw->model, sizeof(yp_hdr.model));
+ yp_hdr.datasize = fw->data_size;
+
+ printf(user, false, "Model: %s\n", yp_hdr.model);
+ printf(user, false, "Version: %s %s %s\n", yp_hdr.version, yp_hdr.region, yp_hdr.extra);
+
+ if(write(user, 0, &yp_hdr, sizeof(yp_hdr)) != sizeof(yp_hdr))
+ {
+ printf(user, true, "Cannot write header\n");
+ return SAMSUNG_WRITE_ERROR;
+ }
+
+ // encrypt data
+ cyclic_xor(fw->data, fw->data_size, g_yp_key, sizeof(g_yp_key));
+ // compute MD5
+ MD5_CTX c;
+ MD5_Init(&c);
+ MD5_Update(&c, fw->data, fw->data_size);
+ MD5_Final(yp_md5.md5, &c);
+
+ // write data
+ if(write(user, sizeof(yp_hdr), fw->data, fw->data_size) != fw->data_size)
+ {
+ // decrypt data so that the firmware data is the same after the call
+ cyclic_xor(fw->data, fw->data_size, g_yp_key, sizeof(g_yp_key));
+ printf(user, true, "Cannot write data\n");
+ return SAMSUNG_WRITE_ERROR;
+ }
+ // decrypt data so that the firmware data is the same after the call
+ cyclic_xor(fw->data, fw->data_size, g_yp_key, sizeof(g_yp_key));
+ // write md5
+ if(write(user, sizeof(yp_hdr) + fw->data_size, &yp_md5, sizeof(yp_md5)) != sizeof(yp_md5))
+ {
+ printf(user, true, "Cannot write md5\n");
+ return SAMSUNG_WRITE_ERROR;
+ }
+
+ return SAMSUNG_SUCCESS;
+}
+
void samsung_free(struct samsung_firmware_t *fw)
{
if(fw)
diff --git a/utils/samsungtools/samsung.h b/utils/samsungtools/samsung.h
index 4336e02651..70ac9c770c 100644
--- a/utils/samsungtools/samsung.h
+++ b/utils/samsungtools/samsung.h
@@ -66,13 +66,17 @@ enum samsung_error_t
SAMSUNG_READ_ERROR = -1,
SAMSUNG_FORMAT_ERROR = -2,
SAMSUNG_MD5_ERROR = -3,
+ SAMSUNG_WRITE_ERROR = -4,
};
typedef int (*samsung_read_t)(void *user, int offset, void *buffer, int size);
+typedef int (*samsung_write_t)(void *user, int offset, void *buffer, int size);
typedef void (*samsung_printf_t)(void *user, bool error, const char *fmt, ...);
struct samsung_firmware_t *samsung_read(samsung_read_t read,
samsung_printf_t printf, void *user, enum samsung_error_t *err);
+enum samsung_error_t samsung_write(samsung_write_t write, samsung_printf_t printf,
+ void *user, struct samsung_firmware_t *fw);
void samsung_free(struct samsung_firmware_t *fw);
#endif /* __SAMSUNG_H__ */