blob: dcf72657cc1cf267567c42de6860d1363946829c [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))
M1chabfeea202016-08-26 06:32:25 +0200221 # version of boot image header or dt size in bytes
222 args.output.write(pack('I', max(args.header_version, filesize(args.dt))))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800223 # 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)
M1chabfeea202016-08-26 06:32:25 +0200233 update_sha(sha, args.dt)
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700234
235 if args.header_version > 0:
236 update_sha(sha, args.recovery_dtbo)
Hridya Valsarajue55998a2019-01-22 08:58:27 -0800237 if args.header_version > 1:
238 update_sha(sha, args.dtb)
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700239
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700240 img_id = pack('32s', sha.digest())
241
242 args.output.write(img_id)
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800243 args.output.write(pack(f'{BOOT_EXTRA_ARGS_SIZE}s', args.extra_cmdline))
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700244
245 if args.header_version > 0:
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -0700246 if args.recovery_dtbo:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800247 # recovery dtbo size in bytes
248 args.output.write(pack('I', filesize(args.recovery_dtbo)))
249 # recovert dtbo offset in the boot image
250 args.output.write(pack('Q', get_recovery_dtbo_offset(args)))
Hridya Valsarajuc1a18a32018-05-31 12:39:58 -0700251 else:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800252 # Set to zero if no recovery dtbo
253 args.output.write(pack('I', 0))
254 args.output.write(pack('Q', 0))
Hridya Valsarajua008dbd2018-03-20 15:26:00 -0700255
Hridya Valsaraju70275852019-01-24 15:59:15 -0800256 # Populate boot image header size for header versions 1 and 2.
257 if args.header_version == 1:
258 args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
259 elif args.header_version == 2:
260 args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
Hridya Valsarajue55998a2019-01-22 08:58:27 -0800261
262 if args.header_version > 1:
Hridya Valsaraju7261bb02019-05-17 16:43:25 -0700263 if filesize(args.dtb) == 0:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800264 raise ValueError('DTB image must not be empty.')
Hridya Valsaraju7261bb02019-05-17 16:43:25 -0700265
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800266 # dtb size in bytes
267 args.output.write(pack('I', filesize(args.dtb)))
268 # dtb physical load address
269 args.output.write(pack('Q', args.base + args.dtb_offset))
270
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700271 pad_file(args.output, args.pagesize)
272 return img_id
273
274
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800275class AsciizBytes:
276 """Parses a string and encodes it as an asciiz bytes object.
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700277
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800278 >>> AsciizBytes(bufsize=4)('foo')
279 b'foo\\x00'
280 >>> AsciizBytes(bufsize=4)('foob')
281 Traceback (most recent call last):
282 ...
283 argparse.ArgumentTypeError: Encoded asciiz length exceeded: max 4, got 5
284 """
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800285
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800286 def __init__(self, bufsize):
287 self.bufsize = bufsize
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800288
289 def __call__(self, arg):
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800290 arg_bytes = arg.encode() + b'\x00'
291 if len(arg_bytes) > self.bufsize:
292 raise ArgumentTypeError(
293 'Encoded asciiz length exceeded: '
294 f'max {self.bufsize}, got {len(arg_bytes)}')
295 return arg_bytes
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700296
297
Yo Chiang69b03b82020-11-12 18:56:08 +0800298class VendorRamdiskTableBuilder:
299 """Vendor ramdisk table builder.
300
301 Attributes:
302 entries: A list of VendorRamdiskTableEntry namedtuple.
303 ramdisk_total_size: Total size in bytes of all ramdisks in the table.
304 """
305
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800306 VendorRamdiskTableEntry = collections.namedtuple( # pylint: disable=invalid-name
Yo Chiang69b03b82020-11-12 18:56:08 +0800307 'VendorRamdiskTableEntry',
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800308 ['ramdisk_path', 'ramdisk_size', 'ramdisk_offset', 'ramdisk_type',
309 'ramdisk_name', 'board_id'])
Yo Chiang69b03b82020-11-12 18:56:08 +0800310
311 def __init__(self):
312 self.entries = []
313 self.ramdisk_total_size = 0
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800314 self.ramdisk_names = set()
Yo Chiang69b03b82020-11-12 18:56:08 +0800315
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800316 def add_entry(self, ramdisk_path, ramdisk_type, ramdisk_name, board_id):
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800317 # Strip any trailing null for simple comparison.
318 stripped_ramdisk_name = ramdisk_name.rstrip(b'\x00')
Yi-Yo Chiang09867512021-03-14 20:50:32 +0800319 if stripped_ramdisk_name in VENDOR_RAMDISK_NAME_BLOCKLIST:
320 raise ValueError(
321 f'Banned vendor ramdisk name: {stripped_ramdisk_name}')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800322 if stripped_ramdisk_name in self.ramdisk_names:
323 raise ValueError(
324 f'Duplicated vendor ramdisk name: {stripped_ramdisk_name}')
325 self.ramdisk_names.add(stripped_ramdisk_name)
326
Yo Chiang69b03b82020-11-12 18:56:08 +0800327 if board_id is None:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800328 board_id = array.array(
329 'I', [0] * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)
Yo Chiang69b03b82020-11-12 18:56:08 +0800330 else:
331 board_id = array.array('I', board_id)
332 if len(board_id) != VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800333 raise ValueError('board_id size must be '
334 f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}')
Yo Chiang69b03b82020-11-12 18:56:08 +0800335
336 with open(ramdisk_path, 'rb') as f:
337 ramdisk_size = filesize(f)
338 self.entries.append(self.VendorRamdiskTableEntry(
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800339 ramdisk_path, ramdisk_size, self.ramdisk_total_size, ramdisk_type,
340 ramdisk_name, board_id))
Yo Chiang69b03b82020-11-12 18:56:08 +0800341 self.ramdisk_total_size += ramdisk_size
342
343 def write_ramdisks_padded(self, fout, alignment):
344 for entry in self.entries:
345 with open(entry.ramdisk_path, 'rb') as f:
346 fout.write(f.read())
347 pad_file(fout, alignment)
348
349 def write_entries_padded(self, fout, alignment):
350 for entry in self.entries:
351 fout.write(pack('I', entry.ramdisk_size))
352 fout.write(pack('I', entry.ramdisk_offset))
353 fout.write(pack('I', entry.ramdisk_type))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800354 fout.write(pack(f'{VENDOR_RAMDISK_NAME_SIZE}s',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800355 entry.ramdisk_name))
Yo Chiang69b03b82020-11-12 18:56:08 +0800356 fout.write(entry.board_id)
357 pad_file(fout, alignment)
358
359
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700360def write_padded_file(f_out, f_in, padding):
361 if f_in is None:
362 return
363 f_out.write(f_in.read())
364 pad_file(f_out, padding)
365
366
Rom Lemarchand764e74d2015-06-02 19:01:25 -0700367def parse_int(x):
Rom Lemarchand7e233d82015-06-04 09:59:01 -0700368 return int(x, 0)
Rom Lemarchand764e74d2015-06-02 19:01:25 -0700369
Tao Baoa1494502019-09-17 10:02:40 -0700370
Sami Tolvanenea649102016-03-14 09:08:59 -0700371def parse_os_version(x):
372 match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
373 if match:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700374 a = int(match.group(1))
Sami Tolvanenea649102016-03-14 09:08:59 -0700375 b = c = 0
376 if match.lastindex >= 2:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700377 b = int(match.group(2))
Sami Tolvanenea649102016-03-14 09:08:59 -0700378 if match.lastindex == 3:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700379 c = int(match.group(3))
Sami Tolvanenea649102016-03-14 09:08:59 -0700380 # 7 bits allocated for each field
381 assert a < 128
382 assert b < 128
383 assert c < 128
384 return (a << 14) | (b << 7) | c
385 return 0
386
Tao Baoa1494502019-09-17 10:02:40 -0700387
Sami Tolvanenea649102016-03-14 09:08:59 -0700388def parse_os_patch_level(x):
Daniel Mentz1a16af72020-01-03 20:20:19 -0800389 match = re.search(r'^(\d{4})-(\d{2})(?:-(\d{2}))?', x)
Sami Tolvanenea649102016-03-14 09:08:59 -0700390 if match:
Sami Tolvanenc4ae0662016-03-29 16:06:37 -0700391 y = int(match.group(1)) - 2000
392 m = int(match.group(2))
Sami Tolvanenea649102016-03-14 09:08:59 -0700393 # 7 bits allocated for the year, 4 bits for the month
Tao Baoa1494502019-09-17 10:02:40 -0700394 assert 0 <= y < 128
395 assert 0 < m <= 12
Sami Tolvanenea649102016-03-14 09:08:59 -0700396 return (y << 4) | m
397 return 0
Rom Lemarchand764e74d2015-06-02 19:01:25 -0700398
Tao Baoa1494502019-09-17 10:02:40 -0700399
Yo Chiang69b03b82020-11-12 18:56:08 +0800400def parse_vendor_ramdisk_type(x):
401 type_dict = {
402 'none': VENDOR_RAMDISK_TYPE_NONE,
403 'platform': VENDOR_RAMDISK_TYPE_PLATFORM,
404 'recovery': VENDOR_RAMDISK_TYPE_RECOVERY,
405 'dlkm': VENDOR_RAMDISK_TYPE_DLKM,
406 }
407 if x.lower() in type_dict:
408 return type_dict[x.lower()]
409 return parse_int(x)
410
411
412def get_vendor_boot_v4_usage():
413 return """vendor boot version 4 arguments:
414 --ramdisk_type {none,platform,recovery,dlkm}
415 specify the type of the ramdisk
Yo Chiange38be232021-01-19 18:15:24 +0800416 --ramdisk_name NAME
417 specify the name of the ramdisk
Yo Chiang69b03b82020-11-12 18:56:08 +0800418 --board_id{0..15} NUMBER
419 specify the value of the board_id vector, defaults to 0
420 --vendor_ramdisk_fragment VENDOR_RAMDISK_FILE
421 path to the vendor ramdisk file
422
423 These options can be specified multiple times, where each vendor ramdisk
424 option group ends with a --vendor_ramdisk_fragment option.
425 Each option group appends an additional ramdisk to the vendor boot image.
426"""
427
428
429def parse_vendor_ramdisk_args(args, args_list):
430 """Parses vendor ramdisk specific arguments.
431
432 Args:
433 args: An argparse.Namespace object. Parsed results are stored into this
434 object.
435 args_list: A list of argument strings to be parsed.
436
437 Returns:
438 A list argument strings that are not parsed by this method.
439 """
Yo Chiang69b03b82020-11-12 18:56:08 +0800440 parser = ArgumentParser(add_help=False)
441 parser.add_argument('--ramdisk_type', type=parse_vendor_ramdisk_type,
442 default=VENDOR_RAMDISK_TYPE_NONE)
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800443 parser.add_argument('--ramdisk_name',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800444 type=AsciizBytes(bufsize=VENDOR_RAMDISK_NAME_SIZE),
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800445 required=True)
Yo Chiang69b03b82020-11-12 18:56:08 +0800446 for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE):
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800447 parser.add_argument(f'--board_id{i}', type=parse_int, default=0)
448 parser.add_argument(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT, required=True)
Yo Chiang69b03b82020-11-12 18:56:08 +0800449
450 unknown_args = []
451
452 vendor_ramdisk_table_builder = VendorRamdiskTableBuilder()
453 if args.vendor_ramdisk is not None:
Yo Chiange38be232021-01-19 18:15:24 +0800454 vendor_ramdisk_table_builder.add_entry(
Yi-Yo Chiangb4b04c22021-03-22 23:12:33 +0800455 args.vendor_ramdisk.name, VENDOR_RAMDISK_TYPE_PLATFORM, b'', None)
Yo Chiang69b03b82020-11-12 18:56:08 +0800456
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800457 while PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT in args_list:
458 idx = args_list.index(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT) + 2
Yo Chiang69b03b82020-11-12 18:56:08 +0800459 vendor_ramdisk_args = args_list[:idx]
460 args_list = args_list[idx:]
461
462 ramdisk_args, extra_args = parser.parse_known_args(vendor_ramdisk_args)
463 ramdisk_args_dict = vars(ramdisk_args)
464 unknown_args.extend(extra_args)
465
466 ramdisk_path = ramdisk_args.vendor_ramdisk_fragment
467 ramdisk_type = ramdisk_args.ramdisk_type
Yo Chiange38be232021-01-19 18:15:24 +0800468 ramdisk_name = ramdisk_args.ramdisk_name
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800469 board_id = [ramdisk_args_dict[f'board_id{i}']
Yo Chiang69b03b82020-11-12 18:56:08 +0800470 for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)]
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800471 vendor_ramdisk_table_builder.add_entry(ramdisk_path, ramdisk_type,
472 ramdisk_name, board_id)
Yo Chiang69b03b82020-11-12 18:56:08 +0800473
474 if len(args_list) > 0:
475 unknown_args.extend(args_list)
476
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800477 args.vendor_ramdisk_total_size = (vendor_ramdisk_table_builder
478 .ramdisk_total_size)
479 args.vendor_ramdisk_table_entry_num = len(vendor_ramdisk_table_builder
480 .entries)
Yo Chiang69b03b82020-11-12 18:56:08 +0800481 args.vendor_ramdisk_table_builder = vendor_ramdisk_table_builder
482 return unknown_args
483
484
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700485def parse_cmdline():
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800486 version_parser = ArgumentParser(add_help=False)
487 version_parser.add_argument('--header_version', type=parse_int, default=0)
488 if version_parser.parse_known_args()[0].header_version < 3:
489 # For boot header v0 to v2, the kernel commandline field is split into
490 # two fields, cmdline and extra_cmdline. Both fields are asciiz strings,
491 # so we minus one here to ensure the encoded string plus the
492 # null-terminator can fit in the buffer size.
493 cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 1
494 else:
495 cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE
496
Yo Chiang69b03b82020-11-12 18:56:08 +0800497 parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
498 epilog=get_vendor_boot_v4_usage())
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800499 parser.add_argument('--kernel', type=FileType('rb'),
500 help='path to the kernel')
501 parser.add_argument('--ramdisk', type=FileType('rb'),
502 help='path to the ramdisk')
503 parser.add_argument('--second', type=FileType('rb'),
504 help='path to the second bootloader')
505 parser.add_argument('--dtb', type=FileType('rb'), help='path to the dtb')
506 dtbo_group = parser.add_mutually_exclusive_group()
507 dtbo_group.add_argument('--recovery_dtbo', type=FileType('rb'),
508 help='path to the recovery DTBO')
509 dtbo_group.add_argument('--recovery_acpio', type=FileType('rb'),
510 metavar='RECOVERY_ACPIO', dest='recovery_dtbo',
511 help='path to the recovery ACPIO')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800512 parser.add_argument('--cmdline', type=AsciizBytes(bufsize=cmdline_size),
513 default='', help='kernel command line arguments')
Tao Baoa1494502019-09-17 10:02:40 -0700514 parser.add_argument('--vendor_cmdline',
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800515 type=AsciizBytes(bufsize=VENDOR_BOOT_ARGS_SIZE),
516 default='',
517 help='vendor boot kernel command line arguments')
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800518 parser.add_argument('--base', type=parse_int, default=0x10000000,
519 help='base address')
520 parser.add_argument('--kernel_offset', type=parse_int, default=0x00008000,
521 help='kernel offset')
522 parser.add_argument('--ramdisk_offset', type=parse_int, default=0x01000000,
523 help='ramdisk offset')
524 parser.add_argument('--second_offset', type=parse_int, default=0x00f00000,
525 help='second bootloader offset')
526 parser.add_argument('--dtb_offset', type=parse_int, default=0x01f00000,
527 help='dtb offset')
Hridya Valsarajue55998a2019-01-22 08:58:27 -0800528
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800529 parser.add_argument('--os_version', type=parse_os_version, default=0,
530 help='operating system version')
531 parser.add_argument('--os_patch_level', type=parse_os_patch_level,
532 default=0, help='operating system patch level')
533 parser.add_argument('--tags_offset', type=parse_int, default=0x00000100,
534 help='tags offset')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800535 parser.add_argument('--board', type=AsciizBytes(bufsize=BOOT_NAME_SIZE),
536 default='', help='board name')
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800537 parser.add_argument('--pagesize', type=parse_int,
538 choices=[2**i for i in range(11, 15)], default=2048,
539 help='page size')
540 parser.add_argument('--id', action='store_true',
541 help='print the image ID on standard output')
542 parser.add_argument('--header_version', type=parse_int, default=0,
543 help='boot image header version')
M1chabfeea202016-08-26 06:32:25 +0200544 parser.add_argument('--dt', help='path to the device tree image', type=FileType('rb'))
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800545 parser.add_argument('-o', '--output', type=FileType('wb'),
546 help='output file name')
547 parser.add_argument('--vendor_boot', type=FileType('wb'),
548 help='vendor boot output file name')
549 parser.add_argument('--vendor_ramdisk', type=FileType('rb'),
550 help='path to the vendor ramdisk')
Devin Moore808d42e2021-01-13 10:20:01 -0800551 parser.add_argument('--vendor_bootconfig', type=FileType('rb'),
552 help='path to the vendor bootconfig file')
Steve Muckle9a09efb2019-07-30 12:24:41 -0700553
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800554 gki_2_0_signing_args = parser.add_argument_group(
555 '[DEPRECATED] GKI 2.0 signing arguments')
556 gki_2_0_signing_args.add_argument(
557 '--gki_signing_algorithm', help='GKI signing algorithm to use')
558 gki_2_0_signing_args.add_argument(
559 '--gki_signing_key', help='path to RSA private key file')
560 gki_2_0_signing_args.add_argument(
561 '--gki_signing_signature_args', default='',
562 help='other hash arguments passed to avbtool')
563 gki_2_0_signing_args.add_argument(
564 '--gki_signing_avbtool_path', default='avbtool',
565 help='path to avbtool for boot signature generation')
566
Yo Chiang69b03b82020-11-12 18:56:08 +0800567 args, extra_args = parser.parse_known_args()
568 if args.vendor_boot is not None and args.header_version > 3:
569 extra_args = parse_vendor_ramdisk_args(args, extra_args)
570 if len(extra_args) > 0:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800571 raise ValueError(f'Unrecognized arguments: {extra_args}')
Yi-Yo Chiang601c2562021-03-04 17:30:59 +0800572
573 if args.header_version < 3:
574 args.extra_cmdline = args.cmdline[BOOT_ARGS_SIZE-1:]
575 args.cmdline = args.cmdline[:BOOT_ARGS_SIZE-1] + b'\x00'
576 assert len(args.cmdline) <= BOOT_ARGS_SIZE
577 assert len(args.extra_cmdline) <= BOOT_EXTRA_ARGS_SIZE
578
M1chabfeea202016-08-26 06:32:25 +0200579 if args.header_version > 0 and args.dt != None:
580 raise ValueError('header_version and dt cannot be set at the same time')
581
Yo Chiang69b03b82020-11-12 18:56:08 +0800582 return args
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700583
584
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800585def add_boot_image_signature(args, pagesize):
586 """Adds the boot image signature.
587
588 Note that the signature will only be verified in VTS to ensure a
589 generic boot.img is used. It will not be used by the device
590 bootloader at boot time. The bootloader should only verify
591 the boot vbmeta at the end of the boot partition (or in the top-level
592 vbmeta partition) via the Android Verified Boot process, when the
593 device boots.
594 """
Yi-Yo Chiangf1d50082021-12-29 01:05:27 +0800595 # Flush the buffer for signature calculation.
596 args.output.flush()
597
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800598 # Outputs the signed vbmeta to a separate file, then append to boot.img
599 # as the boot signature.
600 with tempfile.TemporaryDirectory() as temp_out_dir:
601 boot_signature_output = os.path.join(temp_out_dir, 'boot_signature')
Yi-Yo Chiang743804f2021-12-29 00:43:25 +0800602 generate_gki_certificate(
603 image=args.output.name, avbtool=args.gki_signing_avbtool_path,
604 name='boot', algorithm=args.gki_signing_algorithm,
605 key=args.gki_signing_key, salt='d00df00d',
606 additional_avb_args=args.gki_signing_signature_args.split(),
607 output=boot_signature_output,
608 )
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800609 with open(boot_signature_output, 'rb') as boot_signature:
Yi-Yo Chiang743804f2021-12-29 00:43:25 +0800610 boot_signature_bytes = boot_signature.read()
611 if len(boot_signature_bytes) > BOOT_IMAGE_V4_SIGNATURE_SIZE:
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800612 raise ValueError(
613 f'boot sigature size is > {BOOT_IMAGE_V4_SIGNATURE_SIZE}')
Yi-Yo Chiang743804f2021-12-29 00:43:25 +0800614 boot_signature_bytes += b'\x00' * (
615 BOOT_IMAGE_V4_SIGNATURE_SIZE - len(boot_signature_bytes))
616 assert len(boot_signature_bytes) == BOOT_IMAGE_V4_SIGNATURE_SIZE
617 args.output.write(boot_signature_bytes)
618 pad_file(args.output, pagesize)
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800619
620
Steve Muckle769efcf2019-09-30 11:19:48 -0700621def write_data(args, pagesize):
622 write_padded_file(args.output, args.kernel, pagesize)
623 write_padded_file(args.output, args.ramdisk, pagesize)
624 write_padded_file(args.output, args.second, pagesize)
M1chabfeea202016-08-26 06:32:25 +0200625 write_padded_file(args.output, args.dt, args.pagesize)
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700626
Steve Muckle9a09efb2019-07-30 12:24:41 -0700627 if args.header_version > 0 and args.header_version < 3:
Steve Muckle769efcf2019-09-30 11:19:48 -0700628 write_padded_file(args.output, args.recovery_dtbo, pagesize)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700629 if args.header_version == 2:
Steve Muckle769efcf2019-09-30 11:19:48 -0700630 write_padded_file(args.output, args.dtb, pagesize)
Yi-Yo Chiang3e4ce832022-02-22 18:32:19 +0800631 if args.header_version >= 4 and should_add_legacy_gki_boot_signature(args):
Bowgo Tsai8d0922b2021-02-22 18:19:29 +0800632 add_boot_image_signature(args, pagesize)
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700633
Tao Baoa1494502019-09-17 10:02:40 -0700634
Steve Muckle9a09efb2019-07-30 12:24:41 -0700635def write_vendor_boot_data(args):
Yo Chiang69b03b82020-11-12 18:56:08 +0800636 if args.header_version > 3:
637 builder = args.vendor_ramdisk_table_builder
638 builder.write_ramdisks_padded(args.vendor_boot, args.pagesize)
639 write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
640 builder.write_entries_padded(args.vendor_boot, args.pagesize)
Devin Moore808d42e2021-01-13 10:20:01 -0800641 write_padded_file(args.vendor_boot, args.vendor_bootconfig,
642 args.pagesize)
Yo Chiang69b03b82020-11-12 18:56:08 +0800643 else:
644 write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
645 write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700646
Tao Baoa1494502019-09-17 10:02:40 -0700647
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700648def main():
649 args = parse_cmdline()
Steve Muckle9a09efb2019-07-30 12:24:41 -0700650 if args.vendor_boot is not None:
Yo Chiang69b03b82020-11-12 18:56:08 +0800651 if args.header_version not in {3, 4}:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800652 raise ValueError(
653 '--vendor_boot not compatible with given header version')
Yo Chiang69b03b82020-11-12 18:56:08 +0800654 if args.header_version == 3 and args.vendor_ramdisk is None:
Steve Muckle9a09efb2019-07-30 12:24:41 -0700655 raise ValueError('--vendor_ramdisk missing or invalid')
656 write_vendor_boot_header(args)
657 write_vendor_boot_data(args)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700658 if args.output is not None:
Steve Muckle769efcf2019-09-30 11:19:48 -0700659 if args.second is not None and args.header_version > 2:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800660 raise ValueError(
661 '--second not compatible with given header version')
Steve Muckle9a09efb2019-07-30 12:24:41 -0700662 img_id = write_header(args)
Steve Muckle769efcf2019-09-30 11:19:48 -0700663 if args.header_version > 2:
664 write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
665 else:
666 write_data(args, args.pagesize)
Steve Muckle9a09efb2019-07-30 12:24:41 -0700667 if args.id and img_id is not None:
Yi-Yo Chiangcc1cecc2021-02-20 14:25:06 +0800668 print('0x' + ''.join(f'{octet:02x}' for octet in img_id))
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700669
Tao Baoa1494502019-09-17 10:02:40 -0700670
Rom Lemarchand4ee256c2015-05-19 16:58:40 -0700671if __name__ == '__main__':
672 main()