control.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. # SPDX-License-Identifier: GPL-2.0+
  2. # Copyright (c) 2016 Google, Inc
  3. # Written by Simon Glass <sjg@chromium.org>
  4. #
  5. # Creates binary images from input files controlled by a description
  6. #
  7. from collections import OrderedDict
  8. import os
  9. import sys
  10. import tools
  11. import command
  12. import elf
  13. import fdt
  14. import fdt_util
  15. from image import Image
  16. import tout
  17. # List of images we plan to create
  18. # Make this global so that it can be referenced from tests
  19. images = OrderedDict()
  20. # Records the device-tree files known to binman, keyed by filename (e.g.
  21. # 'u-boot-spl.dtb')
  22. fdt_files = {}
  23. def _ReadImageDesc(binman_node):
  24. """Read the image descriptions from the /binman node
  25. This normally produces a single Image object called 'image'. But if
  26. multiple images are present, they will all be returned.
  27. Args:
  28. binman_node: Node object of the /binman node
  29. Returns:
  30. OrderedDict of Image objects, each of which describes an image
  31. """
  32. images = OrderedDict()
  33. if 'multiple-images' in binman_node.props:
  34. for node in binman_node.subnodes:
  35. images[node.name] = Image(node.name, node)
  36. else:
  37. images['image'] = Image('image', binman_node)
  38. return images
  39. def _FindBinmanNode(dtb):
  40. """Find the 'binman' node in the device tree
  41. Args:
  42. dtb: Fdt object to scan
  43. Returns:
  44. Node object of /binman node, or None if not found
  45. """
  46. for node in dtb.GetRoot().subnodes:
  47. if node.name == 'binman':
  48. return node
  49. return None
  50. def GetFdt(fname):
  51. """Get the Fdt object for a particular device-tree filename
  52. Binman keeps track of at least one device-tree file called u-boot.dtb but
  53. can also have others (e.g. for SPL). This function looks up the given
  54. filename and returns the associated Fdt object.
  55. Args:
  56. fname: Filename to look up (e.g. 'u-boot.dtb').
  57. Returns:
  58. Fdt object associated with the filename
  59. """
  60. return fdt_files[fname]
  61. def GetFdtPath(fname):
  62. return fdt_files[fname]._fname
  63. def Binman(options, args):
  64. """The main control code for binman
  65. This assumes that help and test options have already been dealt with. It
  66. deals with the core task of building images.
  67. Args:
  68. options: Command line options object
  69. args: Command line arguments (list of strings)
  70. """
  71. global images
  72. if options.full_help:
  73. pager = os.getenv('PAGER')
  74. if not pager:
  75. pager = 'more'
  76. fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
  77. 'README')
  78. command.Run(pager, fname)
  79. return 0
  80. # Try to figure out which device tree contains our image description
  81. if options.dt:
  82. dtb_fname = options.dt
  83. else:
  84. board = options.board
  85. if not board:
  86. raise ValueError('Must provide a board to process (use -b <board>)')
  87. board_pathname = os.path.join(options.build_dir, board)
  88. dtb_fname = os.path.join(board_pathname, 'u-boot.dtb')
  89. if not options.indir:
  90. options.indir = ['.']
  91. options.indir.append(board_pathname)
  92. try:
  93. tout.Init(options.verbosity)
  94. elf.debug = options.debug
  95. try:
  96. tools.SetInputDirs(options.indir)
  97. tools.PrepareOutputDir(options.outdir, options.preserve)
  98. # Get the device tree ready by compiling it and copying the compiled
  99. # output into a file in our output directly. Then scan it for use
  100. # in binman.
  101. dtb_fname = fdt_util.EnsureCompiled(dtb_fname)
  102. fname = tools.GetOutputFilename('u-boot-out.dtb')
  103. with open(dtb_fname) as infd:
  104. with open(fname, 'wb') as outfd:
  105. outfd.write(infd.read())
  106. dtb = fdt.FdtScan(fname)
  107. # Note the file so that GetFdt() can find it
  108. fdt_files['u-boot.dtb'] = dtb
  109. node = _FindBinmanNode(dtb)
  110. if not node:
  111. raise ValueError("Device tree '%s' does not have a 'binman' "
  112. "node" % dtb_fname)
  113. images = _ReadImageDesc(node)
  114. # Prepare the device tree by making sure that any missing
  115. # properties are added (e.g. 'pos' and 'size'). The values of these
  116. # may not be correct yet, but we add placeholders so that the
  117. # size of the device tree is correct. Later, in
  118. # SetCalculatedProperties() we will insert the correct values
  119. # without changing the device-tree size, thus ensuring that our
  120. # entry offsets remain the same.
  121. for image in images.values():
  122. if options.update_fdt:
  123. image.AddMissingProperties()
  124. image.ProcessFdt(dtb)
  125. dtb.Pack()
  126. dtb.Flush()
  127. for image in images.values():
  128. # Perform all steps for this image, including checking and
  129. # writing it. This means that errors found with a later
  130. # image will be reported after earlier images are already
  131. # completed and written, but that does not seem important.
  132. image.GetEntryContents()
  133. image.GetEntryOffsets()
  134. image.PackEntries()
  135. image.CheckSize()
  136. image.CheckEntries()
  137. image.SetImagePos()
  138. if options.update_fdt:
  139. image.SetCalculatedProperties()
  140. image.ProcessEntryContents()
  141. image.WriteSymbols()
  142. image.BuildImage()
  143. if options.map:
  144. image.WriteMap()
  145. with open(fname, 'wb') as outfd:
  146. outfd.write(dtb.GetContents())
  147. finally:
  148. tools.FinaliseOutputDir()
  149. finally:
  150. tout.Uninit()
  151. return 0