diff --git a/include/boot_img_hdr.h b/include/boot_img_hdr.h index 58c7390..e92a423 100644 --- a/include/boot_img_hdr.h +++ b/include/boot_img_hdr.h @@ -51,6 +51,8 @@ #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 @@ -79,6 +81,58 @@ struct boot_img_hdr uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ }; +struct boot_img_hdr_elf +{ + 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 name[BOOT_NAME_SIZE]; /* added - asciiz product name */ +}; + typedef struct boot_img_hdr boot_img_hdr; #endif diff --git a/include/libbootimg.h b/include/libbootimg.h index fa4471e..37fef48 100644 --- a/include/libbootimg.h +++ b/include/libbootimg.h @@ -86,6 +86,8 @@ 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 */ + uint8_t is_elf; /*!< Select the ELF boot image format */ }; /** @@ -110,10 +112,30 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma * Loads boot_img_hdr from file on disk * @param hdr pointer to boot_img_hdr structure * @param path path to boot.img to load header from - * @return positive offset of the header from the start of the file if successful, negative value from libbootimg_error if failed. + * @return positive offset of the header from the start of the file if + * successful, negative value from libbootimg_error if failed. */ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path); +/** + * Loads boot_img_hdr or boot_img_hdr_elf from file on disk + * @param hdr pointer to boot_img_hdr structure + * @param hdr_elf pointer to boot_img_hdr_elf structure + * @param is_elf pointer to is_elf attribute + * @param path path to boot.img to load header from + * @return positive offset of the header from the start of the file if + * 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); + +/** + * Updates the header addresses to the blobs. + * @param img pointer to initialized struct bootimg + * @return Zero if successful, negative value from libbootimg_error if failed. + */ +int libbootimg_update_headers(struct bootimg *b); + /** * Frees all resources used by this bootimg struct * @param b pointer to struct bootimg diff --git a/src/libbootimg.c b/src/libbootimg.c index c85730c..e7fb792 100644 --- a/src/libbootimg.c +++ b/src/libbootimg.c @@ -92,6 +92,9 @@ 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->is_elf = 0; img->blobs[LIBBOOTIMG_BLOB_KERNEL].size = &img->hdr.kernel_size; img->blobs[LIBBOOTIMG_BLOB_RAMDISK].size = &img->hdr.ramdisk_size; @@ -109,7 +112,7 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma libbootimg_init_new(img); - res = libbootimg_load_header(&img->hdr, path); + res = libbootimg_load_headers(&img->hdr, img->hdr_elf, &img->is_elf, path); if(res < 0) { libbootimg_destroy(img); @@ -148,7 +151,14 @@ int libbootimg_init_load(struct bootimg *img, const char *path, int load_blob_ma } } - addr += align_size(*blob->size, img->hdr.page_size); + if (!img->is_elf) + { + addr += align_size(*blob->size, img->hdr.page_size); + } + else + { + addr += *blob->size; + } } fclose(f); @@ -164,6 +174,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); for(; blob != blobs_end; ++blob) { free(blob->data); @@ -172,30 +183,72 @@ 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; + 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) { int res = 0; FILE *f; size_t i; + uint32_t cmd_len; static const int known_magic_pos[] = { 0x0, // default 0x100, // HTC signed boot images }; f= fopen(path, "r"); - if(!f) + if (!f) return translate_errnum(errno); res = LIBBOOTIMG_ERROR_INVALID_MAGIC; - for(i = 0; i < sizeof(known_magic_pos)/sizeof(known_magic_pos[0]); ++i) + for (i = 0; i < sizeof(known_magic_pos)/sizeof(known_magic_pos[0]); ++i) { fseek(f, known_magic_pos[i], SEEK_SET); - if(fread(hdr, sizeof(struct boot_img_hdr), 1, f) == 1) + if (fread(hdr, sizeof(struct boot_img_hdr), 1, f) == 1) { - if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) + if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) { + if (is_elf != NULL) + { + *is_elf = 0; + } res = known_magic_pos[i]; break; } + else if (hdr_elf != 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) + { + 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; + } + break; + } + } } else { @@ -208,6 +261,39 @@ int libbootimg_load_header(struct boot_img_hdr *hdr, const char *path) return res; } +int libbootimg_update_headers(struct bootimg *b) +{ + uint32_t addr; + + if (b == NULL) + return translate_errnum(ENOENT); + + if (b->is_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; + + addr = b->hdr_elf->kernel_offset; + + addr += b->hdr_elf->kernel_size; + b->hdr_elf->ramdisk_offset = addr; + + addr += b->hdr_elf->ramdisk_size; + b->hdr_elf->rpm_offset = addr; + + addr += b->hdr_elf->rpm_size; + b->hdr_elf->cmd_offset = addr; + + memcpy(b->hdr_elf->name, b->hdr.name, BOOT_NAME_SIZE); + } + + return 0; +} + int libbootimg_dump_blob(struct bootimg_blob *blob, const char *dest) { FILE *f; @@ -364,31 +450,50 @@ int libbootimg_write_img_fileptr(struct bootimg *b, FILE *f) memset(blank, 0, b->hdr.page_size); // write header - if(fwrite(&b->hdr, sizeof(b->hdr), 1, f) != 1) - goto fail_fwrite; + if (!b->is_elf) + { + 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 + { + libbootimg_update_headers(b); - padding = align_size(sizeof(b->hdr), b->hdr.page_size) - sizeof(b->hdr); - if(fwrite(blank, 1, padding, f) != padding) + if (fwrite(b->hdr_elf, sizeof(*b->hdr_elf), 1, f) != 1) + goto fail_fwrite; + + padding = align_size(sizeof(*b->hdr_elf), b->hdr.page_size) - sizeof(*b->hdr_elf); + } + + if (fwrite(blank, 1, padding, f) != padding) goto fail_fwrite; - for(i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) + for (i = 0; i < LIBBOOTIMG_BLOB_CNT; ++i) { blob = &b->blobs[i]; - if(*blob->size == 0) + if (*blob->size == 0) continue; - if(fwrite(blob->data, *blob->size, 1, f) != 1) + if (fwrite(blob->data, *blob->size, 1, f) != 1) goto fail_fwrite; - padding = align_size(*blob->size, b->hdr.page_size) - *blob->size; - if(fwrite(blank, 1, padding, f) != padding) - goto fail_fwrite; + if (!b->is_elf) + { + padding = align_size(*blob->size, b->hdr.page_size) - *blob->size; + if (fwrite(blank, 1, padding, f) != padding) + goto fail_fwrite; + } } + if (b->is_elf && fwrite(b->hdr.cmdline, b->hdr_elf->cmd_size, 1, f) != 1) + goto fail_fwrite; + pos_end = ftell(f); - if(pos_end > 0) + if (pos_end > 0) res = pos_end - pos_start; else res = translate_errnum(errno);