1*13e8728fSAndroid Build Coastguard Worker#! /usr/bin/env python3 2*13e8728fSAndroid Build Coastguard Worker# Copyright 2017, The Android Open Source Project 3*13e8728fSAndroid Build Coastguard Worker# 4*13e8728fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*13e8728fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*13e8728fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*13e8728fSAndroid Build Coastguard Worker# 8*13e8728fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*13e8728fSAndroid Build Coastguard Worker# 10*13e8728fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*13e8728fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*13e8728fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*13e8728fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*13e8728fSAndroid Build Coastguard Worker# limitations under the License. 15*13e8728fSAndroid Build Coastguard Worker 16*13e8728fSAndroid Build Coastguard Workerfrom __future__ import print_function 17*13e8728fSAndroid Build Coastguard Worker 18*13e8728fSAndroid Build Coastguard Worker"""Tool for packing multiple DTB/DTBO files into a single image""" 19*13e8728fSAndroid Build Coastguard Worker 20*13e8728fSAndroid Build Coastguard Workerimport argparse 21*13e8728fSAndroid Build Coastguard Workerimport fnmatch 22*13e8728fSAndroid Build Coastguard Workerimport os 23*13e8728fSAndroid Build Coastguard Workerimport struct 24*13e8728fSAndroid Build Coastguard Workerimport zlib 25*13e8728fSAndroid Build Coastguard Workerfrom array import array 26*13e8728fSAndroid Build Coastguard Workerfrom collections import namedtuple 27*13e8728fSAndroid Build Coastguard Workerfrom sys import stdout 28*13e8728fSAndroid Build Coastguard Worker 29*13e8728fSAndroid Build Coastguard Workerclass CompressionFormat(object): 30*13e8728fSAndroid Build Coastguard Worker """Enum representing DT compression format for a DT entry. 31*13e8728fSAndroid Build Coastguard Worker """ 32*13e8728fSAndroid Build Coastguard Worker NO_COMPRESSION = 0x00 33*13e8728fSAndroid Build Coastguard Worker ZLIB_COMPRESSION = 0x01 34*13e8728fSAndroid Build Coastguard Worker GZIP_COMPRESSION = 0x02 35*13e8728fSAndroid Build Coastguard Worker 36*13e8728fSAndroid Build Coastguard Workerclass DtEntry(object): 37*13e8728fSAndroid Build Coastguard Worker """Provides individual DT image file arguments to be added to a DTBO. 38*13e8728fSAndroid Build Coastguard Worker 39*13e8728fSAndroid Build Coastguard Worker Attributes: 40*13e8728fSAndroid Build Coastguard Worker REQUIRED_KEYS_V0: 'keys' needed to be present in the dictionary passed to instantiate 41*13e8728fSAndroid Build Coastguard Worker an object of this class when a DTBO header of version 0 is used. 42*13e8728fSAndroid Build Coastguard Worker REQUIRED_KEYS_V1: 'keys' needed to be present in the dictionary passed to instantiate 43*13e8728fSAndroid Build Coastguard Worker an object of this class when a DTBO header of version 1 is used. 44*13e8728fSAndroid Build Coastguard Worker COMPRESSION_FORMAT_MASK: Mask to retrieve compression info for DT entry from flags field 45*13e8728fSAndroid Build Coastguard Worker when a DTBO header of version 1 is used. 46*13e8728fSAndroid Build Coastguard Worker """ 47*13e8728fSAndroid Build Coastguard Worker COMPRESSION_FORMAT_MASK = 0x0f 48*13e8728fSAndroid Build Coastguard Worker REQUIRED_KEYS_V0 = ('dt_file', 'dt_size', 'dt_offset', 'id', 'rev', 49*13e8728fSAndroid Build Coastguard Worker 'custom0', 'custom1', 'custom2', 'custom3') 50*13e8728fSAndroid Build Coastguard Worker REQUIRED_KEYS_V1 = ('dt_file', 'dt_size', 'dt_offset', 'id', 'rev', 51*13e8728fSAndroid Build Coastguard Worker 'flags', 'custom0', 'custom1', 'custom2') 52*13e8728fSAndroid Build Coastguard Worker 53*13e8728fSAndroid Build Coastguard Worker @staticmethod 54*13e8728fSAndroid Build Coastguard Worker def __get_number_or_prop(arg): 55*13e8728fSAndroid Build Coastguard Worker """Converts string to integer or reads the property from DT image. 56*13e8728fSAndroid Build Coastguard Worker 57*13e8728fSAndroid Build Coastguard Worker Args: 58*13e8728fSAndroid Build Coastguard Worker arg: String containing the argument provided on the command line. 59*13e8728fSAndroid Build Coastguard Worker 60*13e8728fSAndroid Build Coastguard Worker Returns: 61*13e8728fSAndroid Build Coastguard Worker An integer property read from DT file or argument string 62*13e8728fSAndroid Build Coastguard Worker converted to integer 63*13e8728fSAndroid Build Coastguard Worker """ 64*13e8728fSAndroid Build Coastguard Worker 65*13e8728fSAndroid Build Coastguard Worker if not arg or arg[0] == '+' or arg[0] == '-': 66*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid argument passed to DTImage') 67*13e8728fSAndroid Build Coastguard Worker if arg[0] == '/': 68*13e8728fSAndroid Build Coastguard Worker # TODO(b/XXX): Use pylibfdt to get property value from DT 69*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid argument passed to DTImage') 70*13e8728fSAndroid Build Coastguard Worker else: 71*13e8728fSAndroid Build Coastguard Worker base = 10 72*13e8728fSAndroid Build Coastguard Worker if arg.startswith('0x') or arg.startswith('0X'): 73*13e8728fSAndroid Build Coastguard Worker base = 16 74*13e8728fSAndroid Build Coastguard Worker elif arg.startswith('0'): 75*13e8728fSAndroid Build Coastguard Worker base = 8 76*13e8728fSAndroid Build Coastguard Worker return int(arg, base) 77*13e8728fSAndroid Build Coastguard Worker 78*13e8728fSAndroid Build Coastguard Worker def __init__(self, **kwargs): 79*13e8728fSAndroid Build Coastguard Worker """Constructor for DtEntry object. 80*13e8728fSAndroid Build Coastguard Worker 81*13e8728fSAndroid Build Coastguard Worker Initializes attributes from dictionary object that contains 82*13e8728fSAndroid Build Coastguard Worker values keyed with names equivalent to the class's attributes. 83*13e8728fSAndroid Build Coastguard Worker 84*13e8728fSAndroid Build Coastguard Worker Args: 85*13e8728fSAndroid Build Coastguard Worker kwargs: Dictionary object containing values to instantiate 86*13e8728fSAndroid Build Coastguard Worker class members with. Expected keys in dictionary are from 87*13e8728fSAndroid Build Coastguard Worker the tuple (_REQUIRED_KEYS) 88*13e8728fSAndroid Build Coastguard Worker """ 89*13e8728fSAndroid Build Coastguard Worker 90*13e8728fSAndroid Build Coastguard Worker self.__version = kwargs['version'] 91*13e8728fSAndroid Build Coastguard Worker required_keys = None 92*13e8728fSAndroid Build Coastguard Worker if self.__version == 0: 93*13e8728fSAndroid Build Coastguard Worker required_keys = self.REQUIRED_KEYS_V0 94*13e8728fSAndroid Build Coastguard Worker elif self.__version == 1: 95*13e8728fSAndroid Build Coastguard Worker required_keys = self.REQUIRED_KEYS_V1 96*13e8728fSAndroid Build Coastguard Worker 97*13e8728fSAndroid Build Coastguard Worker missing_keys = set(required_keys) - set(kwargs) 98*13e8728fSAndroid Build Coastguard Worker if missing_keys: 99*13e8728fSAndroid Build Coastguard Worker raise ValueError('Missing keys in DtEntry constructor: %r' % 100*13e8728fSAndroid Build Coastguard Worker sorted(missing_keys)) 101*13e8728fSAndroid Build Coastguard Worker 102*13e8728fSAndroid Build Coastguard Worker self.__dt_file = kwargs['dt_file'] 103*13e8728fSAndroid Build Coastguard Worker self.__dt_offset = kwargs['dt_offset'] 104*13e8728fSAndroid Build Coastguard Worker self.__dt_size = kwargs['dt_size'] 105*13e8728fSAndroid Build Coastguard Worker self.__id = self.__get_number_or_prop(kwargs['id']) 106*13e8728fSAndroid Build Coastguard Worker self.__rev = self.__get_number_or_prop(kwargs['rev']) 107*13e8728fSAndroid Build Coastguard Worker if self.__version == 1: 108*13e8728fSAndroid Build Coastguard Worker self.__flags = self.__get_number_or_prop(kwargs['flags']) 109*13e8728fSAndroid Build Coastguard Worker self.__custom0 = self.__get_number_or_prop(kwargs['custom0']) 110*13e8728fSAndroid Build Coastguard Worker self.__custom1 = self.__get_number_or_prop(kwargs['custom1']) 111*13e8728fSAndroid Build Coastguard Worker self.__custom2 = self.__get_number_or_prop(kwargs['custom2']) 112*13e8728fSAndroid Build Coastguard Worker if self.__version == 0: 113*13e8728fSAndroid Build Coastguard Worker self.__custom3 = self.__get_number_or_prop(kwargs['custom3']) 114*13e8728fSAndroid Build Coastguard Worker 115*13e8728fSAndroid Build Coastguard Worker def __str__(self): 116*13e8728fSAndroid Build Coastguard Worker sb = [] 117*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:d}'.format(key='dt_size', 118*13e8728fSAndroid Build Coastguard Worker value=self.__dt_size)) 119*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:d}'.format(key='dt_offset', 120*13e8728fSAndroid Build Coastguard Worker value=self.__dt_offset)) 121*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='id', 122*13e8728fSAndroid Build Coastguard Worker value=self.__id)) 123*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='rev', 124*13e8728fSAndroid Build Coastguard Worker value=self.__rev)) 125*13e8728fSAndroid Build Coastguard Worker if self.__version == 1: 126*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='flags', 127*13e8728fSAndroid Build Coastguard Worker value=self.__flags)) 128*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='custom[0]', 129*13e8728fSAndroid Build Coastguard Worker value=self.__custom0)) 130*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='custom[1]', 131*13e8728fSAndroid Build Coastguard Worker value=self.__custom1)) 132*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='custom[2]', 133*13e8728fSAndroid Build Coastguard Worker value=self.__custom2)) 134*13e8728fSAndroid Build Coastguard Worker if self.__version == 0: 135*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key='custom[3]', 136*13e8728fSAndroid Build Coastguard Worker value=self.__custom3)) 137*13e8728fSAndroid Build Coastguard Worker return '\n'.join(sb) 138*13e8728fSAndroid Build Coastguard Worker 139*13e8728fSAndroid Build Coastguard Worker def compression_info(self): 140*13e8728fSAndroid Build Coastguard Worker """CompressionFormat: compression format for DT image file. 141*13e8728fSAndroid Build Coastguard Worker 142*13e8728fSAndroid Build Coastguard Worker Args: 143*13e8728fSAndroid Build Coastguard Worker version: Version of DTBO header, compression is only 144*13e8728fSAndroid Build Coastguard Worker supported from version 1. 145*13e8728fSAndroid Build Coastguard Worker """ 146*13e8728fSAndroid Build Coastguard Worker if self.__version == 0: 147*13e8728fSAndroid Build Coastguard Worker return CompressionFormat.NO_COMPRESSION 148*13e8728fSAndroid Build Coastguard Worker return self.flags & self.COMPRESSION_FORMAT_MASK 149*13e8728fSAndroid Build Coastguard Worker 150*13e8728fSAndroid Build Coastguard Worker @property 151*13e8728fSAndroid Build Coastguard Worker def dt_file(self): 152*13e8728fSAndroid Build Coastguard Worker """file: File handle to the DT image file.""" 153*13e8728fSAndroid Build Coastguard Worker return self.__dt_file 154*13e8728fSAndroid Build Coastguard Worker 155*13e8728fSAndroid Build Coastguard Worker @property 156*13e8728fSAndroid Build Coastguard Worker def size(self): 157*13e8728fSAndroid Build Coastguard Worker """int: size in bytes of the DT image file.""" 158*13e8728fSAndroid Build Coastguard Worker return self.__dt_size 159*13e8728fSAndroid Build Coastguard Worker 160*13e8728fSAndroid Build Coastguard Worker @size.setter 161*13e8728fSAndroid Build Coastguard Worker def size(self, value): 162*13e8728fSAndroid Build Coastguard Worker self.__dt_size = value 163*13e8728fSAndroid Build Coastguard Worker 164*13e8728fSAndroid Build Coastguard Worker @property 165*13e8728fSAndroid Build Coastguard Worker def dt_offset(self): 166*13e8728fSAndroid Build Coastguard Worker """int: offset in DTBO file for this DT image.""" 167*13e8728fSAndroid Build Coastguard Worker return self.__dt_offset 168*13e8728fSAndroid Build Coastguard Worker 169*13e8728fSAndroid Build Coastguard Worker @dt_offset.setter 170*13e8728fSAndroid Build Coastguard Worker def dt_offset(self, value): 171*13e8728fSAndroid Build Coastguard Worker self.__dt_offset = value 172*13e8728fSAndroid Build Coastguard Worker 173*13e8728fSAndroid Build Coastguard Worker @property 174*13e8728fSAndroid Build Coastguard Worker def image_id(self): 175*13e8728fSAndroid Build Coastguard Worker """int: DT entry _id for this DT image.""" 176*13e8728fSAndroid Build Coastguard Worker return self.__id 177*13e8728fSAndroid Build Coastguard Worker 178*13e8728fSAndroid Build Coastguard Worker @property 179*13e8728fSAndroid Build Coastguard Worker def rev(self): 180*13e8728fSAndroid Build Coastguard Worker """int: DT entry _rev for this DT image.""" 181*13e8728fSAndroid Build Coastguard Worker return self.__rev 182*13e8728fSAndroid Build Coastguard Worker 183*13e8728fSAndroid Build Coastguard Worker @property 184*13e8728fSAndroid Build Coastguard Worker def flags(self): 185*13e8728fSAndroid Build Coastguard Worker """int: DT entry _flags for this DT image.""" 186*13e8728fSAndroid Build Coastguard Worker return self.__flags 187*13e8728fSAndroid Build Coastguard Worker 188*13e8728fSAndroid Build Coastguard Worker @property 189*13e8728fSAndroid Build Coastguard Worker def custom0(self): 190*13e8728fSAndroid Build Coastguard Worker """int: DT entry _custom0 for this DT image.""" 191*13e8728fSAndroid Build Coastguard Worker return self.__custom0 192*13e8728fSAndroid Build Coastguard Worker 193*13e8728fSAndroid Build Coastguard Worker @property 194*13e8728fSAndroid Build Coastguard Worker def custom1(self): 195*13e8728fSAndroid Build Coastguard Worker """int: DT entry _custom1 for this DT image.""" 196*13e8728fSAndroid Build Coastguard Worker return self.__custom1 197*13e8728fSAndroid Build Coastguard Worker 198*13e8728fSAndroid Build Coastguard Worker @property 199*13e8728fSAndroid Build Coastguard Worker def custom2(self): 200*13e8728fSAndroid Build Coastguard Worker """int: DT entry custom2 for this DT image.""" 201*13e8728fSAndroid Build Coastguard Worker return self.__custom2 202*13e8728fSAndroid Build Coastguard Worker 203*13e8728fSAndroid Build Coastguard Worker @property 204*13e8728fSAndroid Build Coastguard Worker def custom3(self): 205*13e8728fSAndroid Build Coastguard Worker """int: DT entry custom3 for this DT image.""" 206*13e8728fSAndroid Build Coastguard Worker return self.__custom3 207*13e8728fSAndroid Build Coastguard Worker 208*13e8728fSAndroid Build Coastguard Workerclass Dtbo(object): 209*13e8728fSAndroid Build Coastguard Worker """ 210*13e8728fSAndroid Build Coastguard Worker Provides parser, reader, writer for dumping and creating Device Tree Blob 211*13e8728fSAndroid Build Coastguard Worker Overlay (DTBO) images. 212*13e8728fSAndroid Build Coastguard Worker 213*13e8728fSAndroid Build Coastguard Worker Attributes: 214*13e8728fSAndroid Build Coastguard Worker _DTBO_MAGIC: Device tree table header magic. 215*13e8728fSAndroid Build Coastguard Worker _ACPIO_MAGIC: Advanced Configuration and Power Interface table header 216*13e8728fSAndroid Build Coastguard Worker magic. 217*13e8728fSAndroid Build Coastguard Worker _DT_TABLE_HEADER_SIZE: Size of Device tree table header. 218*13e8728fSAndroid Build Coastguard Worker _DT_TABLE_HEADER_INTS: Number of integers in DT table header. 219*13e8728fSAndroid Build Coastguard Worker _DT_ENTRY_HEADER_SIZE: Size of Device tree entry header within a DTBO. 220*13e8728fSAndroid Build Coastguard Worker _DT_ENTRY_HEADER_INTS: Number of integers in DT entry header. 221*13e8728fSAndroid Build Coastguard Worker _GZIP_COMPRESSION_WBITS: Argument 'wbits' for gzip compression 222*13e8728fSAndroid Build Coastguard Worker _ZLIB_DECOMPRESSION_WBITS: Argument 'wbits' for zlib/gzip compression 223*13e8728fSAndroid Build Coastguard Worker """ 224*13e8728fSAndroid Build Coastguard Worker 225*13e8728fSAndroid Build Coastguard Worker _DTBO_MAGIC = 0xd7b7ab1e 226*13e8728fSAndroid Build Coastguard Worker _ACPIO_MAGIC = 0x41435049 227*13e8728fSAndroid Build Coastguard Worker _DT_TABLE_HEADER_SIZE = struct.calcsize('>8I') 228*13e8728fSAndroid Build Coastguard Worker _DT_TABLE_HEADER_INTS = 8 229*13e8728fSAndroid Build Coastguard Worker _DT_ENTRY_HEADER_SIZE = struct.calcsize('>8I') 230*13e8728fSAndroid Build Coastguard Worker _DT_ENTRY_HEADER_INTS = 8 231*13e8728fSAndroid Build Coastguard Worker _GZIP_COMPRESSION_WBITS = 31 232*13e8728fSAndroid Build Coastguard Worker _ZLIB_DECOMPRESSION_WBITS = 47 233*13e8728fSAndroid Build Coastguard Worker 234*13e8728fSAndroid Build Coastguard Worker def _update_dt_table_header(self): 235*13e8728fSAndroid Build Coastguard Worker """Converts header entries into binary data for DTBO header. 236*13e8728fSAndroid Build Coastguard Worker 237*13e8728fSAndroid Build Coastguard Worker Packs the current Device tree table header attribute values in 238*13e8728fSAndroid Build Coastguard Worker metadata buffer. 239*13e8728fSAndroid Build Coastguard Worker """ 240*13e8728fSAndroid Build Coastguard Worker struct.pack_into('>8I', self.__metadata, 0, self.magic, 241*13e8728fSAndroid Build Coastguard Worker self.total_size, self.header_size, 242*13e8728fSAndroid Build Coastguard Worker self.dt_entry_size, self.dt_entry_count, 243*13e8728fSAndroid Build Coastguard Worker self.dt_entries_offset, self.page_size, 244*13e8728fSAndroid Build Coastguard Worker self.version) 245*13e8728fSAndroid Build Coastguard Worker 246*13e8728fSAndroid Build Coastguard Worker def _update_dt_entry_header(self, dt_entry, metadata_offset): 247*13e8728fSAndroid Build Coastguard Worker """Converts each DT entry header entry into binary data for DTBO file. 248*13e8728fSAndroid Build Coastguard Worker 249*13e8728fSAndroid Build Coastguard Worker Packs the current device tree table entry attribute into 250*13e8728fSAndroid Build Coastguard Worker metadata buffer as device tree entry header. 251*13e8728fSAndroid Build Coastguard Worker 252*13e8728fSAndroid Build Coastguard Worker Args: 253*13e8728fSAndroid Build Coastguard Worker dt_entry: DtEntry object for the header to be packed. 254*13e8728fSAndroid Build Coastguard Worker metadata_offset: Offset into metadata buffer to begin writing. 255*13e8728fSAndroid Build Coastguard Worker dtbo_offset: Offset where the DT image file for this dt_entry can 256*13e8728fSAndroid Build Coastguard Worker be found in the resulting DTBO image. 257*13e8728fSAndroid Build Coastguard Worker """ 258*13e8728fSAndroid Build Coastguard Worker if self.version == 0: 259*13e8728fSAndroid Build Coastguard Worker struct.pack_into('>8I', self.__metadata, metadata_offset, dt_entry.size, 260*13e8728fSAndroid Build Coastguard Worker dt_entry.dt_offset, dt_entry.image_id, dt_entry.rev, 261*13e8728fSAndroid Build Coastguard Worker dt_entry.custom0, dt_entry.custom1, dt_entry.custom2, 262*13e8728fSAndroid Build Coastguard Worker dt_entry.custom3) 263*13e8728fSAndroid Build Coastguard Worker elif self.version == 1: 264*13e8728fSAndroid Build Coastguard Worker struct.pack_into('>8I', self.__metadata, metadata_offset, dt_entry.size, 265*13e8728fSAndroid Build Coastguard Worker dt_entry.dt_offset, dt_entry.image_id, dt_entry.rev, 266*13e8728fSAndroid Build Coastguard Worker dt_entry.flags, dt_entry.custom0, dt_entry.custom1, 267*13e8728fSAndroid Build Coastguard Worker dt_entry.custom2) 268*13e8728fSAndroid Build Coastguard Worker 269*13e8728fSAndroid Build Coastguard Worker 270*13e8728fSAndroid Build Coastguard Worker def _update_metadata(self): 271*13e8728fSAndroid Build Coastguard Worker """Updates the DTBO metadata. 272*13e8728fSAndroid Build Coastguard Worker 273*13e8728fSAndroid Build Coastguard Worker Initialize the internal metadata buffer and fill it with all Device 274*13e8728fSAndroid Build Coastguard Worker Tree table entries and update the DTBO header. 275*13e8728fSAndroid Build Coastguard Worker """ 276*13e8728fSAndroid Build Coastguard Worker 277*13e8728fSAndroid Build Coastguard Worker self.__metadata = array('b', b' ' * self.__metadata_size) 278*13e8728fSAndroid Build Coastguard Worker metadata_offset = self.header_size 279*13e8728fSAndroid Build Coastguard Worker for dt_entry in self.__dt_entries: 280*13e8728fSAndroid Build Coastguard Worker self._update_dt_entry_header(dt_entry, metadata_offset) 281*13e8728fSAndroid Build Coastguard Worker metadata_offset += self.dt_entry_size 282*13e8728fSAndroid Build Coastguard Worker self._update_dt_table_header() 283*13e8728fSAndroid Build Coastguard Worker 284*13e8728fSAndroid Build Coastguard Worker def _read_dtbo_header(self, buf): 285*13e8728fSAndroid Build Coastguard Worker """Reads DTBO file header into metadata buffer. 286*13e8728fSAndroid Build Coastguard Worker 287*13e8728fSAndroid Build Coastguard Worker Unpack and read the DTBO table header from given buffer. The 288*13e8728fSAndroid Build Coastguard Worker buffer size must exactly be equal to _DT_TABLE_HEADER_SIZE. 289*13e8728fSAndroid Build Coastguard Worker 290*13e8728fSAndroid Build Coastguard Worker Args: 291*13e8728fSAndroid Build Coastguard Worker buf: Bytebuffer read directly from the file of size 292*13e8728fSAndroid Build Coastguard Worker _DT_TABLE_HEADER_SIZE. 293*13e8728fSAndroid Build Coastguard Worker """ 294*13e8728fSAndroid Build Coastguard Worker (self.magic, self.total_size, self.header_size, 295*13e8728fSAndroid Build Coastguard Worker self.dt_entry_size, self.dt_entry_count, self.dt_entries_offset, 296*13e8728fSAndroid Build Coastguard Worker self.page_size, self.version) = struct.unpack_from('>8I', buf, 0) 297*13e8728fSAndroid Build Coastguard Worker 298*13e8728fSAndroid Build Coastguard Worker # verify the header 299*13e8728fSAndroid Build Coastguard Worker if self.magic != self._DTBO_MAGIC and self.magic != self._ACPIO_MAGIC: 300*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid magic number 0x%x in DTBO/ACPIO file' % 301*13e8728fSAndroid Build Coastguard Worker (self.magic)) 302*13e8728fSAndroid Build Coastguard Worker 303*13e8728fSAndroid Build Coastguard Worker if self.header_size != self._DT_TABLE_HEADER_SIZE: 304*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid header size (%d) in DTBO/ACPIO file' % 305*13e8728fSAndroid Build Coastguard Worker (self.header_size)) 306*13e8728fSAndroid Build Coastguard Worker 307*13e8728fSAndroid Build Coastguard Worker if self.dt_entry_size != self._DT_ENTRY_HEADER_SIZE: 308*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid DT entry header size (%d) in DTBO/ACPIO file' % 309*13e8728fSAndroid Build Coastguard Worker (self.dt_entry_size)) 310*13e8728fSAndroid Build Coastguard Worker 311*13e8728fSAndroid Build Coastguard Worker def _read_dt_entries_from_metadata(self): 312*13e8728fSAndroid Build Coastguard Worker """Reads individual DT entry headers from metadata buffer. 313*13e8728fSAndroid Build Coastguard Worker 314*13e8728fSAndroid Build Coastguard Worker Unpack and read the DTBO DT entry headers from the internal buffer. 315*13e8728fSAndroid Build Coastguard Worker The buffer size must exactly be equal to _DT_TABLE_HEADER_SIZE + 316*13e8728fSAndroid Build Coastguard Worker (_DT_ENTRY_HEADER_SIZE * dt_entry_count). The method raises exception 317*13e8728fSAndroid Build Coastguard Worker if DT entries have already been set for this object. 318*13e8728fSAndroid Build Coastguard Worker """ 319*13e8728fSAndroid Build Coastguard Worker 320*13e8728fSAndroid Build Coastguard Worker if self.__dt_entries: 321*13e8728fSAndroid Build Coastguard Worker raise ValueError('DTBO DT entries can be added only once') 322*13e8728fSAndroid Build Coastguard Worker 323*13e8728fSAndroid Build Coastguard Worker offset = self.dt_entries_offset // 4 324*13e8728fSAndroid Build Coastguard Worker params = {} 325*13e8728fSAndroid Build Coastguard Worker params['version'] = self.version 326*13e8728fSAndroid Build Coastguard Worker params['dt_file'] = None 327*13e8728fSAndroid Build Coastguard Worker for i in range(0, self.dt_entry_count): 328*13e8728fSAndroid Build Coastguard Worker dt_table_entry = self.__metadata[offset:offset + self._DT_ENTRY_HEADER_INTS] 329*13e8728fSAndroid Build Coastguard Worker params['dt_size'] = dt_table_entry[0] 330*13e8728fSAndroid Build Coastguard Worker params['dt_offset'] = dt_table_entry[1] 331*13e8728fSAndroid Build Coastguard Worker for j in range(2, self._DT_ENTRY_HEADER_INTS): 332*13e8728fSAndroid Build Coastguard Worker required_keys = None 333*13e8728fSAndroid Build Coastguard Worker if self.version == 0: 334*13e8728fSAndroid Build Coastguard Worker required_keys = DtEntry.REQUIRED_KEYS_V0 335*13e8728fSAndroid Build Coastguard Worker elif self.version == 1: 336*13e8728fSAndroid Build Coastguard Worker required_keys = DtEntry.REQUIRED_KEYS_V1 337*13e8728fSAndroid Build Coastguard Worker params[required_keys[j + 1]] = str(dt_table_entry[j]) 338*13e8728fSAndroid Build Coastguard Worker dt_entry = DtEntry(**params) 339*13e8728fSAndroid Build Coastguard Worker self.__dt_entries.append(dt_entry) 340*13e8728fSAndroid Build Coastguard Worker offset += self._DT_ENTRY_HEADER_INTS 341*13e8728fSAndroid Build Coastguard Worker 342*13e8728fSAndroid Build Coastguard Worker def _read_dtbo_image(self): 343*13e8728fSAndroid Build Coastguard Worker """Parse the input file and instantiate this object.""" 344*13e8728fSAndroid Build Coastguard Worker 345*13e8728fSAndroid Build Coastguard Worker # First check if we have enough to read the header 346*13e8728fSAndroid Build Coastguard Worker file_size = os.fstat(self.__file.fileno()).st_size 347*13e8728fSAndroid Build Coastguard Worker if file_size < self._DT_TABLE_HEADER_SIZE: 348*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid DTBO file') 349*13e8728fSAndroid Build Coastguard Worker 350*13e8728fSAndroid Build Coastguard Worker self.__file.seek(0) 351*13e8728fSAndroid Build Coastguard Worker buf = self.__file.read(self._DT_TABLE_HEADER_SIZE) 352*13e8728fSAndroid Build Coastguard Worker self._read_dtbo_header(buf) 353*13e8728fSAndroid Build Coastguard Worker 354*13e8728fSAndroid Build Coastguard Worker self.__metadata_size = (self.header_size + 355*13e8728fSAndroid Build Coastguard Worker self.dt_entry_count * self.dt_entry_size) 356*13e8728fSAndroid Build Coastguard Worker if file_size < self.__metadata_size: 357*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid or truncated DTBO file of size %d expected %d' % 358*13e8728fSAndroid Build Coastguard Worker file_size, self.__metadata_size) 359*13e8728fSAndroid Build Coastguard Worker 360*13e8728fSAndroid Build Coastguard Worker num_ints = (self._DT_TABLE_HEADER_INTS + 361*13e8728fSAndroid Build Coastguard Worker self.dt_entry_count * self._DT_ENTRY_HEADER_INTS) 362*13e8728fSAndroid Build Coastguard Worker if self.dt_entries_offset > self._DT_TABLE_HEADER_SIZE: 363*13e8728fSAndroid Build Coastguard Worker num_ints += (self.dt_entries_offset - self._DT_TABLE_HEADER_SIZE) / 4 364*13e8728fSAndroid Build Coastguard Worker format_str = '>' + str(num_ints) + 'I' 365*13e8728fSAndroid Build Coastguard Worker self.__file.seek(0) 366*13e8728fSAndroid Build Coastguard Worker self.__metadata = struct.unpack(format_str, 367*13e8728fSAndroid Build Coastguard Worker self.__file.read(self.__metadata_size)) 368*13e8728fSAndroid Build Coastguard Worker self._read_dt_entries_from_metadata() 369*13e8728fSAndroid Build Coastguard Worker 370*13e8728fSAndroid Build Coastguard Worker def _find_dt_entry_with_same_file(self, dt_entry): 371*13e8728fSAndroid Build Coastguard Worker """Finds DT Entry that has identical backing DT file. 372*13e8728fSAndroid Build Coastguard Worker 373*13e8728fSAndroid Build Coastguard Worker Args: 374*13e8728fSAndroid Build Coastguard Worker dt_entry: DtEntry object whose 'dtfile' we find for existence in the 375*13e8728fSAndroid Build Coastguard Worker current 'dt_entries'. 376*13e8728fSAndroid Build Coastguard Worker Returns: 377*13e8728fSAndroid Build Coastguard Worker If a match by file path is found, the corresponding DtEntry object 378*13e8728fSAndroid Build Coastguard Worker from internal list is returned. If not, 'None' is returned. 379*13e8728fSAndroid Build Coastguard Worker """ 380*13e8728fSAndroid Build Coastguard Worker 381*13e8728fSAndroid Build Coastguard Worker dt_entry_path = os.path.realpath(dt_entry.dt_file.name) 382*13e8728fSAndroid Build Coastguard Worker for entry in self.__dt_entries: 383*13e8728fSAndroid Build Coastguard Worker entry_path = os.path.realpath(entry.dt_file.name) 384*13e8728fSAndroid Build Coastguard Worker if entry_path == dt_entry_path: 385*13e8728fSAndroid Build Coastguard Worker return entry 386*13e8728fSAndroid Build Coastguard Worker return None 387*13e8728fSAndroid Build Coastguard Worker 388*13e8728fSAndroid Build Coastguard Worker def __init__(self, file_handle, dt_type='dtb', page_size=None, version=0): 389*13e8728fSAndroid Build Coastguard Worker """Constructor for Dtbo Object 390*13e8728fSAndroid Build Coastguard Worker 391*13e8728fSAndroid Build Coastguard Worker Args: 392*13e8728fSAndroid Build Coastguard Worker file_handle: The Dtbo File handle corresponding to this object. 393*13e8728fSAndroid Build Coastguard Worker The file handle can be used to write to (in case of 'create') 394*13e8728fSAndroid Build Coastguard Worker or read from (in case of 'dump') 395*13e8728fSAndroid Build Coastguard Worker """ 396*13e8728fSAndroid Build Coastguard Worker 397*13e8728fSAndroid Build Coastguard Worker self.__file = file_handle 398*13e8728fSAndroid Build Coastguard Worker self.__dt_entries = [] 399*13e8728fSAndroid Build Coastguard Worker self.__metadata = None 400*13e8728fSAndroid Build Coastguard Worker self.__metadata_size = 0 401*13e8728fSAndroid Build Coastguard Worker 402*13e8728fSAndroid Build Coastguard Worker # if page_size is given, assume the object is being instantiated to 403*13e8728fSAndroid Build Coastguard Worker # create a DTBO file 404*13e8728fSAndroid Build Coastguard Worker if page_size: 405*13e8728fSAndroid Build Coastguard Worker if dt_type == 'acpi': 406*13e8728fSAndroid Build Coastguard Worker self.magic = self._ACPIO_MAGIC 407*13e8728fSAndroid Build Coastguard Worker else: 408*13e8728fSAndroid Build Coastguard Worker self.magic = self._DTBO_MAGIC 409*13e8728fSAndroid Build Coastguard Worker self.total_size = self._DT_TABLE_HEADER_SIZE 410*13e8728fSAndroid Build Coastguard Worker self.header_size = self._DT_TABLE_HEADER_SIZE 411*13e8728fSAndroid Build Coastguard Worker self.dt_entry_size = self._DT_ENTRY_HEADER_SIZE 412*13e8728fSAndroid Build Coastguard Worker self.dt_entry_count = 0 413*13e8728fSAndroid Build Coastguard Worker self.dt_entries_offset = self._DT_TABLE_HEADER_SIZE 414*13e8728fSAndroid Build Coastguard Worker self.page_size = page_size 415*13e8728fSAndroid Build Coastguard Worker self.version = version 416*13e8728fSAndroid Build Coastguard Worker self.__metadata_size = self._DT_TABLE_HEADER_SIZE 417*13e8728fSAndroid Build Coastguard Worker else: 418*13e8728fSAndroid Build Coastguard Worker self._read_dtbo_image() 419*13e8728fSAndroid Build Coastguard Worker 420*13e8728fSAndroid Build Coastguard Worker def __str__(self): 421*13e8728fSAndroid Build Coastguard Worker sb = [] 422*13e8728fSAndroid Build Coastguard Worker sb.append('dt_table_header:') 423*13e8728fSAndroid Build Coastguard Worker _keys = ('magic', 'total_size', 'header_size', 'dt_entry_size', 424*13e8728fSAndroid Build Coastguard Worker 'dt_entry_count', 'dt_entries_offset', 'page_size', 'version') 425*13e8728fSAndroid Build Coastguard Worker for key in _keys: 426*13e8728fSAndroid Build Coastguard Worker if key == 'magic': 427*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:08x}'.format(key=key, 428*13e8728fSAndroid Build Coastguard Worker value=self.__dict__[key])) 429*13e8728fSAndroid Build Coastguard Worker else: 430*13e8728fSAndroid Build Coastguard Worker sb.append('{key:>20} = {value:d}'.format(key=key, 431*13e8728fSAndroid Build Coastguard Worker value=self.__dict__[key])) 432*13e8728fSAndroid Build Coastguard Worker count = 0 433*13e8728fSAndroid Build Coastguard Worker for dt_entry in self.__dt_entries: 434*13e8728fSAndroid Build Coastguard Worker sb.append('dt_table_entry[{0:d}]:'.format(count)) 435*13e8728fSAndroid Build Coastguard Worker sb.append(str(dt_entry)) 436*13e8728fSAndroid Build Coastguard Worker count = count + 1 437*13e8728fSAndroid Build Coastguard Worker return '\n'.join(sb) 438*13e8728fSAndroid Build Coastguard Worker 439*13e8728fSAndroid Build Coastguard Worker @property 440*13e8728fSAndroid Build Coastguard Worker def dt_entries(self): 441*13e8728fSAndroid Build Coastguard Worker """Returns a list of DtEntry objects found in DTBO file.""" 442*13e8728fSAndroid Build Coastguard Worker return self.__dt_entries 443*13e8728fSAndroid Build Coastguard Worker 444*13e8728fSAndroid Build Coastguard Worker def compress_dt_entry(self, compression_format, dt_entry_file): 445*13e8728fSAndroid Build Coastguard Worker """Compresses a DT entry. 446*13e8728fSAndroid Build Coastguard Worker 447*13e8728fSAndroid Build Coastguard Worker Args: 448*13e8728fSAndroid Build Coastguard Worker compression_format: Compression format for DT Entry 449*13e8728fSAndroid Build Coastguard Worker dt_entry_file: File handle to read DT entry from. 450*13e8728fSAndroid Build Coastguard Worker 451*13e8728fSAndroid Build Coastguard Worker Returns: 452*13e8728fSAndroid Build Coastguard Worker Compressed DT entry and its length. 453*13e8728fSAndroid Build Coastguard Worker 454*13e8728fSAndroid Build Coastguard Worker Raises: 455*13e8728fSAndroid Build Coastguard Worker ValueError if unrecognized compression format is found. 456*13e8728fSAndroid Build Coastguard Worker """ 457*13e8728fSAndroid Build Coastguard Worker compress_zlib = zlib.compressobj() # zlib 458*13e8728fSAndroid Build Coastguard Worker compress_gzip = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, 459*13e8728fSAndroid Build Coastguard Worker zlib.DEFLATED, self._GZIP_COMPRESSION_WBITS) # gzip 460*13e8728fSAndroid Build Coastguard Worker compression_obj_dict = { 461*13e8728fSAndroid Build Coastguard Worker CompressionFormat.NO_COMPRESSION: None, 462*13e8728fSAndroid Build Coastguard Worker CompressionFormat.ZLIB_COMPRESSION: compress_zlib, 463*13e8728fSAndroid Build Coastguard Worker CompressionFormat.GZIP_COMPRESSION: compress_gzip, 464*13e8728fSAndroid Build Coastguard Worker } 465*13e8728fSAndroid Build Coastguard Worker 466*13e8728fSAndroid Build Coastguard Worker if compression_format not in compression_obj_dict: 467*13e8728fSAndroid Build Coastguard Worker ValueError("Bad compression format %d" % compression_format) 468*13e8728fSAndroid Build Coastguard Worker 469*13e8728fSAndroid Build Coastguard Worker if compression_format is CompressionFormat.NO_COMPRESSION: 470*13e8728fSAndroid Build Coastguard Worker dt_entry = dt_entry_file.read() 471*13e8728fSAndroid Build Coastguard Worker else: 472*13e8728fSAndroid Build Coastguard Worker compression_object = compression_obj_dict[compression_format] 473*13e8728fSAndroid Build Coastguard Worker dt_entry_file.seek(0) 474*13e8728fSAndroid Build Coastguard Worker dt_entry = compression_object.compress(dt_entry_file.read()) 475*13e8728fSAndroid Build Coastguard Worker dt_entry += compression_object.flush() 476*13e8728fSAndroid Build Coastguard Worker return dt_entry, len(dt_entry) 477*13e8728fSAndroid Build Coastguard Worker 478*13e8728fSAndroid Build Coastguard Worker def add_dt_entries(self, dt_entries): 479*13e8728fSAndroid Build Coastguard Worker """Adds DT image files to the DTBO object. 480*13e8728fSAndroid Build Coastguard Worker 481*13e8728fSAndroid Build Coastguard Worker Adds a list of Dtentry Objects to the DTBO image. The changes are not 482*13e8728fSAndroid Build Coastguard Worker committed to the output file until commit() is called. 483*13e8728fSAndroid Build Coastguard Worker 484*13e8728fSAndroid Build Coastguard Worker Args: 485*13e8728fSAndroid Build Coastguard Worker dt_entries: List of DtEntry object to be added. 486*13e8728fSAndroid Build Coastguard Worker 487*13e8728fSAndroid Build Coastguard Worker Returns: 488*13e8728fSAndroid Build Coastguard Worker A buffer containing all DT entries. 489*13e8728fSAndroid Build Coastguard Worker 490*13e8728fSAndroid Build Coastguard Worker Raises: 491*13e8728fSAndroid Build Coastguard Worker ValueError: if the list of DT entries is empty or if a list of DT entries 492*13e8728fSAndroid Build Coastguard Worker has already been added to the DTBO. 493*13e8728fSAndroid Build Coastguard Worker """ 494*13e8728fSAndroid Build Coastguard Worker if not dt_entries: 495*13e8728fSAndroid Build Coastguard Worker raise ValueError('Attempted to add empty list of DT entries') 496*13e8728fSAndroid Build Coastguard Worker 497*13e8728fSAndroid Build Coastguard Worker if self.__dt_entries: 498*13e8728fSAndroid Build Coastguard Worker raise ValueError('DTBO DT entries can be added only once') 499*13e8728fSAndroid Build Coastguard Worker 500*13e8728fSAndroid Build Coastguard Worker dt_entry_count = len(dt_entries) 501*13e8728fSAndroid Build Coastguard Worker dt_offset = (self.header_size + 502*13e8728fSAndroid Build Coastguard Worker dt_entry_count * self.dt_entry_size) 503*13e8728fSAndroid Build Coastguard Worker 504*13e8728fSAndroid Build Coastguard Worker dt_entry_buf = b"" 505*13e8728fSAndroid Build Coastguard Worker for dt_entry in dt_entries: 506*13e8728fSAndroid Build Coastguard Worker if not isinstance(dt_entry, DtEntry): 507*13e8728fSAndroid Build Coastguard Worker raise ValueError('Adding invalid DT entry object to DTBO') 508*13e8728fSAndroid Build Coastguard Worker entry = self._find_dt_entry_with_same_file(dt_entry) 509*13e8728fSAndroid Build Coastguard Worker dt_entry_compression_info = dt_entry.compression_info() 510*13e8728fSAndroid Build Coastguard Worker if entry and (entry.compression_info() == dt_entry_compression_info): 511*13e8728fSAndroid Build Coastguard Worker dt_entry.dt_offset = entry.dt_offset 512*13e8728fSAndroid Build Coastguard Worker dt_entry.size = entry.size 513*13e8728fSAndroid Build Coastguard Worker else: 514*13e8728fSAndroid Build Coastguard Worker dt_entry.dt_offset = dt_offset 515*13e8728fSAndroid Build Coastguard Worker compressed_entry, dt_entry.size = self.compress_dt_entry(dt_entry_compression_info, 516*13e8728fSAndroid Build Coastguard Worker dt_entry.dt_file) 517*13e8728fSAndroid Build Coastguard Worker dt_entry_buf += compressed_entry 518*13e8728fSAndroid Build Coastguard Worker dt_offset += dt_entry.size 519*13e8728fSAndroid Build Coastguard Worker self.total_size += dt_entry.size 520*13e8728fSAndroid Build Coastguard Worker self.__dt_entries.append(dt_entry) 521*13e8728fSAndroid Build Coastguard Worker self.dt_entry_count += 1 522*13e8728fSAndroid Build Coastguard Worker self.__metadata_size += self.dt_entry_size 523*13e8728fSAndroid Build Coastguard Worker self.total_size += self.dt_entry_size 524*13e8728fSAndroid Build Coastguard Worker 525*13e8728fSAndroid Build Coastguard Worker return dt_entry_buf 526*13e8728fSAndroid Build Coastguard Worker 527*13e8728fSAndroid Build Coastguard Worker def extract_dt_file(self, idx, fout, decompress): 528*13e8728fSAndroid Build Coastguard Worker """Extract DT Image files embedded in the DTBO file. 529*13e8728fSAndroid Build Coastguard Worker 530*13e8728fSAndroid Build Coastguard Worker Extracts Device Tree blob image file at given index into a file handle. 531*13e8728fSAndroid Build Coastguard Worker 532*13e8728fSAndroid Build Coastguard Worker Args: 533*13e8728fSAndroid Build Coastguard Worker idx: Index of the DT entry in the DTBO file. 534*13e8728fSAndroid Build Coastguard Worker fout: File handle where the DTB at index idx to be extracted into. 535*13e8728fSAndroid Build Coastguard Worker decompress: If a DT entry is compressed, decompress it before writing 536*13e8728fSAndroid Build Coastguard Worker it to the file handle. 537*13e8728fSAndroid Build Coastguard Worker 538*13e8728fSAndroid Build Coastguard Worker Raises: 539*13e8728fSAndroid Build Coastguard Worker ValueError: if invalid DT entry index or compression format is detected. 540*13e8728fSAndroid Build Coastguard Worker """ 541*13e8728fSAndroid Build Coastguard Worker if idx > self.dt_entry_count: 542*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid index %d of DtEntry' % idx) 543*13e8728fSAndroid Build Coastguard Worker 544*13e8728fSAndroid Build Coastguard Worker size = self.dt_entries[idx].size 545*13e8728fSAndroid Build Coastguard Worker offset = self.dt_entries[idx].dt_offset 546*13e8728fSAndroid Build Coastguard Worker self.__file.seek(offset, 0) 547*13e8728fSAndroid Build Coastguard Worker fout.seek(0) 548*13e8728fSAndroid Build Coastguard Worker compression_format = self.dt_entries[idx].compression_info() 549*13e8728fSAndroid Build Coastguard Worker if decompress and compression_format: 550*13e8728fSAndroid Build Coastguard Worker if (compression_format == CompressionFormat.ZLIB_COMPRESSION or 551*13e8728fSAndroid Build Coastguard Worker compression_format == CompressionFormat.GZIP_COMPRESSION): 552*13e8728fSAndroid Build Coastguard Worker fout.write(zlib.decompress(self.__file.read(size), self._ZLIB_DECOMPRESSION_WBITS)) 553*13e8728fSAndroid Build Coastguard Worker else: 554*13e8728fSAndroid Build Coastguard Worker raise ValueError("Unknown compression format detected") 555*13e8728fSAndroid Build Coastguard Worker else: 556*13e8728fSAndroid Build Coastguard Worker fout.write(self.__file.read(size)) 557*13e8728fSAndroid Build Coastguard Worker 558*13e8728fSAndroid Build Coastguard Worker def commit(self, dt_entry_buf): 559*13e8728fSAndroid Build Coastguard Worker """Write out staged changes to the DTBO object to create a DTBO file. 560*13e8728fSAndroid Build Coastguard Worker 561*13e8728fSAndroid Build Coastguard Worker Writes a fully instantiated Dtbo Object into the output file using the 562*13e8728fSAndroid Build Coastguard Worker file handle present in '_file'. No checks are performed on the object 563*13e8728fSAndroid Build Coastguard Worker except for existence of output file handle on the object before writing 564*13e8728fSAndroid Build Coastguard Worker out the file. 565*13e8728fSAndroid Build Coastguard Worker 566*13e8728fSAndroid Build Coastguard Worker Args: 567*13e8728fSAndroid Build Coastguard Worker dt_entry_buf: Buffer containing all DT entries. 568*13e8728fSAndroid Build Coastguard Worker """ 569*13e8728fSAndroid Build Coastguard Worker if not self.__file: 570*13e8728fSAndroid Build Coastguard Worker raise ValueError('No file given to write to.') 571*13e8728fSAndroid Build Coastguard Worker 572*13e8728fSAndroid Build Coastguard Worker if not self.__dt_entries: 573*13e8728fSAndroid Build Coastguard Worker raise ValueError('No DT image files to embed into DTBO image given.') 574*13e8728fSAndroid Build Coastguard Worker 575*13e8728fSAndroid Build Coastguard Worker self._update_metadata() 576*13e8728fSAndroid Build Coastguard Worker 577*13e8728fSAndroid Build Coastguard Worker self.__file.seek(0) 578*13e8728fSAndroid Build Coastguard Worker self.__file.write(self.__metadata) 579*13e8728fSAndroid Build Coastguard Worker self.__file.write(dt_entry_buf) 580*13e8728fSAndroid Build Coastguard Worker self.__file.flush() 581*13e8728fSAndroid Build Coastguard Worker 582*13e8728fSAndroid Build Coastguard Worker 583*13e8728fSAndroid Build Coastguard Workerdef parse_dt_entry(global_args, arglist): 584*13e8728fSAndroid Build Coastguard Worker """Parse arguments for single DT entry file. 585*13e8728fSAndroid Build Coastguard Worker 586*13e8728fSAndroid Build Coastguard Worker Parses command line arguments for single DT image file while 587*13e8728fSAndroid Build Coastguard Worker creating a Device tree blob overlay (DTBO). 588*13e8728fSAndroid Build Coastguard Worker 589*13e8728fSAndroid Build Coastguard Worker Args: 590*13e8728fSAndroid Build Coastguard Worker global_args: Dtbo object containing global default values 591*13e8728fSAndroid Build Coastguard Worker for DtEntry attributes. 592*13e8728fSAndroid Build Coastguard Worker arglist: Command line argument list for this DtEntry. 593*13e8728fSAndroid Build Coastguard Worker 594*13e8728fSAndroid Build Coastguard Worker Returns: 595*13e8728fSAndroid Build Coastguard Worker A Namespace object containing all values to instantiate DtEntry object. 596*13e8728fSAndroid Build Coastguard Worker """ 597*13e8728fSAndroid Build Coastguard Worker 598*13e8728fSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(add_help=False) 599*13e8728fSAndroid Build Coastguard Worker parser.add_argument('dt_file', nargs='?', 600*13e8728fSAndroid Build Coastguard Worker type=argparse.FileType('rb'), 601*13e8728fSAndroid Build Coastguard Worker default=None) 602*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--id', type=str, dest='id', action='store', 603*13e8728fSAndroid Build Coastguard Worker default=global_args.global_id) 604*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--rev', type=str, dest='rev', 605*13e8728fSAndroid Build Coastguard Worker action='store', default=global_args.global_rev) 606*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--flags', type=str, dest='flags', 607*13e8728fSAndroid Build Coastguard Worker action='store', 608*13e8728fSAndroid Build Coastguard Worker default=global_args.global_flags) 609*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom0', type=str, dest='custom0', 610*13e8728fSAndroid Build Coastguard Worker action='store', 611*13e8728fSAndroid Build Coastguard Worker default=global_args.global_custom0) 612*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom1', type=str, dest='custom1', 613*13e8728fSAndroid Build Coastguard Worker action='store', 614*13e8728fSAndroid Build Coastguard Worker default=global_args.global_custom1) 615*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom2', type=str, dest='custom2', 616*13e8728fSAndroid Build Coastguard Worker action='store', 617*13e8728fSAndroid Build Coastguard Worker default=global_args.global_custom2) 618*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom3', type=str, dest='custom3', 619*13e8728fSAndroid Build Coastguard Worker action='store', 620*13e8728fSAndroid Build Coastguard Worker default=global_args.global_custom3) 621*13e8728fSAndroid Build Coastguard Worker return parser.parse_args(arglist) 622*13e8728fSAndroid Build Coastguard Worker 623*13e8728fSAndroid Build Coastguard Worker 624*13e8728fSAndroid Build Coastguard Workerdef parse_dt_entries(global_args, arg_list): 625*13e8728fSAndroid Build Coastguard Worker """Parse all DT entries from command line. 626*13e8728fSAndroid Build Coastguard Worker 627*13e8728fSAndroid Build Coastguard Worker Parse all DT image files and their corresponding attribute from 628*13e8728fSAndroid Build Coastguard Worker command line 629*13e8728fSAndroid Build Coastguard Worker 630*13e8728fSAndroid Build Coastguard Worker Args: 631*13e8728fSAndroid Build Coastguard Worker global_args: Argument containing default global values for _id, 632*13e8728fSAndroid Build Coastguard Worker _rev and customX. 633*13e8728fSAndroid Build Coastguard Worker arg_list: The remainder of the command line after global options 634*13e8728fSAndroid Build Coastguard Worker DTBO creation have been parsed. 635*13e8728fSAndroid Build Coastguard Worker 636*13e8728fSAndroid Build Coastguard Worker Returns: 637*13e8728fSAndroid Build Coastguard Worker A List of DtEntry objects created after parsing the command line 638*13e8728fSAndroid Build Coastguard Worker given in argument. 639*13e8728fSAndroid Build Coastguard Worker """ 640*13e8728fSAndroid Build Coastguard Worker dt_entries = [] 641*13e8728fSAndroid Build Coastguard Worker img_file_idx = [] 642*13e8728fSAndroid Build Coastguard Worker idx = 0 643*13e8728fSAndroid Build Coastguard Worker # find all positional arguments (i.e. DT image file paths) 644*13e8728fSAndroid Build Coastguard Worker for arg in arg_list: 645*13e8728fSAndroid Build Coastguard Worker if not arg.startswith("--"): 646*13e8728fSAndroid Build Coastguard Worker img_file_idx.append(idx) 647*13e8728fSAndroid Build Coastguard Worker idx = idx + 1 648*13e8728fSAndroid Build Coastguard Worker 649*13e8728fSAndroid Build Coastguard Worker if not img_file_idx: 650*13e8728fSAndroid Build Coastguard Worker raise ValueError('Input DT images must be provided') 651*13e8728fSAndroid Build Coastguard Worker 652*13e8728fSAndroid Build Coastguard Worker total_images = len(img_file_idx) 653*13e8728fSAndroid Build Coastguard Worker for idx in range(total_images): 654*13e8728fSAndroid Build Coastguard Worker start_idx = img_file_idx[idx] 655*13e8728fSAndroid Build Coastguard Worker if idx == total_images - 1: 656*13e8728fSAndroid Build Coastguard Worker argv = arg_list[start_idx:] 657*13e8728fSAndroid Build Coastguard Worker else: 658*13e8728fSAndroid Build Coastguard Worker end_idx = img_file_idx[idx + 1] 659*13e8728fSAndroid Build Coastguard Worker argv = arg_list[start_idx:end_idx] 660*13e8728fSAndroid Build Coastguard Worker args = parse_dt_entry(global_args, argv) 661*13e8728fSAndroid Build Coastguard Worker params = vars(args) 662*13e8728fSAndroid Build Coastguard Worker params['version'] = global_args.version 663*13e8728fSAndroid Build Coastguard Worker params['dt_offset'] = 0 664*13e8728fSAndroid Build Coastguard Worker params['dt_size'] = os.fstat(params['dt_file'].fileno()).st_size 665*13e8728fSAndroid Build Coastguard Worker dt_entries.append(DtEntry(**params)) 666*13e8728fSAndroid Build Coastguard Worker 667*13e8728fSAndroid Build Coastguard Worker return dt_entries 668*13e8728fSAndroid Build Coastguard Worker 669*13e8728fSAndroid Build Coastguard Workerdef parse_config_option(line, is_global, dt_keys, global_key_types): 670*13e8728fSAndroid Build Coastguard Worker """Parses a single line from the configuration file. 671*13e8728fSAndroid Build Coastguard Worker 672*13e8728fSAndroid Build Coastguard Worker Args: 673*13e8728fSAndroid Build Coastguard Worker line: String containing the key=value line from the file. 674*13e8728fSAndroid Build Coastguard Worker is_global: Boolean indicating if we should parse global or DT entry 675*13e8728fSAndroid Build Coastguard Worker specific option. 676*13e8728fSAndroid Build Coastguard Worker dt_keys: Tuple containing all valid DT entry and global option strings 677*13e8728fSAndroid Build Coastguard Worker in configuration file. 678*13e8728fSAndroid Build Coastguard Worker global_key_types: A dict of global options and their corresponding types. It 679*13e8728fSAndroid Build Coastguard Worker contains all exclusive valid global option strings in configuration 680*13e8728fSAndroid Build Coastguard Worker file that are not repeated in dt entry options. 681*13e8728fSAndroid Build Coastguard Worker 682*13e8728fSAndroid Build Coastguard Worker Returns: 683*13e8728fSAndroid Build Coastguard Worker Returns a tuple for parsed key and value for the option. Also, checks 684*13e8728fSAndroid Build Coastguard Worker the key to make sure its valid. 685*13e8728fSAndroid Build Coastguard Worker """ 686*13e8728fSAndroid Build Coastguard Worker 687*13e8728fSAndroid Build Coastguard Worker if line.find('=') == -1: 688*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid line (%s) in configuration file' % line) 689*13e8728fSAndroid Build Coastguard Worker 690*13e8728fSAndroid Build Coastguard Worker key, value = (x.strip() for x in line.split('=')) 691*13e8728fSAndroid Build Coastguard Worker if is_global and key in global_key_types: 692*13e8728fSAndroid Build Coastguard Worker if global_key_types[key] is int: 693*13e8728fSAndroid Build Coastguard Worker value = int(value) 694*13e8728fSAndroid Build Coastguard Worker elif key not in dt_keys: 695*13e8728fSAndroid Build Coastguard Worker raise ValueError('Invalid option (%s) in configuration file' % key) 696*13e8728fSAndroid Build Coastguard Worker 697*13e8728fSAndroid Build Coastguard Worker return key, value 698*13e8728fSAndroid Build Coastguard Worker 699*13e8728fSAndroid Build Coastguard Workerdef parse_config_file(fin, dt_keys, global_key_types): 700*13e8728fSAndroid Build Coastguard Worker """Parses the configuration file for creating DTBO image. 701*13e8728fSAndroid Build Coastguard Worker 702*13e8728fSAndroid Build Coastguard Worker Args: 703*13e8728fSAndroid Build Coastguard Worker fin: File handle for configuration file 704*13e8728fSAndroid Build Coastguard Worker is_global: Boolean indicating if we should parse global or DT entry 705*13e8728fSAndroid Build Coastguard Worker specific option. 706*13e8728fSAndroid Build Coastguard Worker dt_keys: Tuple containing all valid DT entry and global option strings 707*13e8728fSAndroid Build Coastguard Worker in configuration file. 708*13e8728fSAndroid Build Coastguard Worker global_key_types: A dict of global options and their corresponding types. It 709*13e8728fSAndroid Build Coastguard Worker contains all exclusive valid global option strings in configuration 710*13e8728fSAndroid Build Coastguard Worker file that are not repeated in dt entry options. 711*13e8728fSAndroid Build Coastguard Worker 712*13e8728fSAndroid Build Coastguard Worker Returns: 713*13e8728fSAndroid Build Coastguard Worker global_args, dt_args: Tuple of a dictionary with global arguments 714*13e8728fSAndroid Build Coastguard Worker and a list of dictionaries for all DT entry specific arguments the 715*13e8728fSAndroid Build Coastguard Worker following format. 716*13e8728fSAndroid Build Coastguard Worker global_args: 717*13e8728fSAndroid Build Coastguard Worker {'id' : <value>, 'rev' : <value> ...} 718*13e8728fSAndroid Build Coastguard Worker dt_args: 719*13e8728fSAndroid Build Coastguard Worker [{'filename' : 'dt_file_name', 'id' : <value>, 720*13e8728fSAndroid Build Coastguard Worker 'rev' : <value> ...}, 721*13e8728fSAndroid Build Coastguard Worker {'filename' : 'dt_file_name2', 'id' : <value2>, 722*13e8728fSAndroid Build Coastguard Worker 'rev' : <value2> ...}, ... 723*13e8728fSAndroid Build Coastguard Worker ] 724*13e8728fSAndroid Build Coastguard Worker """ 725*13e8728fSAndroid Build Coastguard Worker 726*13e8728fSAndroid Build Coastguard Worker # set all global defaults 727*13e8728fSAndroid Build Coastguard Worker global_args = dict((k, '0') for k in dt_keys) 728*13e8728fSAndroid Build Coastguard Worker global_args['dt_type'] = 'dtb' 729*13e8728fSAndroid Build Coastguard Worker global_args['page_size'] = 2048 730*13e8728fSAndroid Build Coastguard Worker global_args['version'] = 0 731*13e8728fSAndroid Build Coastguard Worker 732*13e8728fSAndroid Build Coastguard Worker dt_args = [] 733*13e8728fSAndroid Build Coastguard Worker found_dt_entry = False 734*13e8728fSAndroid Build Coastguard Worker count = -1 735*13e8728fSAndroid Build Coastguard Worker for line in fin: 736*13e8728fSAndroid Build Coastguard Worker line = line.rstrip() 737*13e8728fSAndroid Build Coastguard Worker if line.lstrip().startswith('#'): 738*13e8728fSAndroid Build Coastguard Worker continue 739*13e8728fSAndroid Build Coastguard Worker comment_idx = line.find('#') 740*13e8728fSAndroid Build Coastguard Worker line = line if comment_idx == -1 else line[0:comment_idx] 741*13e8728fSAndroid Build Coastguard Worker if not line or line.isspace(): 742*13e8728fSAndroid Build Coastguard Worker continue 743*13e8728fSAndroid Build Coastguard Worker if line.startswith((' ', '\t')) and not found_dt_entry: 744*13e8728fSAndroid Build Coastguard Worker # This is a global argument 745*13e8728fSAndroid Build Coastguard Worker key, value = parse_config_option(line, True, dt_keys, global_key_types) 746*13e8728fSAndroid Build Coastguard Worker global_args[key] = value 747*13e8728fSAndroid Build Coastguard Worker elif line.find('=') != -1: 748*13e8728fSAndroid Build Coastguard Worker key, value = parse_config_option(line, False, dt_keys, global_key_types) 749*13e8728fSAndroid Build Coastguard Worker dt_args[-1][key] = value 750*13e8728fSAndroid Build Coastguard Worker else: 751*13e8728fSAndroid Build Coastguard Worker found_dt_entry = True 752*13e8728fSAndroid Build Coastguard Worker count += 1 753*13e8728fSAndroid Build Coastguard Worker dt_args.append({}) 754*13e8728fSAndroid Build Coastguard Worker dt_args[-1]['filename'] = line.strip() 755*13e8728fSAndroid Build Coastguard Worker return global_args, dt_args 756*13e8728fSAndroid Build Coastguard Worker 757*13e8728fSAndroid Build Coastguard Workerdef parse_create_args(arg_list): 758*13e8728fSAndroid Build Coastguard Worker """Parse command line arguments for 'create' sub-command. 759*13e8728fSAndroid Build Coastguard Worker 760*13e8728fSAndroid Build Coastguard Worker Args: 761*13e8728fSAndroid Build Coastguard Worker arg_list: All command line arguments except the outfile file name. 762*13e8728fSAndroid Build Coastguard Worker 763*13e8728fSAndroid Build Coastguard Worker Returns: 764*13e8728fSAndroid Build Coastguard Worker The list of remainder of the command line arguments after parsing 765*13e8728fSAndroid Build Coastguard Worker for 'create'. 766*13e8728fSAndroid Build Coastguard Worker """ 767*13e8728fSAndroid Build Coastguard Worker 768*13e8728fSAndroid Build Coastguard Worker image_arg_index = 0 769*13e8728fSAndroid Build Coastguard Worker for arg in arg_list: 770*13e8728fSAndroid Build Coastguard Worker if not arg.startswith("--"): 771*13e8728fSAndroid Build Coastguard Worker break 772*13e8728fSAndroid Build Coastguard Worker image_arg_index = image_arg_index + 1 773*13e8728fSAndroid Build Coastguard Worker 774*13e8728fSAndroid Build Coastguard Worker argv = arg_list[0:image_arg_index] 775*13e8728fSAndroid Build Coastguard Worker remainder = arg_list[image_arg_index:] 776*13e8728fSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(prog='create', add_help=False) 777*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--dt_type', type=str, dest='dt_type', 778*13e8728fSAndroid Build Coastguard Worker action='store', default='dtb') 779*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--page_size', type=int, dest='page_size', 780*13e8728fSAndroid Build Coastguard Worker action='store', default=2048) 781*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--version', type=int, dest='version', 782*13e8728fSAndroid Build Coastguard Worker action='store', default=0) 783*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--id', type=str, dest='global_id', 784*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 785*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--rev', type=str, dest='global_rev', 786*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 787*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--flags', type=str, dest='global_flags', 788*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 789*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom0', type=str, dest='global_custom0', 790*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 791*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom1', type=str, dest='global_custom1', 792*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 793*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom2', type=str, dest='global_custom2', 794*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 795*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--custom3', type=str, dest='global_custom3', 796*13e8728fSAndroid Build Coastguard Worker action='store', default='0') 797*13e8728fSAndroid Build Coastguard Worker args = parser.parse_args(argv) 798*13e8728fSAndroid Build Coastguard Worker return args, remainder 799*13e8728fSAndroid Build Coastguard Worker 800*13e8728fSAndroid Build Coastguard Workerdef parse_dump_cmd_args(arglist): 801*13e8728fSAndroid Build Coastguard Worker """Parse command line arguments for 'dump' sub-command. 802*13e8728fSAndroid Build Coastguard Worker 803*13e8728fSAndroid Build Coastguard Worker Args: 804*13e8728fSAndroid Build Coastguard Worker arglist: List of all command line arguments including the outfile 805*13e8728fSAndroid Build Coastguard Worker file name if exists. 806*13e8728fSAndroid Build Coastguard Worker 807*13e8728fSAndroid Build Coastguard Worker Returns: 808*13e8728fSAndroid Build Coastguard Worker A namespace object of parsed arguments. 809*13e8728fSAndroid Build Coastguard Worker """ 810*13e8728fSAndroid Build Coastguard Worker 811*13e8728fSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(prog='dump') 812*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--output', '-o', nargs='?', 813*13e8728fSAndroid Build Coastguard Worker type=argparse.FileType('w'), 814*13e8728fSAndroid Build Coastguard Worker dest='outfile', 815*13e8728fSAndroid Build Coastguard Worker default=stdout) 816*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--dtb', '-b', nargs='?', type=str, 817*13e8728fSAndroid Build Coastguard Worker dest='dtfilename') 818*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--decompress', action='store_true', dest='decompress') 819*13e8728fSAndroid Build Coastguard Worker return parser.parse_args(arglist) 820*13e8728fSAndroid Build Coastguard Worker 821*13e8728fSAndroid Build Coastguard Workerdef parse_config_create_cmd_args(arglist): 822*13e8728fSAndroid Build Coastguard Worker """Parse command line arguments for 'cfg_create subcommand. 823*13e8728fSAndroid Build Coastguard Worker 824*13e8728fSAndroid Build Coastguard Worker Args: 825*13e8728fSAndroid Build Coastguard Worker arglist: A list of all command line arguments including the 826*13e8728fSAndroid Build Coastguard Worker mandatory input configuration file name. 827*13e8728fSAndroid Build Coastguard Worker 828*13e8728fSAndroid Build Coastguard Worker Returns: 829*13e8728fSAndroid Build Coastguard Worker A Namespace object of parsed arguments. 830*13e8728fSAndroid Build Coastguard Worker """ 831*13e8728fSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(prog='cfg_create') 832*13e8728fSAndroid Build Coastguard Worker parser.add_argument('conf_file', nargs='?', 833*13e8728fSAndroid Build Coastguard Worker type=argparse.FileType('r'), 834*13e8728fSAndroid Build Coastguard Worker default=None) 835*13e8728fSAndroid Build Coastguard Worker cwd = os.getcwd() 836*13e8728fSAndroid Build Coastguard Worker parser.add_argument('--dtb-dir', '-d', nargs='?', type=str, 837*13e8728fSAndroid Build Coastguard Worker dest='dtbdir', default=cwd) 838*13e8728fSAndroid Build Coastguard Worker return parser.parse_args(arglist) 839*13e8728fSAndroid Build Coastguard Worker 840*13e8728fSAndroid Build Coastguard Workerdef create_dtbo_image(fout, argv): 841*13e8728fSAndroid Build Coastguard Worker """Create Device Tree Blob Overlay image using provided arguments. 842*13e8728fSAndroid Build Coastguard Worker 843*13e8728fSAndroid Build Coastguard Worker Args: 844*13e8728fSAndroid Build Coastguard Worker fout: Output file handle to write to. 845*13e8728fSAndroid Build Coastguard Worker argv: list of command line arguments. 846*13e8728fSAndroid Build Coastguard Worker """ 847*13e8728fSAndroid Build Coastguard Worker 848*13e8728fSAndroid Build Coastguard Worker global_args, remainder = parse_create_args(argv) 849*13e8728fSAndroid Build Coastguard Worker if not remainder: 850*13e8728fSAndroid Build Coastguard Worker raise ValueError('List of dtimages to add to DTBO not provided') 851*13e8728fSAndroid Build Coastguard Worker dt_entries = parse_dt_entries(global_args, remainder) 852*13e8728fSAndroid Build Coastguard Worker dtbo = Dtbo(fout, global_args.dt_type, global_args.page_size, global_args.version) 853*13e8728fSAndroid Build Coastguard Worker dt_entry_buf = dtbo.add_dt_entries(dt_entries) 854*13e8728fSAndroid Build Coastguard Worker dtbo.commit(dt_entry_buf) 855*13e8728fSAndroid Build Coastguard Worker fout.close() 856*13e8728fSAndroid Build Coastguard Worker 857*13e8728fSAndroid Build Coastguard Workerdef dump_dtbo_image(fin, argv): 858*13e8728fSAndroid Build Coastguard Worker """Dump DTBO file. 859*13e8728fSAndroid Build Coastguard Worker 860*13e8728fSAndroid Build Coastguard Worker Dump Device Tree Blob Overlay metadata as output and the device 861*13e8728fSAndroid Build Coastguard Worker tree image files embedded in the DTBO image into file(s) provided 862*13e8728fSAndroid Build Coastguard Worker as arguments 863*13e8728fSAndroid Build Coastguard Worker 864*13e8728fSAndroid Build Coastguard Worker Args: 865*13e8728fSAndroid Build Coastguard Worker fin: Input DTBO image files. 866*13e8728fSAndroid Build Coastguard Worker argv: list of command line arguments. 867*13e8728fSAndroid Build Coastguard Worker """ 868*13e8728fSAndroid Build Coastguard Worker dtbo = Dtbo(fin) 869*13e8728fSAndroid Build Coastguard Worker args = parse_dump_cmd_args(argv) 870*13e8728fSAndroid Build Coastguard Worker if args.dtfilename: 871*13e8728fSAndroid Build Coastguard Worker num_entries = len(dtbo.dt_entries) 872*13e8728fSAndroid Build Coastguard Worker for idx in range(0, num_entries): 873*13e8728fSAndroid Build Coastguard Worker with open(args.dtfilename + '.{:d}'.format(idx), 'wb') as fout: 874*13e8728fSAndroid Build Coastguard Worker dtbo.extract_dt_file(idx, fout, args.decompress) 875*13e8728fSAndroid Build Coastguard Worker args.outfile.write(str(dtbo) + '\n') 876*13e8728fSAndroid Build Coastguard Worker args.outfile.close() 877*13e8728fSAndroid Build Coastguard Worker 878*13e8728fSAndroid Build Coastguard Workerdef create_dtbo_image_from_config(fout, argv): 879*13e8728fSAndroid Build Coastguard Worker """Create DTBO file from a configuration file. 880*13e8728fSAndroid Build Coastguard Worker 881*13e8728fSAndroid Build Coastguard Worker Args: 882*13e8728fSAndroid Build Coastguard Worker fout: Output file handle to write to. 883*13e8728fSAndroid Build Coastguard Worker argv: list of command line arguments. 884*13e8728fSAndroid Build Coastguard Worker """ 885*13e8728fSAndroid Build Coastguard Worker args = parse_config_create_cmd_args(argv) 886*13e8728fSAndroid Build Coastguard Worker if not args.conf_file: 887*13e8728fSAndroid Build Coastguard Worker raise ValueError('Configuration file must be provided') 888*13e8728fSAndroid Build Coastguard Worker 889*13e8728fSAndroid Build Coastguard Worker _DT_KEYS = ('id', 'rev', 'flags', 'custom0', 'custom1', 'custom2', 'custom3') 890*13e8728fSAndroid Build Coastguard Worker _GLOBAL_KEY_TYPES = {'dt_type': str, 'page_size': int, 'version': int} 891*13e8728fSAndroid Build Coastguard Worker 892*13e8728fSAndroid Build Coastguard Worker global_args, dt_args = parse_config_file(args.conf_file, 893*13e8728fSAndroid Build Coastguard Worker _DT_KEYS, _GLOBAL_KEY_TYPES) 894*13e8728fSAndroid Build Coastguard Worker version = global_args['version'] 895*13e8728fSAndroid Build Coastguard Worker 896*13e8728fSAndroid Build Coastguard Worker params = {} 897*13e8728fSAndroid Build Coastguard Worker params['version'] = version 898*13e8728fSAndroid Build Coastguard Worker dt_entries = [] 899*13e8728fSAndroid Build Coastguard Worker for dt_arg in dt_args: 900*13e8728fSAndroid Build Coastguard Worker filepath = dt_arg['filename'] 901*13e8728fSAndroid Build Coastguard Worker if not os.path.isabs(filepath): 902*13e8728fSAndroid Build Coastguard Worker for root, dirnames, filenames in os.walk(args.dtbdir): 903*13e8728fSAndroid Build Coastguard Worker for filename in fnmatch.filter(filenames, os.path.basename(filepath)): 904*13e8728fSAndroid Build Coastguard Worker filepath = os.path.join(root, filename) 905*13e8728fSAndroid Build Coastguard Worker params['dt_file'] = open(filepath, 'rb') 906*13e8728fSAndroid Build Coastguard Worker params['dt_offset'] = 0 907*13e8728fSAndroid Build Coastguard Worker params['dt_size'] = os.fstat(params['dt_file'].fileno()).st_size 908*13e8728fSAndroid Build Coastguard Worker for key in _DT_KEYS: 909*13e8728fSAndroid Build Coastguard Worker if key not in dt_arg: 910*13e8728fSAndroid Build Coastguard Worker params[key] = global_args[key] 911*13e8728fSAndroid Build Coastguard Worker else: 912*13e8728fSAndroid Build Coastguard Worker params[key] = dt_arg[key] 913*13e8728fSAndroid Build Coastguard Worker dt_entries.append(DtEntry(**params)) 914*13e8728fSAndroid Build Coastguard Worker 915*13e8728fSAndroid Build Coastguard Worker # Create and write DTBO file 916*13e8728fSAndroid Build Coastguard Worker dtbo = Dtbo(fout, global_args['dt_type'], global_args['page_size'], version) 917*13e8728fSAndroid Build Coastguard Worker dt_entry_buf = dtbo.add_dt_entries(dt_entries) 918*13e8728fSAndroid Build Coastguard Worker dtbo.commit(dt_entry_buf) 919*13e8728fSAndroid Build Coastguard Worker fout.close() 920*13e8728fSAndroid Build Coastguard Worker 921*13e8728fSAndroid Build Coastguard Workerdef print_default_usage(progname): 922*13e8728fSAndroid Build Coastguard Worker """Prints program's default help string. 923*13e8728fSAndroid Build Coastguard Worker 924*13e8728fSAndroid Build Coastguard Worker Args: 925*13e8728fSAndroid Build Coastguard Worker progname: This program's name. 926*13e8728fSAndroid Build Coastguard Worker """ 927*13e8728fSAndroid Build Coastguard Worker sb = [] 928*13e8728fSAndroid Build Coastguard Worker sb.append(' ' + progname + ' help all') 929*13e8728fSAndroid Build Coastguard Worker sb.append(' ' + progname + ' help <command>\n') 930*13e8728fSAndroid Build Coastguard Worker sb.append(' commands:') 931*13e8728fSAndroid Build Coastguard Worker sb.append(' help, dump, create, cfg_create') 932*13e8728fSAndroid Build Coastguard Worker print('\n'.join(sb)) 933*13e8728fSAndroid Build Coastguard Worker 934*13e8728fSAndroid Build Coastguard Workerdef print_dump_usage(progname): 935*13e8728fSAndroid Build Coastguard Worker """Prints usage for 'dump' sub-command. 936*13e8728fSAndroid Build Coastguard Worker 937*13e8728fSAndroid Build Coastguard Worker Args: 938*13e8728fSAndroid Build Coastguard Worker progname: This program's name. 939*13e8728fSAndroid Build Coastguard Worker """ 940*13e8728fSAndroid Build Coastguard Worker sb = [] 941*13e8728fSAndroid Build Coastguard Worker sb.append(' ' + progname + ' dump <image_file> (<option>...)\n') 942*13e8728fSAndroid Build Coastguard Worker sb.append(' options:') 943*13e8728fSAndroid Build Coastguard Worker sb.append(' -o, --output <filename> Output file name.') 944*13e8728fSAndroid Build Coastguard Worker sb.append(' Default is output to stdout.') 945*13e8728fSAndroid Build Coastguard Worker sb.append(' -b, --dtb <filename> Dump dtb/dtbo files from image.') 946*13e8728fSAndroid Build Coastguard Worker sb.append(' Will output to <filename>.0, <filename>.1, etc.') 947*13e8728fSAndroid Build Coastguard Worker print('\n'.join(sb)) 948*13e8728fSAndroid Build Coastguard Worker 949*13e8728fSAndroid Build Coastguard Workerdef print_create_usage(progname): 950*13e8728fSAndroid Build Coastguard Worker """Prints usage for 'create' subcommand. 951*13e8728fSAndroid Build Coastguard Worker 952*13e8728fSAndroid Build Coastguard Worker Args: 953*13e8728fSAndroid Build Coastguard Worker progname: This program's name. 954*13e8728fSAndroid Build Coastguard Worker """ 955*13e8728fSAndroid Build Coastguard Worker sb = [] 956*13e8728fSAndroid Build Coastguard Worker sb.append(' ' + progname + ' create <image_file> (<global_option>...) (<dtb_file> (<entry_option>...) ...)\n') 957*13e8728fSAndroid Build Coastguard Worker sb.append(' global_options:') 958*13e8728fSAndroid Build Coastguard Worker sb.append(' --dt_type=<type> Device Tree Type (dtb|acpi). Default: dtb') 959*13e8728fSAndroid Build Coastguard Worker sb.append(' --page_size=<number> Page size. Default: 2048') 960*13e8728fSAndroid Build Coastguard Worker sb.append(' --version=<number> DTBO/ACPIO version. Default: 0') 961*13e8728fSAndroid Build Coastguard Worker sb.append(' --id=<number> The default value to set property id in dt_table_entry. Default: 0') 962*13e8728fSAndroid Build Coastguard Worker sb.append(' --rev=<number>') 963*13e8728fSAndroid Build Coastguard Worker sb.append(' --flags=<number>') 964*13e8728fSAndroid Build Coastguard Worker sb.append(' --custom0=<number>') 965*13e8728fSAndroid Build Coastguard Worker sb.append(' --custom1=<number>') 966*13e8728fSAndroid Build Coastguard Worker sb.append(' --custom2=<number>\n') 967*13e8728fSAndroid Build Coastguard Worker sb.append(' --custom3=<number>\n') 968*13e8728fSAndroid Build Coastguard Worker 969*13e8728fSAndroid Build Coastguard Worker sb.append(' The value could be a number or a DT node path.') 970*13e8728fSAndroid Build Coastguard Worker sb.append(' <number> could be a 32-bits digit or hex value, ex. 68000, 0x6800.') 971*13e8728fSAndroid Build Coastguard Worker sb.append(' <path> format is <full_node_path>:<property_name>, ex. /board/:id,') 972*13e8728fSAndroid Build Coastguard Worker sb.append(' will read the value in given FTB file with the path.') 973*13e8728fSAndroid Build Coastguard Worker print('\n'.join(sb)) 974*13e8728fSAndroid Build Coastguard Worker 975*13e8728fSAndroid Build Coastguard Workerdef print_cfg_create_usage(progname): 976*13e8728fSAndroid Build Coastguard Worker """Prints usage for 'cfg_create' sub-command. 977*13e8728fSAndroid Build Coastguard Worker 978*13e8728fSAndroid Build Coastguard Worker Args: 979*13e8728fSAndroid Build Coastguard Worker progname: This program's name. 980*13e8728fSAndroid Build Coastguard Worker """ 981*13e8728fSAndroid Build Coastguard Worker sb = [] 982*13e8728fSAndroid Build Coastguard Worker sb.append(' ' + progname + ' cfg_create <image_file> <config_file> (<option>...)\n') 983*13e8728fSAndroid Build Coastguard Worker sb.append(' options:') 984*13e8728fSAndroid Build Coastguard Worker sb.append(' -d, --dtb-dir <dir> The path to load dtb files.') 985*13e8728fSAndroid Build Coastguard Worker sb.append(' Default is load from the current path.') 986*13e8728fSAndroid Build Coastguard Worker print('\n'.join(sb)) 987*13e8728fSAndroid Build Coastguard Worker 988*13e8728fSAndroid Build Coastguard Workerdef print_usage(cmd, _): 989*13e8728fSAndroid Build Coastguard Worker """Prints usage for this program. 990*13e8728fSAndroid Build Coastguard Worker 991*13e8728fSAndroid Build Coastguard Worker Args: 992*13e8728fSAndroid Build Coastguard Worker cmd: The string sub-command for which help (usage) is requested. 993*13e8728fSAndroid Build Coastguard Worker """ 994*13e8728fSAndroid Build Coastguard Worker prog_name = os.path.basename(__file__) 995*13e8728fSAndroid Build Coastguard Worker if not cmd: 996*13e8728fSAndroid Build Coastguard Worker print_default_usage(prog_name) 997*13e8728fSAndroid Build Coastguard Worker return 998*13e8728fSAndroid Build Coastguard Worker 999*13e8728fSAndroid Build Coastguard Worker HelpCommand = namedtuple('HelpCommand', 'help_cmd, help_func') 1000*13e8728fSAndroid Build Coastguard Worker help_commands = (HelpCommand('dump', print_dump_usage), 1001*13e8728fSAndroid Build Coastguard Worker HelpCommand('create', print_create_usage), 1002*13e8728fSAndroid Build Coastguard Worker HelpCommand('cfg_create', print_cfg_create_usage), 1003*13e8728fSAndroid Build Coastguard Worker ) 1004*13e8728fSAndroid Build Coastguard Worker 1005*13e8728fSAndroid Build Coastguard Worker if cmd == 'all': 1006*13e8728fSAndroid Build Coastguard Worker print_default_usage(prog_name) 1007*13e8728fSAndroid Build Coastguard Worker 1008*13e8728fSAndroid Build Coastguard Worker for help_cmd, help_func in help_commands: 1009*13e8728fSAndroid Build Coastguard Worker if cmd == 'all' or cmd == help_cmd: 1010*13e8728fSAndroid Build Coastguard Worker help_func(prog_name) 1011*13e8728fSAndroid Build Coastguard Worker if cmd != 'all': 1012*13e8728fSAndroid Build Coastguard Worker return 1013*13e8728fSAndroid Build Coastguard Worker 1014*13e8728fSAndroid Build Coastguard Worker print('Unsupported help command: %s' % cmd, end='\n\n') 1015*13e8728fSAndroid Build Coastguard Worker print_default_usage(prog_name) 1016*13e8728fSAndroid Build Coastguard Worker return 1017*13e8728fSAndroid Build Coastguard Worker 1018*13e8728fSAndroid Build Coastguard Workerdef main(): 1019*13e8728fSAndroid Build Coastguard Worker """Main entry point for mkdtboimg.""" 1020*13e8728fSAndroid Build Coastguard Worker 1021*13e8728fSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 1022*13e8728fSAndroid Build Coastguard Worker 1023*13e8728fSAndroid Build Coastguard Worker subparser = parser.add_subparsers(title='subcommand', 1024*13e8728fSAndroid Build Coastguard Worker description='Valid subcommands') 1025*13e8728fSAndroid Build Coastguard Worker 1026*13e8728fSAndroid Build Coastguard Worker create_parser = subparser.add_parser('create', add_help=False) 1027*13e8728fSAndroid Build Coastguard Worker create_parser.add_argument('argfile', nargs='?', 1028*13e8728fSAndroid Build Coastguard Worker action='store', help='Output File', 1029*13e8728fSAndroid Build Coastguard Worker type=argparse.FileType('wb')) 1030*13e8728fSAndroid Build Coastguard Worker create_parser.set_defaults(func=create_dtbo_image) 1031*13e8728fSAndroid Build Coastguard Worker 1032*13e8728fSAndroid Build Coastguard Worker config_parser = subparser.add_parser('cfg_create', add_help=False) 1033*13e8728fSAndroid Build Coastguard Worker config_parser.add_argument('argfile', nargs='?', 1034*13e8728fSAndroid Build Coastguard Worker action='store', 1035*13e8728fSAndroid Build Coastguard Worker type=argparse.FileType('wb')) 1036*13e8728fSAndroid Build Coastguard Worker config_parser.set_defaults(func=create_dtbo_image_from_config) 1037*13e8728fSAndroid Build Coastguard Worker 1038*13e8728fSAndroid Build Coastguard Worker dump_parser = subparser.add_parser('dump', add_help=False) 1039*13e8728fSAndroid Build Coastguard Worker dump_parser.add_argument('argfile', nargs='?', 1040*13e8728fSAndroid Build Coastguard Worker action='store', 1041*13e8728fSAndroid Build Coastguard Worker type=argparse.FileType('rb')) 1042*13e8728fSAndroid Build Coastguard Worker dump_parser.set_defaults(func=dump_dtbo_image) 1043*13e8728fSAndroid Build Coastguard Worker 1044*13e8728fSAndroid Build Coastguard Worker help_parser = subparser.add_parser('help', add_help=False) 1045*13e8728fSAndroid Build Coastguard Worker help_parser.add_argument('argfile', nargs='?', action='store') 1046*13e8728fSAndroid Build Coastguard Worker help_parser.set_defaults(func=print_usage) 1047*13e8728fSAndroid Build Coastguard Worker 1048*13e8728fSAndroid Build Coastguard Worker (subcmd, subcmd_args) = parser.parse_known_args() 1049*13e8728fSAndroid Build Coastguard Worker subcmd.func(subcmd.argfile, subcmd_args) 1050*13e8728fSAndroid Build Coastguard Worker 1051*13e8728fSAndroid Build Coastguard Workerif __name__ == '__main__': 1052*13e8728fSAndroid Build Coastguard Worker main() 1053