blob: ec2958179691a434df917cd1b6f196edaa80e31d [file] [log] [blame]
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +08001#!/usr/bin/env python3
2#
Rom Lemarchand4ee256c2015-05-19 16:58:40 -07003# Copyright 2015, The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080017"""Creates the boot image."""
Tao Baoa1494502019-09-17 10:02:40 -070018
Yi-Yo Chiang601c2562021-03-04 17:30:59 +080019from argparse import (ArgumentParser, ArgumentTypeError,
20 FileType, RawDescriptionHelpFormatter)
Rom Lemarchand4ee256c2015-05-19 16:58:40 -070021from hashlib import sha1
Tao Baoa1494502019-09-17 10:02:40 -070022from os import fstat
Tao Baoa1494502019-09-17 10:02:40 -070023from struct import pack
24
Yo Chiang69b03b82020-11-12 18:56:08 +080025import array
26import collections
Bowgo Tsai8d0922b2021-02-22 18:19:29 +080027import os
Yo Chiang69b03b82020-11-12 18:56:08 +080028import re
Bowgo Tsai8d0922b2021-02-22 18:19:29 +080029import tempfile
Rom Lemarchand4ee256c2015-05-19 16:58:40 -070030
Yi-Yo Chiang743804f2021-12-29 00:43:25 +080031from gki.generate_gki_certificate import generate_gki_certificate
32
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +080033# Constant and structure definition is in
34# system/tools/mkbootimg/include/bootimg/bootimg.h
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080035BOOT_MAGIC = 'ANDROID!'
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +080036BOOT_MAGIC_SIZE = 8
37BOOT_NAME_SIZE = 16
38BOOT_ARGS_SIZE = 512
39BOOT_EXTRA_ARGS_SIZE = 1024
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080040BOOT_IMAGE_HEADER_V1_SIZE = 1648
41BOOT_IMAGE_HEADER_V2_SIZE = 1660
42BOOT_IMAGE_HEADER_V3_SIZE = 1580
Steve Muckle769efcf2019-09-30 11:19:48 -070043BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
Bowgo Tsai8d0922b2021-02-22 18:19:29 +080044BOOT_IMAGE_HEADER_V4_SIZE = 1584
45BOOT_IMAGE_V4_SIGNATURE_SIZE = 4096
Steve Muckle769efcf2019-09-30 11:19:48 -070046
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080047VENDOR_BOOT_MAGIC = 'VNDRBOOT'
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +080048VENDOR_BOOT_MAGIC_SIZE = 8
49VENDOR_BOOT_NAME_SIZE = BOOT_NAME_SIZE
50VENDOR_BOOT_ARGS_SIZE = 2048
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080051VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
Devin Moore808d42e2021-01-13 10:20:01 -080052VENDOR_BOOT_IMAGE_HEADER_V4_SIZE = 2128
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080053
Yo Chiang69b03b82020-11-12 18:56:08 +080054VENDOR_RAMDISK_TYPE_NONE = 0
55VENDOR_RAMDISK_TYPE_PLATFORM = 1
56VENDOR_RAMDISK_TYPE_RECOVERY = 2
57VENDOR_RAMDISK_TYPE_DLKM = 3
Yo Chiange38be232021-01-19 18:15:24 +080058VENDOR_RAMDISK_NAME_SIZE = 32
Yo Chiang69b03b82020-11-12 18:56:08 +080059VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE = 16
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080060VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE = 108
61
Yi-Yo Chiang09867512021-03-14 20:50:32 +080062# Names with special meaning, mustn't be specified in --ramdisk_name.
63VENDOR_RAMDISK_NAME_BLOCKLIST = {b'default'}
64
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080065PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT = '--vendor_ramdisk_fragment'
66
Yo Chiang69b03b82020-11-12 18:56:08 +080067
Rom Lemarchand4ee256c2015-05-19 16:58:40 -070068def filesize(f):
69 if f is None:
70 return 0
71 try:
72 return fstat(f.fileno()).st_size
73 except OSError:
74 return 0
75
76
77def update_sha(sha, f):
78 if f:
79 sha.update(f.read())
80 f.seek(0)
81 sha.update(pack('I', filesize(f)))
82 else:
83 sha.update(pack('I', 0))
84
85
86def pad_file(f, padding):
87 pad = (padding - (f.tell() & (padding - 1))) & (padding - 1)
88 f.write(pack(str(pad) + 'x'))
89
90
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -070091def get_number_of_pages(image_size, page_size):
92 """calculates the number of pages required for the image"""
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +080093 return (image_size + page_size - 1) // page_size
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -070094
95
96def get_recovery_dtbo_offset(args):
97 """calculates the offset of recovery_dtbo image in the boot image"""
98 num_header_pages = 1 # header occupies a page
99 num_kernel_pages = get_number_of_pages(filesize(args.kernel), args.pagesize)
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800100 num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk),
101 args.pagesize)
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -0700102 num_second_pages = get_number_of_pages(filesize(args.second), args.pagesize)
103 dtbo_offset = args.pagesize * (num_header_pages + num_kernel_pages +
104 num_ramdisk_pages + num_second_pages)
105 return dtbo_offset
106
107
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800108def should_add_legacy_gki_boot_signature(args):
Yi-Yo Chiang3e4ce832022-02-22 18:32:19 +0800109 if args.gki_signing_key and args.gki_signing_algorithm:
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800110 return True
111 return False
112
113
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800114def write_header_v3_and_above(args):
115 if args.header_version > 3:
116 boot_header_size = BOOT_IMAGE_HEADER_V4_SIZE
117 else:
118 boot_header_size = BOOT_IMAGE_HEADER_V3_SIZE
119
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +0800120 args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode()))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800121 # kernel size in bytes
122 args.output.write(pack('I', filesize(args.kernel)))
123 # ramdisk size in bytes
124 args.output.write(pack('I', filesize(args.ramdisk)))
125 # os version and patch level
126 args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level))
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800127 args.output.write(pack('I', boot_header_size))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800128 # reserved
129 args.output.write(pack('4I', 0, 0, 0, 0))
130 # version of boot image header
131 args.output.write(pack('I', args.header_version))
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +0800132 args.output.write(pack(f'{BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE}s',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800133 args.cmdline))
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800134 if args.header_version >= 4:
135 # The signature used to verify boot image v4.
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800136 boot_signature_size = 0
Yi-Yo Chiang3e4ce832022-02-22 18:32:19 +0800137 if should_add_legacy_gki_boot_signature(args):
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800138 boot_signature_size = BOOT_IMAGE_V4_SIGNATURE_SIZE
139 args.output.write(pack('I', boot_signature_size))
Steve Muckle769efcf2019-09-30 11:19:48 -0700140 pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700141
Yo Chiang69b03b82020-11-12 18:56:08 +0800142
Steve Muckle9a09efb2019-07-30 12:24:41 -0700143def write_vendor_boot_header(args):
Yo Chiang69b03b82020-11-12 18:56:08 +0800144 if args.header_version > 3:
145 vendor_ramdisk_size = args.vendor_ramdisk_total_size
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800146 vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V4_SIZE
Yo Chiang69b03b82020-11-12 18:56:08 +0800147 else:
148 vendor_ramdisk_size = filesize(args.vendor_ramdisk)
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800149 vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V3_SIZE
Yo Chiang69b03b82020-11-12 18:56:08 +0800150
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +0800151 args.vendor_boot.write(pack(f'{VENDOR_BOOT_MAGIC_SIZE}s',
152 VENDOR_BOOT_MAGIC.encode()))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800153 # version of boot image header
154 args.vendor_boot.write(pack('I', args.header_version))
155 # flash page size
156 args.vendor_boot.write(pack('I', args.pagesize))
157 # kernel physical load address
158 args.vendor_boot.write(pack('I', args.base + args.kernel_offset))
159 # ramdisk physical load address
160 args.vendor_boot.write(pack('I', args.base + args.ramdisk_offset))
161 # ramdisk size in bytes
162 args.vendor_boot.write(pack('I', vendor_ramdisk_size))
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +0800163 args.vendor_boot.write(pack(f'{VENDOR_BOOT_ARGS_SIZE}s',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800164 args.vendor_cmdline))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800165 # kernel tags physical load address
166 args.vendor_boot.write(pack('I', args.base + args.tags_offset))
167 # asciiz product name
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800168 args.vendor_boot.write(pack(f'{VENDOR_BOOT_NAME_SIZE}s', args.board))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800169
170 # header size in bytes
171 args.vendor_boot.write(pack('I', vendor_boot_header_size))
172
173 # dtb size in bytes
174 args.vendor_boot.write(pack('I', filesize(args.dtb)))
175 # dtb physical load address
176 args.vendor_boot.write(pack('Q', args.base + args.dtb_offset))
Yo Chiang69b03b82020-11-12 18:56:08 +0800177
178 if args.header_version > 3:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800179 vendor_ramdisk_table_size = (args.vendor_ramdisk_table_entry_num *
180 VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE)
181 # vendor ramdisk table size in bytes
182 args.vendor_boot.write(pack('I', vendor_ramdisk_table_size))
183 # number of vendor ramdisk table entries
184 args.vendor_boot.write(pack('I', args.vendor_ramdisk_table_entry_num))
185 # vendor ramdisk table entry size in bytes
186 args.vendor_boot.write(pack('I', VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE))
Devin Moore808d42e2021-01-13 10:20:01 -0800187 # bootconfig section size in bytes
188 args.vendor_boot.write(pack('I', filesize(args.vendor_bootconfig)))
Steve Muckle9a09efb2019-07-30 12:24:41 -0700189 pad_file(args.vendor_boot, args.pagesize)
190
Yo Chiang69b03b82020-11-12 18:56:08 +0800191
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700192def write_header(args):
Yo Chiang69b03b82020-11-12 18:56:08 +0800193 if args.header_version > 4:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800194 raise ValueError(
195 f'Boot header version {args.header_version} not supported')
Yo Chiang69b03b82020-11-12 18:56:08 +0800196 if args.header_version in {3, 4}:
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800197 return write_header_v3_and_above(args)
Hridya Valsaraju70275852019-01-24 15:59:15 -0800198
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800199 ramdisk_load_address = ((args.base + args.ramdisk_offset)
200 if filesize(args.ramdisk) > 0 else 0)
201 second_load_address = ((args.base + args.second_offset)
202 if filesize(args.second) > 0 else 0)
203
Yi-Yo Chiang16d6a072021-03-04 16:57:29 +0800204 args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode()))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800205 # kernel size in bytes
206 args.output.write(pack('I', filesize(args.kernel)))
207 # kernel physical load address
208 args.output.write(pack('I', args.base + args.kernel_offset))
209 # ramdisk size in bytes
210 args.output.write(pack('I', filesize(args.ramdisk)))
211 # ramdisk physical load address
212 args.output.write(pack('I', ramdisk_load_address))
213 # second bootloader size in bytes
214 args.output.write(pack('I', filesize(args.second)))
215 # second bootloader physical load address
216 args.output.write(pack('I', second_load_address))
217 # kernel tags physical load address
218 args.output.write(pack('I', args.base + args.tags_offset))
219 # flash page size
220 args.output.write(pack('I', args.pagesize))
221 # version of boot image header
222 args.output.write(pack('I', args.header_version))
223 # os version and patch level
224 args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level))
225 # asciiz product name
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800226 args.output.write(pack(f'{BOOT_NAME_SIZE}s', args.board))
227 args.output.write(pack(f'{BOOT_ARGS_SIZE}s', args.cmdline))
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700228
229 sha = sha1()
230 update_sha(sha, args.kernel)
231 update_sha(sha, args.ramdisk)
232 update_sha(sha, args.second)
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700233
234 if args.header_version > 0:
235 update_sha(sha, args.recovery_dtbo)
Hridya Valsarajue55998a2019-01-22 08:58:27 -0800236 if args.header_version > 1:
237 update_sha(sha, args.dtb)
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700238
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700239 img_id = pack('32s', sha.digest())
240
241 args.output.write(img_id)
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800242 args.output.write(pack(f'{BOOT_EXTRA_ARGS_SIZE}s', args.extra_cmdline))
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700243
244 if args.header_version > 0:
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -0700245 if args.recovery_dtbo:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800246 # recovery dtbo size in bytes
247 args.output.write(pack('I', filesize(args.recovery_dtbo)))
248 # recovert dtbo offset in the boot image
249 args.output.write(pack('Q', get_recovery_dtbo_offset(args)))
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -0700250 else:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800251 # Set to zero if no recovery dtbo
252 args.output.write(pack('I', 0))
253 args.output.write(pack('Q', 0))
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700254
Hridya Valsaraju70275852019-01-24 15:59:15 -0800255 # Populate boot image header size for header versions 1 and 2.
256 if args.header_version == 1:
257 args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
258 elif args.header_version == 2:
259 args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
Hridya Valsarajue55998a2019-01-22 08:58:27 -0800260
261 if args.header_version > 1:
Hridya Valsaraju7261bb02019-05-17 16:43:25 -0700262 if filesize(args.dtb) == 0:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800263 raise ValueError('DTB image must not be empty.')
Hridya Valsaraju7261bb02019-05-17 16:43:25 -0700264
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800265 # dtb size in bytes
266 args.output.write(pack('I', filesize(args.dtb)))
267 # dtb physical load address
268 args.output.write(pack('Q', args.base + args.dtb_offset))
269
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700270 pad_file(args.output, args.pagesize)
271 return img_id
272
273
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800274class AsciizBytes:
275 """Parses a string and encodes it as an asciiz bytes object.
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700276
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800277 >>> AsciizBytes(bufsize=4)('foo')
278 b'foo\\x00'
279 >>> AsciizBytes(bufsize=4)('foob')
280 Traceback (most recent call last):
281 ...
282 argparse.ArgumentTypeError: Encoded asciiz length exceeded: max 4, got 5
283 """
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800284
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800285 def __init__(self, bufsize):
286 self.bufsize = bufsize
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800287
288 def __call__(self, arg):
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800289 arg_bytes = arg.encode() + b'\x00'
290 if len(arg_bytes) > self.bufsize:
291 raise ArgumentTypeError(
292 'Encoded asciiz length exceeded: '
293 f'max {self.bufsize}, got {len(arg_bytes)}')
294 return arg_bytes
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700295
296
Yo Chiang69b03b82020-11-12 18:56:08 +0800297class VendorRamdiskTableBuilder:
298 """Vendor ramdisk table builder.
299
300 Attributes:
301 entries: A list of VendorRamdiskTableEntry namedtuple.
302 ramdisk_total_size: Total size in bytes of all ramdisks in the table.
303 """
304
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800305 VendorRamdiskTableEntry = collections.namedtuple( # pylint: disable=invalid-name
Yo Chiang69b03b82020-11-12 18:56:08 +0800306 'VendorRamdiskTableEntry',
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800307 ['ramdisk_path', 'ramdisk_size', 'ramdisk_offset', 'ramdisk_type',
308 'ramdisk_name', 'board_id'])
Yo Chiang69b03b82020-11-12 18:56:08 +0800309
310 def __init__(self):
311 self.entries = []
312 self.ramdisk_total_size = 0
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800313 self.ramdisk_names = set()
Yo Chiang69b03b82020-11-12 18:56:08 +0800314
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800315 def add_entry(self, ramdisk_path, ramdisk_type, ramdisk_name, board_id):
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800316 # Strip any trailing null for simple comparison.
317 stripped_ramdisk_name = ramdisk_name.rstrip(b'\x00')
Yi-Yo Chiang09867512021-03-14 20:50:32 +0800318 if stripped_ramdisk_name in VENDOR_RAMDISK_NAME_BLOCKLIST:
319 raise ValueError(
320 f'Banned vendor ramdisk name: {stripped_ramdisk_name}')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800321 if stripped_ramdisk_name in self.ramdisk_names:
322 raise ValueError(
323 f'Duplicated vendor ramdisk name: {stripped_ramdisk_name}')
324 self.ramdisk_names.add(stripped_ramdisk_name)
325
Yo Chiang69b03b82020-11-12 18:56:08 +0800326 if board_id is None:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800327 board_id = array.array(
328 'I', [0] * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)
Yo Chiang69b03b82020-11-12 18:56:08 +0800329 else:
330 board_id = array.array('I', board_id)
331 if len(board_id) != VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800332 raise ValueError('board_id size must be '
333 f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}')
Yo Chiang69b03b82020-11-12 18:56:08 +0800334
335 with open(ramdisk_path, 'rb') as f:
336 ramdisk_size = filesize(f)
337 self.entries.append(self.VendorRamdiskTableEntry(
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800338 ramdisk_path, ramdisk_size, self.ramdisk_total_size, ramdisk_type,
339 ramdisk_name, board_id))
Yo Chiang69b03b82020-11-12 18:56:08 +0800340 self.ramdisk_total_size += ramdisk_size
341
342 def write_ramdisks_padded(self, fout, alignment):
343 for entry in self.entries:
344 with open(entry.ramdisk_path, 'rb') as f:
345 fout.write(f.read())
346 pad_file(fout, alignment)
347
348 def write_entries_padded(self, fout, alignment):
349 for entry in self.entries:
350 fout.write(pack('I', entry.ramdisk_size))
351 fout.write(pack('I', entry.ramdisk_offset))
352 fout.write(pack('I', entry.ramdisk_type))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800353 fout.write(pack(f'{VENDOR_RAMDISK_NAME_SIZE}s',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800354 entry.ramdisk_name))
Yo Chiang69b03b82020-11-12 18:56:08 +0800355 fout.write(entry.board_id)
356 pad_file(fout, alignment)
357
358
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700359def write_padded_file(f_out, f_in, padding):
360 if f_in is None:
361 return
362 f_out.write(f_in.read())
363 pad_file(f_out, padding)
364
365
Rom Lemarchand764e74d2015-06-02 19:01:25 -0700366def parse_int(x):
Rom Lemarchand7e233d82015-06-04 09:59:01 -0700367 return int(x, 0)
Rom Lemarchand764e74d2015-06-02 19:01:25 -0700368
Tao Baoa1494502019-09-17 10:02:40 -0700369
Sami Tolvanenea649102016-03-14 09:08:59 -0700370def parse_os_version(x):
371 match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
372 if match:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700373 a = int(match.group(1))
Sami Tolvanenea649102016-03-14 09:08:59 -0700374 b = c = 0
375 if match.lastindex >= 2:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700376 b = int(match.group(2))
Sami Tolvanenea649102016-03-14 09:08:59 -0700377 if match.lastindex == 3:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700378 c = int(match.group(3))
Sami Tolvanenea649102016-03-14 09:08:59 -0700379 # 7 bits allocated for each field
380 assert a < 128
381 assert b < 128
382 assert c < 128
383 return (a << 14) | (b << 7) | c
384 return 0
385
Tao Baoa1494502019-09-17 10:02:40 -0700386
Sami Tolvanenea649102016-03-14 09:08:59 -0700387def parse_os_patch_level(x):
Daniel Mentz1a16af72020-01-03 20:20:19 -0800388 match = re.search(r'^(\d{4})-(\d{2})(?:-(\d{2}))?', x)
Sami Tolvanenea649102016-03-14 09:08:59 -0700389 if match:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700390 y = int(match.group(1)) - 2000
391 m = int(match.group(2))
Sami Tolvanenea649102016-03-14 09:08:59 -0700392 # 7 bits allocated for the year, 4 bits for the month
Tao Baoa1494502019-09-17 10:02:40 -0700393 assert 0 <= y < 128
394 assert 0 < m <= 12
Sami Tolvanenea649102016-03-14 09:08:59 -0700395 return (y << 4) | m
396 return 0
Rom Lemarchand764e74d2015-06-02 19:01:25 -0700397
Tao Baoa1494502019-09-17 10:02:40 -0700398
Yo Chiang69b03b82020-11-12 18:56:08 +0800399def parse_vendor_ramdisk_type(x):
400 type_dict = {
401 'none': VENDOR_RAMDISK_TYPE_NONE,
402 'platform': VENDOR_RAMDISK_TYPE_PLATFORM,
403 'recovery': VENDOR_RAMDISK_TYPE_RECOVERY,
404 'dlkm': VENDOR_RAMDISK_TYPE_DLKM,
405 }
406 if x.lower() in type_dict:
407 return type_dict[x.lower()]
408 return parse_int(x)
409
410
411def get_vendor_boot_v4_usage():
412 return """vendor boot version 4 arguments:
413 --ramdisk_type {none,platform,recovery,dlkm}
414 specify the type of the ramdisk
Yo Chiange38be232021-01-19 18:15:24 +0800415 --ramdisk_name NAME
416 specify the name of the ramdisk
Yo Chiang69b03b82020-11-12 18:56:08 +0800417 --board_id{0..15} NUMBER
418 specify the value of the board_id vector, defaults to 0
419 --vendor_ramdisk_fragment VENDOR_RAMDISK_FILE
420 path to the vendor ramdisk file
421
422 These options can be specified multiple times, where each vendor ramdisk
423 option group ends with a --vendor_ramdisk_fragment option.
424 Each option group appends an additional ramdisk to the vendor boot image.
425"""
426
427
428def parse_vendor_ramdisk_args(args, args_list):
429 """Parses vendor ramdisk specific arguments.
430
431 Args:
432 args: An argparse.Namespace object. Parsed results are stored into this
433 object.
434 args_list: A list of argument strings to be parsed.
435
436 Returns:
437 A list argument strings that are not parsed by this method.
438 """
Yo Chiang69b03b82020-11-12 18:56:08 +0800439 parser = ArgumentParser(add_help=False)
440 parser.add_argument('--ramdisk_type', type=parse_vendor_ramdisk_type,
441 default=VENDOR_RAMDISK_TYPE_NONE)
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800442 parser.add_argument('--ramdisk_name',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800443 type=AsciizBytes(bufsize=VENDOR_RAMDISK_NAME_SIZE),
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800444 required=True)
Yo Chiang69b03b82020-11-12 18:56:08 +0800445 for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE):
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800446 parser.add_argument(f'--board_id{i}', type=parse_int, default=0)
447 parser.add_argument(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT, required=True)
Yo Chiang69b03b82020-11-12 18:56:08 +0800448
449 unknown_args = []
450
451 vendor_ramdisk_table_builder = VendorRamdiskTableBuilder()
452 if args.vendor_ramdisk is not None:
Yo Chiange38be232021-01-19 18:15:24 +0800453 vendor_ramdisk_table_builder.add_entry(
Yi-Yo Chiangb4b04c22021-03-22 23:12:33 +0800454 args.vendor_ramdisk.name, VENDOR_RAMDISK_TYPE_PLATFORM, b'', None)
Yo Chiang69b03b82020-11-12 18:56:08 +0800455
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800456 while PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT in args_list:
457 idx = args_list.index(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT) + 2
Yo Chiang69b03b82020-11-12 18:56:08 +0800458 vendor_ramdisk_args = args_list[:idx]
459 args_list = args_list[idx:]
460
461 ramdisk_args, extra_args = parser.parse_known_args(vendor_ramdisk_args)
462 ramdisk_args_dict = vars(ramdisk_args)
463 unknown_args.extend(extra_args)
464
465 ramdisk_path = ramdisk_args.vendor_ramdisk_fragment
466 ramdisk_type = ramdisk_args.ramdisk_type
Yo Chiange38be232021-01-19 18:15:24 +0800467 ramdisk_name = ramdisk_args.ramdisk_name
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800468 board_id = [ramdisk_args_dict[f'board_id{i}']
Yo Chiang69b03b82020-11-12 18:56:08 +0800469 for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)]
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800470 vendor_ramdisk_table_builder.add_entry(ramdisk_path, ramdisk_type,
471 ramdisk_name, board_id)
Yo Chiang69b03b82020-11-12 18:56:08 +0800472
473 if len(args_list) > 0:
474 unknown_args.extend(args_list)
475
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800476 args.vendor_ramdisk_total_size = (vendor_ramdisk_table_builder
477 .ramdisk_total_size)
478 args.vendor_ramdisk_table_entry_num = len(vendor_ramdisk_table_builder
479 .entries)
Yo Chiang69b03b82020-11-12 18:56:08 +0800480 args.vendor_ramdisk_table_builder = vendor_ramdisk_table_builder
481 return unknown_args
482
483
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700484def parse_cmdline():
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800485 version_parser = ArgumentParser(add_help=False)
486 version_parser.add_argument('--header_version', type=parse_int, default=0)
487 if version_parser.parse_known_args()[0].header_version < 3:
488 # For boot header v0 to v2, the kernel commandline field is split into
489 # two fields, cmdline and extra_cmdline. Both fields are asciiz strings,
490 # so we minus one here to ensure the encoded string plus the
491 # null-terminator can fit in the buffer size.
492 cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 1
493 else:
494 cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE
495
Yo Chiang69b03b82020-11-12 18:56:08 +0800496 parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
497 epilog=get_vendor_boot_v4_usage())
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800498 parser.add_argument('--kernel', type=FileType('rb'),
499 help='path to the kernel')
500 parser.add_argument('--ramdisk', type=FileType('rb'),
501 help='path to the ramdisk')
502 parser.add_argument('--second', type=FileType('rb'),
503 help='path to the second bootloader')
504 parser.add_argument('--dtb', type=FileType('rb'), help='path to the dtb')
505 dtbo_group = parser.add_mutually_exclusive_group()
506 dtbo_group.add_argument('--recovery_dtbo', type=FileType('rb'),
507 help='path to the recovery DTBO')
508 dtbo_group.add_argument('--recovery_acpio', type=FileType('rb'),
509 metavar='RECOVERY_ACPIO', dest='recovery_dtbo',
510 help='path to the recovery ACPIO')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800511 parser.add_argument('--cmdline', type=AsciizBytes(bufsize=cmdline_size),
512 default='', help='kernel command line arguments')
Tao Baoa1494502019-09-17 10:02:40 -0700513 parser.add_argument('--vendor_cmdline',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800514 type=AsciizBytes(bufsize=VENDOR_BOOT_ARGS_SIZE),
515 default='',
516 help='vendor boot kernel command line arguments')
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800517 parser.add_argument('--base', type=parse_int, default=0x10000000,
518 help='base address')
519 parser.add_argument('--kernel_offset', type=parse_int, default=0x00008000,
520 help='kernel offset')
521 parser.add_argument('--ramdisk_offset', type=parse_int, default=0x01000000,
522 help='ramdisk offset')
523 parser.add_argument('--second_offset', type=parse_int, default=0x00f00000,
524 help='second bootloader offset')
525 parser.add_argument('--dtb_offset', type=parse_int, default=0x01f00000,
526 help='dtb offset')
Hridya Valsarajue55998a2019-01-22 08:58:27 -0800527
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800528 parser.add_argument('--os_version', type=parse_os_version, default=0,
529 help='operating system version')
530 parser.add_argument('--os_patch_level', type=parse_os_patch_level,
531 default=0, help='operating system patch level')
532 parser.add_argument('--tags_offset', type=parse_int, default=0x00000100,
533 help='tags offset')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800534 parser.add_argument('--board', type=AsciizBytes(bufsize=BOOT_NAME_SIZE),
535 default='', help='board name')
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800536 parser.add_argument('--pagesize', type=parse_int,
537 choices=[2**i for i in range(11, 15)], default=2048,
538 help='page size')
539 parser.add_argument('--id', action='store_true',
540 help='print the image ID on standard output')
541 parser.add_argument('--header_version', type=parse_int, default=0,
542 help='boot image header version')
543 parser.add_argument('-o', '--output', type=FileType('wb'),
544 help='output file name')
545 parser.add_argument('--vendor_boot', type=FileType('wb'),
546 help='vendor boot output file name')
547 parser.add_argument('--vendor_ramdisk', type=FileType('rb'),
548 help='path to the vendor ramdisk')
Devin Moore808d42e2021-01-13 10:20:01 -0800549 parser.add_argument('--vendor_bootconfig', type=FileType('rb'),
550 help='path to the vendor bootconfig file')
Steve Muckle9a09efb2019-07-30 12:24:41 -0700551
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800552 gki_2_0_signing_args = parser.add_argument_group(
553 '[DEPRECATED] GKI 2.0 signing arguments')
554 gki_2_0_signing_args.add_argument(
555 '--gki_signing_algorithm', help='GKI signing algorithm to use')
556 gki_2_0_signing_args.add_argument(
557 '--gki_signing_key', help='path to RSA private key file')
558 gki_2_0_signing_args.add_argument(
559 '--gki_signing_signature_args', default='',
560 help='other hash arguments passed to avbtool')
561 gki_2_0_signing_args.add_argument(
562 '--gki_signing_avbtool_path', default='avbtool',
563 help='path to avbtool for boot signature generation')
564
Yo Chiang69b03b82020-11-12 18:56:08 +0800565 args, extra_args = parser.parse_known_args()
566 if args.vendor_boot is not None and args.header_version > 3:
567 extra_args = parse_vendor_ramdisk_args(args, extra_args)
568 if len(extra_args) > 0:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800569 raise ValueError(f'Unrecognized arguments: {extra_args}')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800570
571 if args.header_version < 3:
572 args.extra_cmdline = args.cmdline[BOOT_ARGS_SIZE-1:]
573 args.cmdline = args.cmdline[:BOOT_ARGS_SIZE-1] + b'\x00'
574 assert len(args.cmdline) <= BOOT_ARGS_SIZE
575 assert len(args.extra_cmdline) <= BOOT_EXTRA_ARGS_SIZE
576
Yo Chiang69b03b82020-11-12 18:56:08 +0800577 return args
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700578
579
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800580def add_boot_image_signature(args, pagesize):
581 """Adds the boot image signature.
582
583 Note that the signature will only be verified in VTS to ensure a
584 generic boot.img is used. It will not be used by the device
585 bootloader at boot time. The bootloader should only verify
586 the boot vbmeta at the end of the boot partition (or in the top-level
587 vbmeta partition) via the Android Verified Boot process, when the
588 device boots.
589 """
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800590 # Flush the buffer for signature calculation.
591 args.output.flush()
592
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800593 # Outputs the signed vbmeta to a separate file, then append to boot.img
594 # as the boot signature.
595 with tempfile.TemporaryDirectory() as temp_out_dir:
596 boot_signature_output = os.path.join(temp_out_dir, 'boot_signature')
Yi-Yo Chiang743804f2021-12-29 00:43:25 +0800597 generate_gki_certificate(
598 image=args.output.name, avbtool=args.gki_signing_avbtool_path,
599 name='boot', algorithm=args.gki_signing_algorithm,
600 key=args.gki_signing_key, salt='d00df00d',
601 additional_avb_args=args.gki_signing_signature_args.split(),
602 output=boot_signature_output,
603 )
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800604 with open(boot_signature_output, 'rb') as boot_signature:
Yi-Yo Chiang743804f2021-12-29 00:43:25 +0800605 boot_signature_bytes = boot_signature.read()
606 if len(boot_signature_bytes) > BOOT_IMAGE_V4_SIGNATURE_SIZE:
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800607 raise ValueError(
608 f'boot sigature size is > {BOOT_IMAGE_V4_SIGNATURE_SIZE}')
Yi-Yo Chiang743804f2021-12-29 00:43:25 +0800609 boot_signature_bytes += b'\x00' * (
610 BOOT_IMAGE_V4_SIGNATURE_SIZE - len(boot_signature_bytes))
611 assert len(boot_signature_bytes) == BOOT_IMAGE_V4_SIGNATURE_SIZE
612 args.output.write(boot_signature_bytes)
613 pad_file(args.output, pagesize)
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800614
615
Steve Muckle769efcf2019-09-30 11:19:48 -0700616def write_data(args, pagesize):
617 write_padded_file(args.output, args.kernel, pagesize)
618 write_padded_file(args.output, args.ramdisk, pagesize)
619 write_padded_file(args.output, args.second, pagesize)
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700620
Steve Muckle9a09efb2019-07-30 12:24:41 -0700621 if args.header_version > 0 and args.header_version < 3:
Steve Muckle769efcf2019-09-30 11:19:48 -0700622 write_padded_file(args.output, args.recovery_dtbo, pagesize)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700623 if args.header_version == 2:
Steve Muckle769efcf2019-09-30 11:19:48 -0700624 write_padded_file(args.output, args.dtb, pagesize)
Yi-Yo Chiang3e4ce832022-02-22 18:32:19 +0800625 if args.header_version >= 4 and should_add_legacy_gki_boot_signature(args):
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800626 add_boot_image_signature(args, pagesize)
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700627
Tao Baoa1494502019-09-17 10:02:40 -0700628
Steve Muckle9a09efb2019-07-30 12:24:41 -0700629def write_vendor_boot_data(args):
Yo Chiang69b03b82020-11-12 18:56:08 +0800630 if args.header_version > 3:
631 builder = args.vendor_ramdisk_table_builder
632 builder.write_ramdisks_padded(args.vendor_boot, args.pagesize)
633 write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
634 builder.write_entries_padded(args.vendor_boot, args.pagesize)
Devin Moore808d42e2021-01-13 10:20:01 -0800635 write_padded_file(args.vendor_boot, args.vendor_bootconfig,
636 args.pagesize)
Yo Chiang69b03b82020-11-12 18:56:08 +0800637 else:
638 write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
639 write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700640
Tao Baoa1494502019-09-17 10:02:40 -0700641
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700642def main():
643 args = parse_cmdline()
Steve Muckle9a09efb2019-07-30 12:24:41 -0700644 if args.vendor_boot is not None:
Yo Chiang69b03b82020-11-12 18:56:08 +0800645 if args.header_version not in {3, 4}:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800646 raise ValueError(
647 '--vendor_boot not compatible with given header version')
Yo Chiang69b03b82020-11-12 18:56:08 +0800648 if args.header_version == 3 and args.vendor_ramdisk is None:
Steve Muckle9a09efb2019-07-30 12:24:41 -0700649 raise ValueError('--vendor_ramdisk missing or invalid')
650 write_vendor_boot_header(args)
651 write_vendor_boot_data(args)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700652 if args.output is not None:
Steve Muckle769efcf2019-09-30 11:19:48 -0700653 if args.second is not None and args.header_version > 2:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800654 raise ValueError(
655 '--second not compatible with given header version')
Steve Muckle9a09efb2019-07-30 12:24:41 -0700656 img_id = write_header(args)
Steve Muckle769efcf2019-09-30 11:19:48 -0700657 if args.header_version > 2:
658 write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
659 else:
660 write_data(args, args.pagesize)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700661 if args.id and img_id is not None:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800662 print('0x' + ''.join(f'{octet:02x}' for octet in img_id))
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700663
Tao Baoa1494502019-09-17 10:02:40 -0700664
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700665if __name__ == '__main__':
666 main()