image_header.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. # SPDX-License-Identifier: GPL-2.0+
  2. # Copyright (c) 2018 Google, Inc
  3. # Written by Simon Glass <sjg@chromium.org>
  4. """Entry-type module for an image header which points to the FDT map
  5. This creates an 8-byte entry with a magic number and the offset of the FDT map
  6. (which is another entry in the image), relative to the start or end of the
  7. image.
  8. """
  9. import struct
  10. from binman.entry import Entry
  11. from dtoc import fdt_util
  12. IMAGE_HEADER_MAGIC = b'BinM'
  13. IMAGE_HEADER_LEN = 8
  14. def LocateHeaderOffset(data):
  15. """Search an image for an image header
  16. Args:
  17. data: Data to search
  18. Returns:
  19. Offset of image header in the image, or None if not found
  20. """
  21. hdr_pos = data.find(IMAGE_HEADER_MAGIC)
  22. if hdr_pos != -1:
  23. size = len(data)
  24. hdr = data[hdr_pos:hdr_pos + IMAGE_HEADER_LEN]
  25. if len(hdr) == IMAGE_HEADER_LEN:
  26. offset = struct.unpack('<I', hdr[4:])[0]
  27. if hdr_pos == len(data) - IMAGE_HEADER_LEN:
  28. pos = size + offset - (1 << 32)
  29. else:
  30. pos = offset
  31. return pos
  32. return None
  33. class Entry_image_header(Entry):
  34. """An entry which contains a pointer to the FDT map
  35. Properties / Entry arguments:
  36. location: Location of header ("start" or "end" of image). This is
  37. optional. If omitted then the entry must have an offset property.
  38. This adds an 8-byte entry to the start or end of the image, pointing to the
  39. location of the FDT map. The format is a magic number followed by an offset
  40. from the start or end of the image, in twos-compliment format.
  41. This entry must be in the top-level part of the image.
  42. NOTE: If the location is at the start/end, you will probably need to specify
  43. sort-by-offset for the image, unless you actually put the image header
  44. first/last in the entry list.
  45. """
  46. def __init__(self, section, etype, node):
  47. super().__init__(section, etype, node)
  48. self.location = fdt_util.GetString(self._node, 'location')
  49. def _GetHeader(self):
  50. image_pos = self.GetSiblingImagePos('fdtmap')
  51. if image_pos == False:
  52. self.Raise("'image_header' section must have an 'fdtmap' sibling")
  53. elif image_pos is None:
  54. # This will be available when called from ProcessContents(), but not
  55. # when called from ObtainContents()
  56. offset = 0xffffffff
  57. else:
  58. image_size = self.section.GetImageSize() or 0
  59. base = (0 if self.location != 'end' else image_size)
  60. offset = (image_pos - base) & 0xffffffff
  61. data = IMAGE_HEADER_MAGIC + struct.pack('<I', offset)
  62. return data
  63. def ObtainContents(self):
  64. """Obtain a placeholder for the header contents"""
  65. self.SetContents(self._GetHeader())
  66. return True
  67. def Pack(self, offset):
  68. """Special pack method to set the offset to start/end of image"""
  69. if not self.offset:
  70. if self.location not in ['start', 'end']:
  71. self.Raise("Invalid location '%s', expected 'start' or 'end'" %
  72. self.location)
  73. order = self.GetSiblingOrder()
  74. if self.location != order and not self.section.GetSort():
  75. self.Raise("Invalid sibling order '%s' for image-header: Must be at '%s' to match location" %
  76. (order, self.location))
  77. if self.location != 'end':
  78. offset = 0
  79. else:
  80. image_size = self.section.GetImageSize()
  81. if image_size is None:
  82. # We don't know the image, but this must be the last entry,
  83. # so we can assume it goes
  84. offset = offset
  85. else:
  86. offset = image_size - IMAGE_HEADER_LEN
  87. offset += self.section.GetStartOffset()
  88. return super().Pack(offset)
  89. def ProcessContents(self):
  90. """Write an updated version of the FDT map to this entry
  91. This is necessary since image_pos is not available when ObtainContents()
  92. is called, since by then the entries have not been packed in the image.
  93. """
  94. return self.ProcessContentsUpdate(self._GetHeader())