blob: b03fc28fbb492d6ee0672a10701e64d6ab4c26ff [file] [log] [blame]
Simon Glass11e36cc2018-07-17 13:25:38 -06001# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2018 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
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,
7# generally SPI flash.
8
9import collections
10import struct
Simon Glassf3a58c82019-05-17 22:00:48 -060011import sys
12
Simon Glassbf776672020-04-17 18:09:04 -060013from patman import tools
Simon Glass11e36cc2018-07-17 13:25:38 -060014
15# constants imported from lib/fmap.h
Simon Glassf3a58c82019-05-17 22:00:48 -060016FMAP_SIGNATURE = b'__FMAP__'
Simon Glass11e36cc2018-07-17 13:25:38 -060017FMAP_VER_MAJOR = 1
18FMAP_VER_MINOR = 0
19FMAP_STRLEN = 32
20
21FMAP_AREA_STATIC = 1 << 0
22FMAP_AREA_COMPRESSED = 1 << 1
23FMAP_AREA_RO = 1 << 2
24
25FMAP_HEADER_LEN = 56
26FMAP_AREA_LEN = 42
27
28FMAP_HEADER_FORMAT = '<8sBBQI%dsH'% (FMAP_STRLEN)
29FMAP_AREA_FORMAT = '<II%dsH' % (FMAP_STRLEN)
30
31FMAP_HEADER_NAMES = (
32 'signature',
33 'ver_major',
34 'ver_minor',
35 'base',
36 'image_size',
37 'name',
38 'nareas',
39)
40
41FMAP_AREA_NAMES = (
42 'offset',
43 'size',
44 'name',
45 'flags',
46)
47
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
50# the list of areas)
51FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
52FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
53
54
Simon Glassf8f8df62018-09-14 04:57:34 -060055def NameToFmap(name):
Simon Glassf3a58c82019-05-17 22:00:48 -060056 if type(name) == bytes and sys.version_info[0] >= 3:
57 name = name.decode('utf-8') # pragma: no cover (for Python 2)
Simon Glassf8f8df62018-09-14 04:57:34 -060058 return name.replace('\0', '').replace('-', '_').upper()
59
Simon Glass11e36cc2018-07-17 13:25:38 -060060def ConvertName(field_names, fields):
61 """Convert a name to something flashrom likes
62
63 Flashrom requires upper case, underscores instead of hyphens. We remove any
64 null characters as well. This updates the 'name' value in fields.
65
66 Args:
67 field_names: List of field names for this struct
68 fields: Dict:
69 key: Field name
70 value: value of that field (string for the ones we support)
71 """
72 name_index = field_names.index('name')
Simon Glassf3a58c82019-05-17 22:00:48 -060073 fields[name_index] = tools.ToBytes(NameToFmap(fields[name_index]))
Simon Glass11e36cc2018-07-17 13:25:38 -060074
75def DecodeFmap(data):
76 """Decode a flashmap into a header and list of areas
77
78 Args:
79 data: Data block containing the FMAP
80
81 Returns:
82 Tuple:
83 header: FmapHeader object
84 List of FmapArea objects
85 """
86 fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
87 ConvertName(FMAP_HEADER_NAMES, fields)
88 header = FmapHeader(*fields)
89 areas = []
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:]
96 return header, areas
97
98def EncodeFmap(image_size, name, areas):
99 """Create a new FMAP from a list of areas
100
101 Args:
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
105
106 Returns:
107 String containing the FMAP created
108 """
109 def _FormatBlob(fmt, names, obj):
110 params = [getattr(obj, name) for name in names]
Simon Glassf8f8df62018-09-14 04:57:34 -0600111 ConvertName(names, params)
Simon Glass11e36cc2018-07-17 13:25:38 -0600112 return struct.pack(fmt, *params)
113
Simon Glassfc0056e2020-11-08 20:36:18 -0700114 values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
Simon Glass11e36cc2018-07-17 13:25:38 -0600115 blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
116 for area in areas:
117 blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)
118 return blob