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