state.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. # SPDX-License-Identifier: GPL-2.0+
  2. # Copyright 2018 Google, Inc
  3. # Written by Simon Glass <sjg@chromium.org>
  4. #
  5. # Holds and modifies the state information held by binman
  6. #
  7. import hashlib
  8. import re
  9. from sets import Set
  10. import os
  11. import tools
  12. # Records the device-tree files known to binman, keyed by filename (e.g.
  13. # 'u-boot-spl.dtb')
  14. fdt_files = {}
  15. # Arguments passed to binman to provide arguments to entries
  16. entry_args = {}
  17. # True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
  18. # ftest.py)
  19. use_fake_dtb = False
  20. # Set of all device tree files references by images
  21. fdt_set = Set()
  22. # Same as above, but excluding the main one
  23. fdt_subset = Set()
  24. # The DTB which contains the full image information
  25. main_dtb = None
  26. def GetFdt(fname):
  27. """Get the Fdt object for a particular device-tree filename
  28. Binman keeps track of at least one device-tree file called u-boot.dtb but
  29. can also have others (e.g. for SPL). This function looks up the given
  30. filename and returns the associated Fdt object.
  31. Args:
  32. fname: Filename to look up (e.g. 'u-boot.dtb').
  33. Returns:
  34. Fdt object associated with the filename
  35. """
  36. return fdt_files[fname]
  37. def GetFdtPath(fname):
  38. """Get the full pathname of a particular Fdt object
  39. Similar to GetFdt() but returns the pathname associated with the Fdt.
  40. Args:
  41. fname: Filename to look up (e.g. 'u-boot.dtb').
  42. Returns:
  43. Full path name to the associated Fdt
  44. """
  45. return fdt_files[fname]._fname
  46. def GetFdtContents(fname):
  47. """Looks up the FDT pathname and contents
  48. This is used to obtain the Fdt pathname and contents when needed by an
  49. entry. It supports a 'fake' dtb, allowing tests to substitute test data for
  50. the real dtb.
  51. Args:
  52. fname: Filename to look up (e.g. 'u-boot.dtb').
  53. Returns:
  54. tuple:
  55. pathname to Fdt
  56. Fdt data (as bytes)
  57. """
  58. if fname in fdt_files and not use_fake_dtb:
  59. pathname = GetFdtPath(fname)
  60. data = GetFdt(fname).GetContents()
  61. else:
  62. pathname = tools.GetInputFilename(fname)
  63. data = tools.ReadFile(pathname)
  64. return pathname, data
  65. def SetEntryArgs(args):
  66. """Set the value of the entry args
  67. This sets up the entry_args dict which is used to supply entry arguments to
  68. entries.
  69. Args:
  70. args: List of entry arguments, each in the format "name=value"
  71. """
  72. global entry_args
  73. entry_args = {}
  74. if args:
  75. for arg in args:
  76. m = re.match('([^=]*)=(.*)', arg)
  77. if not m:
  78. raise ValueError("Invalid entry arguemnt '%s'" % arg)
  79. entry_args[m.group(1)] = m.group(2)
  80. def GetEntryArg(name):
  81. """Get the value of an entry argument
  82. Args:
  83. name: Name of argument to retrieve
  84. Returns:
  85. String value of argument
  86. """
  87. return entry_args.get(name)
  88. def Prepare(images, dtb):
  89. """Get device tree files ready for use
  90. This sets up a set of device tree files that can be retrieved by GetFdts().
  91. At present there is only one, that for U-Boot proper.
  92. Args:
  93. images: List of images being used
  94. dtb: Main dtb
  95. """
  96. global fdt_set, fdt_subset, fdt_files, main_dtb
  97. # Import these here in case libfdt.py is not available, in which case
  98. # the above help option still works.
  99. import fdt
  100. import fdt_util
  101. # If we are updating the DTBs we need to put these updated versions
  102. # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
  103. # since it is assumed to be the one passed in with options.dt, and
  104. # was handled just above.
  105. main_dtb = dtb
  106. fdt_files.clear()
  107. fdt_files['u-boot.dtb'] = dtb
  108. fdt_subset = Set()
  109. if not use_fake_dtb:
  110. for image in images.values():
  111. fdt_subset.update(image.GetFdtSet())
  112. fdt_subset.discard('u-boot.dtb')
  113. for other_fname in fdt_subset:
  114. infile = tools.GetInputFilename(other_fname)
  115. other_fname_dtb = fdt_util.EnsureCompiled(infile)
  116. out_fname = tools.GetOutputFilename('%s.out' %
  117. os.path.split(other_fname)[1])
  118. tools.WriteFile(out_fname, tools.ReadFile(other_fname_dtb))
  119. other_dtb = fdt.FdtScan(out_fname)
  120. fdt_files[other_fname] = other_dtb
  121. def GetFdts():
  122. """Yield all device tree files being used by binman
  123. Yields:
  124. Device trees being used (U-Boot proper, SPL, TPL)
  125. """
  126. yield main_dtb
  127. for other_fname in fdt_subset:
  128. yield fdt_files[other_fname]
  129. def GetUpdateNodes(node):
  130. """Yield all the nodes that need to be updated in all device trees
  131. The property referenced by this node is added to any device trees which
  132. have the given node. Due to removable of unwanted notes, SPL and TPL may
  133. not have this node.
  134. Args:
  135. node: Node object in the main device tree to look up
  136. Yields:
  137. Node objects in each device tree that is in use (U-Boot proper, which
  138. is node, SPL and TPL)
  139. """
  140. yield node
  141. for dtb in fdt_files.values():
  142. if dtb != node.GetFdt():
  143. other_node = dtb.GetNode(node.path)
  144. if other_node:
  145. yield other_node
  146. def AddZeroProp(node, prop):
  147. """Add a new property to affected device trees with an integer value of 0.
  148. Args:
  149. prop_name: Name of property
  150. """
  151. for n in GetUpdateNodes(node):
  152. n.AddZeroProp(prop)
  153. def AddSubnode(node, name):
  154. """Add a new subnode to a node in affected device trees
  155. Args:
  156. node: Node to add to
  157. name: name of node to add
  158. Returns:
  159. New subnode that was created in main tree
  160. """
  161. first = None
  162. for n in GetUpdateNodes(node):
  163. subnode = n.AddSubnode(name)
  164. if not first:
  165. first = subnode
  166. return first
  167. def AddString(node, prop, value):
  168. """Add a new string property to affected device trees
  169. Args:
  170. prop_name: Name of property
  171. value: String value (which will be \0-terminated in the DT)
  172. """
  173. for n in GetUpdateNodes(node):
  174. n.AddString(prop, value)
  175. def SetInt(node, prop, value):
  176. """Update an integer property in affected device trees with an integer value
  177. This is not allowed to change the size of the FDT.
  178. Args:
  179. prop_name: Name of property
  180. """
  181. for n in GetUpdateNodes(node):
  182. n.SetInt(prop, value)
  183. def CheckAddHashProp(node):
  184. hash_node = node.FindNode('hash')
  185. if hash_node:
  186. algo = hash_node.props.get('algo')
  187. if not algo:
  188. return "Missing 'algo' property for hash node"
  189. if algo.value == 'sha256':
  190. size = 32
  191. else:
  192. return "Unknown hash algorithm '%s'" % algo
  193. for n in GetUpdateNodes(hash_node):
  194. n.AddEmptyProp('value', size)
  195. def CheckSetHashValue(node, get_data_func):
  196. hash_node = node.FindNode('hash')
  197. if hash_node:
  198. algo = hash_node.props.get('algo').value
  199. if algo == 'sha256':
  200. m = hashlib.sha256()
  201. m.update(get_data_func())
  202. data = m.digest()
  203. for n in GetUpdateNodes(hash_node):
  204. n.SetData('value', data)