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