blob: 1ce63d1a8321c9ea88fbab1dfcffaa51db7fb1b4 [file] [log] [blame]
Simon Glass704784b2018-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 Glass616933dd2019-05-17 22:00:48 -060011import sys
12
Simon Glassa997ea52020-04-17 18:09:04 -060013from patman import tools
Simon Glass704784b2018-07-17 13:25:38 -060014
15# constants imported from lib/fmap.h
Simon Glass616933dd2019-05-17 22:00:48 -060016FMAP_SIGNATURE = b'__FMAP__'
Simon Glass704784b2018-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 Glassc64aea52018-09-14 04:57:34 -060055def NameToFmap(name):
Simon Glassd35a8522021-01-06 21:35:10 -070056 if type(name) == bytes:
57 name = name.decode('utf-8')
Simon Glassc64aea52018-09-14 04:57:34 -060058 return name.replace('\0', '').replace('-', '_').upper()
59
Simon Glass704784b2018-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 Glass80025522022-01-29 14:14:04 -070073 fields[name_index] = tools.to_bytes(NameToFmap(fields[name_index]))
Simon Glass704784b2018-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 Glassc64aea52018-09-14 04:57:34 -0600111 ConvertName(names, params)
Simon Glass704784b2018-07-17 13:25:38 -0600112 return struct.pack(fmt, *params)
113
Simon Glass9dfb3112020-11-08 20:36:18 -0700114 values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
Simon Glass704784b2018-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