Example #1
0
 def testLookupPhandle(self):
     """Test looking up a single phandle"""
     dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
     node = dtb.GetNode('/phandle-source2')
     prop = node.props['clocks']
     target = dtb.GetNode('/phandle-target')
     self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
Example #2
0
 def GetNode(self):
     binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
     tools.PrepareOutputDir(None)
     fname = fdt_util.EnsureCompiled(
         os.path.join(binman_dir,('test/05_simple.dts')))
     dtb = fdt.FdtScan(fname)
     return dtb.GetNode('/binman/u-boot')
    def _RunMicrocodeTest(self, dts_fname, nodtb_data):
        data = self._DoReadFile(dts_fname, True)

        # Now check the device tree has no microcode
        second = data[len(nodtb_data):]
        fname = tools.GetOutputFilename('test.dtb')
        with open(fname, 'wb') as fd:
            fd.write(second)
        dtb = fdt.FdtScan(fname)
        ucode = dtb.GetNode('/microcode')
        self.assertTrue(ucode)
        for node in ucode.subnodes:
            self.assertFalse(node.props.get('data'))

        fdt_len = self.GetFdtLen(second)
        third = second[fdt_len:]

        # Check that the microcode appears immediately after the Fdt
        # This matches the concatenation of the data properties in
        # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
        ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
                                 0x78235609)
        self.assertEqual(ucode_data, third[:len(ucode_data)])
        ucode_pos = len(nodtb_data) + fdt_len

        # Check that the microcode pointer was inserted. It should match the
        # expected position and size
        pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
                                   len(ucode_data))
        first = data[:len(nodtb_data)]
        return first, pos_and_size
Example #4
0
    def scan_dtb(self):
        """Scan the device tree to obtain a tree of nodes and properties

        Once this is done, self._fdt.GetRoot() can be called to obtain the
        device tree root node, and progress from there.
        """
        self._fdt = fdt.FdtScan(self._dtb_fname)
Example #5
0
 def testGetPhandleList(self):
     dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
     node = dtb.GetNode('/phandle-source2')
     self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
     node = dtb.GetNode('/phandle-source')
     self.assertEqual([1, 2, 11, 3, 12, 13, 1],
                      fdt_util.GetPhandleList(node, 'clocks'))
     self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
Example #6
0
    def testFdtCellsToCpu(self):
        val = self.node.props['intarray'].value
        self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
        self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))

        dtb2 = fdt.FdtScan('tools/dtoc/dtoc_test_addr64.dts')
        node2 = dtb2.GetNode('/test1')
        val = node2.props['reg'].value
        self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
Example #7
0
    def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
        """Handle running a test for insertion of microcode

        Args:
            dts_fname: Name of test .dts file
            nodtb_data: Data that we expect in the first section
            ucode_second: True if the microsecond entry is second instead of
                third

        Returns:
            Tuple:
                Contents of first region (U-Boot or SPL)
                Position and size components of microcode pointer, as inserted
                    in the above (two 4-byte words)
        """
        data = self._DoReadFile(dts_fname, True)

        # Now check the device tree has no microcode
        if ucode_second:
            ucode_content = data[len(nodtb_data):]
            ucode_pos = len(nodtb_data)
            dtb_with_ucode = ucode_content[16:]
            fdt_len = self.GetFdtLen(dtb_with_ucode)
        else:
            dtb_with_ucode = data[len(nodtb_data):]
            fdt_len = self.GetFdtLen(dtb_with_ucode)
            ucode_content = dtb_with_ucode[fdt_len:]
            ucode_pos = len(nodtb_data) + fdt_len
        fname = tools.GetOutputFilename('test.dtb')
        with open(fname, 'wb') as fd:
            fd.write(dtb_with_ucode)
        dtb = fdt.FdtScan(fname)
        ucode = dtb.GetNode('/microcode')
        self.assertTrue(ucode)
        for node in ucode.subnodes:
            self.assertFalse(node.props.get('data'))

        # Check that the microcode appears immediately after the Fdt
        # This matches the concatenation of the data properties in
        # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
        ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
                                 0x78235609)
        self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])

        # Check that the microcode pointer was inserted. It should match the
        # expected position and size
        pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
                                   len(ucode_data))
        u_boot = data[:len(nodtb_data)]
        return u_boot, pos_and_size
Example #8
0
def UpdateFdtContents(etype, data):
    """Update the contents of a particular device tree

    The device tree is updated and written back to its file. This affects what
    is returned from future called to GetFdtContents(), etc.

    Args:
        etype: Entry type (e.g. 'u-boot-dtb')
        data: Data to replace the DTB with
    """
    dtb, fname, entry = output_fdt_info[etype]
    dtb_fname = dtb.GetFilename()
    tools.WriteFile(dtb_fname, data)
    dtb = fdt.FdtScan(dtb_fname)
    output_fdt_info[etype] = [dtb, fname, entry]
    def ObtainContents(self):
        Entry_blob.ObtainContents(self)

        # If the image does not need microcode, there is nothing to do
        ucode_dest_entry = self.image.FindEntryType(
            'u-boot-spl-with-ucode-ptr')
        if not ucode_dest_entry or not ucode_dest_entry.target_pos:
            ucode_dest_entry = self.image.FindEntryType(
                'u-boot-with-ucode-ptr')
        if not ucode_dest_entry or not ucode_dest_entry.target_pos:
            return True

        # Create a new file to hold the copied device tree
        dtb_name = 'u-boot-dtb-with-ucode.dtb'
        fname = tools.GetOutputFilename(dtb_name)
        with open(fname, 'wb') as fd:
            fd.write(self.data)

        # Remove the microcode
        dtb = fdt.FdtScan(fname)
        ucode = dtb.GetNode('/microcode')
        if not ucode:
            raise self.Raise("No /microcode node found in '%s'" % fname)

        # There's no need to collate it (move all microcode into one place)
        # if we only have one chunk of microcode.
        self.collate = len(ucode.subnodes) > 1
        for node in ucode.subnodes:
            data_prop = node.props.get('data')
            if data_prop:
                self.ucode_data += ''.join(data_prop.bytes)
                if self.collate:
                    prop = node.DeleteProp('data')
                else:
                    # Find the offset in the device tree of the ucode data
                    self.ucode_offset = data_prop.GetOffset() + 12
                    self.ucode_size = len(data_prop.bytes)
        if self.collate:
            dtb.Pack()
            dtb.Flush()

            # Make this file the contents of this entry
            self._pathname = fname
            self.ReadContents()
        return True
Example #10
0
    def testPackUbootMicrocode(self):
        """Test that x86 microcode can be handled correctly

        We expect to see the following in the image, in order:
            u-boot-nodtb.bin with a microcode pointer inserted at the correct
                place
            u-boot.dtb with the microcode removed
            the microcode
        """
        data = self._DoReadFile('34_x86_ucode.dts', True)

        # Now check the device tree has no microcode
        second = data[len(U_BOOT_NODTB_DATA):]
        fname = tools.GetOutputFilename('test.dtb')
        with open(fname, 'wb') as fd:
            fd.write(second)
        dtb = fdt.FdtScan(fname)
        ucode = dtb.GetNode('/microcode')
        self.assertTrue(ucode)
        for node in ucode.subnodes:
            self.assertFalse(node.props.get('data'))

        fdt_len = self.GetFdtLen(second)
        third = second[fdt_len:]

        # Check that the microcode appears immediately after the Fdt
        # This matches the concatenation of the data properties in
        # the /microcode/update@xxx nodes in x86_ucode.dts.
        ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
                                 0x78235609)
        self.assertEqual(ucode_data, third[:len(ucode_data)])
        ucode_pos = len(U_BOOT_NODTB_DATA) + fdt_len

        # Check that the microcode pointer was inserted. It should match the
        # expected position and size
        pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
                                   len(ucode_data))
        first = data[:len(U_BOOT_NODTB_DATA)]
        self.assertEqual(
            'nodtb with microcode' + pos_and_size + ' somewhere in here',
            first)
Example #11
0
def Prepare(images, dtb):
    """Get device tree files ready for use

    This sets up a set of device tree files that can be retrieved by
    GetAllFdts(). This includes U-Boot proper and any SPL device trees.

    Args:
        images: List of images being used
        dtb: Main dtb
    """
    global output_fdt_info, main_dtb, fdt_path_prefix
    # Import these here in case libfdt.py is not available, in which case
    # the above help option still works.
    import fdt
    import fdt_util

    # If we are updating the DTBs we need to put these updated versions
    # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
    # since it is assumed to be the one passed in with options.dt, and
    # was handled just above.
    main_dtb = dtb
    output_fdt_info.clear()
    fdt_path_prefix = ''
    output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb', None]
    output_fdt_info['u-boot-spl-dtb'] = [dtb, 'spl/u-boot-spl.dtb', None]
    output_fdt_info['u-boot-tpl-dtb'] = [dtb, 'tpl/u-boot-tpl.dtb', None]
    if not use_fake_dtb:
        fdt_set = {}
        for image in images.values():
            fdt_set.update(image.GetFdts())
        for etype, other in fdt_set.items():
            entry, other_fname = other
            infile = tools.GetInputFilename(other_fname)
            other_fname_dtb = fdt_util.EnsureCompiled(infile)
            out_fname = tools.GetOutputFilename('%s.out' %
                                                os.path.split(other_fname)[1])
            tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
            other_dtb = fdt.FdtScan(out_fname)
            output_fdt_info[etype] = [other_dtb, out_fname, entry]
Example #12
0
def Prepare(images, dtb):
    """Get device tree files ready for use

    This sets up a set of device tree files that can be retrieved by GetFdts().
    At present there is only one, that for U-Boot proper.

    Args:
        images: List of images being used
        dtb: Main dtb
    """
    global fdt_set, fdt_subset, fdt_files, main_dtb
    # Import these here in case libfdt.py is not available, in which case
    # the above help option still works.
    import fdt
    import fdt_util

    # If we are updating the DTBs we need to put these updated versions
    # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
    # since it is assumed to be the one passed in with options.dt, and
    # was handled just above.
    main_dtb = dtb
    fdt_files.clear()
    fdt_files['u-boot.dtb'] = dtb
    fdt_subset = set()
    if not use_fake_dtb:
        for image in images.values():
            fdt_subset.update(image.GetFdtSet())
        fdt_subset.discard('u-boot.dtb')
        for other_fname in fdt_subset:
            infile = tools.GetInputFilename(other_fname)
            other_fname_dtb = fdt_util.EnsureCompiled(infile)
            out_fname = tools.GetOutputFilename('%s.out' %
                                                os.path.split(other_fname)[1])
            tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
            other_dtb = fdt.FdtScan(out_fname)
            fdt_files[other_fname] = other_dtb
Example #13
0
 def testPhandle(self):
     dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
     node = dtb.GetNode('/phandle-source2')
     prop = node.props['clocks']
     self.assertTrue(fdt32_to_cpu(prop.value) > 0)
Example #14
0
def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
    """Prepare the images to be processed and select the device tree

    This function:
    - reads in the device tree
    - finds and scans the binman node to create all entries
    - selects which images to build
    - Updates the device tress with placeholder properties for offset,
        image-pos, etc.

    Args:
        dtb_fname: Filename of the device tree file to use (.dts or .dtb)
        selected_images: List of images to output, or None for all
        update_fdt: True to update the FDT wth entry offsets, etc.
    """
    # Import these here in case libfdt.py is not available, in which case
    # the above help option still works.
    import fdt
    import fdt_util
    global images

    # Get the device tree ready by compiling it and copying the compiled
    # output into a file in our output directly. Then scan it for use
    # in binman.
    dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
    fname = tools.GetOutputFilename('u-boot.dtb.out')
    tools.WriteFile(fname, tools.ReadFile(dtb_fname))
    dtb = fdt.FdtScan(fname)

    node = _FindBinmanNode(dtb)
    if not node:
        raise ValueError("Device tree '%s' does not have a 'binman' "
                         "node" % dtb_fname)

    images = _ReadImageDesc(node)

    if select_images:
        skip = []
        new_images = OrderedDict()
        for name, image in images.items():
            if name in select_images:
                new_images[name] = image
            else:
                skip.append(name)
        images = new_images
        tout.Notice('Skipping images: %s' % ', '.join(skip))

    state.Prepare(images, dtb)

    # Prepare the device tree by making sure that any missing
    # properties are added (e.g. 'pos' and 'size'). The values of these
    # may not be correct yet, but we add placeholders so that the
    # size of the device tree is correct. Later, in
    # SetCalculatedProperties() we will insert the correct values
    # without changing the device-tree size, thus ensuring that our
    # entry offsets remain the same.
    for image in images.values():
        image.ExpandEntries()
        if update_fdt:
            image.AddMissingProperties()
        image.ProcessFdt(dtb)

    for dtb_item in state.GetAllFdts():
        dtb_item.Sync(auto_resize=True)
        dtb_item.Pack()
        dtb_item.Flush()
    return images
Example #15
0
def Binman(options, args):
    """The main control code for binman

    This assumes that help and test options have already been dealt with. It
    deals with the core task of building images.

    Args:
        options: Command line options object
        args: Command line arguments (list of strings)
    """
    global images

    if options.full_help:
        pager = os.getenv('PAGER')
        if not pager:
            pager = 'more'
        fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
                             'README')
        command.Run(pager, fname)
        return 0

    # Try to figure out which device tree contains our image description
    if options.dt:
        dtb_fname = options.dt
    else:
        board = options.board
        if not board:
            raise ValueError(
                'Must provide a board to process (use -b <board>)')
        board_pathname = os.path.join(options.build_dir, board)
        dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
        if not options.indir:
            options.indir = ['.']
        options.indir.append(board_pathname)

    try:
        # Import these here in case libfdt.py is not available, in which case
        # the above help option still works.
        import fdt
        import fdt_util

        tout.Init(options.verbosity)
        elf.debug = options.debug
        try:
            tools.SetInputDirs(options.indir)
            tools.PrepareOutputDir(options.outdir, options.preserve)
            SetEntryArgs(options.entry_arg)

            # Get the device tree ready by compiling it and copying the compiled
            # output into a file in our output directly. Then scan it for use
            # in binman.
            dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
            fname = tools.GetOutputFilename('u-boot-out.dtb')
            with open(dtb_fname) as infd:
                with open(fname, 'wb') as outfd:
                    outfd.write(infd.read())
            dtb = fdt.FdtScan(fname)

            # Note the file so that GetFdt() can find it
            fdt_files['u-boot.dtb'] = dtb
            node = _FindBinmanNode(dtb)
            if not node:
                raise ValueError("Device tree '%s' does not have a 'binman' "
                                 "node" % dtb_fname)

            images = _ReadImageDesc(node)

            # Prepare the device tree by making sure that any missing
            # properties are added (e.g. 'pos' and 'size'). The values of these
            # may not be correct yet, but we add placeholders so that the
            # size of the device tree is correct. Later, in
            # SetCalculatedProperties() we will insert the correct values
            # without changing the device-tree size, thus ensuring that our
            # entry offsets remain the same.
            for image in images.values():
                if options.update_fdt:
                    image.AddMissingProperties()
                image.ProcessFdt(dtb)

            dtb.Pack()
            dtb.Flush()

            for image in images.values():
                # Perform all steps for this image, including checking and
                # writing it. This means that errors found with a later
                # image will be reported after earlier images are already
                # completed and written, but that does not seem important.
                image.GetEntryContents()
                image.GetEntryOffsets()
                image.PackEntries()
                image.CheckSize()
                image.CheckEntries()
                image.SetImagePos()
                if options.update_fdt:
                    image.SetCalculatedProperties()
                image.ProcessEntryContents()
                image.WriteSymbols()
                image.BuildImage()
                if options.map:
                    image.WriteMap()
            with open(fname, 'wb') as outfd:
                outfd.write(dtb.GetContents())
        finally:
            tools.FinaliseOutputDir()
    finally:
        tout.Uninit()

    return 0
Example #16
0
 def setUp(self):
     self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
Example #17
0
def Binman(args):
    """The main control code for binman

    This assumes that help and test options have already been dealt with. It
    deals with the core task of building images.

    Args:
        args: Command line arguments Namespace object
    """
    global images

    if args.full_help:
        pager = os.getenv('PAGER')
        if not pager:
            pager = 'more'
        fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
                             'README')
        command.Run(pager, fname)
        return 0

    if args.cmd == 'ls':
        ListEntries(args.image, args.paths)
        return 0

    if args.cmd == 'extract':
        try:
            tools.PrepareOutputDir(None)
            ExtractEntries(args.image, args.filename, args.outdir, args.paths,
                           not args.uncompressed)
        finally:
            tools.FinaliseOutputDir()
        return 0

    # Try to figure out which device tree contains our image description
    if args.dt:
        dtb_fname = args.dt
    else:
        board = args.board
        if not board:
            raise ValueError(
                'Must provide a board to process (use -b <board>)')
        board_pathname = os.path.join(args.build_dir, board)
        dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
        if not args.indir:
            args.indir = ['.']
        args.indir.append(board_pathname)

    try:
        # Import these here in case libfdt.py is not available, in which case
        # the above help option still works.
        import fdt
        import fdt_util

        tout.Init(args.verbosity)
        elf.debug = args.debug
        cbfs_util.VERBOSE = args.verbosity > 2
        state.use_fake_dtb = args.fake_dtb
        try:
            tools.SetInputDirs(args.indir)
            tools.PrepareOutputDir(args.outdir, args.preserve)
            tools.SetToolPaths(args.toolpath)
            state.SetEntryArgs(args.entry_arg)

            # Get the device tree ready by compiling it and copying the compiled
            # output into a file in our output directly. Then scan it for use
            # in binman.
            dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
            fname = tools.GetOutputFilename('u-boot.dtb.out')
            tools.WriteFile(fname, tools.ReadFile(dtb_fname))
            dtb = fdt.FdtScan(fname)

            node = _FindBinmanNode(dtb)
            if not node:
                raise ValueError("Device tree '%s' does not have a 'binman' "
                                 "node" % dtb_fname)

            images = _ReadImageDesc(node)

            if args.image:
                skip = []
                new_images = OrderedDict()
                for name, image in images.items():
                    if name in args.image:
                        new_images[name] = image
                    else:
                        skip.append(name)
                images = new_images
                if skip and args.verbosity >= 2:
                    print('Skipping images: %s' % ', '.join(skip))

            state.Prepare(images, dtb)

            # Prepare the device tree by making sure that any missing
            # properties are added (e.g. 'pos' and 'size'). The values of these
            # may not be correct yet, but we add placeholders so that the
            # size of the device tree is correct. Later, in
            # SetCalculatedProperties() we will insert the correct values
            # without changing the device-tree size, thus ensuring that our
            # entry offsets remain the same.
            for image in images.values():
                image.ExpandEntries()
                if args.update_fdt:
                    image.AddMissingProperties()
                image.ProcessFdt(dtb)

            for dtb_item in state.GetFdts():
                dtb_item.Sync(auto_resize=True)
                dtb_item.Pack()
                dtb_item.Flush()

            for image in images.values():
                # Perform all steps for this image, including checking and
                # writing it. This means that errors found with a later
                # image will be reported after earlier images are already
                # completed and written, but that does not seem important.
                image.GetEntryContents()
                image.GetEntryOffsets()

                # We need to pack the entries to figure out where everything
                # should be placed. This sets the offset/size of each entry.
                # However, after packing we call ProcessEntryContents() which
                # may result in an entry changing size. In that case we need to
                # do another pass. Since the device tree often contains the
                # final offset/size information we try to make space for this in
                # AddMissingProperties() above. However, if the device is
                # compressed we cannot know this compressed size in advance,
                # since changing an offset from 0x100 to 0x104 (for example) can
                # alter the compressed size of the device tree. So we need a
                # third pass for this.
                passes = 3
                for pack_pass in range(passes):
                    try:
                        image.PackEntries()
                        image.CheckSize()
                        image.CheckEntries()
                    except Exception as e:
                        if args.map:
                            fname = image.WriteMap()
                            print("Wrote map file '%s' to show errors" % fname)
                        raise
                    image.SetImagePos()
                    if args.update_fdt:
                        image.SetCalculatedProperties()
                        for dtb_item in state.GetFdts():
                            dtb_item.Sync()
                    sizes_ok = image.ProcessEntryContents()
                    if sizes_ok:
                        break
                    image.ResetForPack()
                if not sizes_ok:
                    image.Raise(
                        'Entries expanded after packing (tried %s passes)' %
                        passes)

                image.WriteSymbols()
                image.BuildImage()
                if args.map:
                    image.WriteMap()

            # Write the updated FDTs to our output files
            for dtb_item in state.GetFdts():
                tools.WriteFile(dtb_item._fname, dtb_item.GetContents())

        finally:
            tools.FinaliseOutputDir()
    finally:
        tout.Uninit()

    return 0
Example #18
0
 def setUp(self):
     self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
     self.node = self.dtb.GetNode('/spl-test')
Example #19
0
def Binman(options, args):
    """The main control code for binman

    This assumes that help and test options have already been dealt with. It
    deals with the core task of building images.

    Args:
        options: Command line options object
        args: Command line arguments (list of strings)
    """
    global images

    if options.full_help:
        pager = os.getenv('PAGER')
        if not pager:
            pager = 'more'
        fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
                             'README')
        command.Run(pager, fname)
        return 0

    # Try to figure out which device tree contains our image description
    if options.dt:
        dtb_fname = options.dt
    else:
        board = options.board
        if not board:
            raise ValueError(
                'Must provide a board to process (use -b <board>)')
        board_pathname = os.path.join(options.build_dir, board)
        dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
        if not options.indir:
            options.indir = ['.']
        options.indir.append(board_pathname)

    try:
        tout.Init(options.verbosity)
        elf.debug = options.debug
        try:
            tools.SetInputDirs(options.indir)
            tools.PrepareOutputDir(options.outdir, options.preserve)
            dtb = fdt.FdtScan(dtb_fname)
            node = _FindBinmanNode(dtb)
            if not node:
                raise ValueError("Device tree '%s' does not have a 'binman' "
                                 "node" % dtb_fname)
            images = _ReadImageDesc(node)
            for image in images.values():
                # Perform all steps for this image, including checking and
                # writing it. This means that errors found with a later
                # image will be reported after earlier images are already
                # completed and written, but that does not seem important.
                image.GetEntryContents()
                image.GetEntryPositions()
                image.PackEntries()
                image.CheckSize()
                image.CheckEntries()
                image.ProcessEntryContents()
                image.WriteSymbols()
                image.BuildImage()
                if options.map:
                    image.WriteMap()
        finally:
            tools.FinaliseOutputDir()
    finally:
        tout.Uninit()

    return 0