Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) #!/usr/bin/env python
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) # Copyright 2015, The Android Open Source Project
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) # Licensed under the Apache License, Version 2.0 (the "License");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) # you may not use this file except in compliance with the License.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) # You may obtain a copy of the License at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #     http://www.apache.org/licenses/LICENSE-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) # Unless required by applicable law or agreed to in writing, software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) # distributed under the License is distributed on an "AS IS" BASIS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) # See the License for the specific language governing permissions and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) # limitations under the License.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) from __future__ import print_function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) from argparse import ArgumentParser, FileType, Action
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) from hashlib import sha1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) from os import fstat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) import re
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) from struct import pack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) def filesize(f):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)     if f is None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)         return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)     try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)         return fstat(f.fileno()).st_size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)     except OSError:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)         return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) def update_sha(sha, f):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)     if f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)         sha.update(f.read())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)         f.seek(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)         sha.update(pack('I', filesize(f)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)     else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)         sha.update(pack('I', 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) def pad_file(f, padding):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)     pad = (padding - (f.tell() & (padding - 1))) & (padding - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)     f.write(pack(str(pad) + 'x'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) def get_number_of_pages(image_size, page_size):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51)     """calculates the number of pages required for the image"""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)     return (image_size + page_size - 1) / page_size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) def get_recovery_dtbo_offset(args):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56)     """calculates the offset of recovery_dtbo image in the boot image"""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)     num_header_pages = 1 # header occupies a page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58)     num_kernel_pages = get_number_of_pages(filesize(args.kernel), args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)     num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk), args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)     num_second_pages = get_number_of_pages(filesize(args.second), args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61)     dtbo_offset = args.pagesize * (num_header_pages + num_kernel_pages +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62)                                    num_ramdisk_pages + num_second_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63)     return dtbo_offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) def write_header_v3(args):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67)     BOOT_IMAGE_HEADER_V3_SIZE = 1580
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68)     BOOT_MAGIC = 'ANDROID!'.encode()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70)     args.output.write(pack('8s', BOOT_MAGIC))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71)     args.output.write(pack(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72)         '4I',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73)         filesize(args.kernel),                          # kernel size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74)         filesize(args.ramdisk),                         # ramdisk size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75)         (args.os_version << 11) | args.os_patch_level,  # os version and patch level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76)         BOOT_IMAGE_HEADER_V3_SIZE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78)     args.output.write(pack('4I', 0, 0, 0, 0))           # reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80)     args.output.write(pack('I', args.header_version))   # version of bootimage header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81)     args.output.write(pack('1536s', args.cmdline.encode()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82)     pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) def write_vendor_boot_header(args):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)     VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)     BOOT_MAGIC = 'VNDRBOOT'.encode()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88)     args.vendor_boot.write(pack('8s', BOOT_MAGIC))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89)     args.vendor_boot.write(pack(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)         '5I',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91)         args.header_version,                            # version of header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)         args.pagesize,                                  # flash page size we assume
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)         args.base + args.kernel_offset,                 # kernel physical load addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)         args.base + args.ramdisk_offset,                # ramdisk physical load addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)         filesize(args.vendor_ramdisk)))                 # vendor ramdisk size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96)     args.vendor_boot.write(pack('2048s', args.vendor_cmdline.encode()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97)     args.vendor_boot.write(pack('I', args.base + args.tags_offset)) # physical addr for kernel tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98)     args.vendor_boot.write(pack('16s', args.board.encode())) # asciiz product name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99)     args.vendor_boot.write(pack('I', VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) # header size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)     if filesize(args.dtb) == 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)         raise ValueError("DTB image must not be empty.")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)     args.vendor_boot.write(pack('I', filesize(args.dtb)))   # size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)     args.vendor_boot.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)     pad_file(args.vendor_boot, args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) def write_header(args):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)     BOOT_IMAGE_HEADER_V1_SIZE = 1648
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)     BOOT_IMAGE_HEADER_V2_SIZE = 1660
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)     BOOT_MAGIC = 'ANDROID!'.encode()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)     if args.header_version > 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)         raise ValueError('Boot header version %d not supported' % args.header_version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)     elif args.header_version == 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)         return write_header_v3(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)     args.output.write(pack('8s', BOOT_MAGIC))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)     final_ramdisk_offset = (args.base + args.ramdisk_offset) if filesize(args.ramdisk) > 0 else 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)     final_second_offset = (args.base + args.second_offset) if filesize(args.second) > 0 else 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)     args.output.write(pack(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)         '10I',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)         filesize(args.kernel),                          # size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)         args.base + args.kernel_offset,                 # physical load addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)         filesize(args.ramdisk),                         # size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)         final_ramdisk_offset,                           # physical load addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)         filesize(args.second),                          # size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)         final_second_offset,                            # physical load addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)         args.base + args.tags_offset,                   # physical addr for kernel tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)         args.pagesize,                                  # flash page size we assume
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)         args.header_version,                            # version of bootimage header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)         (args.os_version << 11) | args.os_patch_level)) # os version and patch level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)     args.output.write(pack('16s', args.board.encode())) # asciiz product name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)     args.output.write(pack('512s', args.cmdline[:512].encode()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)     sha = sha1()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)     update_sha(sha, args.kernel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)     update_sha(sha, args.ramdisk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)     update_sha(sha, args.second)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)     if args.header_version > 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)         update_sha(sha, args.recovery_dtbo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)     if args.header_version > 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)         update_sha(sha, args.dtb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)     img_id = pack('32s', sha.digest())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)     args.output.write(img_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)     args.output.write(pack('1024s', args.cmdline[512:].encode()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)     if args.header_version > 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)         args.output.write(pack('I', filesize(args.recovery_dtbo)))   # size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)         if args.recovery_dtbo:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)             args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)         else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)             args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)     # Populate boot image header size for header versions 1 and 2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)     if args.header_version == 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)         args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)     elif args.header_version == 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)         args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)     if args.header_version > 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)         # if filesize(args.dtb) == 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)         #     raise ValueError("DTB image must not be empty.")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)         args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)         args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)     pad_file(args.output, args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)     return img_id
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) class ValidateStrLenAction(Action):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)     def __init__(self, option_strings, dest, nargs=None, **kwargs):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)         if 'maxlen' not in kwargs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)             raise ValueError('maxlen must be set')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)         self.maxlen = int(kwargs['maxlen'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)         del kwargs['maxlen']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)         super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)     def __call__(self, parser, namespace, values, option_string=None):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)         if len(values) > self.maxlen:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)             raise ValueError(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)                 'String argument too long: max {0:d}, got {1:d}'.format(self.maxlen, len(values)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)         setattr(namespace, self.dest, values)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) def write_padded_file(f_out, f_in, padding):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)     if f_in is None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)         return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)     f_out.write(f_in.read())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)     pad_file(f_out, padding)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) def parse_int(x):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)     return int(x, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) def parse_os_version(x):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)     match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)     if match:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)         a = int(match.group(1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)         b = c = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)         if match.lastindex >= 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)             b = int(match.group(2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)         if match.lastindex == 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)             c = int(match.group(3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)         # 7 bits allocated for each field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)         assert a < 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)         assert b < 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)         assert c < 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)         return (a << 14) | (b << 7) | c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)     return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) def parse_os_patch_level(x):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)     match = re.search(r'^(\d{4})-(\d{2})(?:-(\d{2}))?', x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)     if match:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)         y = int(match.group(1)) - 2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)         m = int(match.group(2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)         # 7 bits allocated for the year, 4 bits for the month
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)         assert 0 <= y < 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)         assert 0 < m <= 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)         return (y << 4) | m
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)     return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) def parse_cmdline():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)     parser = ArgumentParser()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)     parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)     parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)     parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)     parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)     recovery_dtbo_group = parser.add_mutually_exclusive_group()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)     recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)                                      type=FileType('rb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)     recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)                                      type=FileType('rb'), metavar='RECOVERY_ACPIO',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)                                      dest='recovery_dtbo')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)     parser.add_argument('--cmdline', help='extra arguments to be passed on the '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)                         'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)     parser.add_argument('--vendor_cmdline',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)                         help='kernel command line arguments contained in vendor boot',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)                         default='', action=ValidateStrLenAction, maxlen=2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)     parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)     parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)     parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)                         default=0x01000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)     parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)                         default=0x00f00000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)     parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)     parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)                         default=0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)     parser.add_argument('--os_patch_level', help='operating system patch level',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)                         type=parse_os_patch_level, default=0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)     parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)     parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)                         maxlen=16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)     parser.add_argument('--pagesize', help='page size', type=parse_int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)                         choices=[2**i for i in range(11, 15)], default=2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)     parser.add_argument('--id', help='print the image ID on standard output',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)                         action='store_true')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)     parser.add_argument('--header_version', help='boot image header version', type=parse_int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)                         default=0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)     parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)     parser.add_argument('--vendor_boot', help='vendor boot output file name', type=FileType('wb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)     parser.add_argument('--vendor_ramdisk', help='path to the vendor ramdisk', type=FileType('rb'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)     return parser.parse_args()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) def write_data(args, pagesize):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)     write_padded_file(args.output, args.kernel, pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)     write_padded_file(args.output, args.ramdisk, pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)     write_padded_file(args.output, args.second, pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)     if args.header_version > 0 and args.header_version < 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)         write_padded_file(args.output, args.recovery_dtbo, pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)     if args.header_version == 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)         write_padded_file(args.output, args.dtb, pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) def write_vendor_boot_data(args):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)     write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)     write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) def main():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)     args = parse_cmdline()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)     if args.vendor_boot is not None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)         if args.header_version < 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)             raise ValueError('--vendor_boot not compatible with given header version')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)         if args.vendor_ramdisk is None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)             raise ValueError('--vendor_ramdisk missing or invalid')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)         write_vendor_boot_header(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)         write_vendor_boot_data(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)     if args.output is not None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)         if args.kernel is None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)             raise ValueError('kernel must be supplied when creating a boot image')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)         if args.second is not None and args.header_version > 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)             raise ValueError('--second not compatible with given header version')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)         img_id = write_header(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)         if args.header_version > 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)             write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)         else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)             write_data(args, args.pagesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)         if args.id and img_id is not None:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)             # Python 2's struct.pack returns a string, but py3 returns bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)             if isinstance(img_id, str):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)                 img_id = [ord(x) for x in img_id]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)             print('0x' + ''.join('{:02x}'.format(c) for c in img_id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if __name__ == '__main__':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)     main()