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