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 def _AddNode(node): 110 """Add a node to the FDT map""" 111 for pname, prop in node.props.items(): 112 fsw.property(pname, prop.bytes) 113 for subnode in node.subnodes: 114 with fsw.add_node(subnode.name): 115 _AddNode(subnode) 116 117 data = state.GetFdtContents('fdtmap')[1] 118 # If we have an fdtmap it means that we are using this as the 119 # fdtmap for this image. 120 if data is None: 121 # Get the FDT data into an Fdt object 122 data = state.GetFdtContents()[1] 123 infdt = Fdt.FromData(data) 124 infdt.Scan() 125 126 # Find the node for the image containing the Fdt-map entry 127 path = self.section.GetPath() 128 self.Detail("Fdtmap: Using section '%s' (path '%s')" % 129 (self.section.name, path)) 130 node = infdt.GetNode(path) 131 if not node: 132 self.Raise("Internal error: Cannot locate node for path '%s'" % 133 path) 134 135 # Build a new tree with all nodes and properties starting from that 136 # node 137 fsw = libfdt.FdtSw() 138 fsw.finish_reservemap() 139 with fsw.add_node(''): 140 fsw.property_string('image-node', node.name) 141 _AddNode(node) 142 fdt = fsw.as_fdt() 143 144 # Pack this new FDT and return its contents 145 fdt.pack() 146 outfdt = Fdt.FromData(fdt.as_bytearray()) 147 data = outfdt.GetContents() 148 data = FDTMAP_MAGIC + tools.get_bytes(0, 8) + data 149 return data 150 151 def ObtainContents(self): 152 """Obtain a placeholder for the fdt-map contents""" 153 self.SetContents(self._GetFdtmap()) 154 return True 155 156 def ProcessContents(self): 157 """Write an updated version of the FDT map to this entry 158 159 This is necessary since new data may have been written back to it during 160 processing, e.g. the image-pos properties. 161 """ 162 return self.ProcessContentsUpdate(self._GetFdtmap()) 163 164 def GetAltFormat(self, data, alt_format): 165 if alt_format == 'fdt': 166 return data[FDTMAP_HDR_LEN:] 167