diff --git a/dtbhtool/Android.mk b/dtbhtool/Android.mk new file mode 100644 index 00000000..9b49c7c1 --- /dev/null +++ b/dtbhtool/Android.mk @@ -0,0 +1,40 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := mkbootimg.c +LOCAL_STATIC_LIBRARIES := libmincrypt + +LOCAL_MODULE := mkbootimg + +include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := unpackbootimg.c +LOCAL_MODULE := unpackbootimg +include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := mkbootimg.c +LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libc +LOCAL_MODULE := utility_mkbootimg +LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_STEM := mkbootimg +LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES +LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities +LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities +LOCAL_FORCE_STATIC_EXECUTABLE := true +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := unpackbootimg.c +LOCAL_STATIC_LIBRARIES := libcutils libc +LOCAL_MODULE := utility_unpackbootimg +LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_STEM := unpackbootimg +LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES +LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities +LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities +LOCAL_FORCE_STATIC_EXECUTABLE := true +include $(BUILD_EXECUTABLE) + +$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE)) diff --git a/dtbhtool/bootimg.h b/dtbhtool/bootimg.h new file mode 100644 index 00000000..4692f0cf --- /dev/null +++ b/dtbhtool/bootimg.h @@ -0,0 +1,100 @@ +/* tools/mkbootimg/bootimg.h +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef _BOOT_IMAGE_H_ +#define _BOOT_IMAGE_H_ + +typedef struct boot_img_hdr boot_img_hdr; + +#define BOOT_MAGIC "ANDROID!" +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 + +struct boot_img_hdr +{ + unsigned char magic[BOOT_MAGIC_SIZE]; + + unsigned kernel_size; /* size in bytes */ + unsigned kernel_addr; /* physical load addr */ + + unsigned ramdisk_size; /* size in bytes */ + unsigned ramdisk_addr; /* physical load addr */ + + unsigned second_size; /* size in bytes */ + unsigned second_addr; /* physical load addr */ + + unsigned tags_addr; /* physical addr for kernel tags */ + unsigned page_size; /* flash page size we assume */ + unsigned dt_size; /* device tree in bytes */ + unsigned unused; /* future expansion: should be 0 */ + unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ + + unsigned char cmdline[BOOT_ARGS_SIZE]; + + unsigned id[8]; /* timestamp / checksum / sha1 / etc */ +}; + +/* +** +-----------------+ +** | boot header | 1 page +** +-----------------+ +** | kernel | n pages +** +-----------------+ +** | ramdisk | m pages +** +-----------------+ +** | second stage | o pages +** +-----------------+ +** | device tree | p pages +** +-----------------+ +** +** n = (kernel_size + page_size - 1) / page_size +** m = (ramdisk_size + page_size - 1) / page_size +** o = (second_size + page_size - 1) / page_size +** p = (dt_size + page_size - 1) / page_size +** +** 0. all entities are page_size aligned in flash +** 1. kernel and ramdisk are required (size != 0) +** 2. second is optional (second_size == 0 -> no second) +** 3. load each element (kernel, ramdisk, second) at +** the specified physical address (kernel_addr, etc) +** 4. prepare tags at tag_addr. kernel_args[] is +** appended to the kernel commandline in the tags. +** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr +** 6. if second_size != 0: jump to second_addr +** else: jump to kernel_addr +*/ + +#if 0 +typedef struct ptentry ptentry; + +struct ptentry { + char name[16]; /* asciiz partition name */ + unsigned start; /* starting block number */ + unsigned length; /* length in blocks */ + unsigned flags; /* set to zero */ +}; + +/* MSM Partition Table ATAG +** +** length: 2 + 7 * n +** atag: 0x4d534d70 +** x n +*/ +#endif + +#endif diff --git a/dtbhtool/mkbootimg.c b/dtbhtool/mkbootimg.c new file mode 100644 index 00000000..06fc95be --- /dev/null +++ b/dtbhtool/mkbootimg.c @@ -0,0 +1,289 @@ +/* tools/mkbootimg/mkbootimg.c +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +#include "mincrypt/sha.h" +#include "bootimg.h" + +static void *load_file(const char *fn, unsigned *_sz) +{ + char *data; + int sz; + int fd; + + data = 0; + fd = open(fn, O_RDONLY); + if(fd < 0) return 0; + + sz = lseek(fd, 0, SEEK_END); + if(sz < 0) goto oops; + + if(lseek(fd, 0, SEEK_SET) != 0) goto oops; + + data = (char*) malloc(sz); + if(data == 0) goto oops; + + if(read(fd, data, sz) != sz) goto oops; + close(fd); + + if(_sz) *_sz = sz; + return data; + +oops: + close(fd); + if(data != 0) free(data); + return 0; +} + +int usage(void) +{ + fprintf(stderr,"usage: mkbootimg\n" + " --kernel \n" + " --ramdisk \n" + " [ --second <2ndbootloader-filename> ]\n" + " [ --cmdline ]\n" + " [ --board ]\n" + " [ --base
]\n" + " [ --pagesize ]\n" + " [ --ramdisk_offset
]\n" + " [ --dt ]\n" + " -o|--output \n" + ); + return 1; +} + + + +static unsigned char padding[131072] = { 0, }; + +int write_padding(int fd, unsigned pagesize, unsigned itemsize) +{ + unsigned pagemask = pagesize - 1; + unsigned count; + + if((itemsize & pagemask) == 0) { + return 0; + } + + count = pagesize - (itemsize & pagemask); + + if(write(fd, padding, count) != count) { + return -1; + } else { + return 0; + } +} + +int main(int argc, char **argv) +{ + boot_img_hdr hdr; + + char *kernel_fn = 0; + void *kernel_data = 0; + char *ramdisk_fn = 0; + void *ramdisk_data = 0; + char *second_fn = 0; + void *second_data = 0; + char *cmdline = ""; + char *bootimg = 0; + char *board = ""; + char *dt_fn = 0; + void *dt_data = 0; + unsigned pagesize = 2048; + int fd; + SHA_CTX ctx; + uint8_t* sha; + unsigned base = 0x10000000; + unsigned kernel_offset = 0x00008000; + unsigned ramdisk_offset = 0x01000000; + unsigned second_offset = 0x00f00000; + unsigned tags_offset = 0x00000100; + + argc--; + argv++; + + memset(&hdr, 0, sizeof(hdr)); + + while(argc > 0){ + char *arg = argv[0]; + char *val = argv[1]; + if(argc < 2) { + return usage(); + } + argc -= 2; + argv += 2; + if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { + bootimg = val; + } else if(!strcmp(arg, "--kernel")) { + kernel_fn = val; + } else if(!strcmp(arg, "--ramdisk")) { + ramdisk_fn = val; + } else if(!strcmp(arg, "--second")) { + second_fn = val; + } else if(!strcmp(arg, "--cmdline")) { + cmdline = val; + } else if(!strcmp(arg, "--base")) { + base = strtoul(val, 0, 16); + } else if(!strcmp(arg, "--kernel_offset")) { + kernel_offset = strtoul(val, 0, 16); + } else if(!strcmp(arg, "--ramdisk_offset")) { + ramdisk_offset = strtoul(val, 0, 16); + } else if(!strcmp(arg, "--second_offset")) { + second_offset = strtoul(val, 0, 16); + } else if(!strcmp(arg, "--tags_offset")) { + tags_offset = strtoul(val, 0, 16); + } else if(!strcmp(arg, "--board")) { + board = val; + } else if(!strcmp(arg,"--pagesize")) { + pagesize = strtoul(val, 0, 10); + if ((pagesize != 2048) && (pagesize != 4096) && (pagesize != 8192) && (pagesize != 16384) && (pagesize != 32768) && (pagesize != 65536) && (pagesize != 131072)) { + fprintf(stderr,"error: unsupported page size %d\n", pagesize); + return -1; + } + } else if(!strcmp(arg, "--dt")) { + dt_fn = val; + } else { + return usage(); + } + } + hdr.page_size = pagesize; + + hdr.kernel_addr = base + kernel_offset; + hdr.ramdisk_addr = base + ramdisk_offset; + hdr.second_addr = base + second_offset; + hdr.tags_addr = base + tags_offset; + + if(bootimg == 0) { + fprintf(stderr,"error: no output filename specified\n"); + return usage(); + } + + if(kernel_fn == 0) { + fprintf(stderr,"error: no kernel image specified\n"); + return usage(); + } + + if(ramdisk_fn == 0) { + fprintf(stderr,"error: no ramdisk image specified\n"); + return usage(); + } + + if(strlen(board) >= BOOT_NAME_SIZE) { + fprintf(stderr,"error: board name too large\n"); + return usage(); + } + + strcpy(hdr.name, board); + + memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); + + if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) { + fprintf(stderr,"error: kernel commandline too large\n"); + return 1; + } + strcpy((char*)hdr.cmdline, cmdline); + + kernel_data = load_file(kernel_fn, &hdr.kernel_size); + if(kernel_data == 0) { + fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); + return 1; + } + + if(!strcmp(ramdisk_fn,"NONE")) { + ramdisk_data = 0; + hdr.ramdisk_size = 0; + } else { + ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); + if(ramdisk_data == 0) { + fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); + return 1; + } + } + + if(second_fn) { + second_data = load_file(second_fn, &hdr.second_size); + if(second_data == 0) { + fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); + return 1; + } + } + + if(dt_fn) { + dt_data = load_file(dt_fn, &hdr.dt_size); + if (dt_data == 0) { + fprintf(stderr,"error: could not load device tree image '%s'\n", dt_fn); + return 1; + } + } + + /* put a hash of the contents in the header so boot images can be + * differentiated based on their first 2k. + */ + SHA_init(&ctx); + SHA_update(&ctx, kernel_data, hdr.kernel_size); + SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); + SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); + SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); + SHA_update(&ctx, second_data, hdr.second_size); + SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); + if(dt_data) { + SHA_update(&ctx, dt_data, hdr.dt_size); + SHA_update(&ctx, &hdr.dt_size, sizeof(hdr.dt_size)); + } + sha = SHA_final(&ctx); + memcpy(hdr.id, sha, + SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); + + fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644); + if(fd < 0) { + fprintf(stderr,"error: could not create '%s'\n", bootimg); + return 1; + } + + if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; + if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; + + if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail; + if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; + + if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail; + if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; + + if(second_data) { + if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail; + if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; + } + + if(dt_data) { + if(write(fd, dt_data, hdr.dt_size) != hdr.dt_size) goto fail; + if(write_padding(fd, pagesize, hdr.dt_size)) goto fail; + } + return 0; + +fail: + unlink(bootimg); + close(fd); + fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, + strerror(errno)); + return 1; +} diff --git a/dtbhtool/unpackbootimg.c b/dtbhtool/unpackbootimg.c new file mode 100644 index 00000000..3d2fda73 --- /dev/null +++ b/dtbhtool/unpackbootimg.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mincrypt/sha.h" +#include "bootimg.h" + +typedef unsigned char byte; + +int read_padding(FILE* f, unsigned itemsize, int pagesize) +{ + byte* buf = (byte*)malloc(sizeof(byte) * pagesize); + unsigned pagemask = pagesize - 1; + unsigned count; + + if((itemsize & pagemask) == 0) { + free(buf); + return 0; + } + + count = pagesize - (itemsize & pagemask); + + fread(buf, count, 1, f); + free(buf); + return count; +} + +void write_string_to_file(char* file, char* string) +{ + FILE* f = fopen(file, "w"); + fwrite(string, strlen(string), 1, f); + fwrite("\n", 1, 1, f); + fclose(f); +} + +int usage() { + printf("usage: unpackbootimg\n"); + printf("\t-i|--input boot.img\n"); + printf("\t[ -o|--output output_directory]\n"); + printf("\t[ -p|--pagesize ]\n"); + return 0; +} + +int main(int argc, char** argv) +{ + char tmp[PATH_MAX]; + char* directory = "./"; + char* filename = NULL; + int pagesize = 0; + + argc--; + argv++; + while(argc > 0){ + char *arg = argv[0]; + char *val = argv[1]; + argc -= 2; + argv += 2; + if(!strcmp(arg, "--input") || !strcmp(arg, "-i")) { + filename = val; + } else if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { + directory = val; + } else if(!strcmp(arg, "--pagesize") || !strcmp(arg, "-p")) { + pagesize = strtoul(val, 0, 16); + } else { + return usage(); + } + } + + if (filename == NULL) { + return usage(); + } + + int total_read = 0; + FILE* f = fopen(filename, "rb"); + boot_img_hdr header; + + //printf("Reading header...\n"); + int i; + for (i = 0; i <= 512; i++) { + fseek(f, i, SEEK_SET); + fread(tmp, BOOT_MAGIC_SIZE, 1, f); + if (memcmp(tmp, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) + break; + } + total_read = i; + if (i > 512) { + printf("Android boot magic not found.\n"); + return 1; + } + fseek(f, i, SEEK_SET); + printf("Android magic found at: %d\n", i); + + fread(&header, sizeof(header), 1, f); + printf("BOARD_KERNEL_CMDLINE %s\n", header.cmdline); + printf("BOARD_KERNEL_BASE %08x\n", header.kernel_addr - 0x00008000); + printf("BOARD_RAMDISK_OFFSET %08x\n", header.ramdisk_addr - header.kernel_addr + 0x00008000); + printf("BOARD_SECOND_OFFSET %08x\n", header.second_addr - header.kernel_addr + 0x00008000); + printf("BOARD_TAGS_OFFSET %08x\n",header.tags_addr - header.kernel_addr + 0x00008000); + printf("BOARD_PAGE_SIZE %d\n", header.page_size); + printf("BOARD_SECOND_SIZE %d\n", header.second_size); + printf("BOARD_DT_SIZE %d\n", header.dt_size); + + if (pagesize == 0) { + pagesize = header.page_size; + } + + //printf("cmdline...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-cmdline"); + write_string_to_file(tmp, header.cmdline); + + //printf("base...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-base"); + char basetmp[200]; + sprintf(basetmp, "%08x", header.kernel_addr - 0x00008000); + write_string_to_file(tmp, basetmp); + + //printf("ramdisk_offset...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-ramdisk_offset"); + char ramdisktmp[200]; + sprintf(ramdisktmp, "%08x", header.ramdisk_addr - header.kernel_addr + 0x00008000); + write_string_to_file(tmp, ramdisktmp); + + //printf("second_offset...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-second_offset"); + char secondtmp[200]; + sprintf(secondtmp, "%08x", header.second_addr - header.kernel_addr + 0x00008000); + write_string_to_file(tmp, secondtmp); + + //printf("tags_offset...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-tags_offset"); + char tagstmp[200]; + sprintf(tagstmp, "%08x", header.tags_addr - header.kernel_addr + 0x00008000); + write_string_to_file(tmp, tagstmp); + + //printf("pagesize...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-pagesize"); + char pagesizetmp[200]; + sprintf(pagesizetmp, "%d", header.page_size); + write_string_to_file(tmp, pagesizetmp); + + total_read += sizeof(header); + //printf("total read: %d\n", total_read); + total_read += read_padding(f, sizeof(header), pagesize); + + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-zImage"); + FILE *k = fopen(tmp, "wb"); + byte* kernel = (byte*)malloc(header.kernel_size); + //printf("Reading kernel...\n"); + fread(kernel, header.kernel_size, 1, f); + total_read += header.kernel_size; + fwrite(kernel, header.kernel_size, 1, k); + fclose(k); + + //printf("total read: %d\n", header.kernel_size); + total_read += read_padding(f, header.kernel_size, pagesize); + + + byte* ramdisk = (byte*)malloc(header.ramdisk_size); + //printf("Reading ramdisk...\n"); + fread(ramdisk, header.ramdisk_size, 1, f); + total_read += header.ramdisk_size; + sprintf(tmp, "%s/%s", directory, basename(filename)); + if(ramdisk[0] == 0x02 && ramdisk[1]== 0x21) + strcat(tmp, "-ramdisk.lz4"); + else + strcat(tmp, "-ramdisk.gz"); + FILE *r = fopen(tmp, "wb"); + fwrite(ramdisk, header.ramdisk_size, 1, r); + fclose(r); + + total_read += read_padding(f, header.ramdisk_size, pagesize); + + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-second"); + FILE *s = fopen(tmp, "wb"); + byte* second = (byte*)malloc(header.second_size); + //printf("Reading second...\n"); + fread(second, header.second_size, 1, f); + total_read += header.second_size; + fwrite(second, header.second_size, 1, r); + fclose(s); + + total_read += read_padding(f, header.second_size, pagesize); + + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-dt"); + FILE *d = fopen(tmp, "wb"); + byte* dt = (byte*)malloc(header.dt_size); + //printf("Reading dt...\n"); + fread(dt, header.dt_size, 1, f); + total_read += header.dt_size; + fwrite(dt, header.dt_size, 1, r); + fclose(d); + + fclose(f); + + //printf("Total Read: %d\n", total_read); + return 0; +}