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