Esempio n. 1
0
    def _GetFdtmap(self):
        """Build an FDT map from the entries in the current image

        Returns:
            FDT map binary data
        """
        def _AddNode(node):
            """Add a node to the FDT map"""
            for pname, prop in node.props.items():
                fsw.property(pname, prop.bytes)
            for subnode in node.subnodes:
                with fsw.add_node(subnode.name):
                    _AddNode(subnode)

        data = state.GetFdtContents('fdtmap')[1]
        # If we have an fdtmap it means that we are using this as the
        # fdtmap for this image.
        if data is None:
            # Get the FDT data into an Fdt object
            data = state.GetFdtContents()[1]
            infdt = Fdt.FromData(data)
            infdt.Scan()

            # Find the node for the image containing the Fdt-map entry
            path = self.section.GetPath()
            self.Detail("Fdtmap: Using section '%s' (path '%s')" %
                        (self.section.name, path))
            node = infdt.GetNode(path)
            if not node:
                self.Raise("Internal error: Cannot locate node for path '%s'" %
                           path)

            # Build a new tree with all nodes and properties starting from that
            # node
            fsw = libfdt.FdtSw()
            fsw.finish_reservemap()
            with fsw.add_node(''):
                fsw.property_string('image-node', node.name)
                _AddNode(node)
            fdt = fsw.as_fdt()

            # Pack this new FDT and return its contents
            fdt.pack()
            outfdt = Fdt.FromData(fdt.as_bytearray())
            data = outfdt.GetContents()
        data = FDTMAP_MAGIC + tools.GetBytes(0, 8) + data
        return data
Esempio n. 2
0
    def SetImagePos(self, image_pos):
        """Set the position in the image

        This sets each subentry's offsets, sizes and positions-in-image
        according to where they ended up in the packed FIT file.

        Args:
            image_pos (int): Position of this entry in the image
        """
        super().SetImagePos(image_pos)

        # If mkimage is missing we'll have empty data,
        # which will cause a FDT_ERR_BADMAGIC error
        if self.mkimage in self.missing_bintools:
            return

        fdt = Fdt.FromData(self.GetData())
        fdt.Scan()

        for image_name, section in self._entries.items():
            path = f"/images/{image_name}"
            node = fdt.GetNode(path)

            data_prop = node.props.get("data")
            data_pos = fdt_util.GetInt(node, "data-position")
            data_offset = fdt_util.GetInt(node, "data-offset")
            data_size = fdt_util.GetInt(node, "data-size")

            # Contents are inside the FIT
            if data_prop is not None:
                # GetOffset() returns offset of a fdt_property struct,
                # which has 3 fdt32_t members before the actual data.
                offset = data_prop.GetOffset() + 12
                size = len(data_prop.bytes)

            # External offset from the base of the FIT
            elif data_pos is not None:
                offset = data_pos
                size = data_size

            # External offset from the end of the FIT, not used in binman
            elif data_offset is not None: # pragma: no cover
                offset = fdt.GetFdtObj().totalsize() + data_offset
                size = data_size

            # This should never happen
            else: # pragma: no cover
                self.Raise(f'{path}: missing data properties')

            section.SetOffsetSize(offset, size)
            section.SetImagePos(self.image_pos)
Esempio n. 3
0
    def _ReadSubnodes(self):
        def _AddNode(base_node, depth, node):
            """Add a node to the FIT

            Args:
                base_node: Base Node of the FIT (with 'description' property)
                depth: Current node depth (0 is the base node)
                node: Current node to process

            There are two cases to deal with:
                - hash and signature nodes which become part of the FIT
                - binman entries which are used to define the 'data' for each
                  image
            """
            for pname, prop in node.props.items():
                if pname.startswith('fit,'):
                    self._fit_props[pname] = prop
                else:
                    fsw.property(pname, prop.bytes)

            rel_path = node.path[len(base_node.path):]
            has_images = depth == 2 and rel_path.startswith('/images/')
            for subnode in node.subnodes:
                if has_images and not (subnode.name.startswith('hash') or
                                       subnode.name.startswith('signature')):
                    # This is a content node. We collect all of these together
                    # and put them in the 'data' property. They do not appear
                    # in the FIT.
                    entry = Entry.Create(self.section, subnode)
                    entry.ReadNode()
                    self._fit_content[rel_path].append(entry)
                else:
                    with fsw.add_node(subnode.name):
                        _AddNode(base_node, depth + 1, subnode)

        # Build a new tree with all nodes and properties starting from the
        # entry node
        fsw = libfdt.FdtSw()
        fsw.finish_reservemap()
        with fsw.add_node(''):
            _AddNode(self._node, 0, self._node)
        fdt = fsw.as_fdt()

        # Pack this new FDT and scan it so we can add the data later
        fdt.pack()
        self._fdt = Fdt.FromData(fdt.as_bytearray())
        self._fdt.Scan()
Esempio n. 4
0
    def _ReadSubnodes(self):
        def _AddNode(base_node, depth, node):
            """Add a node to the FIT

            Args:
                base_node: Base Node of the FIT (with 'description' property)
                depth: Current node depth (0 is the base node)
                node: Current node to process

            There are two cases to deal with:
                - hash and signature nodes which become part of the FIT
                - binman entries which are used to define the 'data' for each
                  image
            """
            for pname, prop in node.props.items():
                if not pname.startswith('fit,'):
                    if pname == 'default':
                        val = prop.value
                        # Handle the 'default' property
                        if val.startswith('@'):
                            if not self._fdts:
                                continue
                            if not self._fit_default_dt:
                                self.Raise(
                                    "Generated 'default' node requires default-dt entry argument"
                                )
                            if self._fit_default_dt not in self._fdts:
                                self.Raise(
                                    "default-dt entry argument '%s' not found in fdt list: %s"
                                    % (self._fit_default_dt, ', '.join(
                                        self._fdts)))
                            seq = self._fdts.index(self._fit_default_dt)
                            val = val[1:].replace('DEFAULT-SEQ', str(seq + 1))
                            fsw.property_string(pname, val)
                            continue
                    fsw.property(pname, prop.bytes)

            rel_path = node.path[len(base_node.path):]
            in_images = rel_path.startswith('/images')
            has_images = depth == 2 and in_images
            if has_images:
                # This node is a FIT subimage node (e.g. "/images/kernel")
                # containing content nodes. We collect the subimage nodes and
                # section entries for them here to merge the content subnodes
                # together and put the merged contents in the subimage node's
                # 'data' property later.
                entry = Entry.Create(self.section, node, etype='section')
                entry.ReadNode()
                self._fit_sections[rel_path] = entry

            for subnode in node.subnodes:
                if has_images and not (subnode.name.startswith('hash') or
                                       subnode.name.startswith('signature')):
                    # This subnode is a content node not meant to appear in
                    # the FIT (e.g. "/images/kernel/u-boot"), so don't call
                    # fsw.add_node() or _AddNode() for it.
                    pass
                elif subnode.name.startswith('@'):
                    if self._fdts:
                        # Generate notes for each FDT
                        for seq, fdt_fname in enumerate(self._fdts):
                            node_name = subnode.name[1:].replace(
                                'SEQ', str(seq + 1))
                            fname = tools.GetInputFilename(fdt_fname + '.dtb')
                            with fsw.add_node(node_name):
                                for pname, prop in subnode.props.items():
                                    val = prop.bytes.replace(
                                        b'NAME', tools.ToBytes(fdt_fname))
                                    val = val.replace(
                                        b'SEQ', tools.ToBytes(str(seq + 1)))
                                    fsw.property(pname, val)

                                    # Add data for 'fdt' nodes (but not 'config')
                                    if depth == 1 and in_images:
                                        fsw.property('data',
                                                     tools.ReadFile(fname))
                    else:
                        if self._fdts is None:
                            if self._fit_list_prop:
                                self.Raise(
                                    "Generator node requires '%s' entry argument"
                                    % self._fit_list_prop.value)
                            else:
                                self.Raise(
                                    "Generator node requires 'fit,fdt-list' property"
                                )
                else:
                    with fsw.add_node(subnode.name):
                        _AddNode(base_node, depth + 1, subnode)

        # Build a new tree with all nodes and properties starting from the
        # entry node
        fsw = libfdt.FdtSw()
        fsw.finish_reservemap()
        with fsw.add_node(''):
            _AddNode(self._node, 0, self._node)
        fdt = fsw.as_fdt()

        # Pack this new FDT and scan it so we can add the data later
        fdt.pack()
        self._fdt = Fdt.FromData(fdt.as_bytearray())
        self._fdt.Scan()
Esempio n. 5
0
    def ReadEntries(self):
        def _process_prop(pname, prop):
            """Process special properties

            Handles properties with generated values. At present the only
            supported property is 'default', i.e. the default device tree in
            the configurations node.

            Args:
                pname (str): Name of property
                prop (Prop): Property to process
            """
            if pname == 'default':
                val = prop.value
                # Handle the 'default' property
                if val.startswith('@'):
                    if not self._fdts:
                        return
                    if not self._fit_default_dt:
                        self.Raise(
                            "Generated 'default' node requires default-dt entry argument"
                        )
                    if self._fit_default_dt not in self._fdts:
                        self.Raise(
                            "default-dt entry argument '%s' not found in fdt list: %s"
                            % (self._fit_default_dt, ', '.join(self._fdts)))
                    seq = self._fdts.index(self._fit_default_dt)
                    val = val[1:].replace('DEFAULT-SEQ', str(seq + 1))
                    fsw.property_string(pname, val)
                    return
            fsw.property(pname, prop.bytes)

        def _scan_gen_fdt_nodes(subnode, depth, in_images):
            """Generate FDT nodes

            This creates one node for each member of self._fdts using the
            provided template. If a property value contains 'NAME' it is
            replaced with the filename of the FDT. If a property value contains
            SEQ it is replaced with the node sequence number, where 1 is the
            first.

            Args:
                subnode (None): Generator node to process
                depth: Current node depth (0 is the base 'fit' node)
                in_images: True if this is inside the 'images' node, so that
                    'data' properties should be generated
            """
            if self._fdts:
                # Generate nodes for each FDT
                for seq, fdt_fname in enumerate(self._fdts):
                    node_name = subnode.name[1:].replace('SEQ', str(seq + 1))
                    fname = tools.get_input_filename(fdt_fname + '.dtb')
                    with fsw.add_node(node_name):
                        for pname, prop in subnode.props.items():
                            val = prop.bytes.replace(b'NAME',
                                                     tools.to_bytes(fdt_fname))
                            val = val.replace(b'SEQ',
                                              tools.to_bytes(str(seq + 1)))
                            fsw.property(pname, val)

                        # Add data for 'images' nodes (but not 'config')
                        if depth == 1 and in_images:
                            fsw.property('data', tools.read_file(fname))
            else:
                if self._fdts is None:
                    if self._fit_list_prop:
                        self.Raise(
                            "Generator node requires '%s' entry argument" %
                            self._fit_list_prop.value)
                    else:
                        self.Raise(
                            "Generator node requires 'fit,fdt-list' property")

        def _scan_node(subnode, depth, in_images):
            """Generate nodes from a template

            This creates one node for each member of self._fdts using the
            provided template. If a property value contains 'NAME' it is
            replaced with the filename of the FDT. If a property value contains
            SEQ it is replaced with the node sequence number, where 1 is the
            first.

            Args:
                subnode (None): Generator node to process
                depth: Current node depth (0 is the base 'fit' node)
                in_images: True if this is inside the 'images' node, so that
                    'data' properties should be generated
            """
            oper = self._get_operation(subnode)
            if oper == OP_GEN_FDT_NODES:
                _scan_gen_fdt_nodes(subnode, depth, in_images)

        def _AddNode(base_node, depth, node):
            """Add a node to the FIT

            Args:
                base_node: Base Node of the FIT (with 'description' property)
                depth: Current node depth (0 is the base 'fit' node)
                node: Current node to process

            There are two cases to deal with:
                - hash and signature nodes which become part of the FIT
                - binman entries which are used to define the 'data' for each
                  image
            """
            for pname, prop in node.props.items():
                if not pname.startswith('fit,'):
                    _process_prop(pname, prop)

            rel_path = node.path[len(base_node.path):]
            in_images = rel_path.startswith('/images')
            has_images = depth == 2 and in_images
            if has_images:
                # This node is a FIT subimage node (e.g. "/images/kernel")
                # containing content nodes. We collect the subimage nodes and
                # section entries for them here to merge the content subnodes
                # together and put the merged contents in the subimage node's
                # 'data' property later.
                entry = Entry.Create(self.section, node, etype='section')
                entry.ReadNode()
                # The hash subnodes here are for mkimage, not binman.
                entry.SetUpdateHash(False)
                self._entries[rel_path] = entry

            for subnode in node.subnodes:
                if has_images and not (subnode.name.startswith('hash') or
                                       subnode.name.startswith('signature')):
                    # This subnode is a content node not meant to appear in
                    # the FIT (e.g. "/images/kernel/u-boot"), so don't call
                    # fsw.add_node() or _AddNode() for it.
                    pass
                elif self.GetImage().generate and subnode.name.startswith('@'):
                    _scan_node(subnode, depth, in_images)
                else:
                    with fsw.add_node(subnode.name):
                        _AddNode(base_node, depth + 1, subnode)

        # Build a new tree with all nodes and properties starting from the
        # entry node
        fsw = libfdt.FdtSw()
        fsw.finish_reservemap()
        with fsw.add_node(''):
            _AddNode(self._node, 0, self._node)
        fdt = fsw.as_fdt()

        # Pack this new FDT and scan it so we can add the data later
        fdt.pack()
        self._fdt = Fdt.FromData(fdt.as_bytearray())
        self._fdt.Scan()