]>
Commit | Line | Data |
---|---|---|
11e36cce SG |
1 | # SPDX-License-Identifier: GPL-2.0+ |
2 | # Copyright (c) 2018 Google, Inc | |
3 | # Written by Simon Glass <[email protected]> | |
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 | ||
9 | import collections | |
10 | import struct | |
f3a58c8a SG |
11 | import sys |
12 | ||
bf776679 | 13 | from patman import tools |
11e36cce SG |
14 | |
15 | # constants imported from lib/fmap.h | |
f3a58c8a | 16 | FMAP_SIGNATURE = b'__FMAP__' |
11e36cce SG |
17 | FMAP_VER_MAJOR = 1 |
18 | FMAP_VER_MINOR = 0 | |
19 | FMAP_STRLEN = 32 | |
20 | ||
21 | FMAP_AREA_STATIC = 1 << 0 | |
22 | FMAP_AREA_COMPRESSED = 1 << 1 | |
23 | FMAP_AREA_RO = 1 << 2 | |
24 | ||
25 | FMAP_HEADER_LEN = 56 | |
26 | FMAP_AREA_LEN = 42 | |
27 | ||
28 | FMAP_HEADER_FORMAT = '<8sBBQI%dsH'% (FMAP_STRLEN) | |
29 | FMAP_AREA_FORMAT = '<II%dsH' % (FMAP_STRLEN) | |
30 | ||
31 | FMAP_HEADER_NAMES = ( | |
32 | 'signature', | |
33 | 'ver_major', | |
34 | 'ver_minor', | |
35 | 'base', | |
36 | 'image_size', | |
37 | 'name', | |
38 | 'nareas', | |
39 | ) | |
40 | ||
41 | FMAP_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) | |
51 | FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES) | |
52 | FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES) | |
53 | ||
54 | ||
f8f8df6e | 55 | def NameToFmap(name): |
f3a58c8a SG |
56 | if type(name) == bytes and sys.version_info[0] >= 3: |
57 | name = name.decode('utf-8') # pragma: no cover (for Python 2) | |
f8f8df6e SG |
58 | return name.replace('\0', '').replace('-', '_').upper() |
59 | ||
11e36cce SG |
60 | def 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') | |
f3a58c8a | 73 | fields[name_index] = tools.ToBytes(NameToFmap(fields[name_index])) |
11e36cce SG |
74 | |
75 | def 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 | ||
98 | def 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] | |
f8f8df6e | 111 | ConvertName(names, params) |
11e36cce SG |
112 | return struct.pack(fmt, *params) |
113 | ||
fc0056e8 | 114 | values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas)) |
11e36cce SG |
115 | 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 |