xref: /openbmc/u-boot/tools/binman/fmap_util.py (revision d24c1d0f4da3b081a4fedf7ae2a08790871f08d0)
111e36cceSSimon Glass# SPDX-License-Identifier: GPL-2.0+
211e36cceSSimon Glass# Copyright (c) 2018 Google, Inc
311e36cceSSimon Glass# Written by Simon Glass <sjg@chromium.org>
411e36cceSSimon Glass#
511e36cceSSimon Glass# Support for flashrom's FMAP format. This supports a header followed by a
611e36cceSSimon Glass# number of 'areas', describing regions of a firmware storage device,
711e36cceSSimon Glass# generally SPI flash.
811e36cceSSimon Glass
911e36cceSSimon Glassimport collections
1011e36cceSSimon Glassimport struct
1111e36cceSSimon Glass
1211e36cceSSimon Glass# constants imported from lib/fmap.h
1311e36cceSSimon GlassFMAP_SIGNATURE = '__FMAP__'
1411e36cceSSimon GlassFMAP_VER_MAJOR = 1
1511e36cceSSimon GlassFMAP_VER_MINOR = 0
1611e36cceSSimon GlassFMAP_STRLEN = 32
1711e36cceSSimon Glass
1811e36cceSSimon GlassFMAP_AREA_STATIC = 1 << 0
1911e36cceSSimon GlassFMAP_AREA_COMPRESSED = 1 << 1
2011e36cceSSimon GlassFMAP_AREA_RO = 1 << 2
2111e36cceSSimon Glass
2211e36cceSSimon GlassFMAP_HEADER_LEN = 56
2311e36cceSSimon GlassFMAP_AREA_LEN = 42
2411e36cceSSimon Glass
2511e36cceSSimon GlassFMAP_HEADER_FORMAT = '<8sBBQI%dsH'% (FMAP_STRLEN)
2611e36cceSSimon GlassFMAP_AREA_FORMAT = '<II%dsH' % (FMAP_STRLEN)
2711e36cceSSimon Glass
2811e36cceSSimon GlassFMAP_HEADER_NAMES = (
2911e36cceSSimon Glass    'signature',
3011e36cceSSimon Glass    'ver_major',
3111e36cceSSimon Glass    'ver_minor',
3211e36cceSSimon Glass    'base',
3311e36cceSSimon Glass    'image_size',
3411e36cceSSimon Glass    'name',
3511e36cceSSimon Glass    'nareas',
3611e36cceSSimon Glass)
3711e36cceSSimon Glass
3811e36cceSSimon GlassFMAP_AREA_NAMES = (
3911e36cceSSimon Glass    'offset',
4011e36cceSSimon Glass    'size',
4111e36cceSSimon Glass    'name',
4211e36cceSSimon Glass    'flags',
4311e36cceSSimon Glass)
4411e36cceSSimon Glass
4511e36cceSSimon Glass# These are the two data structures supported by flashrom, a header (which
4611e36cceSSimon Glass# appears once at the start) and an area (which is repeated until the end of
4711e36cceSSimon Glass# the list of areas)
4811e36cceSSimon GlassFmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
4911e36cceSSimon GlassFmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
5011e36cceSSimon Glass
5111e36cceSSimon Glass
52*f8f8df6eSSimon Glassdef NameToFmap(name):
53*f8f8df6eSSimon Glass    return name.replace('\0', '').replace('-', '_').upper()
54*f8f8df6eSSimon Glass
5511e36cceSSimon Glassdef ConvertName(field_names, fields):
5611e36cceSSimon Glass    """Convert a name to something flashrom likes
5711e36cceSSimon Glass
5811e36cceSSimon Glass    Flashrom requires upper case, underscores instead of hyphens. We remove any
5911e36cceSSimon Glass    null characters as well. This updates the 'name' value in fields.
6011e36cceSSimon Glass
6111e36cceSSimon Glass    Args:
6211e36cceSSimon Glass        field_names: List of field names for this struct
6311e36cceSSimon Glass        fields: Dict:
6411e36cceSSimon Glass            key: Field name
6511e36cceSSimon Glass            value: value of that field (string for the ones we support)
6611e36cceSSimon Glass    """
6711e36cceSSimon Glass    name_index = field_names.index('name')
68*f8f8df6eSSimon Glass    fields[name_index] = NameToFmap(fields[name_index])
6911e36cceSSimon Glass
7011e36cceSSimon Glassdef DecodeFmap(data):
7111e36cceSSimon Glass    """Decode a flashmap into a header and list of areas
7211e36cceSSimon Glass
7311e36cceSSimon Glass    Args:
7411e36cceSSimon Glass        data: Data block containing the FMAP
7511e36cceSSimon Glass
7611e36cceSSimon Glass    Returns:
7711e36cceSSimon Glass        Tuple:
7811e36cceSSimon Glass            header: FmapHeader object
7911e36cceSSimon Glass            List of FmapArea objects
8011e36cceSSimon Glass    """
8111e36cceSSimon Glass    fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
8211e36cceSSimon Glass    ConvertName(FMAP_HEADER_NAMES, fields)
8311e36cceSSimon Glass    header = FmapHeader(*fields)
8411e36cceSSimon Glass    areas = []
8511e36cceSSimon Glass    data = data[FMAP_HEADER_LEN:]
8611e36cceSSimon Glass    for area in range(header.nareas):
8711e36cceSSimon Glass        fields = list(struct.unpack(FMAP_AREA_FORMAT, data[:FMAP_AREA_LEN]))
8811e36cceSSimon Glass        ConvertName(FMAP_AREA_NAMES, fields)
8911e36cceSSimon Glass        areas.append(FmapArea(*fields))
9011e36cceSSimon Glass        data = data[FMAP_AREA_LEN:]
9111e36cceSSimon Glass    return header, areas
9211e36cceSSimon Glass
9311e36cceSSimon Glassdef EncodeFmap(image_size, name, areas):
9411e36cceSSimon Glass    """Create a new FMAP from a list of areas
9511e36cceSSimon Glass
9611e36cceSSimon Glass    Args:
9711e36cceSSimon Glass        image_size: Size of image, to put in the header
9811e36cceSSimon Glass        name: Name of image, to put in the header
9911e36cceSSimon Glass        areas: List of FmapArea objects
10011e36cceSSimon Glass
10111e36cceSSimon Glass    Returns:
10211e36cceSSimon Glass        String containing the FMAP created
10311e36cceSSimon Glass    """
10411e36cceSSimon Glass    def _FormatBlob(fmt, names, obj):
10511e36cceSSimon Glass        params = [getattr(obj, name) for name in names]
106*f8f8df6eSSimon Glass        ConvertName(names, params)
10711e36cceSSimon Glass        return struct.pack(fmt, *params)
10811e36cceSSimon Glass
10911e36cceSSimon Glass    values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
11011e36cceSSimon Glass    blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
11111e36cceSSimon Glass    for area in areas:
11211e36cceSSimon Glass        blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)
11311e36cceSSimon Glass    return blob
114