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 -vinput 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.newsplit_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