blob: 40f2dbfe0f58d459e7e53ac2da87d2799b71e459 [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 Glass131444f2023-02-23 18:18:04 -070013from u_boot_pylib 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
Simon Glasscda991e2023-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 Glass704784b2018-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 Glassc64aea52018-09-14 04:57:34 -060058def NameToFmap(name):
Simon Glassd35a8522021-01-06 21:35:10 -070059 if type(name) == bytes:
60 name = name.decode('utf-8')
Simon Glassc64aea52018-09-14 04:57:34 -060061 return name.replace('\0', '').replace('-', '_').upper()
62
Simon Glass704784b2018-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 Glass80025522022-01-29 14:14:04 -070076 fields[name_index] = tools.to_bytes(NameToFmap(fields[name_index]))
Simon Glass704784b2018-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 Glassc64aea52018-09-14 04:57:34 -0600114 ConvertName(names, params)
Simon Glass704784b2018-07-17 13:25:38 -0600115 return struct.pack(fmt, *params)
116
Simon Glass9dfb3112020-11-08 20:36:18 -0700117 values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
Simon Glass704784b2018-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