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,
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 # These are the two data structures supported by flashrom, a header (which
49 # appears once at the start) and an area (which is repeated until the end of
51 FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
52 FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
56 if type(name) == bytes and sys.version_info[0] >= 3:
57 name = name.decode('utf-8') # pragma: no cover (for Python 2)
58 return name.replace('\0', '').replace('-', '_').upper()
60 def ConvertName(field_names, fields):
61 """Convert a name to something flashrom likes
63 Flashrom requires upper case, underscores instead of hyphens. We remove any
64 null characters as well. This updates the 'name' value in fields.
67 field_names: List of field names for this struct
70 value: value of that field (string for the ones we support)
72 name_index = field_names.index('name')
73 fields[name_index] = tools.ToBytes(NameToFmap(fields[name_index]))
76 """Decode a flashmap into a header and list of areas
79 data: Data block containing the FMAP
83 header: FmapHeader object
84 List of FmapArea objects
86 fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
87 ConvertName(FMAP_HEADER_NAMES, fields)
88 header = FmapHeader(*fields)
90 data = data[FMAP_HEADER_LEN:]
91 for area in range(header.nareas):
92 fields = list(struct.unpack(FMAP_AREA_FORMAT, data[:FMAP_AREA_LEN]))
93 ConvertName(FMAP_AREA_NAMES, fields)
94 areas.append(FmapArea(*fields))
95 data = data[FMAP_AREA_LEN:]
98 def EncodeFmap(image_size, name, areas):
99 """Create a new FMAP from a list of areas
102 image_size: Size of image, to put in the header
103 name: Name of image, to put in the header
104 areas: List of FmapArea objects
107 String containing the FMAP created
109 def _FormatBlob(fmt, names, obj):
110 params = [getattr(obj, name) for name in names]
111 ConvertName(names, params)
112 return struct.pack(fmt, *params)
114 values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size,
115 tools.FromUnicode(name), len(areas))
116 blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
118 blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)