From 097352a3ecf608f0934e1628c6b3cb783cf65b6c Mon Sep 17 00:00:00 2001 From: Andrew Ryabinin Date: Wed, 10 Oct 2012 12:17:48 +0400 Subject: Introduce mkrk27boot - tool for patching bootloader images of rk27xx targets. Change-Id: I37e15111eb9e761b8c6c25f9c1f65a827894a192 --- rbutil/mkrk27boot/Makefile | 77 +++++++++++ rbutil/mkrk27boot/ata-sim.c | 122 ++++++++++++++++++ rbutil/mkrk27boot/autoconf.h | 37 ++++++ rbutil/mkrk27boot/main.c | 55 ++++++++ rbutil/mkrk27boot/mkrk27boot.c | 281 +++++++++++++++++++++++++++++++++++++++++ rbutil/mkrk27boot/mkrk27boot.h | 36 ++++++ 6 files changed, 608 insertions(+) create mode 100644 rbutil/mkrk27boot/Makefile create mode 100644 rbutil/mkrk27boot/ata-sim.c create mode 100644 rbutil/mkrk27boot/autoconf.h create mode 100644 rbutil/mkrk27boot/main.c create mode 100644 rbutil/mkrk27boot/mkrk27boot.c create mode 100644 rbutil/mkrk27boot/mkrk27boot.h diff --git a/rbutil/mkrk27boot/Makefile b/rbutil/mkrk27boot/Makefile new file mode 100644 index 0000000000..cd1b7800de --- /dev/null +++ b/rbutil/mkrk27boot/Makefile @@ -0,0 +1,77 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +FIRMWARE = ../../firmware/ + +DRIVERS = $(FIRMWARE)drivers/ +EXPORT = $(FIRMWARE)export/ + +BUILDDATE=$(shell date -u +'-DYEAR=%Y -DMONTH=%m -DDAY=%d') +INCLUDE = -I$(EXPORT) -I$(FIRMWARE)include -I$(FIRMWARE)target/hosted -I$(FIRMWARE)target/hosted/sdl +DEFINES = -DTEST_FAT -DDISK_WRITE -DHAVE_FAT16SUPPORT -D__PCTOOL__ + +SIM_FLAGS = -Wall -g -std=gnu99 -Wno-pointer-sign $(DEFINES) $(BUILDDATE) -I. $(INCLUDE) -I$(FIRMWARE)/libc/include +FLAGS = -Wall -g -std=gnu99 -Wno-pointer-sign $(DEFINES) -I. $(INCLUDE) + +OUTPUT = mkrk27boot + + +# inputs +LIBSOURCES := $(DRIVERS)fat.c $(FIRMWARE)libc/ctype.c $(FIRMWARE)libc/strtok.c \ + $(FIRWARE)libc/errno.c$(FIRMWARE)common/strlcpy.c $(FIRMWARE)common/unicode.c \ + $(FIRMWARE)common/file.c $(FIRMWARE)common/dir_uncached.c $(FIRMWARE)common/disk.c ata-sim.c mkrk27boot.c + +SOURCES := $(LIBSOURCES) main.c + +include ../libtools.make + +define sim_compile + @echo CC $< + $(SILENT)mkdir -p $(dir $@) + $(SILENT)$(CROSS)$(CC) $(SIM_FLAGS) -c -o $@ $< +endef + +define compile + @echo CC $< + $(SILENT)mkdir -p $(dir $@) + $(SILENT)$(CROSS)$(CC) $(FLAGS) -c -o $@ $< +endef + +$(OBJDIR)fat.o: $(DRIVERS)fat.c $(EXPORT)fat.h $(EXPORT)ata.h autoconf.h + $(sim_compile) + +$(OBJDIR)ctype.o: $(FIRMWARE)libc/ctype.c autoconf.h + $(sim_compile) + +$(OBJDIR)strtok.o: $(FIRMWARE)libc/strtok.c $(FIRMWARE)libc/include/string.h autoconf.h + $(sim_compile) + +$(OBJDIR)errno.o: $(FIRMWARE)libc/errno.c $(FIRMWARE)libc/include/errno.h autoconf.h + $(sim_compile) + +$(OBJDIR)disk.o: $(FIRMWARE)common/disk.c autoconf.h + $(sim_compile) + +$(OBJDIR)dir_uncached.o: $(FIRMWARE)common/dir_uncached.c autoconf.h + $(sim_compile) + +$(OBJDIR)file.o: $(FIRMWARE)common/file.c $(FIRMWARE)/include/file.h autoconf.h + $(sim_compile) + +$(OBJDIR)unicode.o: $(FIRMWARE)common/unicode.c autoconf.h + $(sim_compile) + +$(OBJDIR)strlcpy.o: $(FIRMWARE)common/strlcpy.c autoconf.h + $(sim_compile) + +$(OBJDIR)ata-sim.o: ata-sim.c $(EXPORT)ata.h autoconf.h + $(compile) + +$(OBJDIR)mkrk27boot.o: mkrk27boot.c mkrk27boot.h autoconf.h + $(compile) diff --git a/rbutil/mkrk27boot/ata-sim.c b/rbutil/mkrk27boot/ata-sim.c new file mode 100644 index 0000000000..129c4b36a9 --- /dev/null +++ b/rbutil/mkrk27boot/ata-sim.c @@ -0,0 +1,122 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2012 by Andrew Ryabinin + * + * major portion of code is taken from firmware/test/fat/ata-sim.c + * + * 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 "debug.h" +#include "dir.h" + +#define BLOCK_SIZE 512 + +static FILE* file; + +extern char *img_filename; + +void mutex_init(struct mutex* l) {} +void mutex_lock(struct mutex* l) {} +void mutex_unlock(struct mutex* l) {} + +void panicf( char *fmt, ...) { + va_list ap; + va_start( ap, fmt ); + fprintf(stderr,"***PANIC*** "); + vfprintf(stderr, fmt, ap ); + va_end( ap ); + exit(1); +} + +void debugf(const char *fmt, ...) { + va_list ap; + va_start( ap, fmt ); + fprintf(stderr,"DEBUGF: "); + vfprintf( stderr, fmt, ap ); + va_end( ap ); +} + +void ldebugf(const char* file, int line, const char *fmt, ...) { + va_list ap; + va_start( ap, fmt ); + fprintf( stderr, "%s:%d ", file, line ); + vfprintf( stderr, fmt, ap ); + va_end( ap ); +} + +int storage_read_sectors(unsigned long start, int count, void* buf) +{ + if ( count > 1 ) + DEBUGF("[Reading %d blocks: 0x%lx to 0x%lx]\n", + count, start, start+count-1); + else + DEBUGF("[Reading block 0x%lx]\n", start); + + if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { + perror("fseek"); + return -1; + } + if(!fread(buf,BLOCK_SIZE,count,file)) { + DEBUGF("ata_write_sectors(0x%lx, 0x%x, %p)\n", start, count, buf ); + perror("fread"); + panicf("Disk error\n"); + } + return 0; +} + +int storage_write_sectors(unsigned long start, int count, void* buf) +{ + if ( count > 1 ) + DEBUGF("[Writing %d blocks: 0x%lx to 0x%lx]\n", + count, start, start+count-1); + else + DEBUGF("[Writing block 0x%lx]\n", start); + + if (start == 0) + panicf("Writing on sector 0!\n"); + + if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { + perror("fseek"); + return -1; + } + if(!fwrite(buf,BLOCK_SIZE,count,file)) { + DEBUGF("ata_write_sectors(0x%lx, 0x%x, %p)\n", start, count, buf ); + perror("fwrite"); + panicf("Disk error\n"); + } + return 0; +} + +int ata_init(void) +{ + file=fopen(img_filename,"rb+"); + if(!file) { + fprintf(stderr, "read_disk() - Could not find \"%s\"\n",img_filename); + return -1; + } + return 0; +} + +void ata_exit(void) +{ + fclose(file); +} diff --git a/rbutil/mkrk27boot/autoconf.h b/rbutil/mkrk27boot/autoconf.h new file mode 100644 index 0000000000..a4907d4599 --- /dev/null +++ b/rbutil/mkrk27boot/autoconf.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2012 by Andrew Ryabinin + * + * 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. + * + ****************************************************************************/ +#ifndef __BUILD_AUTOCONF_H +#define __BUILD_AUTOCONF_H + +/* assume little endian for now */ +#define ROCKBOX_LITTLE_ENDIAN 1 + +#define ROCKBOX_DIR "../../" + +/* Rename rockbox API functions which may conflict with system's functions. + This will allow to link libmkrk27boot with rbutil safely. */ +#define read(x,y,z) mkrk27_read(x,y,z) +#define write(x,y,z) mkrk27_write(x,y,z) + +/* This should resolve confilict with ipodpatcher's filesize function. */ +#define filesize(x) mkrk27_filesize(x) + +#endif diff --git a/rbutil/mkrk27boot/main.c b/rbutil/mkrk27boot/main.c new file mode 100644 index 0000000000..5ba69b5a98 --- /dev/null +++ b/rbutil/mkrk27boot/main.c @@ -0,0 +1,55 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2012 by Andrew Ryabinin + * + * 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 "mkrk27boot.h" + + +int main(int argc, char **argv) +{ + char* img_file = NULL; + char* rkw_file = NULL; + char* out_img_file = NULL; + char* out_rkw_file = NULL; + + if (argc == 4) { + img_file = argv[1]; + rkw_file = argv[2]; + out_img_file = argv[3]; + out_rkw_file = "BASE.RKW"; + } else if (argc == 5) { + img_file = argv[1]; + rkw_file = argv[2]; + out_img_file = argv[3]; + out_rkw_file = argv[4]; + } else { + fprintf(stdout, "\tusage: mkrk27boot []\n"); + fprintf(stdout, "\tIf output rkw file is not specified, the default is to put rkw file to BASE.RKW\n"); + return -1; + } + if (mkrk27_patch(img_file, rkw_file, out_img_file, out_rkw_file)) { + fprintf(stdout, "%s\n", mkrk27_get_error()); + return -1; + } + fprintf(stdout, "Success!\n"); + return 0; +} + diff --git a/rbutil/mkrk27boot/mkrk27boot.c b/rbutil/mkrk27boot/mkrk27boot.c new file mode 100644 index 0000000000..4b51e281c7 --- /dev/null +++ b/rbutil/mkrk27boot/mkrk27boot.c @@ -0,0 +1,281 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2012 by Andrew Ryabinin + * + * based on firmware/test/fat/main.c + * + * 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 +#include "disk.h" +#include "dir.h" +#include "file.h" +#include "ata.h" +#include "storage.h" +#include "mkrk27boot.h" + + +const char *img_filename; +static char mkrk27_error_msg[256]; + +static void mkrk27_set_error(const char *msg, ...) { + va_list ap; + va_start(ap, msg); + snprintf(mkrk27_error_msg, sizeof(mkrk27_error_msg), msg, ap); + va_end(ap); + return; +} + + + +/* Extracts in_file from FAT image to out_file */ +static int extract_file(const char *in_file, const char* out_file) { + char buf[81920]; + int nread; + + int fd = open(in_file, O_RDONLY); + if (fd < 0) { + mkrk27_set_error("Failed to open file %s. ", in_file); + return -1; + } + + FILE *file = fopen(out_file, "wb"); + if (!file) { + mkrk27_set_error("Failed to open file %s. ", out_file); + close(fd); + return -1; + } + + while (nread = read(fd, buf, sizeof buf), nread > 0) { + char *out_ptr = buf; + int nwritten; + + do { + nwritten = fwrite(buf, 1, nread, file); + + if (nwritten >= 0) { + nread -= nwritten; + out_ptr += nwritten; + } else if (errno != EINTR) { + mkrk27_set_error("Writting to file %s failed.", out_file); + goto exit; + } + } while(nread > 0); + } + + if (nread == 0) { + fclose(file); + close(fd); + return 0; + } else { + mkrk27_set_error("Copy from %s to %s failed.", out_file, in_file); + } +exit: + fclose(file); + close(fd); + return -1; +} + +/* Replace out_file in FAT image with in_file */ +static int replace_file(const char *in_file, const char *out_file) { + char buf[81920]; + int fd; + int nread; + + fd = creat(out_file, 0666); + if (fd < 0) { + mkrk27_set_error("Failed to open file %s. ", out_file); + return -1; + } + + FILE *file = fopen(in_file, "rb"); + if (!file) { + mkrk27_set_error("Failed to open file %s. ", in_file); + close(fd); + return -1; + } + + while (nread = fread(buf, 1, sizeof buf, file), nread > 0) { + char *out_ptr = buf; + int nwritten; + + do { + nwritten = write(fd, buf, nread); + if (nwritten >= 0) { + nread -= nwritten; + out_ptr += nwritten; + } else { + mkrk27_set_error("Writting to file %s failed.", out_file); + goto exit; + } + } while(nread > 0); + } + + if (nread == 0) { + fclose(file); + close(fd); + return 0; + } else { + mkrk27_set_error("Replacing %s with %s failed.", out_file, in_file); + } + +exit: + fclose(file); + close(fd); + return -1; +} + +static int mkrk27_init(const char *filename) { + int i; + int rc; + srand(clock()); + + img_filename = filename; + + if(ata_init()) { + mkrk27_set_error("Warning! The disk is uninitialized\n"); + return -1; + } + + struct partinfo *pinfo = disk_init(); + + if (!pinfo) { + mkrk27_set_error("Failed reading partitions\n"); + return -1; + } + + for ( i=0; i<4; i++ ) { + if ( pinfo[i].type == PARTITION_TYPE_FAT32 +#ifdef HAVE_FAT16SUPPORT + || pinfo[i].type == PARTITION_TYPE_FAT16 +#endif + ) { + rc = fat_mount(IF_MV2(0,) IF_MD2(0,) pinfo[i].start); + if(rc) { + mkrk27_set_error("mount: %d",rc); + return -1; + } + break; + } + } + if ( i==4 ) { + if(fat_mount(IF_MV2(0,) IF_MD2(0,) 0)) { + mkrk27_set_error("FAT32 partition!"); + return -1; + } + } + return 0; +} + +extern void ata_exit(void); + +static void mkrk27_deinit(void) { + ata_exit(); +} + +/* copy file */ +static int copy(const char *to, const char *from) { + FILE* fd_to, *fd_from; + char buf[4096]; + ssize_t nread; + + if (to == from) { + return 0; + } + + fd_from = fopen(from, "rb"); + if (!fd_from) { + mkrk27_set_error("Failed to open file %s.", from); + return -1; + } + + fd_to = fopen(to, "wb"); + if (!fd_to) { + mkrk27_set_error("Failed to open file %s.", to); + goto out_error; + } + + while (nread = fread(buf, 1, sizeof buf, fd_from), nread > 0) { + char *out_ptr = buf; + ssize_t nwritten; + + do { + nwritten = fwrite(out_ptr, 1, nread, fd_to); + + if (nwritten >= 0) + { + nread -= nwritten; + out_ptr += nwritten; + } + else if (errno != EINTR) + { + mkrk27_set_error( "Writing to file %s failed.", to); + goto out_error; + } + } while (nread > 0); + } + + if (nread == 0) { + fclose(fd_to); + fclose(fd_from); + return 0; + } else { + mkrk27_set_error("Copy from %s to %s failed.", from, to); + } + +out_error: + + fclose(fd_from); + fclose(fd_to); + + return -1; +} + +char* mkrk27_get_error(void) { + return mkrk27_error_msg; +} + + +/* Patch rk27 firmware. + - img_file - original FAT image file, containing OF, + - rkw_file - rkw file which will replace BASE.RKW from OF, + - out_img_file - patched img file, + - out_rkw_file - BASE.RKW extracted from OF. +*/ +int mkrk27_patch(const char* img_file, const char* rkw_file, const char* out_img_file, const char* out_rkw_file) { + if (copy(out_img_file, img_file)) { + return -1; + } + if (mkrk27_init(out_img_file)) { + return -1; + } + if (extract_file("/SYSTEM/BASE.RKW", out_rkw_file)) { + return -1; + } + if (replace_file(rkw_file, "/SYSTEM/BASE.RKW") || + replace_file(rkw_file, "/SYSTEM00/BASE.RKW")) { + return -1; + } + mkrk27_deinit(); + return 0; +} diff --git a/rbutil/mkrk27boot/mkrk27boot.h b/rbutil/mkrk27boot/mkrk27boot.h new file mode 100644 index 0000000000..dc8c2e8133 --- /dev/null +++ b/rbutil/mkrk27boot/mkrk27boot.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2012 by Andrew Ryabinin + * + * 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. + * + ****************************************************************************/ +#ifndef _MKRK27BOOT_H +#define _MKRK27BOOT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int mkrk27_patch(const char* img_file, const char* rkw_file, const char* out_img_file, const char* out_rkw_file); +char *mkrk27_get_error(void); + +#ifdef __cplusplus +} +#endif + + +#endif -- cgit