xref: /aosp_15_r20/system/libufdt/utils/src/mkdtboimg.py (revision 13e8728f0cffde9369df671f7b293a048a99c7ed)
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