Add an entry which can hold an FMAP region as used by flashrom, an open-source flashing tool used on Linux x86 machines. This provides a simplified non-hierarchical view of the entries in the image and has a signature at the start to allow flashrom to find it in the image. Signed-off-by: Simon Glass <sjg@chromium.org>lime2-spi
parent
5a5da7ce15
commit
11e36ccea1
@ -0,0 +1,61 @@ |
|||||||
|
# SPDX-License-Identifier: GPL-2.0+ |
||||||
|
# Copyright (c) 2018 Google, Inc |
||||||
|
# Written by Simon Glass <sjg@chromium.org> |
||||||
|
# |
||||||
|
# Entry-type module for a Flash map, as used by the flashrom SPI flash tool |
||||||
|
# |
||||||
|
|
||||||
|
from entry import Entry |
||||||
|
import fmap_util |
||||||
|
|
||||||
|
|
||||||
|
class Entry_fmap(Entry): |
||||||
|
"""An entry which contains an Fmap section |
||||||
|
|
||||||
|
Properties / Entry arguments: |
||||||
|
None |
||||||
|
|
||||||
|
FMAP is a simple format used by flashrom, an open-source utility for |
||||||
|
reading and writing the SPI flash, typically on x86 CPUs. The format |
||||||
|
provides flashrom with a list of areas, so it knows what it in the flash. |
||||||
|
It can then read or write just a single area, instead of the whole flash. |
||||||
|
|
||||||
|
The format is defined by the flashrom project, in the file lib/fmap.h - |
||||||
|
see www.flashrom.org/Flashrom for more information. |
||||||
|
|
||||||
|
When used, this entry will be populated with an FMAP which reflects the |
||||||
|
entries in the current image. Note that any hierarchy is squashed, since |
||||||
|
FMAP does not support this. |
||||||
|
""" |
||||||
|
def __init__(self, section, etype, node): |
||||||
|
Entry.__init__(self, section, etype, node) |
||||||
|
|
||||||
|
def _GetFmap(self): |
||||||
|
"""Build an FMAP from the entries in the current image |
||||||
|
|
||||||
|
Returns: |
||||||
|
FMAP binary data |
||||||
|
""" |
||||||
|
def _AddEntries(areas, entry): |
||||||
|
entries = entry.GetEntries() |
||||||
|
if entries: |
||||||
|
for subentry in entries.values(): |
||||||
|
_AddEntries(areas, subentry) |
||||||
|
else: |
||||||
|
areas.append(fmap_util.FmapArea(entry.image_pos or 0, |
||||||
|
entry.size or 0, entry.name, 0)) |
||||||
|
|
||||||
|
entries = self.section.GetEntries() |
||||||
|
areas = [] |
||||||
|
for entry in entries.values(): |
||||||
|
_AddEntries(areas, entry) |
||||||
|
return fmap_util.EncodeFmap(self.section.GetSize() or 0, self.name, |
||||||
|
areas) |
||||||
|
|
||||||
|
def ObtainContents(self): |
||||||
|
"""Obtain a placeholder for the fmap contents""" |
||||||
|
self.SetContents(self._GetFmap()) |
||||||
|
return True |
||||||
|
|
||||||
|
def ProcessContents(self): |
||||||
|
self.SetContents(self._GetFmap()) |
@ -0,0 +1,109 @@ |
|||||||
|
# SPDX-License-Identifier: GPL-2.0+ |
||||||
|
# Copyright (c) 2018 Google, Inc |
||||||
|
# Written by Simon Glass <sjg@chromium.org> |
||||||
|
# |
||||||
|
# Support for flashrom's FMAP format. This supports a header followed by a |
||||||
|
# number of 'areas', describing regions of a firmware storage device, |
||||||
|
# generally SPI flash. |
||||||
|
|
||||||
|
import collections |
||||||
|
import struct |
||||||
|
|
||||||
|
# constants imported from lib/fmap.h |
||||||
|
FMAP_SIGNATURE = '__FMAP__' |
||||||
|
FMAP_VER_MAJOR = 1 |
||||||
|
FMAP_VER_MINOR = 0 |
||||||
|
FMAP_STRLEN = 32 |
||||||
|
|
||||||
|
FMAP_AREA_STATIC = 1 << 0 |
||||||
|
FMAP_AREA_COMPRESSED = 1 << 1 |
||||||
|
FMAP_AREA_RO = 1 << 2 |
||||||
|
|
||||||
|
FMAP_HEADER_LEN = 56 |
||||||
|
FMAP_AREA_LEN = 42 |
||||||
|
|
||||||
|
FMAP_HEADER_FORMAT = '<8sBBQI%dsH'% (FMAP_STRLEN) |
||||||
|
FMAP_AREA_FORMAT = '<II%dsH' % (FMAP_STRLEN) |
||||||
|
|
||||||
|
FMAP_HEADER_NAMES = ( |
||||||
|
'signature', |
||||||
|
'ver_major', |
||||||
|
'ver_minor', |
||||||
|
'base', |
||||||
|
'image_size', |
||||||
|
'name', |
||||||
|
'nareas', |
||||||
|
) |
||||||
|
|
||||||
|
FMAP_AREA_NAMES = ( |
||||||
|
'offset', |
||||||
|
'size', |
||||||
|
'name', |
||||||
|
'flags', |
||||||
|
) |
||||||
|
|
||||||
|
# These are the two data structures supported by flashrom, a header (which |
||||||
|
# appears once at the start) and an area (which is repeated until the end of |
||||||
|
# the list of areas) |
||||||
|
FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES) |
||||||
|
FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES) |
||||||
|
|
||||||
|
|
||||||
|
def ConvertName(field_names, fields): |
||||||
|
"""Convert a name to something flashrom likes |
||||||
|
|
||||||
|
Flashrom requires upper case, underscores instead of hyphens. We remove any |
||||||
|
null characters as well. This updates the 'name' value in fields. |
||||||
|
|
||||||
|
Args: |
||||||
|
field_names: List of field names for this struct |
||||||
|
fields: Dict: |
||||||
|
key: Field name |
||||||
|
value: value of that field (string for the ones we support) |
||||||
|
""" |
||||||
|
name_index = field_names.index('name') |
||||||
|
fields[name_index] = fields[name_index].replace('\0', '').replace('-', '_').upper() |
||||||
|
|
||||||
|
def DecodeFmap(data): |
||||||
|
"""Decode a flashmap into a header and list of areas |
||||||
|
|
||||||
|
Args: |
||||||
|
data: Data block containing the FMAP |
||||||
|
|
||||||
|
Returns: |
||||||
|
Tuple: |
||||||
|
header: FmapHeader object |
||||||
|
List of FmapArea objects |
||||||
|
""" |
||||||
|
fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN])) |
||||||
|
ConvertName(FMAP_HEADER_NAMES, fields) |
||||||
|
header = FmapHeader(*fields) |
||||||
|
areas = [] |
||||||
|
data = data[FMAP_HEADER_LEN:] |
||||||
|
for area in range(header.nareas): |
||||||
|
fields = list(struct.unpack(FMAP_AREA_FORMAT, data[:FMAP_AREA_LEN])) |
||||||
|
ConvertName(FMAP_AREA_NAMES, fields) |
||||||
|
areas.append(FmapArea(*fields)) |
||||||
|
data = data[FMAP_AREA_LEN:] |
||||||
|
return header, areas |
||||||
|
|
||||||
|
def EncodeFmap(image_size, name, areas): |
||||||
|
"""Create a new FMAP from a list of areas |
||||||
|
|
||||||
|
Args: |
||||||
|
image_size: Size of image, to put in the header |
||||||
|
name: Name of image, to put in the header |
||||||
|
areas: List of FmapArea objects |
||||||
|
|
||||||
|
Returns: |
||||||
|
String containing the FMAP created |
||||||
|
""" |
||||||
|
def _FormatBlob(fmt, names, obj): |
||||||
|
params = [getattr(obj, name) for name in names] |
||||||
|
return struct.pack(fmt, *params) |
||||||
|
|
||||||
|
values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas)) |
||||||
|
blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values) |
||||||
|
for area in areas: |
||||||
|
blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area) |
||||||
|
return blob |
@ -0,0 +1,29 @@ |
|||||||
|
// SPDX-License-Identifier: GPL-2.0+ |
||||||
|
/dts-v1/; |
||||||
|
|
||||||
|
/ { |
||||||
|
#address-cells = <1>; |
||||||
|
#size-cells = <1>; |
||||||
|
|
||||||
|
binman { |
||||||
|
section@0 { |
||||||
|
read-only; |
||||||
|
name-prefix = "ro-"; |
||||||
|
size = <0x10>; |
||||||
|
pad-byte = <0x21>; |
||||||
|
|
||||||
|
u-boot { |
||||||
|
}; |
||||||
|
}; |
||||||
|
section@1 { |
||||||
|
name-prefix = "rw-"; |
||||||
|
size = <0x10>; |
||||||
|
pad-byte = <0x61>; |
||||||
|
|
||||||
|
u-boot { |
||||||
|
}; |
||||||
|
}; |
||||||
|
fmap { |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
Loading…
Reference in new issue