From 890e1df1bec891d9203724541e81f8fbe5183388 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 19 Feb 2024 01:57:06 +0000
Subject: [PATCH] default settings GPIO PA4 PA6 PA3 PB5
---
kernel/scripts/unpack_bootimg | 577 ++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 447 insertions(+), 130 deletions(-)
diff --git a/kernel/scripts/unpack_bootimg b/kernel/scripts/unpack_bootimg
index 83c2bbe..a3f1a50 100755
--- a/kernel/scripts/unpack_bootimg
+++ b/kernel/scripts/unpack_bootimg
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+#
# Copyright 2018, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,18 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""unpacks the bootimage.
+"""Unpacks the boot image.
Extracts the kernel, ramdisk, second bootloader, dtb and recovery dtbo images.
"""
-from __future__ import print_function
-from argparse import ArgumentParser, FileType
+from argparse import ArgumentParser, RawDescriptionHelpFormatter
from struct import unpack
import os
+import shlex
BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
-VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
+VENDOR_RAMDISK_NAME_SIZE = 32
+VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE = 16
+
def create_out_dir(dir_path):
"""creates a directory 'dir_path' if it does not exist"""
@@ -50,196 +53,510 @@
def format_os_version(os_version):
+ if os_version == 0:
+ return None
a = os_version >> 14
b = os_version >> 7 & ((1<<7) - 1)
c = os_version & ((1<<7) - 1)
- return '{}.{}.{}'.format(a, b, c)
+ return f'{a}.{b}.{c}'
def format_os_patch_level(os_patch_level):
+ if os_patch_level == 0:
+ return None
y = os_patch_level >> 4
y += 2000
m = os_patch_level & ((1<<4) - 1)
- return '{:04d}-{:02d}'.format(y, m)
+ return f'{y:04d}-{m:02d}'
-def print_os_version_patch_level(value):
- os_version = value >> 11
- os_patch_level = value & ((1<<11) - 1)
- print('os version: %s' % format_os_version(os_version))
- print('os patch level: %s' % format_os_patch_level(os_patch_level))
+def decode_os_version_patch_level(os_version_patch_level):
+ """Returns a tuple of (os_version, os_patch_level)."""
+ os_version = os_version_patch_level >> 11
+ os_patch_level = os_version_patch_level & ((1<<11) - 1)
+ return (format_os_version(os_version),
+ format_os_patch_level(os_patch_level))
-def unpack_bootimage(args):
+class BootImageInfoFormatter:
+ """Formats the boot image info."""
+
+ def format_pretty_text(self):
+ lines = []
+ lines.append(f'boot magic: {self.boot_magic}')
+
+ if self.header_version < 3:
+ lines.append(f'kernel_size: {self.kernel_size}')
+ lines.append(
+ f'kernel load address: {self.kernel_load_address:#010x}')
+ lines.append(f'ramdisk size: {self.ramdisk_size}')
+ lines.append(
+ f'ramdisk load address: {self.ramdisk_load_address:#010x}')
+ lines.append(f'second bootloader size: {self.second_size}')
+ lines.append(
+ f'second bootloader load address: '
+ f'{self.second_load_address:#010x}')
+ lines.append(
+ f'kernel tags load address: {self.tags_load_address:#010x}')
+ lines.append(f'page size: {self.page_size}')
+ else:
+ lines.append(f'kernel_size: {self.kernel_size}')
+ lines.append(f'ramdisk size: {self.ramdisk_size}')
+
+ lines.append(f'os version: {self.os_version}')
+ lines.append(f'os patch level: {self.os_patch_level}')
+ lines.append(f'boot image header version: {self.header_version}')
+
+ if self.header_version < 3:
+ lines.append(f'product name: {self.product_name}')
+
+ lines.append(f'command line args: {self.cmdline}')
+
+ if self.header_version < 3:
+ lines.append(f'additional command line args: {self.extra_cmdline}')
+
+ if self.header_version in {1, 2}:
+ lines.append(f'recovery dtbo size: {self.recovery_dtbo_size}')
+ lines.append(
+ f'recovery dtbo offset: {self.recovery_dtbo_offset:#018x}')
+ lines.append(f'boot header size: {self.boot_header_size}')
+
+ if self.header_version == 2:
+ lines.append(f'dtb size: {self.dtb_size}')
+ lines.append(f'dtb address: {self.dtb_load_address:#018x}')
+
+ if self.header_version >= 4:
+ lines.append(
+ f'boot.img signature size: {self.boot_signature_size}')
+
+ return '\n'.join(lines)
+
+ def format_mkbootimg_argument(self):
+ args = []
+ args.extend(['--header_version', str(self.header_version)])
+ if self.os_version:
+ args.extend(['--os_version', self.os_version])
+ if self.os_patch_level:
+ args.extend(['--os_patch_level', self.os_patch_level])
+
+ args.extend(['--kernel', os.path.join(self.image_dir, 'kernel')])
+ args.extend(['--ramdisk', os.path.join(self.image_dir, 'ramdisk')])
+
+ if self.header_version <= 2:
+ if self.second_size > 0:
+ args.extend(['--second',
+ os.path.join(self.image_dir, 'second')])
+ if self.recovery_dtbo_size > 0:
+ args.extend(['--recovery_dtbo',
+ os.path.join(self.image_dir, 'recovery_dtbo')])
+ if self.dtb_size > 0:
+ args.extend(['--dtb', os.path.join(self.image_dir, 'dtb')])
+
+ args.extend(['--pagesize', f'{self.page_size:#010x}'])
+
+ # Kernel load address is base + kernel_offset in mkbootimg.py.
+ # However we don't know the value of 'base' when unpacking a boot
+ # image in this script, so we set 'base' to zero and 'kernel_offset'
+ # to the kernel load address, 'ramdisk_offset' to the ramdisk load
+ # address, ... etc.
+ args.extend(['--base', f'{0:#010x}'])
+ args.extend(['--kernel_offset',
+ f'{self.kernel_load_address:#010x}'])
+ args.extend(['--ramdisk_offset',
+ f'{self.ramdisk_load_address:#010x}'])
+ args.extend(['--second_offset',
+ f'{self.second_load_address:#010x}'])
+ args.extend(['--tags_offset', f'{self.tags_load_address:#010x}'])
+
+ # dtb is added in boot image v2, and is absent in v1 or v0.
+ if self.header_version == 2:
+ # dtb_offset is uint64_t.
+ args.extend(['--dtb_offset', f'{self.dtb_load_address:#018x}'])
+
+ args.extend(['--board', self.product_name])
+ args.extend(['--cmdline', self.cmdline + self.extra_cmdline])
+ else:
+ args.extend(['--cmdline', self.cmdline])
+
+ return args
+
+
+def unpack_boot_image(boot_img, output_dir):
"""extracts kernel, ramdisk, second bootloader and recovery dtbo"""
- kernel_ramdisk_second_info = unpack('9I', args.boot_img.read(9 * 4))
- version = kernel_ramdisk_second_info[8]
- if version < 3:
- print('kernel_size: %s' % kernel_ramdisk_second_info[0])
- print('kernel load address: %#x' % kernel_ramdisk_second_info[1])
- print('ramdisk size: %s' % kernel_ramdisk_second_info[2])
- print('ramdisk load address: %#x' % kernel_ramdisk_second_info[3])
- print('second bootloader size: %s' % kernel_ramdisk_second_info[4])
- print('second bootloader load address: %#x' % kernel_ramdisk_second_info[5])
- print('kernel tags load address: %#x' % kernel_ramdisk_second_info[6])
- print('page size: %s' % kernel_ramdisk_second_info[7])
- print_os_version_patch_level(unpack('I', args.boot_img.read(1 * 4))[0])
+ info = BootImageInfoFormatter()
+ info.boot_magic = unpack('8s', boot_img.read(8))[0].decode()
+
+ kernel_ramdisk_second_info = unpack('9I', boot_img.read(9 * 4))
+ # header_version is always at [8] regardless of the value of header_version.
+ info.header_version = kernel_ramdisk_second_info[8]
+
+ if info.header_version < 3:
+ info.kernel_size = kernel_ramdisk_second_info[0]
+ info.kernel_load_address = kernel_ramdisk_second_info[1]
+ info.ramdisk_size = kernel_ramdisk_second_info[2]
+ info.ramdisk_load_address = kernel_ramdisk_second_info[3]
+ info.second_size = kernel_ramdisk_second_info[4]
+ info.second_load_address = kernel_ramdisk_second_info[5]
+ info.tags_load_address = kernel_ramdisk_second_info[6]
+ info.page_size = kernel_ramdisk_second_info[7]
+ os_version_patch_level = unpack('I', boot_img.read(1 * 4))[0]
else:
- print('kernel_size: %s' % kernel_ramdisk_second_info[0])
- print('ramdisk size: %s' % kernel_ramdisk_second_info[1])
- print_os_version_patch_level(kernel_ramdisk_second_info[2])
+ info.kernel_size = kernel_ramdisk_second_info[0]
+ info.ramdisk_size = kernel_ramdisk_second_info[1]
+ os_version_patch_level = kernel_ramdisk_second_info[2]
+ info.second_size = 0
+ info.page_size = BOOT_IMAGE_HEADER_V3_PAGESIZE
- print('boot image header version: %s' % version)
+ info.os_version, info.os_patch_level = decode_os_version_patch_level(
+ os_version_patch_level)
- if version < 3:
- product_name = cstr(unpack('16s', args.boot_img.read(16))[0].decode())
- print('product name: %s' % product_name)
- cmdline = cstr(unpack('512s', args.boot_img.read(512))[0].decode())
- print('command line args: %s' % cmdline)
+ if info.header_version < 3:
+ info.product_name = cstr(unpack('16s',
+ boot_img.read(16))[0].decode())
+ info.cmdline = cstr(unpack('512s', boot_img.read(512))[0].decode())
+ boot_img.read(32) # ignore SHA
+ info.extra_cmdline = cstr(unpack('1024s',
+ boot_img.read(1024))[0].decode())
else:
- cmdline = cstr(unpack('1536s', args.boot_img.read(1536))[0].decode())
- print('command line args: %s' % cmdline)
+ info.cmdline = cstr(unpack('1536s',
+ boot_img.read(1536))[0].decode())
- if version < 3:
- args.boot_img.read(32) # ignore SHA
-
- if version < 3:
- extra_cmdline = cstr(unpack('1024s',
- args.boot_img.read(1024))[0].decode())
- print('additional command line args: %s' % extra_cmdline)
-
- if version < 3:
- kernel_size = kernel_ramdisk_second_info[0]
- ramdisk_size = kernel_ramdisk_second_info[2]
- second_size = kernel_ramdisk_second_info[4]
- page_size = kernel_ramdisk_second_info[7]
+ if info.header_version in {1, 2}:
+ info.recovery_dtbo_size = unpack('I', boot_img.read(1 * 4))[0]
+ info.recovery_dtbo_offset = unpack('Q', boot_img.read(8))[0]
+ info.boot_header_size = unpack('I', boot_img.read(4))[0]
else:
- kernel_size = kernel_ramdisk_second_info[0]
- ramdisk_size = kernel_ramdisk_second_info[1]
- second_size = 0
- page_size = BOOT_IMAGE_HEADER_V3_PAGESIZE
+ info.recovery_dtbo_size = 0
- if 0 < version < 3:
- recovery_dtbo_size = unpack('I', args.boot_img.read(1 * 4))[0]
- print('recovery dtbo size: %s' % recovery_dtbo_size)
- recovery_dtbo_offset = unpack('Q', args.boot_img.read(8))[0]
- print('recovery dtbo offset: %#x' % recovery_dtbo_offset)
- boot_header_size = unpack('I', args.boot_img.read(4))[0]
- print('boot header size: %s' % boot_header_size)
+ if info.header_version == 2:
+ info.dtb_size = unpack('I', boot_img.read(4))[0]
+ info.dtb_load_address = unpack('Q', boot_img.read(8))[0]
else:
- recovery_dtbo_size = 0
- if 1 < version < 3:
- dtb_size = unpack('I', args.boot_img.read(4))[0]
- print('dtb size: %s' % dtb_size)
- dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
- print('dtb address: %#x' % dtb_load_address)
- else:
- dtb_size = 0
+ info.dtb_size = 0
+ info.dtb_load_address = 0
+ if info.header_version >= 4:
+ info.boot_signature_size = unpack('I', boot_img.read(4))[0]
+ else:
+ info.boot_signature_size = 0
# The first page contains the boot header
num_header_pages = 1
- num_kernel_pages = get_number_of_pages(kernel_size, page_size)
- kernel_offset = page_size * num_header_pages # header occupies a page
- image_info_list = [(kernel_offset, kernel_size, 'kernel')]
+ # Convenient shorthand.
+ page_size = info.page_size
- num_ramdisk_pages = get_number_of_pages(ramdisk_size, page_size)
+ num_kernel_pages = get_number_of_pages(info.kernel_size, page_size)
+ kernel_offset = page_size * num_header_pages # header occupies a page
+ image_info_list = [(kernel_offset, info.kernel_size, 'kernel')]
+
+ num_ramdisk_pages = get_number_of_pages(info.ramdisk_size, page_size)
ramdisk_offset = page_size * (num_header_pages + num_kernel_pages
) # header + kernel
- image_info_list.append((ramdisk_offset, ramdisk_size, 'ramdisk'))
+ image_info_list.append((ramdisk_offset, info.ramdisk_size, 'ramdisk'))
- if second_size > 0:
+ if info.second_size > 0:
second_offset = page_size * (
num_header_pages + num_kernel_pages + num_ramdisk_pages
) # header + kernel + ramdisk
- image_info_list.append((second_offset, second_size, 'second'))
+ image_info_list.append((second_offset, info.second_size, 'second'))
- if recovery_dtbo_size > 0:
- image_info_list.append((recovery_dtbo_offset, recovery_dtbo_size,
+ if info.recovery_dtbo_size > 0:
+ image_info_list.append((info.recovery_dtbo_offset,
+ info.recovery_dtbo_size,
'recovery_dtbo'))
- if dtb_size > 0:
- num_second_pages = get_number_of_pages(second_size, page_size)
- num_recovery_dtbo_pages = get_number_of_pages(recovery_dtbo_size, page_size)
+ if info.dtb_size > 0:
+ num_second_pages = get_number_of_pages(info.second_size, page_size)
+ num_recovery_dtbo_pages = get_number_of_pages(
+ info.recovery_dtbo_size, page_size)
dtb_offset = page_size * (
- num_header_pages + num_kernel_pages + num_ramdisk_pages + num_second_pages +
- num_recovery_dtbo_pages
- )
+ num_header_pages + num_kernel_pages + num_ramdisk_pages +
+ num_second_pages + num_recovery_dtbo_pages)
- image_info_list.append((dtb_offset, dtb_size, 'dtb'))
+ image_info_list.append((dtb_offset, info.dtb_size, 'dtb'))
- for image_info in image_info_list:
- extract_image(image_info[0], image_info[1], args.boot_img,
- os.path.join(args.out, image_info[2]))
+ if info.boot_signature_size > 0:
+ # boot signature only exists in boot.img version >= v4.
+ # There are only kernel and ramdisk pages before the signature.
+ boot_signature_offset = page_size * (
+ num_header_pages + num_kernel_pages + num_ramdisk_pages)
+
+ image_info_list.append((boot_signature_offset, info.boot_signature_size,
+ 'boot_signature'))
+
+ create_out_dir(output_dir)
+ for offset, size, name in image_info_list:
+ extract_image(offset, size, boot_img, os.path.join(output_dir, name))
+ info.image_dir = output_dir
+
+ return info
-def unpack_vendor_bootimage(args):
- kernel_ramdisk_info = unpack('5I', args.boot_img.read(5 * 4))
- print('vendor boot image header version: %s' % kernel_ramdisk_info[0])
- print('kernel load address: %#x' % kernel_ramdisk_info[2])
- print('ramdisk load address: %#x' % kernel_ramdisk_info[3])
- print('vendor ramdisk size: %s' % kernel_ramdisk_info[4])
+class VendorBootImageInfoFormatter:
+ """Formats the vendor_boot image info."""
- cmdline = cstr(unpack('2048s', args.boot_img.read(2048))[0].decode())
- print('vendor command line args: %s' % cmdline)
+ def format_pretty_text(self):
+ lines = []
+ lines.append(f'boot magic: {self.boot_magic}')
+ lines.append(f'vendor boot image header version: {self.header_version}')
+ lines.append(f'page size: {self.page_size:#010x}')
+ lines.append(f'kernel load address: {self.kernel_load_address:#010x}')
+ lines.append(f'ramdisk load address: {self.ramdisk_load_address:#010x}')
+ if self.header_version > 3:
+ lines.append(
+ f'vendor ramdisk total size: {self.vendor_ramdisk_size}')
+ else:
+ lines.append(f'vendor ramdisk size: {self.vendor_ramdisk_size}')
+ lines.append(f'vendor command line args: {self.cmdline}')
+ lines.append(
+ f'kernel tags load address: {self.tags_load_address:#010x}')
+ lines.append(f'product name: {self.product_name}')
+ lines.append(f'vendor boot image header size: {self.header_size}')
+ lines.append(f'dtb size: {self.dtb_size}')
+ lines.append(f'dtb address: {self.dtb_load_address:#018x}')
+ if self.header_version > 3:
+ lines.append(
+ f'vendor ramdisk table size: {self.vendor_ramdisk_table_size}')
+ lines.append('vendor ramdisk table: [')
+ indent = lambda level: ' ' * 4 * level
+ for entry in self.vendor_ramdisk_table:
+ (output_ramdisk_name, ramdisk_size, ramdisk_offset,
+ ramdisk_type, ramdisk_name, board_id) = entry
+ lines.append(indent(1) + f'{output_ramdisk_name}: ''{')
+ lines.append(indent(2) + f'size: {ramdisk_size}')
+ lines.append(indent(2) + f'offset: {ramdisk_offset}')
+ lines.append(indent(2) + f'type: {ramdisk_type:#x}')
+ lines.append(indent(2) + f'name: {ramdisk_name}')
+ lines.append(indent(2) + 'board_id: [')
+ stride = 4
+ for row_idx in range(0, len(board_id), stride):
+ row = board_id[row_idx:row_idx + stride]
+ lines.append(
+ indent(3) + ' '.join(f'{e:#010x},' for e in row))
+ lines.append(indent(2) + ']')
+ lines.append(indent(1) + '}')
+ lines.append(']')
+ lines.append(
+ f'vendor bootconfig size: {self.vendor_bootconfig_size}')
- tags_load_address = unpack('I', args.boot_img.read(1 * 4))[0]
- print('kernel tags load address: %#x' % tags_load_address)
+ return '\n'.join(lines)
- product_name = cstr(unpack('16s', args.boot_img.read(16))[0].decode())
- print('product name: %s' % product_name)
+ def format_mkbootimg_argument(self):
+ args = []
+ args.extend(['--header_version', str(self.header_version)])
+ args.extend(['--pagesize', f'{self.page_size:#010x}'])
+ args.extend(['--base', f'{0:#010x}'])
+ args.extend(['--kernel_offset', f'{self.kernel_load_address:#010x}'])
+ args.extend(['--ramdisk_offset', f'{self.ramdisk_load_address:#010x}'])
+ args.extend(['--tags_offset', f'{self.tags_load_address:#010x}'])
+ args.extend(['--dtb_offset', f'{self.dtb_load_address:#018x}'])
+ args.extend(['--vendor_cmdline', self.cmdline])
+ args.extend(['--board', self.product_name])
- dtb_size = unpack('2I', args.boot_img.read(2 * 4))[1]
- print('dtb size: %s' % dtb_size)
- dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
- print('dtb address: %#x' % dtb_load_address)
+ if self.dtb_size > 0:
+ args.extend(['--dtb', os.path.join(self.image_dir, 'dtb')])
- ramdisk_size = kernel_ramdisk_info[4]
- page_size = kernel_ramdisk_info[1]
+ if self.header_version > 3:
+ args.extend(['--vendor_bootconfig',
+ os.path.join(self.image_dir, 'bootconfig')])
+ for entry in self.vendor_ramdisk_table:
+ (output_ramdisk_name, _, _, ramdisk_type,
+ ramdisk_name, board_id) = entry
+ args.extend(['--ramdisk_type', str(ramdisk_type)])
+ args.extend(['--ramdisk_name', ramdisk_name])
+ for idx, e in enumerate(board_id):
+ if e:
+ args.extend([f'--board_id{idx}', f'{e:#010x}'])
+ vendor_ramdisk_path = os.path.join(
+ self.image_dir, output_ramdisk_name)
+ args.extend(['--vendor_ramdisk_fragment', vendor_ramdisk_path])
+ else:
+ args.extend(['--vendor_ramdisk',
+ os.path.join(self.image_dir, 'vendor_ramdisk')])
+
+ return args
+
+
+def unpack_vendor_boot_image(boot_img, output_dir):
+ info = VendorBootImageInfoFormatter()
+ info.boot_magic = unpack('8s', boot_img.read(8))[0].decode()
+ info.header_version = unpack('I', boot_img.read(4))[0]
+ info.page_size = unpack('I', boot_img.read(4))[0]
+ info.kernel_load_address = unpack('I', boot_img.read(4))[0]
+ info.ramdisk_load_address = unpack('I', boot_img.read(4))[0]
+ info.vendor_ramdisk_size = unpack('I', boot_img.read(4))[0]
+ info.cmdline = cstr(unpack('2048s', boot_img.read(2048))[0].decode())
+ info.tags_load_address = unpack('I', boot_img.read(4))[0]
+ info.product_name = cstr(unpack('16s', boot_img.read(16))[0].decode())
+ info.header_size = unpack('I', boot_img.read(4))[0]
+ info.dtb_size = unpack('I', boot_img.read(4))[0]
+ info.dtb_load_address = unpack('Q', boot_img.read(8))[0]
+
+ # Convenient shorthand.
+ page_size = info.page_size
# The first pages contain the boot header
- num_boot_header_pages = get_number_of_pages(VENDOR_BOOT_IMAGE_HEADER_V3_SIZE, page_size)
- num_boot_ramdisk_pages = get_number_of_pages(ramdisk_size, page_size)
- ramdisk_offset = page_size * num_boot_header_pages
- image_info_list = [(ramdisk_offset, ramdisk_size, 'vendor_ramdisk')]
+ num_boot_header_pages = get_number_of_pages(info.header_size, page_size)
+ num_boot_ramdisk_pages = get_number_of_pages(
+ info.vendor_ramdisk_size, page_size)
+ num_boot_dtb_pages = get_number_of_pages(info.dtb_size, page_size)
+
+ ramdisk_offset_base = page_size * num_boot_header_pages
+ image_info_list = []
+
+ if info.header_version > 3:
+ info.vendor_ramdisk_table_size = unpack('I', boot_img.read(4))[0]
+ vendor_ramdisk_table_entry_num = unpack('I', boot_img.read(4))[0]
+ vendor_ramdisk_table_entry_size = unpack('I', boot_img.read(4))[0]
+ info.vendor_bootconfig_size = unpack('I', boot_img.read(4))[0]
+ num_vendor_ramdisk_table_pages = get_number_of_pages(
+ info.vendor_ramdisk_table_size, page_size)
+ vendor_ramdisk_table_offset = page_size * (
+ num_boot_header_pages + num_boot_ramdisk_pages + num_boot_dtb_pages)
+
+ vendor_ramdisk_table = []
+ vendor_ramdisk_symlinks = []
+ for idx in range(vendor_ramdisk_table_entry_num):
+ entry_offset = vendor_ramdisk_table_offset + (
+ vendor_ramdisk_table_entry_size * idx)
+ boot_img.seek(entry_offset)
+ ramdisk_size = unpack('I', boot_img.read(4))[0]
+ ramdisk_offset = unpack('I', boot_img.read(4))[0]
+ ramdisk_type = unpack('I', boot_img.read(4))[0]
+ ramdisk_name = cstr(unpack(
+ f'{VENDOR_RAMDISK_NAME_SIZE}s',
+ boot_img.read(VENDOR_RAMDISK_NAME_SIZE))[0].decode())
+ board_id = unpack(
+ f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}I',
+ boot_img.read(
+ 4 * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE))
+ output_ramdisk_name = f'vendor_ramdisk{idx:02}'
+
+ image_info_list.append((ramdisk_offset_base + ramdisk_offset,
+ ramdisk_size, output_ramdisk_name))
+ vendor_ramdisk_symlinks.append((output_ramdisk_name, ramdisk_name))
+ vendor_ramdisk_table.append(
+ (output_ramdisk_name, ramdisk_size, ramdisk_offset,
+ ramdisk_type, ramdisk_name, board_id))
+
+ info.vendor_ramdisk_table = vendor_ramdisk_table
+
+ bootconfig_offset = page_size * (num_boot_header_pages
+ + num_boot_ramdisk_pages + num_boot_dtb_pages
+ + num_vendor_ramdisk_table_pages)
+ image_info_list.append((bootconfig_offset, info.vendor_bootconfig_size,
+ 'bootconfig'))
+ else:
+ image_info_list.append(
+ (ramdisk_offset_base, info.vendor_ramdisk_size, 'vendor_ramdisk'))
dtb_offset = page_size * (num_boot_header_pages + num_boot_ramdisk_pages
) # header + vendor_ramdisk
- image_info_list.append((dtb_offset, dtb_size, 'dtb'))
+ if info.dtb_size > 0:
+ image_info_list.append((dtb_offset, info.dtb_size, 'dtb'))
- for image_info in image_info_list:
- extract_image(image_info[0], image_info[1], args.boot_img,
- os.path.join(args.out, image_info[2]))
+ create_out_dir(output_dir)
+ for offset, size, name in image_info_list:
+ extract_image(offset, size, boot_img, os.path.join(output_dir, name))
+ info.image_dir = output_dir
+
+ if info.header_version > 3:
+ vendor_ramdisk_by_name_dir = os.path.join(
+ output_dir, 'vendor-ramdisk-by-name')
+ create_out_dir(vendor_ramdisk_by_name_dir)
+ for src, dst in vendor_ramdisk_symlinks:
+ src_pathname = os.path.join('..', src)
+ dst_pathname = os.path.join(
+ vendor_ramdisk_by_name_dir, f'ramdisk_{dst}')
+ if os.path.lexists(dst_pathname):
+ os.remove(dst_pathname)
+ os.symlink(src_pathname, dst_pathname)
+
+ return info
-def unpack_image(args):
- boot_magic = unpack('8s', args.boot_img.read(8))[0].decode()
- print('boot_magic: %s' % boot_magic)
- if boot_magic == "ANDROID!":
- unpack_bootimage(args)
- elif boot_magic == "VNDRBOOT":
- unpack_vendor_bootimage(args)
+def unpack_bootimg(boot_img, output_dir):
+ """Unpacks the |boot_img| to |output_dir|, and returns the 'info' object."""
+ with open(boot_img, 'rb') as image_file:
+ boot_magic = unpack('8s', image_file.read(8))[0].decode()
+ image_file.seek(0)
+ if boot_magic == 'ANDROID!':
+ info = unpack_boot_image(image_file, output_dir)
+ elif boot_magic == 'VNDRBOOT':
+ info = unpack_vendor_boot_image(image_file, output_dir)
+ else:
+ raise ValueError(f'Not an Android boot image, magic: {boot_magic}')
+
+ return info
+
+
+def print_bootimg_info(info, output_format, null_separator):
+ """Format and print boot image info."""
+ if output_format == 'mkbootimg':
+ mkbootimg_args = info.format_mkbootimg_argument()
+ if null_separator:
+ print('\0'.join(mkbootimg_args) + '\0', end='')
+ else:
+ print(shlex.join(mkbootimg_args))
+ else:
+ print(info.format_pretty_text())
+
+
+def get_unpack_usage():
+ return """Output format:
+
+ * info
+
+ Pretty-printed info-rich text format suitable for human inspection.
+
+ * mkbootimg
+
+ Output shell-escaped (quoted) argument strings that can be used to
+ reconstruct the boot image. For example:
+
+ $ unpack_bootimg --boot_img vendor_boot.img --out out --format=mkbootimg |
+ tee mkbootimg_args
+ $ sh -c "mkbootimg $(cat mkbootimg_args) --vendor_boot repacked.img"
+
+ vendor_boot.img and repacked.img would be equivalent.
+
+ If the -0 option is specified, output unescaped null-terminated argument
+ strings that are suitable to be parsed by a shell script (xargs -0 format):
+
+ $ unpack_bootimg --boot_img vendor_boot.img --out out --format=mkbootimg \\
+ -0 | tee mkbootimg_args
+ $ declare -a MKBOOTIMG_ARGS=()
+ $ while IFS= read -r -d '' ARG; do
+ MKBOOTIMG_ARGS+=("${ARG}")
+ done <mkbootimg_args
+ $ mkbootimg "${MKBOOTIMG_ARGS[@]}" --vendor_boot repacked.img
+"""
def parse_cmdline():
"""parse command line arguments"""
parser = ArgumentParser(
- description='Unpacks boot.img/recovery.img, extracts the kernel,'
- 'ramdisk, second bootloader, recovery dtbo and dtb')
- parser.add_argument(
- '--boot_img',
- help='path to boot image',
- type=FileType('rb'),
- required=True)
- parser.add_argument('--out', help='path to out binaries', default='out')
+ formatter_class=RawDescriptionHelpFormatter,
+ description='Unpacks boot, recovery or vendor_boot image.',
+ epilog=get_unpack_usage(),
+ )
+ parser.add_argument('--boot_img', required=True,
+ help='path to the boot, recovery or vendor_boot image')
+ parser.add_argument('--out', default='out',
+ help='output directory of the unpacked images')
+ parser.add_argument('--format', choices=['info', 'mkbootimg'],
+ default='info',
+ help='text output format (default: info)')
+ parser.add_argument('-0', '--null', action='store_true',
+ help='output null-terminated argument strings')
return parser.parse_args()
def main():
"""parse arguments and unpack boot image"""
args = parse_cmdline()
- create_out_dir(args.out)
- unpack_image(args)
+ info = unpack_bootimg(args.boot_img, args.out)
+ print_bootimg_info(info, args.format, args.null)
if __name__ == '__main__':
--
Gitblit v1.6.2