diff --git a/Android.mk b/Android.mk index d7b4251..5a14e38 100644 --- a/Android.mk +++ b/Android.mk @@ -13,10 +13,12 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_UNSTRIPPED_PATH := $(TARGET_OUT_EXECUTABLES_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libc +LOCAL_CFLAGS := -DDEBUG_KMSG +LOCAL_STATIC_LIBRARIES := libc libcutils include $(BUILD_EXECUTABLE) +# bbootimge_host include $(CLEAR_VARS) LOCAL_SRC_FILES:= $(bbootimg_src_file) @@ -36,14 +38,19 @@ LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin LOCAL_MODULE_STEM := bbootimg LOCAL_SRC_FILES:= src/bbootimg.c src/libbootimg.c -LOCAL_SHARED_LIBRARIES := libc -include $(BUILD_EXECUTABLE) +LOCAL_CFLAGS := -DDEBUG_KMSG +LOCAL_SHARED_LIBRARIES := libc libcutils +include $(BUILD_EXECUTABLE) # libbootimg include $(CLEAR_VARS) + LOCAL_SRC_FILES := src/libbootimg.c LOCAL_MODULE := libbootimg LOCAL_MODULE_TAGS := eng + +LOCAL_CFLAGS := -DDEBUG_KMSG + include $(BUILD_STATIC_LIBRARY) diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index 1f7f59e..6ce3a33 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -20,7 +20,7 @@ #include /* -** +-----------------+ +** +-----------------+ ** | boot header | 1 page ** +-----------------+ ** | kernel | n pages @@ -51,11 +51,24 @@ #define BOOT_MAGIC "ANDROID!" #define BOOT_MAGIC_SIZE 8 -#define BOOT_MAGIC_ELF "ELF" -#define BOOT_MAGIC_ELF_SIZE 3 #define BOOT_NAME_SIZE 16 #define BOOT_ARGS_SIZE 512 +#define BOOT_MAGIC_ELF "ELF" +#define BOOT_MAGIC_ELF_SIZE 3 +#define VER_ELF_1 (1 << 0) +#define VER_ELF_2 (1 << 1) + +#define OUT_ELF (1 << 0) /* Same output format: ELF container */ +#define OUT_AND (1 << 1) /* Different output format: standard Android container */ + +#define ELF_PROG_KER 0 +#define ELF_PROG_RAM 1 +#define ELF_PROG_RPM 2 +#define ELF_PROG_CMD 3 + +#define ELF_SECT_CMD 0 + struct boot_img_hdr { uint8_t magic[BOOT_MAGIC_SIZE]; @@ -81,59 +94,64 @@ struct boot_img_hdr uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ }; -struct boot_img_hdr_elf +struct boot_img_elf_hdr { uint8_t magic[8]; /* .ELF (0x00 to 0x07) */ - uint8_t unused[8]; /* unused chars */ - uint16_t type; /* boot type */ - uint16_t machine; /* boot machine */ - uint32_t version; /* boot version */ - uint32_t entry_addr; /* boot entry */ - uint32_t phoff; /* boot phoff */ - uint32_t shoff; /* boot shoff */ - uint32_t flags; /* boot flags */ - uint16_t ehsize; /* boot ehsize */ - uint16_t phentsize; /* boot phentsize */ - uint16_t phnum; /* boot phnum */ - uint16_t shentsize; /* boot shentsize */ - uint16_t shnum; /* boot shnum */ - uint16_t shstrndx; /* boot shstrndx */ - uint32_t kernel_type; /* kernel type (0x34 to 0x37) */ - uint32_t kernel_offset; /* kernel offset (0x38 to 0x3B) */ - uint32_t kernel_vaddr; /* kernel address (0x3C to 0x3F) */ - uint32_t kernel_paddr; /* kernel address duplicate */ - uint32_t kernel_size; /* kernel size (0x44 to 0x47) */ - uint32_t kernel_msize; /* kernel size duplicate */ - uint32_t kernel_flags; /* kernel flags (0x4C to 0x4F) */ - uint32_t kernel_align; /* kernel alignment */ - uint32_t ramdisk_type; /* kernel type (0x54) */ - uint32_t ramdisk_offset; /* ramdisk offset (0x58 to 0x5B) */ - uint32_t ramdisk_vaddr; /* ramdisk address (0x5C to 0x5F) */ - uint32_t ramdisk_paddr; /* ramdisk address duplicate */ - uint32_t ramdisk_size; /* ramdisk size (0x64 to 0x67) */ - uint32_t ramdisk_msize; /* ramdisk size duplicate */ - uint32_t ramdisk_flags; /* ramdisk flags (0x6C to 0x6F) */ - uint32_t ramdisk_align; /* cmdline alignment */ - uint32_t rpm_type; /* rpm type (0x74 to 0x77) */ - uint32_t rpm_offset; /* rpm offset (0x78 to 0x7B) */ - uint32_t rpm_vaddr; /* rpm address (0x7C to 0x7F) */ - uint32_t rpm_paddr; /* rpm address duplicate */ - uint32_t rpm_size; /* rpm size (0x84 to 0x87) */ - uint32_t rpm_msize; /* rpm size duplicate */ - uint32_t rpm_flags; /* rpm flags (0x8C to 0x8F) */ - uint32_t rpm_align; /* rpm alignment */ - uint32_t cmd_type; /* cmdline type (0x94 to 0x97) */ - uint32_t cmd_offset; /* cmdline offset (0x98 to 0x9B) */ - uint32_t cmd_vaddr; /* cmdline address (0x9C to 0x9F) */ - uint32_t cmd_paddr; /* cmdline address duplicate */ - uint32_t cmd_size; /* cmdline size (0xA4 to 0xA7) */ - uint32_t cmd_msize; /* cmdline size duplicate */ - uint32_t cmd_flags; /* cmdline flags (0xAC to 0xAF) */ - uint32_t cmd_align; /* cmdline alignment */ - uint8_t header_vals[3900]; /* header additional values */ - uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ + uint8_t unused[8]; /* unused chars (0x08 to 0x0F) */ + uint16_t type; /* boot type (0x10 to 0x11) */ + uint16_t machine; /* boot machine (0x12 to 0x13) */ + uint32_t version; /* boot version (0x14 to 0x17) */ + uint32_t entry_addr; /* boot entry (0x18 to 0x1B) */ + uint32_t phoff; /* boot phoff (0x1C to 0x1F) */ + uint32_t shoff; /* boot shoff (0x20 to 0x23) */ + uint32_t flags; /* boot flags (0x24 to 0x27) */ + uint16_t ehsize; /* boot ehsize (0x28 to 0x29) */ + uint16_t phentsize; /* boot phentsize (0x2A to 0x2B) */ + uint16_t phnum; /* boot phnum (0x2C to 0x2D) */ + uint16_t shentsize; /* boot shentsize (0x2E to 0x2F)*/ + uint16_t shnum; /* boot shnum (0x30 to 0x31) */ + uint16_t shstrndx; /* boot shstrndx (0x32 to 0x33) */ +}; + +struct boot_img_elf_info +{ + struct boot_img_elf_hdr hdr; /* The ELF file header. */ + struct boot_img_elf_prog_hdr* prog; /* The program header entries. */ + struct boot_img_elf_sect_hdr* sect; /* The section header entries. */ + struct boot_img_elf_misc_hdr* misc; /* Miscellaneous information found in some ELF versions. */ + uint8_t elf_version; + uint8_t elf_out_format; + uint32_t cmdline_size; +}; + +struct boot_img_elf_prog_hdr +{ + uint32_t type; /* type (position + 0x0 to 0x3) */ + uint32_t offset; /* offset (position + 0x4 to 0x7) */ + uint32_t vaddr; /* address (position + 0x8 to 0xB) */ + uint32_t paddr; /* address duplicate (position + 0xC to 0xF) */ + uint32_t size; /* size (position + 0x10 to 0x13) */ + uint32_t msize; /* size duplicate (position + 0x14 to 0x17) */ + uint32_t flags; /* flags (position + 0x18 to 0x1B) */ + uint32_t align; /* alignment (position + 0x1C to 0x1F)*/ }; -typedef struct boot_img_hdr boot_img_hdr; +struct boot_img_elf_sect_hdr +{ + uint32_t name; + uint32_t type; + uint32_t flags; + uint32_t addr; + uint32_t offset; + uint32_t size; + uint8_t misc[16]; +}; + +struct boot_img_elf_misc_hdr +{ + uint8_t* data; /* header additional data */ + uint32_t data_size; /* header additional size */ + uint8_t name[BOOT_NAME_SIZE]; /* added - asciiz product name */ +}; #endif diff --git a/include/libbootimg.h b/include/libbootimg.h index 1aed9d1..dd4efe0 100644 --- a/include/libbootimg.h +++ b/include/libbootimg.h @@ -11,11 +11,20 @@ extern "C" { #include #include +#include #include "boot_img_hdr.h" #define LIBBOOTIMG_VERSION 0x000203 // 0xMMNNPP #define LIBBOOTIMG_VERSION_STR "0.2.3" +#ifdef DEBUG_KMSG +#define LOG_DBG(fmt, ...) klog_write(3, "<3>%s: " fmt, "libbootimg", ##__VA_ARGS__) +#elif DEBUG_STDOUT +#define LOG_DBG printf("libbootimg: "); printf +#else +#define LOG_DBG(fmt, ...) "" +#endif + /** * Enum containing possible blob types in a boot image. */ @@ -84,10 +93,12 @@ struct bootimg_blob struct bootimg { struct boot_img_hdr hdr; /*!< Boot image header */ - struct bootimg_blob blobs[LIBBOOTIMG_BLOB_CNT]; /*!< Blobs packed in the boot image. */ - int start_offset; /*!< Offset of the boot image structure from the start of the file. Only used when loading blobs from boot.img file. */ - struct boot_img_hdr_elf* hdr_elf; /*!< Boot image header in ELF format */ + struct bootimg_blob blob; /* Complete blob */ + uint32_t blob_size; /* Size of the complete blob */ + struct bootimg_blob blobs[LIBBOOTIMG_BLOB_CNT]; /*!< Blobs packed in the boot image */ + int start_offset; /*!< Offset of the boot image structure from the start of the file. Only used when loading blobs from boot.img file */ uint8_t is_elf; /*!< Select the ELF boot image format */ + struct boot_img_elf_info* hdr_info; /*!< Boot image meta-information for ELF formats */ }; /** @@ -117,6 +128,62 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma */ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); +/** + * Determines the ELF boot image version (custom definition) and the + * required output format (ELF or ANDROID!) based on the number of + * program headers given by the ELF header. + * @param hdr_info pointer to the structure holding the read header information + */ +void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info); + +/** + * Reads the program headers from the given ELF file and adds the content + * of each header to the given structure. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the section headers from the given ELF file and adds the content + * of each header to the given structure. + * @param hdr_info structure holding the meta-information of the given ELF file + * @param f pointer to the file descriptor of the ELF file + * @return zero on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f); + +/** + * Reads the miscellaneous information from the given ELF file and adds the content + * to the given structure. This information is present in some ELF versions and + * required for them to operate properly (version 1). + * @param hdr_info structure holding the meta-information of the given ELF file + * @param size of the bootimage pagesize needed for alignment + * @param f pointer to the file descriptor of the ELF file + * @return one on success or the error code returned by the file operations. + */ +int libbootimg_load_elf_misc_header(struct boot_img_elf_info *hdr_info, uint32_t page_size, FILE *f); + +/** + * Extracts the kernel boot command line from an ELF file and adds it to + * the generic structure describing the blob (-> hdr). + * @param hdr pointer to boot_img_hdr structure + * @param elf_info structure holding the meta-information of the given ELF file. + * @param f pointer to the file descriptor of the ELF file. + */ +void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info *elf_info, FILE *f); + +/** + * Returns a pointer referencing the ELF program header which describes the content + * of a given type like the kernel or ramdisk part of a boot image. + * @param hdr_info structure holding the meta-information of the given ELF file. + * @param type integer value that describes the desired pointer as given in the enum + * {@link libbootimg_blob_type}. + * @return pointer to the program header describing the desired part of the boot image. + */ +struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_info, int type); + /** * Loads boot_img_hdr or boot_img_hdr_elf from file on disk * @param hdr pointer to boot_img_hdr structure @@ -127,7 +194,7 @@ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); * successful, negative value from libbootimg_error if failed. */ int libbootimg_load_headers(struct boot_img_hdr *hdr, - struct boot_img_hdr_elf *hdr_elf, uint8_t *is_elf, const char *path); + struct boot_img_elf_info *hdr_elf, uint8_t *is_elf, const char *path); /** * Updates the header addresses to the blobs. @@ -142,8 +209,6 @@ int libbootimg_update_headers(struct bootimg *b); */ void libbootimg_destroy(struct bootimg *b); - - /** * Writes blob to a file. * @param blob pointer to source struct bootimg_blob @@ -244,6 +309,14 @@ int libbootimg_write_img(struct bootimg *b, const char *dest); */ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f); +/** + * Writes boot image to a file: Updated implementation that effectively *injects* data into an existing boot image + * @param b pointer to struct bootimg + * @param f pointer to FILE to write data into + * @return number of bytes written to the file if successful, negative value from libbootimg_error if failed. + */ +int libbootimg_write_img_fileptr_new(struct bootimg *b, FILE *f); + /** * Writes boot image to a file and then calls libbootimg_destroy. * The bootimg struct is destroyed even if this function fails. @@ -274,6 +347,41 @@ const char *libbootimg_version_str(void); */ const char *libbootimg_error_str(int error); +/** + * Prints the content of the boot image information to the stdout or + * the kernel log (dmesg). + * @param hdr pointer to the boot image information. + */ +void print_hdr_to_log(struct boot_img_hdr* hdr); + +/** + * Prints the content of an elf header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_info pointer to the elf header information. + */ +void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info); + +/** + * Prints the content of an elf program header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_prog_hdr pointer to the program header information. + */ +void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr); + +/** + * Prints the content of an elf section header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_sect_hdr pointer to the section header information. + */ +void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr); + +/** + * Prints the content of an elf misc header described by the given structure + * to the stdout or the kernel log (dmesg). + * @param elf_sect_hdr pointer to the section header information. + */ +void print_elf_misc_hdr_to_log(struct boot_img_elf_misc_hdr* elf_misc_hdr); + #ifdef __cplusplus } #endif diff --git a/src/libbootimg.c b/src/libbootimg.c index 12a5df0..ebd80f6 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -72,8 +72,13 @@ static void fill_id_hashes(struct bootimg *b) int i = 0; // hash blobs - for(; i < LIBBOOTIMG_BLOB_CNT && i < 5; ++i) - b->hdr.id[i] = calc_fnv_hash(b->blobs[i].data, *b->blobs[i].size); + for (; i < LIBBOOTIMG_BLOB_CNT ; ++i) + { + if (b->blobs[i].size != NULL) + { + b->hdr.id[i] = calc_fnv_hash(b->blobs[i].data, *b->blobs[i].size); + } + } // hash kernel, ramdisk and second _addr and _size together b->hdr.id[i++] = calc_fnv_hash(&b->hdr.kernel_size, sizeof(uint32_t)*6); @@ -92,8 +97,8 @@ void libbootimg_init_new(struct bootimg *img) memset(img, 0, sizeof(struct bootimg)); memcpy(img->hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); img->hdr.page_size = DEFAULT_PAGE_SIZE; - img->hdr_elf = malloc(sizeof(struct boot_img_hdr_elf)); - memset(img->hdr_elf, sizeof(struct boot_img_hdr_elf), 0); + img->hdr_info = malloc(sizeof(struct boot_img_elf_info)); + memset(img->hdr_info, sizeof(struct boot_img_elf_info), 0); img->is_elf = 0; img->blobs[LIBBOOTIMG_BLOB_KERNEL].size = &img->hdr.kernel_size; @@ -102,6 +107,30 @@ void libbootimg_init_new(struct bootimg *img) img->blobs[LIBBOOTIMG_BLOB_DTB].size = &img->hdr.dt_size; } +int libbootimg_read_blob(int64_t addr, struct bootimg_blob* blob, FILE* f) +{ + int res = 0; + if (fseek(f, addr, SEEK_SET) < 0) + { + if (errno == EINVAL) + { + res = LIBBOOTIMG_ERROR_IMG_EOF; + } + else + { + res = translate_errnum(errno); + } + return res; + } + blob->data = malloc(*blob->size); + if (fread(blob->data, *blob->size, 1, f) != 1) + { + res = translate_fread_error(f); + return res; + } + return res; +} + int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_mask) { int i; @@ -112,7 +141,7 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma libbootimg_init_new(img); - res = libbootimg_load_headers(&img->hdr, img->hdr_elf, &img->is_elf, path); + res = libbootimg_load_headers(&img->hdr, img->hdr_info, &img->is_elf, path); if(res < 0) { libbootimg_destroy(img); @@ -127,38 +156,27 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma addr = img->start_offset + img->hdr.page_size; - for(i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) + for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { blob = &img->blobs[i]; - if((load_blob_mask & (1 << i)) && *blob->size != 0) + if (img->is_elf) { - if(fseek(f, addr, SEEK_SET) < 0) + struct boot_img_elf_prog_hdr *cur_prog_hdr = get_elf_proc_hdr_of(img->hdr_info, i); + if (cur_prog_hdr != NULL) { - if(errno == EINVAL) - res = LIBBOOTIMG_ERROR_IMG_EOF; - else - res = translate_errnum(errno); - goto fail; - } - - blob->data = malloc(*blob->size); - - if(fread(blob->data, *blob->size, 1, f) != 1) - { - res = translate_fread_error(f); - goto fail; + res = libbootimg_read_blob(cur_prog_hdr->offset, blob, f); } } + else if ((load_blob_mask & (1 << i)) && *blob->size != 0) + { + res = libbootimg_read_blob(addr, blob, f); + } if (!img->is_elf) { addr += align_size(*blob->size, img->hdr.page_size); } - else - { - addr += *blob->size; - } } fclose(f); @@ -174,7 +192,7 @@ void libbootimg_destroy(struct bootimg *b) { struct bootimg_blob *blob = b->blobs; struct bootimg_blob * const blobs_end = blob + LIBBOOTIMG_BLOB_CNT; - free(b->hdr_elf); + free(b->hdr_info); for(; blob != blobs_end; ++blob) { free(blob->data); @@ -184,12 +202,12 @@ void libbootimg_destroy(struct bootimg *b) int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path) { - struct boot_img_hdr_elf hdr_elf; + struct boot_img_elf_info hdr_elf; return libbootimg_load_headers(hdr, &hdr_elf, NULL, path); } int libbootimg_load_headers(struct boot_img_hdr *hdr, - struct boot_img_hdr_elf *hdr_elf, uint8_t *is_elf, const char *path) + struct boot_img_elf_info *hdr_info, uint8_t *is_elf, const char *path) { int res = 0; FILE *f; @@ -219,33 +237,98 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, res = known_magic_pos[i]; break; } - else if (hdr_elf != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, + else if (hdr_info != NULL && memcmp(hdr->magic + 1, BOOT_MAGIC_ELF, BOOT_MAGIC_ELF_SIZE) == 0) { fseek(f, 0, SEEK_SET); - if (fread(hdr_elf, sizeof(struct boot_img_hdr_elf), 1, f) == 1) + if (fread(&hdr_info->hdr, sizeof(struct boot_img_elf_hdr), 1, f) == 1) { - hdr->kernel_size = hdr_elf->kernel_size; - hdr->kernel_addr = hdr_elf->kernel_offset; - hdr->ramdisk_size = hdr_elf->ramdisk_size; - hdr->ramdisk_addr = hdr_elf->ramdisk_offset; - hdr->second_size = hdr_elf->rpm_size; - hdr->second_addr = hdr_elf->rpm_offset; - hdr->page_size = hdr_elf->kernel_offset; - hdr->tags_addr = 0; - hdr->dt_size = 0; hdr->id[0] = '\0'; - memcpy(hdr->name, hdr_elf->name, BOOT_NAME_SIZE); - cmd_len = hdr_elf->cmd_size; - memset(hdr->cmdline, '\0', BOOT_ARGS_SIZE); - fseek(f, hdr_elf->cmd_offset, SEEK_SET); - fread(hdr->cmdline, cmd_len < BOOT_ARGS_SIZE ? - cmd_len : BOOT_ARGS_SIZE, 1, f); + res = known_magic_pos[i]; if (is_elf != NULL) { *is_elf = 1; + print_elf_hdr_to_log(hdr_info); + } + + libbootimg_get_elf_version(hdr_info); + + res = libbootimg_load_elf_prog_header(hdr_info, f); + if (res != 1) + { + break; } + + // Update the standard boot image meta-information with + // the information found in the elf file + struct boot_img_elf_prog_hdr *kernel_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_KERNEL); + hdr->kernel_size = kernel_hdr->size; + hdr->kernel_addr = kernel_hdr->offset; + + struct boot_img_elf_prog_hdr *ramdisk_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_RAMDISK); + hdr->ramdisk_size = ramdisk_hdr->size; + hdr->ramdisk_addr = ramdisk_hdr->offset; + + struct boot_img_elf_prog_hdr *second_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_SECOND); + if (second_hdr != NULL) + { + hdr->second_size = second_hdr->size; + hdr->second_addr = second_hdr->offset; + } + else + { + hdr->second_size = 0; + hdr->second_addr = 0; + } + + struct boot_img_elf_prog_hdr *dtb_hdr = get_elf_proc_hdr_of(hdr_info, + LIBBOOTIMG_BLOB_DTB); + if (dtb_hdr != NULL) + { + hdr->dt_size = dtb_hdr->size; + hdr->tags_addr = dtb_hdr->offset; + } + else + { + hdr->dt_size = 0; + hdr->tags_addr = 0; + } + + // ELF files version 1 are page aligned, version 2 are not + if (hdr_info->elf_version == VER_ELF_1) + { + hdr->page_size = hdr->kernel_addr; + } + else + { + hdr->page_size = DEFAULT_PAGE_SIZE; + } + + if (hdr_info->elf_version == VER_ELF_1) + { + res = libbootimg_load_elf_misc_header(hdr_info, hdr->page_size, f); + if (res != 1) + { + break; + } + memcpy(hdr->name, hdr_info->misc->name, BOOT_NAME_SIZE); + } + else if (hdr_info->elf_version == VER_ELF_2) + { + res = libbootimg_load_elf_sect_header(hdr_info, f); + if (res != 1) + { + break; + } + } + + libbootimg_read_cmdline(hdr, hdr_info, f); + + print_hdr_to_log(hdr); break; } } @@ -261,36 +344,271 @@ int libbootimg_load_headers(struct boot_img_hdr *hdr, return res; } +void libbootimg_get_elf_version(struct boot_img_elf_info *hdr_info) +{ + switch (hdr_info->hdr.phnum) + { + case 3: + // Version 2 (found in Z2, 8960) has 3 program headers + 1 section header + hdr_info->elf_version = VER_ELF_2; + // Also the bootloader does not load modified elf images + // Output to standard Android container format + hdr_info->elf_out_format = OUT_AND; + break; + case 4: + default: + // Version 1 (found in SP, 8960) has 4 program headers + hdr_info->elf_version = VER_ELF_1; + hdr_info->elf_out_format = OUT_ELF; + break; + } +} + +int libbootimg_load_elf_prog_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + int prog_entry_size = sizeof(struct boot_img_elf_prog_hdr); + struct boot_img_elf_prog_hdr *prog_entry; + prog_entry = malloc(prog_entry_size * hdr_info->hdr.phnum); + hdr_info->prog = prog_entry; + + int prog_entry_idx = 0; + for (; prog_entry_idx < hdr_info->hdr.phnum; ++prog_entry_idx) + { + LOG_DBG("Reading program header %u/%u.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + res = fread(&prog_entry[prog_entry_idx], prog_entry_size, 1, f); + if (res == 1) + { + LOG_DBG("Program header %u/%u successfully read.\n", prog_entry_idx + 1, hdr_info->hdr.phnum); + print_elf_prog_hdr_to_log(&hdr_info->prog[prog_entry_idx]); + } + else + { + break; + } + } + return res; +} + +int libbootimg_load_elf_sect_header(struct boot_img_elf_info *hdr_info, FILE *f) +{ + int res = 0; + int sect_entry_size = sizeof(struct boot_img_elf_sect_hdr); + struct boot_img_elf_sect_hdr *sect_entry; + + fseek(f, hdr_info->hdr.shoff, SEEK_SET); + sect_entry = malloc(hdr_info->hdr.shentsize * hdr_info->hdr.shnum); + hdr_info->sect = sect_entry; + + int sect_entry_idx = 0; + for (; sect_entry_idx < hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Reading section header %u/%u.\n", sect_entry_idx + 1, hdr_info->hdr.shnum); + res = fread(§_entry[sect_entry_idx], sect_entry_size, 1, f); + + if (res == 1) + { + LOG_DBG("Section header %u/%u successfully read.\n", sect_entry_idx + 1, hdr_info->hdr.shnum); + print_elf_sect_hdr_to_log(&hdr_info->sect[sect_entry_idx]); + } + else + { + break; + } + } + + return res; +} + +int libbootimg_load_elf_misc_header(struct boot_img_elf_info *hdr_info, uint32_t page_size, FILE *f) +{ + if (hdr_info->elf_version != VER_ELF_1) + { + return -1; + } + + int res = 0; + int misc_entry_size = sizeof(struct boot_img_elf_misc_hdr); + struct boot_img_elf_misc_hdr *misc; + + int misc_offset = hdr_info->hdr.phoff + hdr_info->hdr.phnum * hdr_info->hdr.phentsize; + + fseek(f, misc_offset, SEEK_SET); + misc = malloc(misc_entry_size); + hdr_info->misc = misc; + + misc->data_size = (page_size - misc_offset - sizeof(misc->name)) * + sizeof(uint8_t); + misc->data = malloc(misc->data_size); + + res = fread(misc->data, misc->data_size, 1, f); + if (res == 1) + { + res = fread(misc->name, sizeof(misc->name), 1, f); + } + + LOG_DBG("Misc data size: %u / %u\n", misc->data_size, page_size); + LOG_DBG("Misc boot name: %s\n", misc->name); + + return res; +} + +void libbootimg_read_cmdline(struct boot_img_hdr *hdr, struct boot_img_elf_info *elf_info, FILE *f) +{ + unsigned char buf[BOOT_ARGS_SIZE]; + int cmdline_start_pos = 0; + int cmd_len_max = 0; + + if (elf_info->elf_version == VER_ELF_1) + { + cmdline_start_pos = elf_info->prog[ELF_PROG_CMD].offset; + elf_info->cmdline_size = elf_info->prog[ELF_PROG_CMD].size; + cmd_len_max = elf_info->cmdline_size; + } + else if (elf_info->elf_version == VER_ELF_2) + { + cmdline_start_pos = elf_info->sect[ELF_SECT_CMD].offset; + elf_info->cmdline_size = elf_info->sect[ELF_SECT_CMD].size; + cmd_len_max = elf_info->cmdline_size; + } + cmd_len_max = cmd_len_max < BOOT_ARGS_SIZE ? cmd_len_max : BOOT_ARGS_SIZE; + + memset(&hdr->cmdline, '\0', BOOT_ARGS_SIZE); + memset(&buf, '\0', BOOT_ARGS_SIZE); + fseek(f, cmdline_start_pos, SEEK_SET); + fread(buf, cmd_len_max, 1, f); + + int buf_offset = 0; + if (elf_info->elf_version == VER_ELF_2) + { + buf_offset = 8; + } + + int buf_idx = 0; + for (; buf_idx < cmd_len_max; ++buf_idx) + { + hdr->cmdline[buf_idx] = buf[buf_idx + buf_offset]; + if (buf[buf_idx + buf_offset] == '\0') + { + break; + } + } + LOG_DBG("Cmd line: %s\n", hdr->cmdline); +} + +struct boot_img_elf_prog_hdr* get_elf_proc_hdr_of(struct boot_img_elf_info *elf_info, int type) +{ + switch (type) + { + case LIBBOOTIMG_BLOB_KERNEL: + return &elf_info->prog[ELF_PROG_KER]; + case LIBBOOTIMG_BLOB_RAMDISK: + return &elf_info->prog[ELF_PROG_RAM]; + case LIBBOOTIMG_BLOB_SECOND: + if (elf_info->elf_version == VER_ELF_1) + { + return &elf_info->prog[ELF_PROG_RPM]; + } + break; + case LIBBOOTIMG_BLOB_DTB: + if (elf_info->elf_version == VER_ELF_2) + { + return &elf_info->prog[ELF_PROG_RPM]; + } + break; + default: + break; + } + return NULL; +} + int libbootimg_update_headers(struct bootimg *b) { - uint32_t addr; + uint32_t addr = 0; if (b == NULL) return translate_errnum(ENOENT); - if (b->is_elf) + if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - b->hdr_elf->kernel_size = b->hdr.kernel_size; - b->hdr_elf->kernel_msize = b->hdr.kernel_size; - b->hdr_elf->ramdisk_size = b->hdr.ramdisk_size; - b->hdr_elf->ramdisk_msize = b->hdr.ramdisk_size; - b->hdr_elf->rpm_size = b->hdr.second_size; - b->hdr_elf->rpm_msize = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_KER].size = b->hdr.kernel_size; + b->hdr_info->prog[ELF_PROG_KER].msize = b->hdr.kernel_size; + b->hdr_info->prog[ELF_PROG_RAM].size = b->hdr.ramdisk_size; + b->hdr_info->prog[ELF_PROG_RAM].msize = b->hdr.ramdisk_size; + b->hdr_info->prog[ELF_PROG_RPM].size = b->hdr.second_size; + b->hdr_info->prog[ELF_PROG_RPM].msize = b->hdr.second_size; + + if (b->hdr_info->elf_version == VER_ELF_1) + { + b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr_info->cmdline_size; + b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr_info->cmdline_size; + } + else + { + b->hdr_info->prog[ELF_PROG_CMD].size = b->hdr.dt_size; + b->hdr_info->prog[ELF_PROG_CMD].msize = b->hdr.dt_size; + } + + LOG_DBG("Updating program headers...\n"); - addr = b->hdr_elf->kernel_offset; + addr = b->hdr_info->prog[ELF_PROG_KER].offset; - addr += b->hdr_elf->kernel_size; - b->hdr_elf->ramdisk_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_KER].size; + b->hdr_info->prog[ELF_PROG_RAM].offset = addr; - addr += b->hdr_elf->ramdisk_size; - b->hdr_elf->rpm_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_RAM].size; + b->hdr_info->prog[ELF_PROG_RPM].offset = addr; - addr += b->hdr_elf->rpm_size; - b->hdr_elf->cmd_offset = addr; + addr += b->hdr_info->prog[ELF_PROG_RPM].size; + b->hdr_info->prog[ELF_PROG_CMD].offset = addr; - memcpy(b->hdr_elf->name, b->hdr.name, BOOT_NAME_SIZE); + addr += b->hdr_info->prog[ELF_PROG_CMD].size; + + // Also, we need to update the address/offset pointers & sizes + // in the section header table + int sect_entry_idx = 0; + for (; sect_entry_idx < b->hdr_info->hdr.shnum; ++sect_entry_idx) + { + LOG_DBG("Updating section header entry %d/%d...\n", + sect_entry_idx + 1, b->hdr_info->hdr.shnum); + b->hdr_info->sect[sect_entry_idx].offset = addr; + addr += b->hdr_info->sect[sect_entry_idx].size; + } + + if (b->hdr_info->elf_version == VER_ELF_1) + { + LOG_DBG("Updating misc header: name %s...\n", b->hdr.name); + memcpy(b->hdr_info->misc->name, b->hdr.name, BOOT_NAME_SIZE); + } + + // The section header is placed after the last section + if (b->hdr_info->hdr.shnum > 0) + { + b->hdr_info->hdr.shoff = addr; + } + + } + else if (b->is_elf && b->hdr_info->elf_out_format == OUT_AND) + { + // ELF format found in stock Sony ROMs for, e.g, the Xperia Z2. + // If more formats exist, we should differ the assignments at + // the bottom of this function by the "elf version" + + b->hdr.magic[0] = 'A'; + b->hdr.magic[1] = 'N'; + b->hdr.magic[2] = 'D'; + b->hdr.magic[3] = 'R'; + b->hdr.magic[4] = 'O'; + b->hdr.magic[5] = 'I'; + b->hdr.magic[6] = 'D'; + b->hdr.magic[7] = '!'; + + b->hdr.kernel_addr = b->hdr_info->prog[ELF_PROG_KER].paddr; + b->hdr.ramdisk_addr = b->hdr_info->prog[ELF_PROG_RAM].paddr; + b->hdr.tags_addr = b->hdr_info->prog[ELF_PROG_RPM].paddr; } + print_hdr_to_log(&b->hdr); return 0; } @@ -402,12 +720,6 @@ int libbootimg_write_img(struct bootimg *b, const char *dest) FILE *f; int res; - if(b->hdr.kernel_size == 0 || b->hdr.ramdisk_size == 0) - return LIBBOOTIMG_ERROR_MISSING_BLOB; - - if(b->hdr.page_size < sizeof(b->hdr)) - return LIBBOOTIMG_ERROR_INVALID_PAGESIZE; - f = fopen(dest, "w"); if(!f) return translate_errnum(errno); @@ -423,10 +735,12 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) int i; int res = 0; char *blank = NULL; - size_t padding; + size_t padding = 0; struct bootimg_blob *blob; - int pos_start, pos_end; + int pos_start; + int pos_end = 0; + LOG_DBG("Writing.\n"); pos_start = ftell(f); if(pos_start < 0) return translate_errnum(errno); @@ -449,47 +763,139 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) blank = malloc(b->hdr.page_size); memset(blank, 0, b->hdr.page_size); - // write header - if (!b->is_elf) + // Update & write header + libbootimg_update_headers(b); + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) { if (fwrite(&b->hdr, sizeof(b->hdr), 1, f) != 1) goto fail_fwrite; padding = align_size(sizeof(b->hdr), b->hdr.page_size) - sizeof(b->hdr); } - else + else if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) { - libbootimg_update_headers(b); - - if (fwrite(b->hdr_elf, sizeof(*b->hdr_elf), 1, f) != 1) + if (fwrite(&b->hdr_info->hdr, sizeof(b->hdr_info->hdr), 1, f) != 1) + { goto fail_fwrite; + } + + // Write the Program headers. + int num_prog_hdr = b->hdr_info->hdr.phnum; + int hdr_entry_idx = 0; + for (; hdr_entry_idx < num_prog_hdr; ++hdr_entry_idx) + { + print_elf_prog_hdr_to_log(&b->hdr_info->prog[hdr_entry_idx]); + if (fwrite(&b->hdr_info->prog[hdr_entry_idx], + b->hdr_info->hdr.phentsize, 1, f) == 1) + { + LOG_DBG("Program header %u/%u writing successful.\n", + hdr_entry_idx + 1, b->hdr_info->hdr.phnum); + } + else + { + LOG_DBG("Program failed %u/%u writing failed.\n", + hdr_entry_idx + 1, b->hdr_info->hdr.phnum); + goto fail_fwrite; + } + } - padding = align_size(sizeof(*b->hdr_elf), b->hdr.page_size) - sizeof(*b->hdr_elf); + if (b->hdr_info->elf_version == VER_ELF_1) + { + print_elf_misc_hdr_to_log(b->hdr_info->misc); + if (fwrite(b->hdr_info->misc->data, b->hdr_info->misc->data_size, + 1, f) != 1) + { + LOG_DBG("Misc data writing successful.\n"); + goto fail_fwrite; + } + else if (fwrite(b->hdr_info->misc->name, + sizeof(b->hdr_info->misc->name), 1, f) != 1) + { + LOG_DBG("Misc boot name writing failed.\n"); + goto fail_fwrite; + } + else + { + LOG_DBG("Misc header writing successful.\n"); + } + } + else if (b->hdr_info->elf_version == VER_ELF_2) + { + // Fill remaining block with 0s up to first prog entry + // (misc data NOT written back!) + uint32_t header_size = sizeof(b->hdr_info->hdr) + + b->hdr_info->hdr.phnum * b->hdr_info->hdr.phentsize + + b->hdr_info->hdr.shnum * b->hdr_info->hdr.shentsize; + uint32_t blank_size = b->hdr.page_size - header_size; + if (fwrite(blank, blank_size, 1, f) != blank_size) + { + goto fail_fwrite; + } + } } - if (fwrite(blank, 1, padding, f) != padding) - goto fail_fwrite; + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) + { + if (fwrite(blank, 1, padding, f) != padding) + goto fail_fwrite; + } for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { + LOG_DBG("Writing blob number %d/%d...\n", i + 1, LIBBOOTIMG_BLOB_CNT); + LOG_DBG("Writing to position 0x%lx.\n", ftell(f)); blob = &b->blobs[i]; if (*blob->size == 0) continue; if (fwrite(blob->data, *blob->size, 1, f) != 1) + { + LOG_DBG("Writing blob %d failed.\n", i + 1); goto fail_fwrite; + } - if (!b->is_elf) + if (!b->is_elf || b->hdr_info->elf_out_format == OUT_AND) { padding = align_size(*blob->size, b->hdr.page_size) - *blob->size; if (fwrite(blank, 1, padding, f) != padding) + { + LOG_DBG("Writing padding of blob %d failed.\n", i + 1); goto fail_fwrite; + } } } - if (b->is_elf && fwrite(b->hdr.cmdline, b->hdr_elf->cmd_size, 1, f) != 1) - goto fail_fwrite; + if (b->is_elf && b->hdr_info->elf_out_format == OUT_ELF) + { + if (b->hdr_info->elf_version == VER_ELF_1) + { + pos_end += b->hdr_info->cmdline_size; + LOG_DBG("cmdline: %s\n", b->hdr.cmdline); + LOG_DBG("cmdline: %x\n", b->hdr_info->cmdline_size); + // Write the cmdline (last part ref by the prog header) + if (fwrite(&b->hdr.cmdline, b->hdr_info->cmdline_size, 1, f) != 1) + { + LOG_DBG("Failed to write the cmdline.\n"); + goto fail_fwrite; + } + } + + // Write the section header if needed by the ELF + if (b->hdr_info->hdr.shnum > 0) + { + LOG_DBG("Writing section header.\n"); + fseek(f, b->hdr_info->hdr.shoff, SEEK_SET); + if (fwrite(b->hdr_info->sect, b->hdr_info->hdr.shentsize, 1, f) == 1) + { + print_elf_sect_hdr_to_log(&b->hdr_info->sect[ELF_SECT_CMD]); + } + else + { + goto fail_fwrite; + } + } + } pos_end = ftell(f); @@ -525,7 +931,7 @@ const char *libbootimg_version_str(void) const char *libbootimg_error_str(int error) { - switch(error) + switch (error) { case LIBBOOTIMG_SUCCESS: return "No errors"; case LIBBOOTIMG_ERROR_IO: return "Input/output error"; @@ -542,3 +948,86 @@ const char *libbootimg_error_str(int error) default: return "Unknown error"; } } + +void print_hdr_to_log(struct boot_img_hdr* hdr) +{ + LOG_DBG("* kernel size = %u bytes (%.2f MB)\n", hdr->kernel_size, + (double )hdr->kernel_size / 0x100000); + LOG_DBG(" ramdisk size = %u bytes (%.2f MB)\n", hdr->ramdisk_size, + (double )hdr->ramdisk_size / 0x100000); + if (hdr->second_size) + { + LOG_DBG(" second stage size = %u bytes (%.2f MB)\n", hdr->second_size, + (double )hdr->second_size / 0x100000); + } + if (hdr->dt_size) + { + LOG_DBG(" device tree size = %u bytes (%.2f MB)\n", hdr->dt_size, + (double )hdr->dt_size / 0x100000); + } + LOG_DBG("* load addresses:\n"); + LOG_DBG(" kernel: 0x%08x\n", hdr->kernel_addr); + LOG_DBG(" ramdisk: 0x%08x\n", hdr->ramdisk_addr); + if (hdr->second_size) + { + LOG_DBG(" second stage: 0x%08x\n", hdr->second_addr); + } + LOG_DBG(" tags: 0x%08x\n", hdr->tags_addr); +} + +void print_elf_hdr_to_log(struct boot_img_elf_info* elf_info) +{ + (void)elf_info; + LOG_DBG("========= ELF header content =========\n"); + LOG_DBG("Type (0x10 to 0x11) = %x\n", elf_info->hdr.type); + LOG_DBG("Machine (0x12 to 0x13) = %x\n", elf_info->hdr.machine); + LOG_DBG("Version (0x14 to 0x17) = %x\n", elf_info->hdr.version); + LOG_DBG("Entry Address (0x18 to 0x1B) = %x\n", elf_info->hdr.entry_addr); + LOG_DBG("Phys Offset (0x1C to 0x1F) = %x\n", elf_info->hdr.phoff); + LOG_DBG("Section Offset (0x20 to 0x23) = %x\n", elf_info->hdr.shoff); + LOG_DBG("Flags (0x24 to 0x27) = %x\n", elf_info->hdr.flags); + LOG_DBG("Ehsize (0x28 to 0x29) = %x\n", elf_info->hdr.ehsize); + LOG_DBG("Ph entry size (0x2A to 0x2B) = %x\n", elf_info->hdr.phentsize); + LOG_DBG("Ph number (0x2C to 0x2D) = %x\n", elf_info->hdr.phnum); + LOG_DBG("Sect entry size (0x2E to 0x2F) = %x\n", elf_info->hdr.shentsize); + LOG_DBG("Sect number (0x30 to 0x31) = %x\n", elf_info->hdr.shnum); + LOG_DBG("Sect strndx (0x32 to 0x33) = %x\n", elf_info->hdr.shstrndx); + LOG_DBG("======================================\n"); +} + +void print_elf_prog_hdr_to_log(struct boot_img_elf_prog_hdr* elf_prog_hdr) +{ + (void)elf_prog_hdr; + LOG_DBG("===== ELF program header content =====\n"); + LOG_DBG("Type = %x\n", elf_prog_hdr->type); + LOG_DBG("Offset = %x\n", elf_prog_hdr->offset); + LOG_DBG("VAddr = %x\n", elf_prog_hdr->vaddr); + LOG_DBG("PAddr = %x\n", elf_prog_hdr->paddr); + LOG_DBG("Size = %x\n", elf_prog_hdr->size); + LOG_DBG("MSize = %x\n", elf_prog_hdr->msize); + LOG_DBG("Flags = %x\n", elf_prog_hdr->flags); + LOG_DBG("Align = %x\n", elf_prog_hdr->align); + LOG_DBG("======================================\n"); +} + +void print_elf_sect_hdr_to_log(struct boot_img_elf_sect_hdr* elf_sect_hdr) +{ + (void)elf_sect_hdr; + LOG_DBG("===== ELF section header content =====\n"); + LOG_DBG("Name = %x\n", elf_sect_hdr->name); + LOG_DBG("Type = %x\n", elf_sect_hdr->type); + LOG_DBG("Flags = %x\n", elf_sect_hdr->flags); + LOG_DBG("Address = %x\n", elf_sect_hdr->addr); + LOG_DBG("Offset = %x\n", elf_sect_hdr->offset); + LOG_DBG("Size = %x\n", elf_sect_hdr->size); + LOG_DBG("======================================\n"); +} + +void print_elf_misc_hdr_to_log(struct boot_img_elf_misc_hdr* elf_misc_hdr) +{ + (void)elf_misc_hdr; + LOG_DBG("====== ELF misc header content =======\n"); + LOG_DBG("Data size = %u\n", elf_misc_hdr->data_size); + LOG_DBG("Boot name = %s\n", elf_misc_hdr->name); + LOG_DBG("======================================\n"); +}