xref: /openbmc/u-boot/tools/binman/bsection.py (revision d24c1d0f4da3b081a4fedf7ae2a08790871f08d0)
18f1da50cSSimon Glass# SPDX-License-Identifier: GPL-2.0+
28f1da50cSSimon Glass# Copyright (c) 2018 Google, Inc
38f1da50cSSimon Glass# Written by Simon Glass <sjg@chromium.org>
48f1da50cSSimon Glass#
58f1da50cSSimon Glass# Base class for sections (collections of entries)
68f1da50cSSimon Glass#
78f1da50cSSimon Glass
88f1da50cSSimon Glassfrom __future__ import print_function
98f1da50cSSimon Glass
108f1da50cSSimon Glassfrom collections import OrderedDict
11539aece5SSimon Glassfrom sets import Set
128f1da50cSSimon Glassimport sys
138f1da50cSSimon Glass
148f1da50cSSimon Glassimport fdt_util
158f1da50cSSimon Glassimport re
16f46621d2SSimon Glassimport state
178f1da50cSSimon Glassimport tools
188f1da50cSSimon Glass
198f1da50cSSimon Glassclass Section(object):
208f1da50cSSimon Glass    """A section which contains multiple entries
218f1da50cSSimon Glass
228f1da50cSSimon Glass    A section represents a collection of entries. There must be one or more
238f1da50cSSimon Glass    sections in an image. Sections are used to group entries together.
248f1da50cSSimon Glass
258f1da50cSSimon Glass    Attributes:
268f1da50cSSimon Glass        _node: Node object that contains the section definition in device tree
2708723a7aSSimon Glass        _parent_section: Parent Section object which created this Section
288f1da50cSSimon Glass        _size: Section size in bytes, or None if not known yet
298f1da50cSSimon Glass        _align_size: Section size alignment, or None
308f1da50cSSimon Glass        _pad_before: Number of bytes before the first entry starts. This
313ab9598dSSimon Glass            effectively changes the place where entry offset 0 starts
328f1da50cSSimon Glass        _pad_after: Number of bytes after the last entry ends. The last
338f1da50cSSimon Glass            entry will finish on or before this boundary
348f1da50cSSimon Glass        _pad_byte: Byte to use to pad the section where there is no entry
353ab9598dSSimon Glass        _sort: True if entries should be sorted by offset, False if they
368f1da50cSSimon Glass            must be in-order in the device tree description
378f1da50cSSimon Glass        _skip_at_start: Number of bytes before the first entry starts. These
383ab9598dSSimon Glass            effectively adjust the starting offset of entries. For example,
398f1da50cSSimon Glass            if _pad_before is 16, then the first entry would start at 16.
403ab9598dSSimon Glass            An entry with offset = 20 would in fact be written at offset 4
418f1da50cSSimon Glass            in the image file.
428f1da50cSSimon Glass        _end_4gb: Indicates that the section ends at the 4GB boundary. This is
433ab9598dSSimon Glass            used for x86 images, which want to use offsets such that a memory
443ab9598dSSimon Glass            address (like 0xff800000) is the first entry offset. This causes
453ab9598dSSimon Glass            _skip_at_start to be set to the starting memory address.
46c8d48efbSSimon Glass        _name_prefix: Prefix to add to the name of all entries within this
47c8d48efbSSimon Glass            section
488f1da50cSSimon Glass        _entries: OrderedDict() of entries
498f1da50cSSimon Glass    """
5008723a7aSSimon Glass    def __init__(self, name, parent_section, node, image, test=False):
518f1da50cSSimon Glass        global entry
528f1da50cSSimon Glass        global Entry
538f1da50cSSimon Glass        import entry
548f1da50cSSimon Glass        from entry import Entry
558f1da50cSSimon Glass
5608723a7aSSimon Glass        self._parent_section = parent_section
578122f396SSimon Glass        self._name = name
588f1da50cSSimon Glass        self._node = node
5908723a7aSSimon Glass        self._image = image
603ab9598dSSimon Glass        self._offset = 0
618f1da50cSSimon Glass        self._size = None
628f1da50cSSimon Glass        self._align_size = None
638f1da50cSSimon Glass        self._pad_before = 0
648f1da50cSSimon Glass        self._pad_after = 0
658f1da50cSSimon Glass        self._pad_byte = 0
668f1da50cSSimon Glass        self._sort = False
6794b57db0SJagdish Gediya        self._skip_at_start = None
688f1da50cSSimon Glass        self._end_4gb = False
69c8d48efbSSimon Glass        self._name_prefix = ''
708f1da50cSSimon Glass        self._entries = OrderedDict()
71*f8f8df6eSSimon Glass        self._image_pos = None
728f1da50cSSimon Glass        if not test:
738f1da50cSSimon Glass            self._ReadNode()
748f1da50cSSimon Glass            self._ReadEntries()
758f1da50cSSimon Glass
768f1da50cSSimon Glass    def _ReadNode(self):
778f1da50cSSimon Glass        """Read properties from the section node"""
788f1da50cSSimon Glass        self._size = fdt_util.GetInt(self._node, 'size')
798f1da50cSSimon Glass        self._align_size = fdt_util.GetInt(self._node, 'align-size')
808f1da50cSSimon Glass        if tools.NotPowerOfTwo(self._align_size):
818f1da50cSSimon Glass            self._Raise("Alignment size %s must be a power of two" %
828f1da50cSSimon Glass                        self._align_size)
838f1da50cSSimon Glass        self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
848f1da50cSSimon Glass        self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
858f1da50cSSimon Glass        self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0)
863ab9598dSSimon Glass        self._sort = fdt_util.GetBool(self._node, 'sort-by-offset')
878f1da50cSSimon Glass        self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb')
8894b57db0SJagdish Gediya        self._skip_at_start = fdt_util.GetInt(self._node, 'skip-at-start')
898f1da50cSSimon Glass        if self._end_4gb:
9094b57db0SJagdish Gediya            if not self._size:
9194b57db0SJagdish Gediya                self._Raise("Section size must be provided when using end-at-4gb")
9294b57db0SJagdish Gediya            if self._skip_at_start is not None:
9394b57db0SJagdish Gediya                self._Raise("Provide either 'end-at-4gb' or 'skip-at-start'")
9494b57db0SJagdish Gediya            else:
958f1da50cSSimon Glass                self._skip_at_start = 0x100000000 - self._size
9694b57db0SJagdish Gediya        else:
9794b57db0SJagdish Gediya            if self._skip_at_start is None:
9894b57db0SJagdish Gediya                self._skip_at_start = 0
99c8d48efbSSimon Glass        self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
1008f1da50cSSimon Glass
1018f1da50cSSimon Glass    def _ReadEntries(self):
1028f1da50cSSimon Glass        for node in self._node.subnodes:
103e0e5df93SSimon Glass            if node.name == 'hash':
104e0e5df93SSimon Glass                continue
105c8d48efbSSimon Glass            entry = Entry.Create(self, node)
106c8d48efbSSimon Glass            entry.SetPrefix(self._name_prefix)
107c8d48efbSSimon Glass            self._entries[node.name] = entry
1088f1da50cSSimon Glass
109539aece5SSimon Glass    def GetFdtSet(self):
110539aece5SSimon Glass        """Get the set of device tree files used by this image"""
111539aece5SSimon Glass        fdt_set = Set()
112539aece5SSimon Glass        for entry in self._entries.values():
113539aece5SSimon Glass            fdt_set.update(entry.GetFdtSet())
114539aece5SSimon Glass        return fdt_set
115539aece5SSimon Glass
1168122f396SSimon Glass    def SetOffset(self, offset):
1178122f396SSimon Glass        self._offset = offset
1188122f396SSimon Glass
1190a98b28bSSimon Glass    def ExpandEntries(self):
1200a98b28bSSimon Glass        for entry in self._entries.values():
1210a98b28bSSimon Glass            entry.ExpandEntries()
1220a98b28bSSimon Glass
123078ab1a2SSimon Glass    def AddMissingProperties(self):
1248122f396SSimon Glass        """Add new properties to the device tree as needed for this entry"""
125dbf6be9fSSimon Glass        for prop in ['offset', 'size', 'image-pos']:
1268122f396SSimon Glass            if not prop in self._node.props:
127f46621d2SSimon Glass                state.AddZeroProp(self._node, prop)
128e0e5df93SSimon Glass        state.CheckAddHashProp(self._node)
129078ab1a2SSimon Glass        for entry in self._entries.values():
130078ab1a2SSimon Glass            entry.AddMissingProperties()
131078ab1a2SSimon Glass
132078ab1a2SSimon Glass    def SetCalculatedProperties(self):
133f46621d2SSimon Glass        state.SetInt(self._node, 'offset', self._offset)
134f46621d2SSimon Glass        state.SetInt(self._node, 'size', self._size)
135*f8f8df6eSSimon Glass        image_pos = self._image_pos
136*f8f8df6eSSimon Glass        if self._parent_section:
137*f8f8df6eSSimon Glass            image_pos -= self._parent_section.GetRootSkipAtStart()
138*f8f8df6eSSimon Glass        state.SetInt(self._node, 'image-pos', image_pos)
139078ab1a2SSimon Glass        for entry in self._entries.values():
140078ab1a2SSimon Glass            entry.SetCalculatedProperties()
141078ab1a2SSimon Glass
142ecab8973SSimon Glass    def ProcessFdt(self, fdt):
143ecab8973SSimon Glass        todo = self._entries.values()
144ecab8973SSimon Glass        for passnum in range(3):
145ecab8973SSimon Glass            next_todo = []
146ecab8973SSimon Glass            for entry in todo:
147ecab8973SSimon Glass                if not entry.ProcessFdt(fdt):
148ecab8973SSimon Glass                    next_todo.append(entry)
149ecab8973SSimon Glass            todo = next_todo
150ecab8973SSimon Glass            if not todo:
151ecab8973SSimon Glass                break
152ecab8973SSimon Glass        if todo:
153ecab8973SSimon Glass            self._Raise('Internal error: Could not complete processing of Fdt: '
154ecab8973SSimon Glass                        'remaining %s' % todo)
155ecab8973SSimon Glass        return True
156ecab8973SSimon Glass
1578f1da50cSSimon Glass    def CheckSize(self):
1588f1da50cSSimon Glass        """Check that the section contents does not exceed its size, etc."""
1598f1da50cSSimon Glass        contents_size = 0
1608f1da50cSSimon Glass        for entry in self._entries.values():
1613ab9598dSSimon Glass            contents_size = max(contents_size, entry.offset + entry.size)
1628f1da50cSSimon Glass
1638f1da50cSSimon Glass        contents_size -= self._skip_at_start
1648f1da50cSSimon Glass
1658f1da50cSSimon Glass        size = self._size
1668f1da50cSSimon Glass        if not size:
1678f1da50cSSimon Glass            size = self._pad_before + contents_size + self._pad_after
1688f1da50cSSimon Glass            size = tools.Align(size, self._align_size)
1698f1da50cSSimon Glass
1708f1da50cSSimon Glass        if self._size and contents_size > self._size:
1718f1da50cSSimon Glass            self._Raise("contents size %#x (%d) exceeds section size %#x (%d)" %
1728f1da50cSSimon Glass                       (contents_size, contents_size, self._size, self._size))
1738f1da50cSSimon Glass        if not self._size:
1748f1da50cSSimon Glass            self._size = size
1758f1da50cSSimon Glass        if self._size != tools.Align(self._size, self._align_size):
1768f1da50cSSimon Glass            self._Raise("Size %#x (%d) does not match align-size %#x (%d)" %
1778f1da50cSSimon Glass                  (self._size, self._size, self._align_size, self._align_size))
1788f1da50cSSimon Glass        return size
1798f1da50cSSimon Glass
1808f1da50cSSimon Glass    def _Raise(self, msg):
1818f1da50cSSimon Glass        """Raises an error for this section
1828f1da50cSSimon Glass
1838f1da50cSSimon Glass        Args:
1848f1da50cSSimon Glass            msg: Error message to use in the raise string
1858f1da50cSSimon Glass        Raises:
1868f1da50cSSimon Glass            ValueError()
1878f1da50cSSimon Glass        """
1888f1da50cSSimon Glass        raise ValueError("Section '%s': %s" % (self._node.path, msg))
1898f1da50cSSimon Glass
1908f1da50cSSimon Glass    def GetPath(self):
1918f1da50cSSimon Glass        """Get the path of an image (in the FDT)
1928f1da50cSSimon Glass
1938f1da50cSSimon Glass        Returns:
1948f1da50cSSimon Glass            Full path of the node for this image
1958f1da50cSSimon Glass        """
1968f1da50cSSimon Glass        return self._node.path
1978f1da50cSSimon Glass
1988f1da50cSSimon Glass    def FindEntryType(self, etype):
1998f1da50cSSimon Glass        """Find an entry type in the section
2008f1da50cSSimon Glass
2018f1da50cSSimon Glass        Args:
2028f1da50cSSimon Glass            etype: Entry type to find
2038f1da50cSSimon Glass        Returns:
2048f1da50cSSimon Glass            entry matching that type, or None if not found
2058f1da50cSSimon Glass        """
2068f1da50cSSimon Glass        for entry in self._entries.values():
2078f1da50cSSimon Glass            if entry.etype == etype:
2088f1da50cSSimon Glass                return entry
2098f1da50cSSimon Glass        return None
2108f1da50cSSimon Glass
2118f1da50cSSimon Glass    def GetEntryContents(self):
2128f1da50cSSimon Glass        """Call ObtainContents() for each entry
2138f1da50cSSimon Glass
2148f1da50cSSimon Glass        This calls each entry's ObtainContents() a few times until they all
2158f1da50cSSimon Glass        return True. We stop calling an entry's function once it returns
2168f1da50cSSimon Glass        True. This allows the contents of one entry to depend on another.
2178f1da50cSSimon Glass
2188f1da50cSSimon Glass        After 3 rounds we give up since it's likely an error.
2198f1da50cSSimon Glass        """
2208f1da50cSSimon Glass        todo = self._entries.values()
2218f1da50cSSimon Glass        for passnum in range(3):
2228f1da50cSSimon Glass            next_todo = []
2238f1da50cSSimon Glass            for entry in todo:
2248f1da50cSSimon Glass                if not entry.ObtainContents():
2258f1da50cSSimon Glass                    next_todo.append(entry)
2268f1da50cSSimon Glass            todo = next_todo
2278f1da50cSSimon Glass            if not todo:
2288f1da50cSSimon Glass                break
229736bb0aeSSimon Glass        if todo:
230736bb0aeSSimon Glass            self._Raise('Internal error: Could not complete processing of '
231736bb0aeSSimon Glass                        'contents: remaining %s' % todo)
232736bb0aeSSimon Glass        return True
2338f1da50cSSimon Glass
2343ab9598dSSimon Glass    def _SetEntryOffsetSize(self, name, offset, size):
2353ab9598dSSimon Glass        """Set the offset and size of an entry
2368f1da50cSSimon Glass
2378f1da50cSSimon Glass        Args:
2388f1da50cSSimon Glass            name: Entry name to update
2393ab9598dSSimon Glass            offset: New offset
2408f1da50cSSimon Glass            size: New size
2418f1da50cSSimon Glass        """
2428f1da50cSSimon Glass        entry = self._entries.get(name)
2438f1da50cSSimon Glass        if not entry:
2443ab9598dSSimon Glass            self._Raise("Unable to set offset/size for unknown entry '%s'" %
2453ab9598dSSimon Glass                        name)
2463ab9598dSSimon Glass        entry.SetOffsetSize(self._skip_at_start + offset, size)
2478f1da50cSSimon Glass
2483ab9598dSSimon Glass    def GetEntryOffsets(self):
2493ab9598dSSimon Glass        """Handle entries that want to set the offset/size of other entries
2508f1da50cSSimon Glass
2513ab9598dSSimon Glass        This calls each entry's GetOffsets() method. If it returns a list
2528f1da50cSSimon Glass        of entries to update, it updates them.
2538f1da50cSSimon Glass        """
2548f1da50cSSimon Glass        for entry in self._entries.values():
2553ab9598dSSimon Glass            offset_dict = entry.GetOffsets()
2563ab9598dSSimon Glass            for name, info in offset_dict.iteritems():
2573ab9598dSSimon Glass                self._SetEntryOffsetSize(name, *info)
2588f1da50cSSimon Glass
2598f1da50cSSimon Glass    def PackEntries(self):
2608f1da50cSSimon Glass        """Pack all entries into the section"""
2613ab9598dSSimon Glass        offset = self._skip_at_start
2628f1da50cSSimon Glass        for entry in self._entries.values():
2633ab9598dSSimon Glass            offset = entry.Pack(offset)
2643ab9598dSSimon Glass        self._size = self.CheckSize()
2658f1da50cSSimon Glass
2668f1da50cSSimon Glass    def _SortEntries(self):
2673ab9598dSSimon Glass        """Sort entries by offset"""
2683ab9598dSSimon Glass        entries = sorted(self._entries.values(), key=lambda entry: entry.offset)
2698f1da50cSSimon Glass        self._entries.clear()
2708f1da50cSSimon Glass        for entry in entries:
2718f1da50cSSimon Glass            self._entries[entry._node.name] = entry
2728f1da50cSSimon Glass
273ba64a0bbSSimon Glass    def _ExpandEntries(self):
274ba64a0bbSSimon Glass        """Expand any entries that are permitted to"""
275ba64a0bbSSimon Glass        exp_entry = None
276ba64a0bbSSimon Glass        for entry in self._entries.values():
277ba64a0bbSSimon Glass            if exp_entry:
278ba64a0bbSSimon Glass                exp_entry.ExpandToLimit(entry.offset)
279ba64a0bbSSimon Glass                exp_entry = None
280ba64a0bbSSimon Glass            if entry.expand_size:
281ba64a0bbSSimon Glass                exp_entry = entry
282ba64a0bbSSimon Glass        if exp_entry:
283ba64a0bbSSimon Glass            exp_entry.ExpandToLimit(self._size)
284ba64a0bbSSimon Glass
2858f1da50cSSimon Glass    def CheckEntries(self):
286ba64a0bbSSimon Glass        """Check that entries do not overlap or extend outside the section
287ba64a0bbSSimon Glass
288ba64a0bbSSimon Glass        This also sorts entries, if needed and expands
289ba64a0bbSSimon Glass        """
2908f1da50cSSimon Glass        if self._sort:
2918f1da50cSSimon Glass            self._SortEntries()
292ba64a0bbSSimon Glass        self._ExpandEntries()
2933ab9598dSSimon Glass        offset = 0
2948f1da50cSSimon Glass        prev_name = 'None'
2958f1da50cSSimon Glass        for entry in self._entries.values():
2963ab9598dSSimon Glass            entry.CheckOffset()
2973ab9598dSSimon Glass            if (entry.offset < self._skip_at_start or
298b4e1a38cSSimon Glass                entry.offset + entry.size > self._skip_at_start + self._size):
2993ab9598dSSimon Glass                entry.Raise("Offset %#x (%d) is outside the section starting "
3008f1da50cSSimon Glass                            "at %#x (%d)" %
3013ab9598dSSimon Glass                            (entry.offset, entry.offset, self._skip_at_start,
3028f1da50cSSimon Glass                             self._skip_at_start))
3033ab9598dSSimon Glass            if entry.offset < offset:
3043ab9598dSSimon Glass                entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
3058f1da50cSSimon Glass                            "ending at %#x (%d)" %
3063ab9598dSSimon Glass                            (entry.offset, entry.offset, prev_name, offset, offset))
3073ab9598dSSimon Glass            offset = entry.offset + entry.size
3088f1da50cSSimon Glass            prev_name = entry.GetPath()
3098f1da50cSSimon Glass
310dbf6be9fSSimon Glass    def SetImagePos(self, image_pos):
311dbf6be9fSSimon Glass        self._image_pos = image_pos
312dbf6be9fSSimon Glass        for entry in self._entries.values():
313dbf6be9fSSimon Glass            entry.SetImagePos(image_pos)
314dbf6be9fSSimon Glass
3158f1da50cSSimon Glass    def ProcessEntryContents(self):
3168f1da50cSSimon Glass        """Call the ProcessContents() method for each entry
3178f1da50cSSimon Glass
3188f1da50cSSimon Glass        This is intended to adjust the contents as needed by the entry type.
3198f1da50cSSimon Glass        """
3208f1da50cSSimon Glass        for entry in self._entries.values():
3218f1da50cSSimon Glass            entry.ProcessContents()
3228f1da50cSSimon Glass
3238f1da50cSSimon Glass    def WriteSymbols(self):
3248f1da50cSSimon Glass        """Write symbol values into binary files for access at run time"""
3258f1da50cSSimon Glass        for entry in self._entries.values():
3268f1da50cSSimon Glass            entry.WriteSymbols(self)
3278f1da50cSSimon Glass
3283ab9598dSSimon Glass    def BuildSection(self, fd, base_offset):
3298f1da50cSSimon Glass        """Write the section to a file"""
3303ab9598dSSimon Glass        fd.seek(base_offset)
3318f1da50cSSimon Glass        fd.write(self.GetData())
3328f1da50cSSimon Glass
3338f1da50cSSimon Glass    def GetData(self):
3348122f396SSimon Glass        """Get the contents of the section"""
3358f1da50cSSimon Glass        section_data = chr(self._pad_byte) * self._size
3368f1da50cSSimon Glass
3378f1da50cSSimon Glass        for entry in self._entries.values():
3388f1da50cSSimon Glass            data = entry.GetData()
3393ab9598dSSimon Glass            base = self._pad_before + entry.offset - self._skip_at_start
3408f1da50cSSimon Glass            section_data = (section_data[:base] + data +
3418f1da50cSSimon Glass                            section_data[base + len(data):])
3428f1da50cSSimon Glass        return section_data
3438f1da50cSSimon Glass
3448f1da50cSSimon Glass    def LookupSymbol(self, sym_name, optional, msg):
3458f1da50cSSimon Glass        """Look up a symbol in an ELF file
3468f1da50cSSimon Glass
3478f1da50cSSimon Glass        Looks up a symbol in an ELF file. Only entry types which come from an
3488f1da50cSSimon Glass        ELF image can be used by this function.
3498f1da50cSSimon Glass
3503ab9598dSSimon Glass        At present the only entry property supported is offset.
3518f1da50cSSimon Glass
3528f1da50cSSimon Glass        Args:
3538f1da50cSSimon Glass            sym_name: Symbol name in the ELF file to look up in the format
3548f1da50cSSimon Glass                _binman_<entry>_prop_<property> where <entry> is the name of
3558f1da50cSSimon Glass                the entry and <property> is the property to find (e.g.
3563ab9598dSSimon Glass                _binman_u_boot_prop_offset). As a special case, you can append
3578f1da50cSSimon Glass                _any to <entry> to have it search for any matching entry. E.g.
3583ab9598dSSimon Glass                _binman_u_boot_any_prop_offset will match entries called u-boot,
3598f1da50cSSimon Glass                u-boot-img and u-boot-nodtb)
3608f1da50cSSimon Glass            optional: True if the symbol is optional. If False this function
3618f1da50cSSimon Glass                will raise if the symbol is not found
3628f1da50cSSimon Glass            msg: Message to display if an error occurs
3638f1da50cSSimon Glass
3648f1da50cSSimon Glass        Returns:
3658f1da50cSSimon Glass            Value that should be assigned to that symbol, or None if it was
3668f1da50cSSimon Glass                optional and not found
3678f1da50cSSimon Glass
3688f1da50cSSimon Glass        Raises:
3698f1da50cSSimon Glass            ValueError if the symbol is invalid or not found, or references a
3708f1da50cSSimon Glass                property which is not supported
3718f1da50cSSimon Glass        """
3728f1da50cSSimon Glass        m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name)
3738f1da50cSSimon Glass        if not m:
3748f1da50cSSimon Glass            raise ValueError("%s: Symbol '%s' has invalid format" %
3758f1da50cSSimon Glass                             (msg, sym_name))
3768f1da50cSSimon Glass        entry_name, prop_name = m.groups()
3778f1da50cSSimon Glass        entry_name = entry_name.replace('_', '-')
3788f1da50cSSimon Glass        entry = self._entries.get(entry_name)
3798f1da50cSSimon Glass        if not entry:
3808f1da50cSSimon Glass            if entry_name.endswith('-any'):
3818f1da50cSSimon Glass                root = entry_name[:-4]
3828f1da50cSSimon Glass                for name in self._entries:
3838f1da50cSSimon Glass                    if name.startswith(root):
3848f1da50cSSimon Glass                        rest = name[len(root):]
3858f1da50cSSimon Glass                        if rest in ['', '-img', '-nodtb']:
3868f1da50cSSimon Glass                            entry = self._entries[name]
3878f1da50cSSimon Glass        if not entry:
3888f1da50cSSimon Glass            err = ("%s: Entry '%s' not found in list (%s)" %
3898f1da50cSSimon Glass                   (msg, entry_name, ','.join(self._entries.keys())))
3908f1da50cSSimon Glass            if optional:
3918f1da50cSSimon Glass                print('Warning: %s' % err, file=sys.stderr)
3928f1da50cSSimon Glass                return None
3938f1da50cSSimon Glass            raise ValueError(err)
3943ab9598dSSimon Glass        if prop_name == 'offset':
3953ab9598dSSimon Glass            return entry.offset
396dbf6be9fSSimon Glass        elif prop_name == 'image_pos':
397dbf6be9fSSimon Glass            return entry.image_pos
3988f1da50cSSimon Glass        else:
3998f1da50cSSimon Glass            raise ValueError("%s: No such property '%s'" % (msg, prop_name))
4008f1da50cSSimon Glass
4018f1da50cSSimon Glass    def GetEntries(self):
4028122f396SSimon Glass        """Get the number of entries in a section
4038122f396SSimon Glass
4048122f396SSimon Glass        Returns:
4058122f396SSimon Glass            Number of entries in a section
4068122f396SSimon Glass        """
4078f1da50cSSimon Glass        return self._entries
4083b0c3821SSimon Glass
4098122f396SSimon Glass    def GetSize(self):
4108122f396SSimon Glass        """Get the size of a section in bytes
4118122f396SSimon Glass
4128122f396SSimon Glass        This is only meaningful if the section has a pre-defined size, or the
4138122f396SSimon Glass        entries within it have been packed, so that the size has been
4148122f396SSimon Glass        calculated.
4158122f396SSimon Glass
4168122f396SSimon Glass        Returns:
4178122f396SSimon Glass            Entry size in bytes
4188122f396SSimon Glass        """
4198122f396SSimon Glass        return self._size
4208122f396SSimon Glass
4213b0c3821SSimon Glass    def WriteMap(self, fd, indent):
4223b0c3821SSimon Glass        """Write a map of the section to a .map file
4233b0c3821SSimon Glass
4243b0c3821SSimon Glass        Args:
4253b0c3821SSimon Glass            fd: File to write the map to
4263b0c3821SSimon Glass        """
4271be70d20SSimon Glass        Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size,
4281be70d20SSimon Glass                           self._image_pos)
4293b0c3821SSimon Glass        for entry in self._entries.values():
4308122f396SSimon Glass            entry.WriteMap(fd, indent + 1)
43124d0d3c3SSimon Glass
43224d0d3c3SSimon Glass    def GetContentsByPhandle(self, phandle, source_entry):
43324d0d3c3SSimon Glass        """Get the data contents of an entry specified by a phandle
43424d0d3c3SSimon Glass
43524d0d3c3SSimon Glass        This uses a phandle to look up a node and and find the entry
43624d0d3c3SSimon Glass        associated with it. Then it returnst he contents of that entry.
43724d0d3c3SSimon Glass
43824d0d3c3SSimon Glass        Args:
43924d0d3c3SSimon Glass            phandle: Phandle to look up (integer)
44024d0d3c3SSimon Glass            source_entry: Entry containing that phandle (used for error
44124d0d3c3SSimon Glass                reporting)
44224d0d3c3SSimon Glass
44324d0d3c3SSimon Glass        Returns:
44424d0d3c3SSimon Glass            data from associated entry (as a string), or None if not found
44524d0d3c3SSimon Glass        """
44624d0d3c3SSimon Glass        node = self._node.GetFdt().LookupPhandle(phandle)
44724d0d3c3SSimon Glass        if not node:
44824d0d3c3SSimon Glass            source_entry.Raise("Cannot find node for phandle %d" % phandle)
44924d0d3c3SSimon Glass        for entry in self._entries.values():
45024d0d3c3SSimon Glass            if entry._node == node:
451*f8f8df6eSSimon Glass                return entry.GetData()
45224d0d3c3SSimon Glass        source_entry.Raise("Cannot find entry for node '%s'" % node.name)
453ba64a0bbSSimon Glass
454ba64a0bbSSimon Glass    def ExpandSize(self, size):
455ba64a0bbSSimon Glass        if size != self._size:
456ba64a0bbSSimon Glass            self._size = size
457*f8f8df6eSSimon Glass
458*f8f8df6eSSimon Glass    def GetRootSkipAtStart(self):
459*f8f8df6eSSimon Glass        if self._parent_section:
460*f8f8df6eSSimon Glass            return self._parent_section.GetRootSkipAtStart()
461*f8f8df6eSSimon Glass        return self._skip_at_start
462*f8f8df6eSSimon Glass
463*f8f8df6eSSimon Glass    def GetImageSize(self):
464*f8f8df6eSSimon Glass        return self._image._size
465