.. | .. |
---|
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__': |
---|