1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2018 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # Support for flashrom's FMAP format. This supports a header followed by a
6 # number of 'areas', describing regions of a firmware storage device,
13 from u_boot_pylib import tools
15 # constants imported from lib/fmap.h
16 FMAP_SIGNATURE = b'__FMAP__'
21 FMAP_AREA_STATIC = 1 << 0
22 FMAP_AREA_COMPRESSED = 1 << 1
28 FMAP_HEADER_FORMAT = '<8sBBQI%dsH'% (FMAP_STRLEN)
29 FMAP_AREA_FORMAT = '<II%dsH' % (FMAP_STRLEN)
48 # Flags supported by areas (bits 2:0 are unused so not included here)
49 FMAP_AREA_PRESERVE = 1 << 3 # Preserved by any firmware updates
51 # These are the two data structures supported by flashrom, a header (which
52 # appears once at the start) and an area (which is repeated until the end of
54 FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
55 FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
59 if type(name) == bytes:
60 name = name.decode('utf-8')
61 return name.replace('\0', '').replace('-', '_').upper()
63 def ConvertName(field_names, fields):
64 """Convert a name to something flashrom likes
66 Flashrom requires upper case, underscores instead of hyphens. We remove any
67 null characters as well. This updates the 'name' value in fields.
70 field_names: List of field names for this struct
73 value: value of that field (string for the ones we support)
75 name_index = field_names.index('name')
76 fields[name_index] = tools.to_bytes(NameToFmap(fields[name_index]))
79 """Decode a flashmap into a header and list of areas
82 data: Data block containing the FMAP
86 header: FmapHeader object
87 List of FmapArea objects
89 fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
90 ConvertName(FMAP_HEADER_NAMES, fields)
91 header = FmapHeader(*fields)
93 data = data[FMAP_HEADER_LEN:]
94 for area in range(header.nareas):
95 fields = list(struct.unpack(FMAP_AREA_FORMAT, data[:FMAP_AREA_LEN]))
96 ConvertName(FMAP_AREA_NAMES, fields)
97 areas.append(FmapArea(*fields))
98 data = data[FMAP_AREA_LEN:]
101 def EncodeFmap(image_size, name, areas):
102 """Create a new FMAP from a list of areas
105 image_size: Size of image, to put in the header
106 name: Name of image, to put in the header
107 areas: List of FmapArea objects
110 String containing the FMAP created
112 def _FormatBlob(fmt, names, obj):
113 params = [getattr(obj, name) for name in names]
114 ConvertName(names, params)
115 return struct.pack(fmt, *params)
117 values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
118 blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
120 blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)