Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 1 | # SPDX-License-Identifier: GPL-2.0+ |
| 2 | # Copyright (c) 2018 Google, Inc |
| 3 | # Written by Simon Glass <sjg@chromium.org> |
| 4 | # |
| 5 | # Base class for sections (collections of entries) |
| 6 | # |
| 7 | |
| 8 | from __future__ import print_function |
| 9 | |
| 10 | from collections import OrderedDict |
| 11 | import sys |
| 12 | |
| 13 | import fdt_util |
| 14 | import re |
Simon Glass | c8135dc | 2018-09-14 04:57:21 -0600 | [diff] [blame] | 15 | import state |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 16 | import tools |
| 17 | |
| 18 | class Section(object): |
| 19 | """A section which contains multiple entries |
| 20 | |
| 21 | A section represents a collection of entries. There must be one or more |
| 22 | sections in an image. Sections are used to group entries together. |
| 23 | |
| 24 | Attributes: |
| 25 | _node: Node object that contains the section definition in device tree |
Simon Glass | 7c767ad | 2018-09-14 04:57:33 -0600 | [diff] [blame] | 26 | _parent_section: Parent Section object which created this Section |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 27 | _size: Section size in bytes, or None if not known yet |
| 28 | _align_size: Section size alignment, or None |
| 29 | _pad_before: Number of bytes before the first entry starts. This |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 30 | effectively changes the place where entry offset 0 starts |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 31 | _pad_after: Number of bytes after the last entry ends. The last |
| 32 | entry will finish on or before this boundary |
| 33 | _pad_byte: Byte to use to pad the section where there is no entry |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 34 | _sort: True if entries should be sorted by offset, False if they |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 35 | must be in-order in the device tree description |
| 36 | _skip_at_start: Number of bytes before the first entry starts. These |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 37 | effectively adjust the starting offset of entries. For example, |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 38 | if _pad_before is 16, then the first entry would start at 16. |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 39 | An entry with offset = 20 would in fact be written at offset 4 |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 40 | in the image file. |
| 41 | _end_4gb: Indicates that the section ends at the 4GB boundary. This is |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 42 | used for x86 images, which want to use offsets such that a memory |
| 43 | address (like 0xff800000) is the first entry offset. This causes |
| 44 | _skip_at_start to be set to the starting memory address. |
Simon Glass | 3b78d53 | 2018-06-01 09:38:21 -0600 | [diff] [blame] | 45 | _name_prefix: Prefix to add to the name of all entries within this |
| 46 | section |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 47 | _entries: OrderedDict() of entries |
| 48 | """ |
Simon Glass | 7c767ad | 2018-09-14 04:57:33 -0600 | [diff] [blame] | 49 | def __init__(self, name, parent_section, node, image, test=False): |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 50 | global entry |
| 51 | global Entry |
| 52 | import entry |
| 53 | from entry import Entry |
| 54 | |
Simon Glass | 7c767ad | 2018-09-14 04:57:33 -0600 | [diff] [blame] | 55 | self._parent_section = parent_section |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 56 | self._name = name |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 57 | self._node = node |
Simon Glass | 7c767ad | 2018-09-14 04:57:33 -0600 | [diff] [blame] | 58 | self._image = image |
Simon Glass | eb023b3 | 2019-04-25 21:58:39 -0600 | [diff] [blame] | 59 | self._offset = None |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 60 | self._size = None |
| 61 | self._align_size = None |
| 62 | self._pad_before = 0 |
| 63 | self._pad_after = 0 |
| 64 | self._pad_byte = 0 |
| 65 | self._sort = False |
Jagdish Gediya | 0fb978c | 2018-09-03 21:35:07 +0530 | [diff] [blame] | 66 | self._skip_at_start = None |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 67 | self._end_4gb = False |
Simon Glass | 3b78d53 | 2018-06-01 09:38:21 -0600 | [diff] [blame] | 68 | self._name_prefix = '' |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 69 | self._entries = OrderedDict() |
Simon Glass | c64aea5 | 2018-09-14 04:57:34 -0600 | [diff] [blame] | 70 | self._image_pos = None |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 71 | if not test: |
| 72 | self._ReadNode() |
| 73 | self._ReadEntries() |
| 74 | |
| 75 | def _ReadNode(self): |
| 76 | """Read properties from the section node""" |
Simon Glass | eb023b3 | 2019-04-25 21:58:39 -0600 | [diff] [blame] | 77 | self._offset = fdt_util.GetInt(self._node, 'offset') |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 78 | self._size = fdt_util.GetInt(self._node, 'size') |
| 79 | self._align_size = fdt_util.GetInt(self._node, 'align-size') |
| 80 | if tools.NotPowerOfTwo(self._align_size): |
| 81 | self._Raise("Alignment size %s must be a power of two" % |
| 82 | self._align_size) |
| 83 | self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0) |
| 84 | self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0) |
| 85 | self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0) |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 86 | self._sort = fdt_util.GetBool(self._node, 'sort-by-offset') |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 87 | self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb') |
Jagdish Gediya | 0fb978c | 2018-09-03 21:35:07 +0530 | [diff] [blame] | 88 | self._skip_at_start = fdt_util.GetInt(self._node, 'skip-at-start') |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 89 | if self._end_4gb: |
Jagdish Gediya | 0fb978c | 2018-09-03 21:35:07 +0530 | [diff] [blame] | 90 | if not self._size: |
| 91 | self._Raise("Section size must be provided when using end-at-4gb") |
| 92 | if self._skip_at_start is not None: |
| 93 | self._Raise("Provide either 'end-at-4gb' or 'skip-at-start'") |
| 94 | else: |
| 95 | self._skip_at_start = 0x100000000 - self._size |
| 96 | else: |
| 97 | if self._skip_at_start is None: |
| 98 | self._skip_at_start = 0 |
Simon Glass | 3b78d53 | 2018-06-01 09:38:21 -0600 | [diff] [blame] | 99 | self._name_prefix = fdt_util.GetString(self._node, 'name-prefix') |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 100 | |
| 101 | def _ReadEntries(self): |
| 102 | for node in self._node.subnodes: |
Simon Glass | ae7cf03 | 2018-09-14 04:57:31 -0600 | [diff] [blame] | 103 | if node.name == 'hash': |
| 104 | continue |
Simon Glass | 3b78d53 | 2018-06-01 09:38:21 -0600 | [diff] [blame] | 105 | entry = Entry.Create(self, node) |
| 106 | entry.SetPrefix(self._name_prefix) |
| 107 | self._entries[node.name] = entry |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 108 | |
Simon Glass | 0c9d5b5 | 2018-09-14 04:57:22 -0600 | [diff] [blame] | 109 | def GetFdtSet(self): |
| 110 | """Get the set of device tree files used by this image""" |
Simon Glass | 4aea954 | 2019-05-14 15:53:39 -0600 | [diff] [blame] | 111 | fdt_set = set() |
Simon Glass | 0c9d5b5 | 2018-09-14 04:57:22 -0600 | [diff] [blame] | 112 | for entry in self._entries.values(): |
| 113 | fdt_set.update(entry.GetFdtSet()) |
| 114 | return fdt_set |
| 115 | |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 116 | def SetOffset(self, offset): |
| 117 | self._offset = offset |
| 118 | |
Simon Glass | ac6328c | 2018-09-14 04:57:28 -0600 | [diff] [blame] | 119 | def ExpandEntries(self): |
| 120 | for entry in self._entries.values(): |
| 121 | entry.ExpandEntries() |
| 122 | |
Simon Glass | e22f8fa | 2018-07-06 10:27:41 -0600 | [diff] [blame] | 123 | def AddMissingProperties(self): |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 124 | """Add new properties to the device tree as needed for this entry""" |
Simon Glass | 9dcc861 | 2018-08-01 15:22:42 -0600 | [diff] [blame] | 125 | for prop in ['offset', 'size', 'image-pos']: |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 126 | if not prop in self._node.props: |
Simon Glass | c8135dc | 2018-09-14 04:57:21 -0600 | [diff] [blame] | 127 | state.AddZeroProp(self._node, prop) |
Simon Glass | ae7cf03 | 2018-09-14 04:57:31 -0600 | [diff] [blame] | 128 | state.CheckAddHashProp(self._node) |
Simon Glass | e22f8fa | 2018-07-06 10:27:41 -0600 | [diff] [blame] | 129 | for entry in self._entries.values(): |
| 130 | entry.AddMissingProperties() |
| 131 | |
| 132 | def SetCalculatedProperties(self): |
Simon Glass | eb023b3 | 2019-04-25 21:58:39 -0600 | [diff] [blame] | 133 | state.SetInt(self._node, 'offset', self._offset or 0) |
Simon Glass | c8135dc | 2018-09-14 04:57:21 -0600 | [diff] [blame] | 134 | state.SetInt(self._node, 'size', self._size) |
Simon Glass | c64aea5 | 2018-09-14 04:57:34 -0600 | [diff] [blame] | 135 | image_pos = self._image_pos |
| 136 | if self._parent_section: |
| 137 | image_pos -= self._parent_section.GetRootSkipAtStart() |
| 138 | state.SetInt(self._node, 'image-pos', image_pos) |
Simon Glass | e22f8fa | 2018-07-06 10:27:41 -0600 | [diff] [blame] | 139 | for entry in self._entries.values(): |
| 140 | entry.SetCalculatedProperties() |
| 141 | |
Simon Glass | 9230773 | 2018-07-06 10:27:40 -0600 | [diff] [blame] | 142 | def ProcessFdt(self, fdt): |
| 143 | todo = self._entries.values() |
| 144 | for passnum in range(3): |
| 145 | next_todo = [] |
| 146 | for entry in todo: |
| 147 | if not entry.ProcessFdt(fdt): |
| 148 | next_todo.append(entry) |
| 149 | todo = next_todo |
| 150 | if not todo: |
| 151 | break |
| 152 | if todo: |
| 153 | self._Raise('Internal error: Could not complete processing of Fdt: ' |
| 154 | 'remaining %s' % todo) |
| 155 | return True |
| 156 | |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 157 | def CheckSize(self): |
| 158 | """Check that the section contents does not exceed its size, etc.""" |
| 159 | contents_size = 0 |
| 160 | for entry in self._entries.values(): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 161 | contents_size = max(contents_size, entry.offset + entry.size) |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 162 | |
| 163 | contents_size -= self._skip_at_start |
| 164 | |
| 165 | size = self._size |
| 166 | if not size: |
| 167 | size = self._pad_before + contents_size + self._pad_after |
| 168 | size = tools.Align(size, self._align_size) |
| 169 | |
| 170 | if self._size and contents_size > self._size: |
| 171 | self._Raise("contents size %#x (%d) exceeds section size %#x (%d)" % |
| 172 | (contents_size, contents_size, self._size, self._size)) |
| 173 | if not self._size: |
| 174 | self._size = size |
| 175 | if self._size != tools.Align(self._size, self._align_size): |
| 176 | self._Raise("Size %#x (%d) does not match align-size %#x (%d)" % |
| 177 | (self._size, self._size, self._align_size, self._align_size)) |
| 178 | return size |
| 179 | |
| 180 | def _Raise(self, msg): |
| 181 | """Raises an error for this section |
| 182 | |
| 183 | Args: |
| 184 | msg: Error message to use in the raise string |
| 185 | Raises: |
| 186 | ValueError() |
| 187 | """ |
| 188 | raise ValueError("Section '%s': %s" % (self._node.path, msg)) |
| 189 | |
| 190 | def GetPath(self): |
| 191 | """Get the path of an image (in the FDT) |
| 192 | |
| 193 | Returns: |
| 194 | Full path of the node for this image |
| 195 | """ |
| 196 | return self._node.path |
| 197 | |
| 198 | def FindEntryType(self, etype): |
| 199 | """Find an entry type in the section |
| 200 | |
| 201 | Args: |
| 202 | etype: Entry type to find |
| 203 | Returns: |
| 204 | entry matching that type, or None if not found |
| 205 | """ |
| 206 | for entry in self._entries.values(): |
| 207 | if entry.etype == etype: |
| 208 | return entry |
| 209 | return None |
| 210 | |
| 211 | def GetEntryContents(self): |
| 212 | """Call ObtainContents() for each entry |
| 213 | |
| 214 | This calls each entry's ObtainContents() a few times until they all |
| 215 | return True. We stop calling an entry's function once it returns |
| 216 | True. This allows the contents of one entry to depend on another. |
| 217 | |
| 218 | After 3 rounds we give up since it's likely an error. |
| 219 | """ |
| 220 | todo = self._entries.values() |
| 221 | for passnum in range(3): |
| 222 | next_todo = [] |
| 223 | for entry in todo: |
| 224 | if not entry.ObtainContents(): |
| 225 | next_todo.append(entry) |
| 226 | todo = next_todo |
| 227 | if not todo: |
| 228 | break |
Simon Glass | 6ba679c | 2018-07-06 10:27:17 -0600 | [diff] [blame] | 229 | if todo: |
| 230 | self._Raise('Internal error: Could not complete processing of ' |
| 231 | 'contents: remaining %s' % todo) |
| 232 | return True |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 233 | |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 234 | def _SetEntryOffsetSize(self, name, offset, size): |
| 235 | """Set the offset and size of an entry |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 236 | |
| 237 | Args: |
| 238 | name: Entry name to update |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 239 | offset: New offset |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 240 | size: New size |
| 241 | """ |
| 242 | entry = self._entries.get(name) |
| 243 | if not entry: |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 244 | self._Raise("Unable to set offset/size for unknown entry '%s'" % |
| 245 | name) |
| 246 | entry.SetOffsetSize(self._skip_at_start + offset, size) |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 247 | |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 248 | def GetEntryOffsets(self): |
| 249 | """Handle entries that want to set the offset/size of other entries |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 250 | |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 251 | This calls each entry's GetOffsets() method. If it returns a list |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 252 | of entries to update, it updates them. |
| 253 | """ |
| 254 | for entry in self._entries.values(): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 255 | offset_dict = entry.GetOffsets() |
Simon Glass | 5f3645b | 2019-05-14 15:53:41 -0600 | [diff] [blame] | 256 | for name, info in offset_dict.items(): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 257 | self._SetEntryOffsetSize(name, *info) |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 258 | |
| 259 | def PackEntries(self): |
| 260 | """Pack all entries into the section""" |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 261 | offset = self._skip_at_start |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 262 | for entry in self._entries.values(): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 263 | offset = entry.Pack(offset) |
| 264 | self._size = self.CheckSize() |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 265 | |
| 266 | def _SortEntries(self): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 267 | """Sort entries by offset""" |
| 268 | entries = sorted(self._entries.values(), key=lambda entry: entry.offset) |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 269 | self._entries.clear() |
| 270 | for entry in entries: |
| 271 | self._entries[entry._node.name] = entry |
| 272 | |
Simon Glass | fa79a81 | 2018-09-14 04:57:29 -0600 | [diff] [blame] | 273 | def _ExpandEntries(self): |
| 274 | """Expand any entries that are permitted to""" |
| 275 | exp_entry = None |
| 276 | for entry in self._entries.values(): |
| 277 | if exp_entry: |
| 278 | exp_entry.ExpandToLimit(entry.offset) |
| 279 | exp_entry = None |
| 280 | if entry.expand_size: |
| 281 | exp_entry = entry |
| 282 | if exp_entry: |
| 283 | exp_entry.ExpandToLimit(self._size) |
| 284 | |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 285 | def CheckEntries(self): |
Simon Glass | fa79a81 | 2018-09-14 04:57:29 -0600 | [diff] [blame] | 286 | """Check that entries do not overlap or extend outside the section |
| 287 | |
| 288 | This also sorts entries, if needed and expands |
| 289 | """ |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 290 | if self._sort: |
| 291 | self._SortEntries() |
Simon Glass | fa79a81 | 2018-09-14 04:57:29 -0600 | [diff] [blame] | 292 | self._ExpandEntries() |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 293 | offset = 0 |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 294 | prev_name = 'None' |
| 295 | for entry in self._entries.values(): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 296 | entry.CheckOffset() |
| 297 | if (entry.offset < self._skip_at_start or |
Simon Glass | 2a7c4b6 | 2018-09-14 04:57:27 -0600 | [diff] [blame] | 298 | entry.offset + entry.size > self._skip_at_start + self._size): |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 299 | entry.Raise("Offset %#x (%d) is outside the section starting " |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 300 | "at %#x (%d)" % |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 301 | (entry.offset, entry.offset, self._skip_at_start, |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 302 | self._skip_at_start)) |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 303 | if entry.offset < offset: |
| 304 | entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' " |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 305 | "ending at %#x (%d)" % |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 306 | (entry.offset, entry.offset, prev_name, offset, offset)) |
| 307 | offset = entry.offset + entry.size |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 308 | prev_name = entry.GetPath() |
| 309 | |
Simon Glass | 9dcc861 | 2018-08-01 15:22:42 -0600 | [diff] [blame] | 310 | def SetImagePos(self, image_pos): |
| 311 | self._image_pos = image_pos |
| 312 | for entry in self._entries.values(): |
| 313 | entry.SetImagePos(image_pos) |
| 314 | |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 315 | def ProcessEntryContents(self): |
| 316 | """Call the ProcessContents() method for each entry |
| 317 | |
| 318 | This is intended to adjust the contents as needed by the entry type. |
| 319 | """ |
| 320 | for entry in self._entries.values(): |
| 321 | entry.ProcessContents() |
| 322 | |
| 323 | def WriteSymbols(self): |
| 324 | """Write symbol values into binary files for access at run time""" |
| 325 | for entry in self._entries.values(): |
| 326 | entry.WriteSymbols(self) |
| 327 | |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 328 | def BuildSection(self, fd, base_offset): |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 329 | """Write the section to a file""" |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 330 | fd.seek(base_offset) |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 331 | fd.write(self.GetData()) |
| 332 | |
| 333 | def GetData(self): |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 334 | """Get the contents of the section""" |
Simon Glass | ac0d495 | 2019-05-14 15:53:47 -0600 | [diff] [blame] | 335 | section_data = tools.GetBytes(self._pad_byte, self._size) |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 336 | |
| 337 | for entry in self._entries.values(): |
| 338 | data = entry.GetData() |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 339 | base = self._pad_before + entry.offset - self._skip_at_start |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 340 | section_data = (section_data[:base] + data + |
| 341 | section_data[base + len(data):]) |
| 342 | return section_data |
| 343 | |
| 344 | def LookupSymbol(self, sym_name, optional, msg): |
| 345 | """Look up a symbol in an ELF file |
| 346 | |
| 347 | Looks up a symbol in an ELF file. Only entry types which come from an |
| 348 | ELF image can be used by this function. |
| 349 | |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 350 | At present the only entry property supported is offset. |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 351 | |
| 352 | Args: |
| 353 | sym_name: Symbol name in the ELF file to look up in the format |
| 354 | _binman_<entry>_prop_<property> where <entry> is the name of |
| 355 | the entry and <property> is the property to find (e.g. |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 356 | _binman_u_boot_prop_offset). As a special case, you can append |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 357 | _any to <entry> to have it search for any matching entry. E.g. |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 358 | _binman_u_boot_any_prop_offset will match entries called u-boot, |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 359 | u-boot-img and u-boot-nodtb) |
| 360 | optional: True if the symbol is optional. If False this function |
| 361 | will raise if the symbol is not found |
| 362 | msg: Message to display if an error occurs |
| 363 | |
| 364 | Returns: |
| 365 | Value that should be assigned to that symbol, or None if it was |
| 366 | optional and not found |
| 367 | |
| 368 | Raises: |
| 369 | ValueError if the symbol is invalid or not found, or references a |
| 370 | property which is not supported |
| 371 | """ |
| 372 | m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name) |
| 373 | if not m: |
| 374 | raise ValueError("%s: Symbol '%s' has invalid format" % |
| 375 | (msg, sym_name)) |
| 376 | entry_name, prop_name = m.groups() |
| 377 | entry_name = entry_name.replace('_', '-') |
| 378 | entry = self._entries.get(entry_name) |
| 379 | if not entry: |
| 380 | if entry_name.endswith('-any'): |
| 381 | root = entry_name[:-4] |
| 382 | for name in self._entries: |
| 383 | if name.startswith(root): |
| 384 | rest = name[len(root):] |
| 385 | if rest in ['', '-img', '-nodtb']: |
| 386 | entry = self._entries[name] |
| 387 | if not entry: |
| 388 | err = ("%s: Entry '%s' not found in list (%s)" % |
| 389 | (msg, entry_name, ','.join(self._entries.keys()))) |
| 390 | if optional: |
| 391 | print('Warning: %s' % err, file=sys.stderr) |
| 392 | return None |
| 393 | raise ValueError(err) |
Simon Glass | e8561af | 2018-08-01 15:22:37 -0600 | [diff] [blame] | 394 | if prop_name == 'offset': |
| 395 | return entry.offset |
Simon Glass | 9dcc861 | 2018-08-01 15:22:42 -0600 | [diff] [blame] | 396 | elif prop_name == 'image_pos': |
| 397 | return entry.image_pos |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 398 | else: |
| 399 | raise ValueError("%s: No such property '%s'" % (msg, prop_name)) |
| 400 | |
| 401 | def GetEntries(self): |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 402 | """Get the number of entries in a section |
| 403 | |
| 404 | Returns: |
| 405 | Number of entries in a section |
| 406 | """ |
Simon Glass | eca3221 | 2018-06-01 09:38:12 -0600 | [diff] [blame] | 407 | return self._entries |
Simon Glass | 3073266 | 2018-06-01 09:38:20 -0600 | [diff] [blame] | 408 | |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 409 | def GetSize(self): |
| 410 | """Get the size of a section in bytes |
| 411 | |
| 412 | This is only meaningful if the section has a pre-defined size, or the |
| 413 | entries within it have been packed, so that the size has been |
| 414 | calculated. |
| 415 | |
| 416 | Returns: |
| 417 | Entry size in bytes |
| 418 | """ |
| 419 | return self._size |
| 420 | |
Simon Glass | 3073266 | 2018-06-01 09:38:20 -0600 | [diff] [blame] | 421 | def WriteMap(self, fd, indent): |
| 422 | """Write a map of the section to a .map file |
| 423 | |
| 424 | Args: |
| 425 | fd: File to write the map to |
| 426 | """ |
Simon Glass | eb023b3 | 2019-04-25 21:58:39 -0600 | [diff] [blame] | 427 | Entry.WriteMapLine(fd, indent, self._name, self._offset or 0, |
| 428 | self._size, self._image_pos) |
Simon Glass | 3073266 | 2018-06-01 09:38:20 -0600 | [diff] [blame] | 429 | for entry in self._entries.values(): |
Simon Glass | 3a9a2b8 | 2018-07-17 13:25:28 -0600 | [diff] [blame] | 430 | entry.WriteMap(fd, indent + 1) |
Simon Glass | 5c35016 | 2018-07-17 13:25:47 -0600 | [diff] [blame] | 431 | |
| 432 | def GetContentsByPhandle(self, phandle, source_entry): |
| 433 | """Get the data contents of an entry specified by a phandle |
| 434 | |
| 435 | This uses a phandle to look up a node and and find the entry |
| 436 | associated with it. Then it returnst he contents of that entry. |
| 437 | |
| 438 | Args: |
| 439 | phandle: Phandle to look up (integer) |
| 440 | source_entry: Entry containing that phandle (used for error |
| 441 | reporting) |
| 442 | |
| 443 | Returns: |
| 444 | data from associated entry (as a string), or None if not found |
| 445 | """ |
| 446 | node = self._node.GetFdt().LookupPhandle(phandle) |
| 447 | if not node: |
| 448 | source_entry.Raise("Cannot find node for phandle %d" % phandle) |
| 449 | for entry in self._entries.values(): |
| 450 | if entry._node == node: |
Simon Glass | c64aea5 | 2018-09-14 04:57:34 -0600 | [diff] [blame] | 451 | return entry.GetData() |
Simon Glass | 5c35016 | 2018-07-17 13:25:47 -0600 | [diff] [blame] | 452 | source_entry.Raise("Cannot find entry for node '%s'" % node.name) |
Simon Glass | fa79a81 | 2018-09-14 04:57:29 -0600 | [diff] [blame] | 453 | |
| 454 | def ExpandSize(self, size): |
| 455 | if size != self._size: |
| 456 | self._size = size |
Simon Glass | c64aea5 | 2018-09-14 04:57:34 -0600 | [diff] [blame] | 457 | |
| 458 | def GetRootSkipAtStart(self): |
| 459 | if self._parent_section: |
| 460 | return self._parent_section.GetRootSkipAtStart() |
| 461 | return self._skip_at_start |
| 462 | |
| 463 | def GetImageSize(self): |
| 464 | return self._image._size |