blob: 40f2dbfe0f58d459e7e53ac2da87d2799b71e459 [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 Glass4583c002023-02-23 18:18:04 -070013from u_boot_pylib 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
Simon Glass9dbb02b2023-02-12 17:11:15 -070048# Flags supported by areas (bits 2:0 are unused so not included here)
49FMAP_AREA_PRESERVE = 1 << 3 # Preserved by any firmware updates
50
Simon Glass11e36cc2018-07-17 13:25:38 -060051# 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
53# the list of areas)
54FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
55FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
56
57
Simon Glassf8f8df62018-09-14 04:57:34 -060058def NameToFmap(name):
Simon Glass9fc6ebd2021-01-06 21:35:10 -070059 if type(name) == bytes:
60 name = name.decode('utf-8')
Simon Glassf8f8df62018-09-14 04:57:34 -060061 return name.replace('\0', '').replace('-', '_').upper()
62
Simon Glass11e36cc2018-07-17 13:25:38 -060063def ConvertName(field_names, fields):
64 """Convert a name to something flashrom likes
65
66 Flashrom requires upper case, underscores instead of hyphens. We remove any
67 null characters as well. This updates the 'name' value in fields.
68
69 Args:
70 field_names: List of field names for this struct
71 fields: Dict:
72 key: Field name
73 value: value of that field (string for the ones we support)
74 """
75 name_index = field_names.index('name')
Simon Glassc1aa66e2022-01-29 14:14:04 -070076 fields[name_index] = tools.to_bytes(NameToFmap(fields[name_index]))
Simon Glass11e36cc2018-07-17 13:25:38 -060077
78def DecodeFmap(data):
79 """Decode a flashmap into a header and list of areas
80
81 Args:
82 data: Data block containing the FMAP
83
84 Returns:
85 Tuple:
86 header: FmapHeader object
87 List of FmapArea objects
88 """
89 fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
90 ConvertName(FMAP_HEADER_NAMES, fields)
91 header = FmapHeader(*fields)
92 areas = []
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:]
99 return header, areas
100
101def EncodeFmap(image_size, name, areas):
102 """Create a new FMAP from a list of areas
103
104 Args:
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
108
109 Returns:
110 String containing the FMAP created
111 """
112 def _FormatBlob(fmt, names, obj):
113 params = [getattr(obj, name) for name in names]
Simon Glassf8f8df62018-09-14 04:57:34 -0600114 ConvertName(names, params)
Simon Glass11e36cc2018-07-17 13:25:38 -0600115 return struct.pack(fmt, *params)
116
Simon Glassfc0056e2020-11-08 20:36:18 -0700117 values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
Simon Glass11e36cc2018-07-17 13:25:38 -0600118 blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
119 for area in areas:
120 blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)
121 return blob