From c876d3bbefe0dc00c27ca0c12d29da5874946962 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Wed, 15 Dec 2021 21:04:28 +0100 Subject: rbutil: Merge rbutil with utils folder. rbutil uses several components from the utils folder, and can be considered part of utils too. Having it in a separate folder is an arbitrary split that doesn't help anymore these days, so merge them. This also allows other utils to easily use libtools.make without the need to navigate to a different folder. Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21 --- utils/mknwzboot/mknwzboot.c | 294 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 utils/mknwzboot/mknwzboot.c (limited to 'utils/mknwzboot/mknwzboot.c') diff --git a/utils/mknwzboot/mknwzboot.c b/utils/mknwzboot/mknwzboot.c new file mode 100644 index 0000000000..22885674d8 --- /dev/null +++ b/utils/mknwzboot/mknwzboot.c @@ -0,0 +1,294 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by 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 +#include +#include +#include +#include +#include "mknwzboot.h" +#include "upg.h" + +#include "install_script.h" +#include "uninstall_script.h" + +struct nwz_model_desc_t +{ + /* Descriptive name of this model */ + const char *model_name; + /* Model name used in the Rockbox header in ".sansa" files - these match the + -add parameter to the "scramble" tool */ + const char *rb_model_name; + /* Model number used to initialise the checksum in the Rockbox header in + ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */ + const int rb_model_num; + /* Codename used in upgtool */ + const char *codename; +}; + +static const struct nwz_model_desc_t nwz_models[] = +{ + { "Sony NWZ-E350 Series", "e350", 109, "nwz-e350" }, + { "Sony NWZ-E450 Series", "e450", 100, "nwz-e450" }, + { "Sony NWZ-E460 Series", "e460", 101, "nwz-e460" }, + { "Sony NWZ-E470 Series", "e470", 103, "nwz-e470" }, + { "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" }, + { "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" }, + { "Sony NW-A20 Series", "a20", 106, "nw-a20" }, + { "Sony NWZ-A860 Series", "a860", 107, "nwz-a860" }, + { "Sony NWZ-S750 Series", "s750", 108, "nwz-s750" }, +}; + +#define NR_NWZ_MODELS (sizeof(nwz_models) / sizeof(nwz_models[0])) + +void dump_nwz_dev_info(const char *prefix) +{ + printf("%smknwzboot models:\n", prefix); + for(int i = 0; i < NR_NWZ_MODELS; i++) + { + printf("%s %s: rb_model=%s rb_num=%d codename=%s\n", prefix, + nwz_models[i].model_name, nwz_models[i].rb_model_name, + nwz_models[i].rb_model_num, nwz_models[i].codename); + } +} + +/* read a file to a buffer */ +static void *read_file(const char *file, size_t *size) +{ + FILE *f = fopen(file, "rb"); + if(f == NULL) + { + printf("[ERR] Cannot open file '%s' for reading: %m\n", file); + return NULL; + } + fseek(f, 0, SEEK_END); + *size = ftell(f); + fseek(f, 0, SEEK_SET); + void *buffer = malloc(*size); + if(fread(buffer, *size, 1, f) != 1) + { + free(buffer); + fclose(f); + printf("[ERR] Cannot read file '%s': %m\n", file); + return NULL; + } + fclose(f); + return buffer; +} + +/* write a file from a buffer */ +static bool write_file(const char *file, void *buffer, size_t size) +{ + FILE *f = fopen(file, "wb"); + if(f == NULL) + { + printf("[ERR] Cannot open file '%s' for writing: %m\n", file); + return false; + } + if(fwrite(buffer, size, 1, f) != 1) + { + fclose(f); + printf("[ERR] Cannot write file '%s': %m\n", file); + return false; + } + fclose(f); + return true; +} + +static unsigned int be2int(unsigned char* buf) +{ + return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); +} + +static int find_model(uint8_t *boot, size_t boot_size) +{ + if(boot_size < 8) + { + printf("[ERR] Boot file is too small to be valid\n"); + return -1; + } + /* find model by comparing magic scramble value */ + int model = 0; + for(; model < NR_NWZ_MODELS; model++) + if(memcmp(boot + 4, nwz_models[model].rb_model_name, 4) == 0) + break; + if(model == NR_NWZ_MODELS) + { + printf("[ERR] This player is not supported: %.4s\n", boot + 4); + return -1; + } + printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name); + /* verify checksum */ + uint32_t sum = nwz_models[model].rb_model_num; + for(int i = 8; i < boot_size; i++) + sum += boot[i]; + if(sum != be2int(boot)) + { + printf("[ERR] Checksum mismatch\n"); + return -1; + } + return model; +} + +static int find_model2(const char *model_str) +{ + /* since it can be confusing for the user, we accept both rbmodel and codename */ + /* find model by comparing magic scramble value */ + int model = 0; + for(; model < NR_NWZ_MODELS; model++) + if(strcmp(nwz_models[model].rb_model_name, model_str) == 0 || + strcmp(nwz_models[model].codename, model_str) == 0) + break; + if(model == NR_NWZ_MODELS) + { + printf("[ERR] Unknown model: %s\n", model_str); + return -1; + } + printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name); + return model; +} + +static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE]) +{ + const char *codename = nwz_models[model].codename; + for(int i = 0; g_model_list[i].model; i++) + if(strcmp(g_model_list[i].model, codename) == 0) + { + if(decrypt_keysig(g_model_list[i].kas, key, sig) == 0) + return true; + printf("[ERR] Cannot decrypt kas '%s'\n", g_model_list[i].kas); + return false; + } + printf("[ERR] Codename '%s' matches to entry in upg database\n", codename); + return false; +} + +void nwz_printf(void *u, bool err, color_t c, const char *f, ...) +{ + (void)err; + (void)c; + bool *debug = u; + va_list args; + va_start(args, f); + if(err || *debug) + vprintf(f, args); + va_end(args); +} + +static void *memdup(void *data, size_t size) +{ + void *buf = malloc(size); + memcpy(buf, data, size); + return buf; +} + +int mknwzboot(const char *bootfile, const char *outfile, bool debug) +{ + size_t boot_size; + uint8_t *boot = read_file(bootfile, &boot_size); + if(boot == NULL) + { + printf("[ERR] Cannot open boot file\n"); + return 1; + } + /* check that it is a valid scrambled file */ + int model = find_model(boot, boot_size); + if(model < 0) + { + free(boot); + printf("[ERR] Invalid boot file\n"); + return 2; + } + /* find keys */ + char key[NWZ_KEY_SIZE]; + char sig[NWZ_SIG_SIZE]; + if(!get_model_keysig(model, key, sig)) + { + printf("[ERR][INTERNAL] Cannot get keys for model\n"); + return 3; + } + /* create the upg file */ + struct upg_file_t *upg = upg_new(); + /* first file is the install script: we have to copy data because upg_free() + * will free it */ + upg_append(upg, memdup(install_script, LEN_install_script), LEN_install_script); + /* second file is the bootloader content (expected to be a tar file): we have + * to copy data because upg_free() will free it */ + upg_append(upg, memdup(boot + 8, boot_size - 8), boot_size - 8); + free(boot); + /* write file to buffer */ + size_t upg_size; + void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf); + upg_free(upg); + if(upg_buf == NULL) + { + printf("[ERR] Cannot create UPG file\n"); + return 4; + } + if(!write_file(outfile, upg_buf, upg_size)) + { + free(upg_buf); + printf("[ERR] Cannpt write UPG file\n"); + return 5; + } + free(upg_buf); + return 0; +} + +int mknwzboot_uninst(const char *model_string, const char *outfile, bool debug) +{ + /* check that it is a valid scrambled file */ + int model = find_model2(model_string); + if(model < 0) + { + printf("[ERR] Invalid model\n"); + return 2; + } + /* find keys */ + char key[NWZ_KEY_SIZE]; + char sig[NWZ_SIG_SIZE]; + if(!get_model_keysig(model, key, sig)) + { + printf("[ERR][INTERNAL] Cannot get keys for model\n"); + return 3; + } + /* create the upg file */ + struct upg_file_t *upg = upg_new(); + /* first file is the uninstall script: we have to copy data because upg_free() + * will free it */ + upg_append(upg, memdup(uninstall_script, LEN_uninstall_script), LEN_uninstall_script); + /* write file to buffer */ + size_t upg_size; + void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf); + upg_free(upg); + if(upg_buf == NULL) + { + printf("[ERR] Cannot create UPG file\n"); + return 4; + } + if(!write_file(outfile, upg_buf, upg_size)) + { + free(upg_buf); + printf("[ERR] Cannpt write UPG file\n"); + return 5; + } + free(upg_buf); + return 0; +} -- cgit v1.2.3