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 a full map of the firmware image 6 7This handles putting an FDT into the image with just the information about the 8image. 9""" 10 11from binman.entry import Entry 12from u_boot_pylib import tools 13from u_boot_pylib import tout 14 15FDTMAP_MAGIC = b'_FDTMAP_' 16FDTMAP_HDR_LEN = 16 17 18# These is imported if needed 19Fdt = None 20libfdt = None 21state = None 22 23def LocateFdtmap(data): 24 """Search an image for an fdt map 25 26 Args: 27 data: Data to search 28 29 Returns: 30 Position of fdt map in data, or None if not found. Note that the 31 position returned is of the FDT header, i.e. before the FDT data 32 """ 33 hdr_pos = data.find(FDTMAP_MAGIC) 34 size = len(data) 35 if hdr_pos != -1: 36 hdr = data[hdr_pos:hdr_pos + FDTMAP_HDR_LEN] 37 if len(hdr) == FDTMAP_HDR_LEN: 38 return hdr_pos 39 return None 40 41class Entry_fdtmap(Entry): 42 """An entry which contains an FDT map 43 44 Properties / Entry arguments: 45 None 46 47 An FDT map is just a header followed by an FDT containing a list of all the 48 entries in the image. The root node corresponds to the image node in the 49 original FDT, and an image-name property indicates the image name in that 50 original tree. 51 52 The header is the string _FDTMAP_ followed by 8 unused bytes. 53 54 When used, this entry will be populated with an FDT map which reflects the 55 entries in the current image. Hierarchy is preserved, and all offsets and 56 sizes are included. 57 58 Note that the -u option must be provided to ensure that binman updates the 59 FDT with the position of each entry. 60 61 Example output for a simple image with U-Boot and an FDT map:: 62 63 / { 64 image-name = "binman"; 65 size = <0x00000112>; 66 image-pos = <0x00000000>; 67 offset = <0x00000000>; 68 u-boot { 69 size = <0x00000004>; 70 image-pos = <0x00000000>; 71 offset = <0x00000000>; 72 }; 73 fdtmap { 74 size = <0x0000010e>; 75 image-pos = <0x00000004>; 76 offset = <0x00000004>; 77 }; 78 }; 79 80 If allow-repack is used then 'orig-offset' and 'orig-size' properties are 81 added as necessary. See the binman README. 82 83 When extracting files, an alternative 'fdt' format is available for fdtmaps. 84 Use `binman extract -F fdt ...` to use this. It will export a devicetree, 85 without the fdtmap header, so it can be viewed with `fdtdump`. 86 """ 87 def __init__(self, section, etype, node): 88 # Put these here to allow entry-docs and help to work without libfdt 89 global libfdt 90 global state 91 global Fdt 92 93 import libfdt 94 from binman import state 95 from dtoc.fdt import Fdt 96 97 super().__init__(section, etype, node) 98 self.alt_formats = ['fdt'] 99 100 def CheckAltFormats(self, alt_formats): 101 alt_formats['fdt'] = self, 'Extract the devicetree blob from the fdtmap' 102 103 def _GetFdtmap(self): 104 """Build an FDT map from the entries in the current image 105 106 Returns: 107 FDT map binary data 108 """ 109 fsw = libfdt.FdtSw() 110 fsw.finish_reservemap() 111 112 def _AddNode(node): 113 """Add a node to the FDT map""" 114 for pname, prop in node.props.items(): 115 fsw.property(pname, prop.bytes) 116 for subnode in node.subnodes: 117 with fsw.add_node(subnode.name): 118 _AddNode(subnode) 119 120 data = state.GetFdtContents('fdtmap')[1] 121 # If we have an fdtmap it means that we are using this as the 122 # fdtmap for this image. 123 if data is None: 124 # Get the FDT data into an Fdt object 125 data = state.GetFdtContents()[1] 126 infdt = Fdt.FromData(data) 127 infdt.Scan() 128 129 # Find the node for the image containing the Fdt-map entry 130 path = self.section.GetPath() 131 self.Detail("Fdtmap: Using section '%s' (path '%s')" % 132 (self.section.name, path)) 133 node = infdt.GetNode(path) 134 if not node: 135 self.Raise("Internal error: Cannot locate node for path '%s'" % 136 path) 137 138 # Build a new tree with all nodes and properties starting from that 139 # node 140 with fsw.add_node(''): 141 fsw.property_string('image-node', node.name) 142 _AddNode(node) 143 fdt = fsw.as_fdt() 144 145 # Pack this new FDT and return its contents 146 fdt.pack() 147 outfdt = Fdt.FromData(fdt.as_bytearray()) 148 data = outfdt.GetContents() 149 data = FDTMAP_MAGIC + tools.get_bytes(0, 8) + data 150 return data 151 152 def ObtainContents(self): 153 """Obtain a placeholder for the fdt-map contents""" 154 self.SetContents(self._GetFdtmap()) 155 return True 156 157 def ProcessContents(self): 158 """Write an updated version of the FDT map to this entry 159 160 This is necessary since new data may have been written back to it during 161 processing, e.g. the image-pos properties. 162 """ 163 return self.ProcessContentsUpdate(self._GetFdtmap()) 164 165 def GetAltFormat(self, data, alt_format): 166 if alt_format == 'fdt': 167 return data[FDTMAP_HDR_LEN:] 168