1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Copyright 2015, The Android Open Source Project 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# Licensed under the Apache License, Version 2.0 (the "License"); 6*4882a593Smuzhiyun# you may not use this file except in compliance with the License. 7*4882a593Smuzhiyun# You may obtain a copy of the License at 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun# http://www.apache.org/licenses/LICENSE-2.0 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# Unless required by applicable law or agreed to in writing, software 12*4882a593Smuzhiyun# distributed under the License is distributed on an "AS IS" BASIS, 13*4882a593Smuzhiyun# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*4882a593Smuzhiyun# See the License for the specific language governing permissions and 15*4882a593Smuzhiyun# limitations under the License. 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun"""Creates the boot image.""" 18*4882a593Smuzhiyun 19*4882a593Smuzhiyunfrom argparse import (ArgumentParser, ArgumentTypeError, 20*4882a593Smuzhiyun FileType, RawDescriptionHelpFormatter) 21*4882a593Smuzhiyunfrom hashlib import sha1 22*4882a593Smuzhiyunfrom os import fstat 23*4882a593Smuzhiyunfrom struct import pack 24*4882a593Smuzhiyun 25*4882a593Smuzhiyunimport array 26*4882a593Smuzhiyunimport collections 27*4882a593Smuzhiyunimport os 28*4882a593Smuzhiyunimport re 29*4882a593Smuzhiyunimport tempfile 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun# from gki.generate_gki_certificate import generate_gki_certificate 32*4882a593Smuzhiyundef generate_gki_certificate(image, avbtool, name, algorithm, key, salt, 33*4882a593Smuzhiyun additional_avb_args, output): 34*4882a593Smuzhiyun """Shell out to avbtool to generate a GKI certificate.""" 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun # Need to specify a value of --partition_size for avbtool to work. 37*4882a593Smuzhiyun # We use 64 MB below, but avbtool will not resize the boot image to 38*4882a593Smuzhiyun # this size because --do_not_append_vbmeta_image is also specified. 39*4882a593Smuzhiyun avbtool_cmd = [ 40*4882a593Smuzhiyun avbtool, 'add_hash_footer', 41*4882a593Smuzhiyun '--partition_name', name, 42*4882a593Smuzhiyun '--partition_size', str(64 * 1024 * 1024), 43*4882a593Smuzhiyun '--image', image, 44*4882a593Smuzhiyun '--algorithm', algorithm, 45*4882a593Smuzhiyun '--key', key, 46*4882a593Smuzhiyun '--do_not_append_vbmeta_image', 47*4882a593Smuzhiyun '--output_vbmeta_image', output, 48*4882a593Smuzhiyun ] 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun if salt is not None: 51*4882a593Smuzhiyun avbtool_cmd += ['--salt', salt] 52*4882a593Smuzhiyun 53*4882a593Smuzhiyun avbtool_cmd += additional_avb_args 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun subprocess.check_call(avbtool_cmd) 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun# Constant and structure definition is in 59*4882a593Smuzhiyun# system/tools/mkbootimg/include/bootimg/bootimg.h 60*4882a593SmuzhiyunBOOT_MAGIC = 'ANDROID!' 61*4882a593SmuzhiyunBOOT_MAGIC_SIZE = 8 62*4882a593SmuzhiyunBOOT_NAME_SIZE = 16 63*4882a593SmuzhiyunBOOT_ARGS_SIZE = 512 64*4882a593SmuzhiyunBOOT_EXTRA_ARGS_SIZE = 1024 65*4882a593SmuzhiyunBOOT_IMAGE_HEADER_V1_SIZE = 1648 66*4882a593SmuzhiyunBOOT_IMAGE_HEADER_V2_SIZE = 1660 67*4882a593SmuzhiyunBOOT_IMAGE_HEADER_V3_SIZE = 1580 68*4882a593SmuzhiyunBOOT_IMAGE_HEADER_V3_PAGESIZE = 4096 69*4882a593SmuzhiyunBOOT_IMAGE_HEADER_V4_SIZE = 1584 70*4882a593SmuzhiyunBOOT_IMAGE_V4_SIGNATURE_SIZE = 4096 71*4882a593Smuzhiyun 72*4882a593SmuzhiyunVENDOR_BOOT_MAGIC = 'VNDRBOOT' 73*4882a593SmuzhiyunVENDOR_BOOT_MAGIC_SIZE = 8 74*4882a593SmuzhiyunVENDOR_BOOT_NAME_SIZE = BOOT_NAME_SIZE 75*4882a593SmuzhiyunVENDOR_BOOT_ARGS_SIZE = 2048 76*4882a593SmuzhiyunVENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112 77*4882a593SmuzhiyunVENDOR_BOOT_IMAGE_HEADER_V4_SIZE = 2128 78*4882a593Smuzhiyun 79*4882a593SmuzhiyunVENDOR_RAMDISK_TYPE_NONE = 0 80*4882a593SmuzhiyunVENDOR_RAMDISK_TYPE_PLATFORM = 1 81*4882a593SmuzhiyunVENDOR_RAMDISK_TYPE_RECOVERY = 2 82*4882a593SmuzhiyunVENDOR_RAMDISK_TYPE_DLKM = 3 83*4882a593SmuzhiyunVENDOR_RAMDISK_NAME_SIZE = 32 84*4882a593SmuzhiyunVENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE = 16 85*4882a593SmuzhiyunVENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE = 108 86*4882a593Smuzhiyun 87*4882a593Smuzhiyun# Names with special meaning, mustn't be specified in --ramdisk_name. 88*4882a593SmuzhiyunVENDOR_RAMDISK_NAME_BLOCKLIST = {b'default'} 89*4882a593Smuzhiyun 90*4882a593SmuzhiyunPARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT = '--vendor_ramdisk_fragment' 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun 93*4882a593Smuzhiyundef filesize(f): 94*4882a593Smuzhiyun if f is None: 95*4882a593Smuzhiyun return 0 96*4882a593Smuzhiyun try: 97*4882a593Smuzhiyun return fstat(f.fileno()).st_size 98*4882a593Smuzhiyun except OSError: 99*4882a593Smuzhiyun return 0 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun 102*4882a593Smuzhiyundef update_sha(sha, f): 103*4882a593Smuzhiyun if f: 104*4882a593Smuzhiyun sha.update(f.read()) 105*4882a593Smuzhiyun f.seek(0) 106*4882a593Smuzhiyun sha.update(pack('I', filesize(f))) 107*4882a593Smuzhiyun else: 108*4882a593Smuzhiyun sha.update(pack('I', 0)) 109*4882a593Smuzhiyun 110*4882a593Smuzhiyun 111*4882a593Smuzhiyundef pad_file(f, padding): 112*4882a593Smuzhiyun pad = (padding - (f.tell() & (padding - 1))) & (padding - 1) 113*4882a593Smuzhiyun f.write(pack(str(pad) + 'x')) 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun 116*4882a593Smuzhiyundef get_number_of_pages(image_size, page_size): 117*4882a593Smuzhiyun """calculates the number of pages required for the image""" 118*4882a593Smuzhiyun return (image_size + page_size - 1) // page_size 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun 121*4882a593Smuzhiyundef get_recovery_dtbo_offset(args): 122*4882a593Smuzhiyun """calculates the offset of recovery_dtbo image in the boot image""" 123*4882a593Smuzhiyun num_header_pages = 1 # header occupies a page 124*4882a593Smuzhiyun num_kernel_pages = get_number_of_pages(filesize(args.kernel), args.pagesize) 125*4882a593Smuzhiyun num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk), 126*4882a593Smuzhiyun args.pagesize) 127*4882a593Smuzhiyun num_second_pages = get_number_of_pages(filesize(args.second), args.pagesize) 128*4882a593Smuzhiyun dtbo_offset = args.pagesize * (num_header_pages + num_kernel_pages + 129*4882a593Smuzhiyun num_ramdisk_pages + num_second_pages) 130*4882a593Smuzhiyun return dtbo_offset 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun 133*4882a593Smuzhiyundef should_add_legacy_gki_boot_signature(args): 134*4882a593Smuzhiyun if args.gki_signing_key and args.gki_signing_algorithm: 135*4882a593Smuzhiyun return True 136*4882a593Smuzhiyun return False 137*4882a593Smuzhiyun 138*4882a593Smuzhiyun 139*4882a593Smuzhiyundef write_header_v3_and_above(args): 140*4882a593Smuzhiyun if args.header_version > 3: 141*4882a593Smuzhiyun boot_header_size = BOOT_IMAGE_HEADER_V4_SIZE 142*4882a593Smuzhiyun else: 143*4882a593Smuzhiyun boot_header_size = BOOT_IMAGE_HEADER_V3_SIZE 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode())) 146*4882a593Smuzhiyun # kernel size in bytes 147*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.kernel))) 148*4882a593Smuzhiyun # ramdisk size in bytes 149*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.ramdisk))) 150*4882a593Smuzhiyun # os version and patch level 151*4882a593Smuzhiyun args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level)) 152*4882a593Smuzhiyun args.output.write(pack('I', boot_header_size)) 153*4882a593Smuzhiyun # reserved 154*4882a593Smuzhiyun args.output.write(pack('4I', 0, 0, 0, 0)) 155*4882a593Smuzhiyun # version of boot image header 156*4882a593Smuzhiyun args.output.write(pack('I', args.header_version)) 157*4882a593Smuzhiyun args.output.write(pack(f'{BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE}s', 158*4882a593Smuzhiyun args.cmdline)) 159*4882a593Smuzhiyun if args.header_version >= 4: 160*4882a593Smuzhiyun # The signature used to verify boot image v4. 161*4882a593Smuzhiyun boot_signature_size = 0 162*4882a593Smuzhiyun if should_add_legacy_gki_boot_signature(args): 163*4882a593Smuzhiyun boot_signature_size = BOOT_IMAGE_V4_SIGNATURE_SIZE 164*4882a593Smuzhiyun args.output.write(pack('I', boot_signature_size)) 165*4882a593Smuzhiyun pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE) 166*4882a593Smuzhiyun 167*4882a593Smuzhiyun 168*4882a593Smuzhiyundef write_vendor_boot_header(args): 169*4882a593Smuzhiyun if args.header_version > 3: 170*4882a593Smuzhiyun vendor_ramdisk_size = args.vendor_ramdisk_total_size 171*4882a593Smuzhiyun vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V4_SIZE 172*4882a593Smuzhiyun else: 173*4882a593Smuzhiyun vendor_ramdisk_size = filesize(args.vendor_ramdisk) 174*4882a593Smuzhiyun vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V3_SIZE 175*4882a593Smuzhiyun 176*4882a593Smuzhiyun args.vendor_boot.write(pack(f'{VENDOR_BOOT_MAGIC_SIZE}s', 177*4882a593Smuzhiyun VENDOR_BOOT_MAGIC.encode())) 178*4882a593Smuzhiyun # version of boot image header 179*4882a593Smuzhiyun args.vendor_boot.write(pack('I', args.header_version)) 180*4882a593Smuzhiyun # flash page size 181*4882a593Smuzhiyun args.vendor_boot.write(pack('I', args.pagesize)) 182*4882a593Smuzhiyun # kernel physical load address 183*4882a593Smuzhiyun args.vendor_boot.write(pack('I', args.base + args.kernel_offset)) 184*4882a593Smuzhiyun # ramdisk physical load address 185*4882a593Smuzhiyun args.vendor_boot.write(pack('I', args.base + args.ramdisk_offset)) 186*4882a593Smuzhiyun # ramdisk size in bytes 187*4882a593Smuzhiyun args.vendor_boot.write(pack('I', vendor_ramdisk_size)) 188*4882a593Smuzhiyun args.vendor_boot.write(pack(f'{VENDOR_BOOT_ARGS_SIZE}s', 189*4882a593Smuzhiyun args.vendor_cmdline)) 190*4882a593Smuzhiyun # kernel tags physical load address 191*4882a593Smuzhiyun args.vendor_boot.write(pack('I', args.base + args.tags_offset)) 192*4882a593Smuzhiyun # asciiz product name 193*4882a593Smuzhiyun args.vendor_boot.write(pack(f'{VENDOR_BOOT_NAME_SIZE}s', args.board)) 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun # header size in bytes 196*4882a593Smuzhiyun args.vendor_boot.write(pack('I', vendor_boot_header_size)) 197*4882a593Smuzhiyun 198*4882a593Smuzhiyun # dtb size in bytes 199*4882a593Smuzhiyun args.vendor_boot.write(pack('I', filesize(args.dtb))) 200*4882a593Smuzhiyun # dtb physical load address 201*4882a593Smuzhiyun args.vendor_boot.write(pack('Q', args.base + args.dtb_offset)) 202*4882a593Smuzhiyun 203*4882a593Smuzhiyun if args.header_version > 3: 204*4882a593Smuzhiyun vendor_ramdisk_table_size = (args.vendor_ramdisk_table_entry_num * 205*4882a593Smuzhiyun VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE) 206*4882a593Smuzhiyun # vendor ramdisk table size in bytes 207*4882a593Smuzhiyun args.vendor_boot.write(pack('I', vendor_ramdisk_table_size)) 208*4882a593Smuzhiyun # number of vendor ramdisk table entries 209*4882a593Smuzhiyun args.vendor_boot.write(pack('I', args.vendor_ramdisk_table_entry_num)) 210*4882a593Smuzhiyun # vendor ramdisk table entry size in bytes 211*4882a593Smuzhiyun args.vendor_boot.write(pack('I', VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE)) 212*4882a593Smuzhiyun # bootconfig section size in bytes 213*4882a593Smuzhiyun args.vendor_boot.write(pack('I', filesize(args.vendor_bootconfig))) 214*4882a593Smuzhiyun pad_file(args.vendor_boot, args.pagesize) 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun 217*4882a593Smuzhiyundef write_header(args): 218*4882a593Smuzhiyun if args.header_version > 4: 219*4882a593Smuzhiyun raise ValueError( 220*4882a593Smuzhiyun f'Boot header version {args.header_version} not supported') 221*4882a593Smuzhiyun if args.header_version in {3, 4}: 222*4882a593Smuzhiyun return write_header_v3_and_above(args) 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun ramdisk_load_address = ((args.base + args.ramdisk_offset) 225*4882a593Smuzhiyun if filesize(args.ramdisk) > 0 else 0) 226*4882a593Smuzhiyun second_load_address = ((args.base + args.second_offset) 227*4882a593Smuzhiyun if filesize(args.second) > 0 else 0) 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode())) 230*4882a593Smuzhiyun # kernel size in bytes 231*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.kernel))) 232*4882a593Smuzhiyun # kernel physical load address 233*4882a593Smuzhiyun args.output.write(pack('I', args.base + args.kernel_offset)) 234*4882a593Smuzhiyun # ramdisk size in bytes 235*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.ramdisk))) 236*4882a593Smuzhiyun # ramdisk physical load address 237*4882a593Smuzhiyun args.output.write(pack('I', ramdisk_load_address)) 238*4882a593Smuzhiyun # second bootloader size in bytes 239*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.second))) 240*4882a593Smuzhiyun # second bootloader physical load address 241*4882a593Smuzhiyun args.output.write(pack('I', second_load_address)) 242*4882a593Smuzhiyun # kernel tags physical load address 243*4882a593Smuzhiyun args.output.write(pack('I', args.base + args.tags_offset)) 244*4882a593Smuzhiyun # flash page size 245*4882a593Smuzhiyun args.output.write(pack('I', args.pagesize)) 246*4882a593Smuzhiyun # version of boot image header 247*4882a593Smuzhiyun args.output.write(pack('I', args.header_version)) 248*4882a593Smuzhiyun # os version and patch level 249*4882a593Smuzhiyun args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level)) 250*4882a593Smuzhiyun # asciiz product name 251*4882a593Smuzhiyun args.output.write(pack(f'{BOOT_NAME_SIZE}s', args.board)) 252*4882a593Smuzhiyun args.output.write(pack(f'{BOOT_ARGS_SIZE}s', args.cmdline)) 253*4882a593Smuzhiyun 254*4882a593Smuzhiyun sha = sha1() 255*4882a593Smuzhiyun update_sha(sha, args.kernel) 256*4882a593Smuzhiyun update_sha(sha, args.ramdisk) 257*4882a593Smuzhiyun update_sha(sha, args.second) 258*4882a593Smuzhiyun 259*4882a593Smuzhiyun if args.header_version > 0: 260*4882a593Smuzhiyun update_sha(sha, args.recovery_dtbo) 261*4882a593Smuzhiyun if args.header_version > 1: 262*4882a593Smuzhiyun update_sha(sha, args.dtb) 263*4882a593Smuzhiyun 264*4882a593Smuzhiyun img_id = pack('32s', sha.digest()) 265*4882a593Smuzhiyun 266*4882a593Smuzhiyun args.output.write(img_id) 267*4882a593Smuzhiyun args.output.write(pack(f'{BOOT_EXTRA_ARGS_SIZE}s', args.extra_cmdline)) 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun if args.header_version > 0: 270*4882a593Smuzhiyun if args.recovery_dtbo: 271*4882a593Smuzhiyun # recovery dtbo size in bytes 272*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.recovery_dtbo))) 273*4882a593Smuzhiyun # recovert dtbo offset in the boot image 274*4882a593Smuzhiyun args.output.write(pack('Q', get_recovery_dtbo_offset(args))) 275*4882a593Smuzhiyun else: 276*4882a593Smuzhiyun # Set to zero if no recovery dtbo 277*4882a593Smuzhiyun args.output.write(pack('I', 0)) 278*4882a593Smuzhiyun args.output.write(pack('Q', 0)) 279*4882a593Smuzhiyun 280*4882a593Smuzhiyun # Populate boot image header size for header versions 1 and 2. 281*4882a593Smuzhiyun if args.header_version == 1: 282*4882a593Smuzhiyun args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE)) 283*4882a593Smuzhiyun elif args.header_version == 2: 284*4882a593Smuzhiyun args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE)) 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun if args.header_version > 1: 287*4882a593Smuzhiyun # if filesize(args.dtb) == 0: 288*4882a593Smuzhiyun # raise ValueError('DTB image must not be empty.') 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun # dtb size in bytes 291*4882a593Smuzhiyun args.output.write(pack('I', filesize(args.dtb))) 292*4882a593Smuzhiyun # dtb physical load address 293*4882a593Smuzhiyun args.output.write(pack('Q', args.base + args.dtb_offset)) 294*4882a593Smuzhiyun 295*4882a593Smuzhiyun pad_file(args.output, args.pagesize) 296*4882a593Smuzhiyun return img_id 297*4882a593Smuzhiyun 298*4882a593Smuzhiyun 299*4882a593Smuzhiyunclass AsciizBytes: 300*4882a593Smuzhiyun """Parses a string and encodes it as an asciiz bytes object. 301*4882a593Smuzhiyun 302*4882a593Smuzhiyun >>> AsciizBytes(bufsize=4)('foo') 303*4882a593Smuzhiyun b'foo\\x00' 304*4882a593Smuzhiyun >>> AsciizBytes(bufsize=4)('foob') 305*4882a593Smuzhiyun Traceback (most recent call last): 306*4882a593Smuzhiyun ... 307*4882a593Smuzhiyun argparse.ArgumentTypeError: Encoded asciiz length exceeded: max 4, got 5 308*4882a593Smuzhiyun """ 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun def __init__(self, bufsize): 311*4882a593Smuzhiyun self.bufsize = bufsize 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun def __call__(self, arg): 314*4882a593Smuzhiyun arg_bytes = arg.encode() + b'\x00' 315*4882a593Smuzhiyun if len(arg_bytes) > self.bufsize: 316*4882a593Smuzhiyun raise ArgumentTypeError( 317*4882a593Smuzhiyun 'Encoded asciiz length exceeded: ' 318*4882a593Smuzhiyun f'max {self.bufsize}, got {len(arg_bytes)}') 319*4882a593Smuzhiyun return arg_bytes 320*4882a593Smuzhiyun 321*4882a593Smuzhiyun 322*4882a593Smuzhiyunclass VendorRamdiskTableBuilder: 323*4882a593Smuzhiyun """Vendor ramdisk table builder. 324*4882a593Smuzhiyun 325*4882a593Smuzhiyun Attributes: 326*4882a593Smuzhiyun entries: A list of VendorRamdiskTableEntry namedtuple. 327*4882a593Smuzhiyun ramdisk_total_size: Total size in bytes of all ramdisks in the table. 328*4882a593Smuzhiyun """ 329*4882a593Smuzhiyun 330*4882a593Smuzhiyun VendorRamdiskTableEntry = collections.namedtuple( # pylint: disable=invalid-name 331*4882a593Smuzhiyun 'VendorRamdiskTableEntry', 332*4882a593Smuzhiyun ['ramdisk_path', 'ramdisk_size', 'ramdisk_offset', 'ramdisk_type', 333*4882a593Smuzhiyun 'ramdisk_name', 'board_id']) 334*4882a593Smuzhiyun 335*4882a593Smuzhiyun def __init__(self): 336*4882a593Smuzhiyun self.entries = [] 337*4882a593Smuzhiyun self.ramdisk_total_size = 0 338*4882a593Smuzhiyun self.ramdisk_names = set() 339*4882a593Smuzhiyun 340*4882a593Smuzhiyun def add_entry(self, ramdisk_path, ramdisk_type, ramdisk_name, board_id): 341*4882a593Smuzhiyun # Strip any trailing null for simple comparison. 342*4882a593Smuzhiyun stripped_ramdisk_name = ramdisk_name.rstrip(b'\x00') 343*4882a593Smuzhiyun if stripped_ramdisk_name in VENDOR_RAMDISK_NAME_BLOCKLIST: 344*4882a593Smuzhiyun raise ValueError( 345*4882a593Smuzhiyun f'Banned vendor ramdisk name: {stripped_ramdisk_name}') 346*4882a593Smuzhiyun if stripped_ramdisk_name in self.ramdisk_names: 347*4882a593Smuzhiyun raise ValueError( 348*4882a593Smuzhiyun f'Duplicated vendor ramdisk name: {stripped_ramdisk_name}') 349*4882a593Smuzhiyun self.ramdisk_names.add(stripped_ramdisk_name) 350*4882a593Smuzhiyun 351*4882a593Smuzhiyun if board_id is None: 352*4882a593Smuzhiyun board_id = array.array( 353*4882a593Smuzhiyun 'I', [0] * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE) 354*4882a593Smuzhiyun else: 355*4882a593Smuzhiyun board_id = array.array('I', board_id) 356*4882a593Smuzhiyun if len(board_id) != VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE: 357*4882a593Smuzhiyun raise ValueError('board_id size must be ' 358*4882a593Smuzhiyun f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}') 359*4882a593Smuzhiyun 360*4882a593Smuzhiyun with open(ramdisk_path, 'rb') as f: 361*4882a593Smuzhiyun ramdisk_size = filesize(f) 362*4882a593Smuzhiyun self.entries.append(self.VendorRamdiskTableEntry( 363*4882a593Smuzhiyun ramdisk_path, ramdisk_size, self.ramdisk_total_size, ramdisk_type, 364*4882a593Smuzhiyun ramdisk_name, board_id)) 365*4882a593Smuzhiyun self.ramdisk_total_size += ramdisk_size 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun def write_ramdisks_padded(self, fout, alignment): 368*4882a593Smuzhiyun for entry in self.entries: 369*4882a593Smuzhiyun with open(entry.ramdisk_path, 'rb') as f: 370*4882a593Smuzhiyun fout.write(f.read()) 371*4882a593Smuzhiyun pad_file(fout, alignment) 372*4882a593Smuzhiyun 373*4882a593Smuzhiyun def write_entries_padded(self, fout, alignment): 374*4882a593Smuzhiyun for entry in self.entries: 375*4882a593Smuzhiyun fout.write(pack('I', entry.ramdisk_size)) 376*4882a593Smuzhiyun fout.write(pack('I', entry.ramdisk_offset)) 377*4882a593Smuzhiyun fout.write(pack('I', entry.ramdisk_type)) 378*4882a593Smuzhiyun fout.write(pack(f'{VENDOR_RAMDISK_NAME_SIZE}s', 379*4882a593Smuzhiyun entry.ramdisk_name)) 380*4882a593Smuzhiyun fout.write(entry.board_id) 381*4882a593Smuzhiyun pad_file(fout, alignment) 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun 384*4882a593Smuzhiyundef write_padded_file(f_out, f_in, padding): 385*4882a593Smuzhiyun if f_in is None: 386*4882a593Smuzhiyun return 387*4882a593Smuzhiyun f_out.write(f_in.read()) 388*4882a593Smuzhiyun pad_file(f_out, padding) 389*4882a593Smuzhiyun 390*4882a593Smuzhiyun 391*4882a593Smuzhiyundef parse_int(x): 392*4882a593Smuzhiyun return int(x, 0) 393*4882a593Smuzhiyun 394*4882a593Smuzhiyun 395*4882a593Smuzhiyundef parse_os_version(x): 396*4882a593Smuzhiyun match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x) 397*4882a593Smuzhiyun if match: 398*4882a593Smuzhiyun a = int(match.group(1)) 399*4882a593Smuzhiyun b = c = 0 400*4882a593Smuzhiyun if match.lastindex >= 2: 401*4882a593Smuzhiyun b = int(match.group(2)) 402*4882a593Smuzhiyun if match.lastindex == 3: 403*4882a593Smuzhiyun c = int(match.group(3)) 404*4882a593Smuzhiyun # 7 bits allocated for each field 405*4882a593Smuzhiyun assert a < 128 406*4882a593Smuzhiyun assert b < 128 407*4882a593Smuzhiyun assert c < 128 408*4882a593Smuzhiyun return (a << 14) | (b << 7) | c 409*4882a593Smuzhiyun return 0 410*4882a593Smuzhiyun 411*4882a593Smuzhiyun 412*4882a593Smuzhiyundef parse_os_patch_level(x): 413*4882a593Smuzhiyun match = re.search(r'^(\d{4})-(\d{2})(?:-(\d{2}))?', x) 414*4882a593Smuzhiyun if match: 415*4882a593Smuzhiyun y = int(match.group(1)) - 2000 416*4882a593Smuzhiyun m = int(match.group(2)) 417*4882a593Smuzhiyun # 7 bits allocated for the year, 4 bits for the month 418*4882a593Smuzhiyun assert 0 <= y < 128 419*4882a593Smuzhiyun assert 0 < m <= 12 420*4882a593Smuzhiyun return (y << 4) | m 421*4882a593Smuzhiyun return 0 422*4882a593Smuzhiyun 423*4882a593Smuzhiyun 424*4882a593Smuzhiyundef parse_vendor_ramdisk_type(x): 425*4882a593Smuzhiyun type_dict = { 426*4882a593Smuzhiyun 'none': VENDOR_RAMDISK_TYPE_NONE, 427*4882a593Smuzhiyun 'platform': VENDOR_RAMDISK_TYPE_PLATFORM, 428*4882a593Smuzhiyun 'recovery': VENDOR_RAMDISK_TYPE_RECOVERY, 429*4882a593Smuzhiyun 'dlkm': VENDOR_RAMDISK_TYPE_DLKM, 430*4882a593Smuzhiyun } 431*4882a593Smuzhiyun if x.lower() in type_dict: 432*4882a593Smuzhiyun return type_dict[x.lower()] 433*4882a593Smuzhiyun return parse_int(x) 434*4882a593Smuzhiyun 435*4882a593Smuzhiyun 436*4882a593Smuzhiyundef get_vendor_boot_v4_usage(): 437*4882a593Smuzhiyun return """vendor boot version 4 arguments: 438*4882a593Smuzhiyun --ramdisk_type {none,platform,recovery,dlkm} 439*4882a593Smuzhiyun specify the type of the ramdisk 440*4882a593Smuzhiyun --ramdisk_name NAME 441*4882a593Smuzhiyun specify the name of the ramdisk 442*4882a593Smuzhiyun --board_id{0..15} NUMBER 443*4882a593Smuzhiyun specify the value of the board_id vector, defaults to 0 444*4882a593Smuzhiyun --vendor_ramdisk_fragment VENDOR_RAMDISK_FILE 445*4882a593Smuzhiyun path to the vendor ramdisk file 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun These options can be specified multiple times, where each vendor ramdisk 448*4882a593Smuzhiyun option group ends with a --vendor_ramdisk_fragment option. 449*4882a593Smuzhiyun Each option group appends an additional ramdisk to the vendor boot image. 450*4882a593Smuzhiyun""" 451*4882a593Smuzhiyun 452*4882a593Smuzhiyun 453*4882a593Smuzhiyundef parse_vendor_ramdisk_args(args, args_list): 454*4882a593Smuzhiyun """Parses vendor ramdisk specific arguments. 455*4882a593Smuzhiyun 456*4882a593Smuzhiyun Args: 457*4882a593Smuzhiyun args: An argparse.Namespace object. Parsed results are stored into this 458*4882a593Smuzhiyun object. 459*4882a593Smuzhiyun args_list: A list of argument strings to be parsed. 460*4882a593Smuzhiyun 461*4882a593Smuzhiyun Returns: 462*4882a593Smuzhiyun A list argument strings that are not parsed by this method. 463*4882a593Smuzhiyun """ 464*4882a593Smuzhiyun parser = ArgumentParser(add_help=False) 465*4882a593Smuzhiyun parser.add_argument('--ramdisk_type', type=parse_vendor_ramdisk_type, 466*4882a593Smuzhiyun default=VENDOR_RAMDISK_TYPE_NONE) 467*4882a593Smuzhiyun parser.add_argument('--ramdisk_name', 468*4882a593Smuzhiyun type=AsciizBytes(bufsize=VENDOR_RAMDISK_NAME_SIZE), 469*4882a593Smuzhiyun required=True) 470*4882a593Smuzhiyun for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE): 471*4882a593Smuzhiyun parser.add_argument(f'--board_id{i}', type=parse_int, default=0) 472*4882a593Smuzhiyun parser.add_argument(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT, required=True) 473*4882a593Smuzhiyun 474*4882a593Smuzhiyun unknown_args = [] 475*4882a593Smuzhiyun 476*4882a593Smuzhiyun vendor_ramdisk_table_builder = VendorRamdiskTableBuilder() 477*4882a593Smuzhiyun if args.vendor_ramdisk is not None: 478*4882a593Smuzhiyun vendor_ramdisk_table_builder.add_entry( 479*4882a593Smuzhiyun args.vendor_ramdisk.name, VENDOR_RAMDISK_TYPE_PLATFORM, b'', None) 480*4882a593Smuzhiyun 481*4882a593Smuzhiyun while PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT in args_list: 482*4882a593Smuzhiyun idx = args_list.index(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT) + 2 483*4882a593Smuzhiyun vendor_ramdisk_args = args_list[:idx] 484*4882a593Smuzhiyun args_list = args_list[idx:] 485*4882a593Smuzhiyun 486*4882a593Smuzhiyun ramdisk_args, extra_args = parser.parse_known_args(vendor_ramdisk_args) 487*4882a593Smuzhiyun ramdisk_args_dict = vars(ramdisk_args) 488*4882a593Smuzhiyun unknown_args.extend(extra_args) 489*4882a593Smuzhiyun 490*4882a593Smuzhiyun ramdisk_path = ramdisk_args.vendor_ramdisk_fragment 491*4882a593Smuzhiyun ramdisk_type = ramdisk_args.ramdisk_type 492*4882a593Smuzhiyun ramdisk_name = ramdisk_args.ramdisk_name 493*4882a593Smuzhiyun board_id = [ramdisk_args_dict[f'board_id{i}'] 494*4882a593Smuzhiyun for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)] 495*4882a593Smuzhiyun vendor_ramdisk_table_builder.add_entry(ramdisk_path, ramdisk_type, 496*4882a593Smuzhiyun ramdisk_name, board_id) 497*4882a593Smuzhiyun 498*4882a593Smuzhiyun if len(args_list) > 0: 499*4882a593Smuzhiyun unknown_args.extend(args_list) 500*4882a593Smuzhiyun 501*4882a593Smuzhiyun args.vendor_ramdisk_total_size = (vendor_ramdisk_table_builder 502*4882a593Smuzhiyun .ramdisk_total_size) 503*4882a593Smuzhiyun args.vendor_ramdisk_table_entry_num = len(vendor_ramdisk_table_builder 504*4882a593Smuzhiyun .entries) 505*4882a593Smuzhiyun args.vendor_ramdisk_table_builder = vendor_ramdisk_table_builder 506*4882a593Smuzhiyun return unknown_args 507*4882a593Smuzhiyun 508*4882a593Smuzhiyun 509*4882a593Smuzhiyundef parse_cmdline(): 510*4882a593Smuzhiyun version_parser = ArgumentParser(add_help=False) 511*4882a593Smuzhiyun version_parser.add_argument('--header_version', type=parse_int, default=0) 512*4882a593Smuzhiyun if version_parser.parse_known_args()[0].header_version < 3: 513*4882a593Smuzhiyun # For boot header v0 to v2, the kernel commandline field is split into 514*4882a593Smuzhiyun # two fields, cmdline and extra_cmdline. Both fields are asciiz strings, 515*4882a593Smuzhiyun # so we minus one here to ensure the encoded string plus the 516*4882a593Smuzhiyun # null-terminator can fit in the buffer size. 517*4882a593Smuzhiyun cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 1 518*4882a593Smuzhiyun else: 519*4882a593Smuzhiyun cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE 520*4882a593Smuzhiyun 521*4882a593Smuzhiyun parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter, 522*4882a593Smuzhiyun epilog=get_vendor_boot_v4_usage()) 523*4882a593Smuzhiyun parser.add_argument('--kernel', type=FileType('rb'), 524*4882a593Smuzhiyun help='path to the kernel') 525*4882a593Smuzhiyun parser.add_argument('--ramdisk', type=FileType('rb'), 526*4882a593Smuzhiyun help='path to the ramdisk') 527*4882a593Smuzhiyun parser.add_argument('--second', type=FileType('rb'), 528*4882a593Smuzhiyun help='path to the second bootloader') 529*4882a593Smuzhiyun parser.add_argument('--dtb', type=FileType('rb'), help='path to the dtb') 530*4882a593Smuzhiyun dtbo_group = parser.add_mutually_exclusive_group() 531*4882a593Smuzhiyun dtbo_group.add_argument('--recovery_dtbo', type=FileType('rb'), 532*4882a593Smuzhiyun help='path to the recovery DTBO') 533*4882a593Smuzhiyun dtbo_group.add_argument('--recovery_acpio', type=FileType('rb'), 534*4882a593Smuzhiyun metavar='RECOVERY_ACPIO', dest='recovery_dtbo', 535*4882a593Smuzhiyun help='path to the recovery ACPIO') 536*4882a593Smuzhiyun parser.add_argument('--cmdline', type=AsciizBytes(bufsize=cmdline_size), 537*4882a593Smuzhiyun default='', help='kernel command line arguments') 538*4882a593Smuzhiyun parser.add_argument('--vendor_cmdline', 539*4882a593Smuzhiyun type=AsciizBytes(bufsize=VENDOR_BOOT_ARGS_SIZE), 540*4882a593Smuzhiyun default='', 541*4882a593Smuzhiyun help='vendor boot kernel command line arguments') 542*4882a593Smuzhiyun parser.add_argument('--base', type=parse_int, default=0x10000000, 543*4882a593Smuzhiyun help='base address') 544*4882a593Smuzhiyun parser.add_argument('--kernel_offset', type=parse_int, default=0x00008000, 545*4882a593Smuzhiyun help='kernel offset') 546*4882a593Smuzhiyun parser.add_argument('--ramdisk_offset', type=parse_int, default=0x01000000, 547*4882a593Smuzhiyun help='ramdisk offset') 548*4882a593Smuzhiyun parser.add_argument('--second_offset', type=parse_int, default=0x00f00000, 549*4882a593Smuzhiyun help='second bootloader offset') 550*4882a593Smuzhiyun parser.add_argument('--dtb_offset', type=parse_int, default=0x01f00000, 551*4882a593Smuzhiyun help='dtb offset') 552*4882a593Smuzhiyun 553*4882a593Smuzhiyun parser.add_argument('--os_version', type=parse_os_version, default=0, 554*4882a593Smuzhiyun help='operating system version') 555*4882a593Smuzhiyun parser.add_argument('--os_patch_level', type=parse_os_patch_level, 556*4882a593Smuzhiyun default=0, help='operating system patch level') 557*4882a593Smuzhiyun parser.add_argument('--tags_offset', type=parse_int, default=0x00000100, 558*4882a593Smuzhiyun help='tags offset') 559*4882a593Smuzhiyun parser.add_argument('--board', type=AsciizBytes(bufsize=BOOT_NAME_SIZE), 560*4882a593Smuzhiyun default='', help='board name') 561*4882a593Smuzhiyun parser.add_argument('--pagesize', type=parse_int, 562*4882a593Smuzhiyun choices=[2**i for i in range(11, 15)], default=2048, 563*4882a593Smuzhiyun help='page size') 564*4882a593Smuzhiyun parser.add_argument('--id', action='store_true', 565*4882a593Smuzhiyun help='print the image ID on standard output') 566*4882a593Smuzhiyun parser.add_argument('--header_version', type=parse_int, default=0, 567*4882a593Smuzhiyun help='boot image header version') 568*4882a593Smuzhiyun parser.add_argument('-o', '--output', type=FileType('wb'), 569*4882a593Smuzhiyun help='output file name') 570*4882a593Smuzhiyun parser.add_argument('--vendor_boot', type=FileType('wb'), 571*4882a593Smuzhiyun help='vendor boot output file name') 572*4882a593Smuzhiyun parser.add_argument('--vendor_ramdisk', type=FileType('rb'), 573*4882a593Smuzhiyun help='path to the vendor ramdisk') 574*4882a593Smuzhiyun parser.add_argument('--vendor_bootconfig', type=FileType('rb'), 575*4882a593Smuzhiyun help='path to the vendor bootconfig file') 576*4882a593Smuzhiyun 577*4882a593Smuzhiyun gki_2_0_signing_args = parser.add_argument_group( 578*4882a593Smuzhiyun '[DEPRECATED] GKI 2.0 signing arguments') 579*4882a593Smuzhiyun gki_2_0_signing_args.add_argument( 580*4882a593Smuzhiyun '--gki_signing_algorithm', help='GKI signing algorithm to use') 581*4882a593Smuzhiyun gki_2_0_signing_args.add_argument( 582*4882a593Smuzhiyun '--gki_signing_key', help='path to RSA private key file') 583*4882a593Smuzhiyun gki_2_0_signing_args.add_argument( 584*4882a593Smuzhiyun '--gki_signing_signature_args', default='', 585*4882a593Smuzhiyun help='other hash arguments passed to avbtool') 586*4882a593Smuzhiyun gki_2_0_signing_args.add_argument( 587*4882a593Smuzhiyun '--gki_signing_avbtool_path', default='avbtool', 588*4882a593Smuzhiyun help='path to avbtool for boot signature generation') 589*4882a593Smuzhiyun 590*4882a593Smuzhiyun args, extra_args = parser.parse_known_args() 591*4882a593Smuzhiyun if args.vendor_boot is not None and args.header_version > 3: 592*4882a593Smuzhiyun extra_args = parse_vendor_ramdisk_args(args, extra_args) 593*4882a593Smuzhiyun if len(extra_args) > 0: 594*4882a593Smuzhiyun raise ValueError(f'Unrecognized arguments: {extra_args}') 595*4882a593Smuzhiyun 596*4882a593Smuzhiyun if args.header_version < 3: 597*4882a593Smuzhiyun args.extra_cmdline = args.cmdline[BOOT_ARGS_SIZE-1:] 598*4882a593Smuzhiyun args.cmdline = args.cmdline[:BOOT_ARGS_SIZE-1] + b'\x00' 599*4882a593Smuzhiyun assert len(args.cmdline) <= BOOT_ARGS_SIZE 600*4882a593Smuzhiyun assert len(args.extra_cmdline) <= BOOT_EXTRA_ARGS_SIZE 601*4882a593Smuzhiyun 602*4882a593Smuzhiyun return args 603*4882a593Smuzhiyun 604*4882a593Smuzhiyun 605*4882a593Smuzhiyundef add_boot_image_signature(args, pagesize): 606*4882a593Smuzhiyun """Adds the boot image signature. 607*4882a593Smuzhiyun 608*4882a593Smuzhiyun Note that the signature will only be verified in VTS to ensure a 609*4882a593Smuzhiyun generic boot.img is used. It will not be used by the device 610*4882a593Smuzhiyun bootloader at boot time. The bootloader should only verify 611*4882a593Smuzhiyun the boot vbmeta at the end of the boot partition (or in the top-level 612*4882a593Smuzhiyun vbmeta partition) via the Android Verified Boot process, when the 613*4882a593Smuzhiyun device boots. 614*4882a593Smuzhiyun """ 615*4882a593Smuzhiyun # Flush the buffer for signature calculation. 616*4882a593Smuzhiyun args.output.flush() 617*4882a593Smuzhiyun 618*4882a593Smuzhiyun # Outputs the signed vbmeta to a separate file, then append to boot.img 619*4882a593Smuzhiyun # as the boot signature. 620*4882a593Smuzhiyun with tempfile.TemporaryDirectory() as temp_out_dir: 621*4882a593Smuzhiyun boot_signature_output = os.path.join(temp_out_dir, 'boot_signature') 622*4882a593Smuzhiyun generate_gki_certificate( 623*4882a593Smuzhiyun image=args.output.name, avbtool=args.gki_signing_avbtool_path, 624*4882a593Smuzhiyun name='boot', algorithm=args.gki_signing_algorithm, 625*4882a593Smuzhiyun key=args.gki_signing_key, salt='d00df00d', 626*4882a593Smuzhiyun additional_avb_args=args.gki_signing_signature_args.split(), 627*4882a593Smuzhiyun output=boot_signature_output, 628*4882a593Smuzhiyun ) 629*4882a593Smuzhiyun with open(boot_signature_output, 'rb') as boot_signature: 630*4882a593Smuzhiyun boot_signature_bytes = boot_signature.read() 631*4882a593Smuzhiyun if len(boot_signature_bytes) > BOOT_IMAGE_V4_SIGNATURE_SIZE: 632*4882a593Smuzhiyun raise ValueError( 633*4882a593Smuzhiyun f'boot sigature size is > {BOOT_IMAGE_V4_SIGNATURE_SIZE}') 634*4882a593Smuzhiyun boot_signature_bytes += b'\x00' * ( 635*4882a593Smuzhiyun BOOT_IMAGE_V4_SIGNATURE_SIZE - len(boot_signature_bytes)) 636*4882a593Smuzhiyun assert len(boot_signature_bytes) == BOOT_IMAGE_V4_SIGNATURE_SIZE 637*4882a593Smuzhiyun args.output.write(boot_signature_bytes) 638*4882a593Smuzhiyun pad_file(args.output, pagesize) 639*4882a593Smuzhiyun 640*4882a593Smuzhiyun 641*4882a593Smuzhiyundef write_data(args, pagesize): 642*4882a593Smuzhiyun write_padded_file(args.output, args.kernel, pagesize) 643*4882a593Smuzhiyun write_padded_file(args.output, args.ramdisk, pagesize) 644*4882a593Smuzhiyun write_padded_file(args.output, args.second, pagesize) 645*4882a593Smuzhiyun 646*4882a593Smuzhiyun if args.header_version > 0 and args.header_version < 3: 647*4882a593Smuzhiyun write_padded_file(args.output, args.recovery_dtbo, pagesize) 648*4882a593Smuzhiyun if args.header_version == 2: 649*4882a593Smuzhiyun write_padded_file(args.output, args.dtb, pagesize) 650*4882a593Smuzhiyun if args.header_version >= 4 and should_add_legacy_gki_boot_signature(args): 651*4882a593Smuzhiyun add_boot_image_signature(args, pagesize) 652*4882a593Smuzhiyun 653*4882a593Smuzhiyun 654*4882a593Smuzhiyundef write_vendor_boot_data(args): 655*4882a593Smuzhiyun if args.header_version > 3: 656*4882a593Smuzhiyun builder = args.vendor_ramdisk_table_builder 657*4882a593Smuzhiyun builder.write_ramdisks_padded(args.vendor_boot, args.pagesize) 658*4882a593Smuzhiyun write_padded_file(args.vendor_boot, args.dtb, args.pagesize) 659*4882a593Smuzhiyun builder.write_entries_padded(args.vendor_boot, args.pagesize) 660*4882a593Smuzhiyun write_padded_file(args.vendor_boot, args.vendor_bootconfig, 661*4882a593Smuzhiyun args.pagesize) 662*4882a593Smuzhiyun else: 663*4882a593Smuzhiyun write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize) 664*4882a593Smuzhiyun write_padded_file(args.vendor_boot, args.dtb, args.pagesize) 665*4882a593Smuzhiyun 666*4882a593Smuzhiyun 667*4882a593Smuzhiyundef main(): 668*4882a593Smuzhiyun args = parse_cmdline() 669*4882a593Smuzhiyun if args.vendor_boot is not None: 670*4882a593Smuzhiyun if args.header_version not in {3, 4}: 671*4882a593Smuzhiyun raise ValueError( 672*4882a593Smuzhiyun '--vendor_boot not compatible with given header version') 673*4882a593Smuzhiyun if args.header_version == 3 and args.vendor_ramdisk is None: 674*4882a593Smuzhiyun raise ValueError('--vendor_ramdisk missing or invalid') 675*4882a593Smuzhiyun write_vendor_boot_header(args) 676*4882a593Smuzhiyun write_vendor_boot_data(args) 677*4882a593Smuzhiyun if args.output is not None: 678*4882a593Smuzhiyun if args.second is not None and args.header_version > 2: 679*4882a593Smuzhiyun raise ValueError( 680*4882a593Smuzhiyun '--second not compatible with given header version') 681*4882a593Smuzhiyun img_id = write_header(args) 682*4882a593Smuzhiyun if args.header_version > 2: 683*4882a593Smuzhiyun write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE) 684*4882a593Smuzhiyun else: 685*4882a593Smuzhiyun write_data(args, args.pagesize) 686*4882a593Smuzhiyun if args.id and img_id is not None: 687*4882a593Smuzhiyun print('0x' + ''.join(f'{octet:02x}' for octet in img_id)) 688*4882a593Smuzhiyun 689*4882a593Smuzhiyun 690*4882a593Smuzhiyunif __name__ == '__main__': 691*4882a593Smuzhiyun main() 692