How to SPLIT BOOT.IMG file into kernel and ramdisk.gz (Android)
This article shows how to split a boot.img file into kernel and ramdisk parts.
In Android systems kernel and initial ramdisk filesystem are usually joined into an only file, named boot.img, and flashed into the device.
Recover image files have same structure too.
mkbootimg is the tool which builds a boot.img file from its kernel and ramdisk parts.
Boot.img file could also contain a second filesystem within it.
Split boot.img file using a python script
Copy split_boot_img.py code at the end of this article in a file named split_boot_img.py
Then execute (you need to already have a boot.img file):
$ python split_boot_img.py -i boot.img -o parts
# This splits boot.img, create parts directory and stores there zImage (kernel) and ramdisk.gz.E.g: Splitting a boot.img file from my Samsung S5570 tass device shows this result:
$ python split_boot_img.py -i boot.img -o foo -v
input file: boot.img output directory: foo Creating directory: foo boot_magic correct: ANDROID! kernel size: 3627948 kernel address: 325091328 Base: 325058560 (hex): 0x13600000 ramdisk size: 3155625 ramdisk address: 341835776 second size: 0 second address: 340787200 tags address: 325058816 page size: 4096 product name: cmdline: File foo/zImage written (length=3627948). File foo/ramdisk.gz written (length=3155625).
To rebuild boot.img file (in my tass device):
$ mkbootimg --kernel zImage --ramdisk ramdisk.gz --base 13600000 --pagesize 4096 -o boot.img.new
split_boot_img python code
https://github.com/vhernando/split_boot_img
#!/usr/bin/python # From mkbootimg source code in Android sources. # system/core/mkbootimg/mkbootimg.c # system/core/mkbooting/bootimg.h # #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 unused[2]; /* 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 */ # }; import sys import argparse import os INPUT_FILE = "boot.img" KERNEL_FILE_NAME = "zImage" RAMDISK_FILE_NAME = "ramdisk.gz" SECOND_FILE_NAME = "second" class BootImgHdr: MAGIC_SIZE = 8 MAGIC = "ANDROID!" NAME_SIZE = 16 ARGS_SIZE = 512 BASE_KERNEL_ADDR = 0x00008000 BASE_RAMDISK_ADDR = 0x01000000 BASE_SECOND_ADDR = 0x00F00000 BASE_TAGS_ADDR = 0x00000100 class IOFile: UNSIGNED_INT_SIZE = 4 def __init__(self, file_name): try: self.file = open(file_name, "rb") except IOError as e: print "Error opening: {0}".format(file_name) print "I/O error({0}): {1}".format(e.errno, e.strerror) sys.exit(1) def read(self, number_bytes, string): try: stream = self.file.read(number_bytes) except IOError as e: print "Error reading from: {0}".format(string) print "I/O error({0}): {1}".format(e.errno, e.strerror) self.close() sys.exit(1) if len(stream) < number_bytes: print "Error reading ", string self.close() sys.exit(1) else: return stream def seek(self, nBytes, pos): try: self.file.seek(nBytes, pos) except IOError as e: print "Error seeking" print "I/O error({0}): {1}".format(e.errno, e.strerror) self.close() sys.exit(1) def close(self): if self.file: self.file.close() def write(self, file_name, start, file_size): self.file.seek(start, 0) with open(file_name, "wb") as out_file: s = self.read(file_size, file_name) try: out_file.write(s) except IOError as e: print "Error writting file: {0}".format(file_name) print "I/O error({0}): {1}".format(e.errno, e.strerror) self.close() sys.exit(1) print "File {0} written (length={1}).".format(file_name, file_size) def get_unsigned_int(self, number_s): "Convert some bytes to an unsigned int" number_s = number_s[::-1] number_s = number_s.encode('hex') return int(number_s, 16) def read_uint(self, string=None): s = self.read(self.UNSIGNED_INT_SIZE, string) result = self.get_unsigned_int(s) if string: print "{0}: {1}".format(string, result) return result def main(): parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbosity", action="store_true", help="increase output verbosity") parser.add_argument("-i", "--input_file", default=INPUT_FILE, help="boot image input file") help_o = "write kernel, ramdisk, etc in this output directory" parser.add_argument("-o", "--output_dir", default=".", help=help_o) args = parser.parse_args() in_file_name = args.input_file output_dir = args.output_dir kernel_file_name = os.path.join(output_dir, KERNEL_FILE_NAME) ramdisk_file_name = os.path.join(output_dir, RAMDISK_FILE_NAME) second_file_name = os.path.join(output_dir, SECOND_FILE_NAME) verb = args.verbosity if verb: print print "input file: {0}".format(in_file_name) print "output directory: {0}".format(output_dir) print in_file = IOFile(in_file_name) # Create output directory if it does not exist if not os.path.exists(output_dir): print "Creating directory: {}".format(output_dir) os.makedirs(output_dir) elif not os.path.isdir(output_dir): print "ERROR: {0} exists but it is not a directory.".format(output_dir) sys.exit(1) hdr = BootImgHdr() hdr.boot_magic = in_file.read(hdr.MAGIC_SIZE, "boot magic") if hdr.boot_magic == hdr.MAGIC: if verb: print "boot_magic correct: ", hdr.boot_magic else: print "boot_magic not correct: ", hdr.boot_magic in_file.close() sys.exit(1) # Read kernel size hdr.kernel_size = in_file.read_uint("kernel size") # Read kernel address if verb: hdr.kernel_addr = in_file.read_uint("kernel address") else: hdr.kernel_addr = in_file.read_uint() hdr.base = hdr.kernel_addr - hdr.BASE_KERNEL_ADDR if verb: print "Base: {0} (hex): {1}".format(hdr.base, hex(hdr.base)) else: print "Base (hex): {0}".format(hex(hdr.base)) # Read ramdisk size hdr.ramdisk_size = in_file.read_uint("ramdisk size") # Read ramdisk address if verb: hdr.ramdisk_addr = in_file.read_uint("ramdisk address") else: hdr.ramdisk_addr = in_file.read_uint() base = hdr.ramdisk_addr - hdr.BASE_RAMDISK_ADDR if base != hdr.base: print ("ERROR: Base from ramdisk address does not match" " the one from kernel address. {0}".format(base)) # Read second size hdr.second_size = in_file.read_uint("second size") # Read second address if verb: hdr.second_addr = in_file.read_uint("second address") else: hdr.second_addr = in_file.read_uint() base = hdr.second_addr - hdr.BASE_SECOND_ADDR if base != hdr.base: print ("ERROR: Base from second address does not match" " the one from kernel address. {0}".format(base)) # Read tags address if verb: hdr.tags_addr = in_file.read_uint("tags address") else: hdr.tags_addr = in_file.read_uint() base = hdr.tags_addr - hdr.BASE_TAGS_ADDR if base != hdr.base: print ("ERROR: Base from tags address does not match" " the one from kernel address. {0}".format(base)) # Read page size hdr.page_size = in_file.read_uint("page size") # Discard unused parts in_file.seek(in_file.UNSIGNED_INT_SIZE * 2, 1) # Read asciiz product name. #unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ hdr.product_name = in_file.read(hdr.NAME_SIZE, "product name") print "product name: ", hdr.product_name.rstrip("\0") # Read cmdline. hdr.cmdline = in_file.read(hdr.ARGS_SIZE, "cmdline") print "cmdline: ", hdr.cmdline.rstrip("\0") # /* # ** +-----------------+ # ** | boot header | 1 page # ** +-----------------+ # ** | kernel | n pages # ** +-----------------+ # ** | ramdisk | m pages # ** +-----------------+ # ** | second stage | o 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 # ** # ** 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 # */ # Download kernel kernel_page = 1 in_file.write(kernel_file_name, kernel_page * hdr.page_size, hdr.kernel_size) # Download ramdisk ramdisk_page = ((hdr.kernel_size + hdr.page_size - 1) / hdr.page_size + kernel_page) in_file.write(ramdisk_file_name, ramdisk_page * hdr.page_size, hdr.ramdisk_size) # Download second file if available if hdr.second_size != 0: second_page = ((hdr.second_size + hdr.page_size - 1) / hdr.page_size + ramdisk_page) in_file.write(second_file_name, second_page * hdr.page_size, hdr.second_size) if __name__ == "__main__": main()
You may also be interested in
How to BUILD the LINUX KERNEL for the ANDROID EMULATOR (Eclair version)
How to build Android CyanogenMod 7.2.0 for Samsung GT-S5570 tass phone from source code in Debian
0 comentarios:
Post a Comment