uboot/tools/binman/fmap_util.py
<<
>>
Prefs
   1# 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
  11import sys
  12
  13from patman import tools
  14
  15# constants imported from lib/fmap.h
  16FMAP_SIGNATURE = b'__FMAP__'
  17FMAP_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
  48# These are the two data structures supported by flashrom, a header (which
  49# appears once at the start) and an area (which is repeated until the end of
  50# the list of areas)
  51FmapHeader = collections.namedtuple('FmapHeader', FMAP_HEADER_NAMES)
  52FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
  53
  54
  55def NameToFmap(name):
  56    if type(name) == bytes:
  57        name = name.decode('utf-8')
  58    return name.replace('\0', '').replace('-', '_').upper()
  59
  60def ConvertName(field_names, fields):
  61    """Convert a name to something flashrom likes
  62
  63    Flashrom requires upper case, underscores instead of hyphens. We remove any
  64    null characters as well. This updates the 'name' value in fields.
  65
  66    Args:
  67        field_names: List of field names for this struct
  68        fields: Dict:
  69            key: Field name
  70            value: value of that field (string for the ones we support)
  71    """
  72    name_index = field_names.index('name')
  73    fields[name_index] = tools.ToBytes(NameToFmap(fields[name_index]))
  74
  75def DecodeFmap(data):
  76    """Decode a flashmap into a header and list of areas
  77
  78    Args:
  79        data: Data block containing the FMAP
  80
  81    Returns:
  82        Tuple:
  83            header: FmapHeader object
  84            List of FmapArea objects
  85    """
  86    fields = list(struct.unpack(FMAP_HEADER_FORMAT, data[:FMAP_HEADER_LEN]))
  87    ConvertName(FMAP_HEADER_NAMES, fields)
  88    header = FmapHeader(*fields)
  89    areas = []
  90    data = data[FMAP_HEADER_LEN:]
  91    for area in range(header.nareas):
  92        fields = list(struct.unpack(FMAP_AREA_FORMAT, data[:FMAP_AREA_LEN]))
  93        ConvertName(FMAP_AREA_NAMES, fields)
  94        areas.append(FmapArea(*fields))
  95        data = data[FMAP_AREA_LEN:]
  96    return header, areas
  97
  98def EncodeFmap(image_size, name, areas):
  99    """Create a new FMAP from a list of areas
 100
 101    Args:
 102        image_size: Size of image, to put in the header
 103        name: Name of image, to put in the header
 104        areas: List of FmapArea objects
 105
 106    Returns:
 107        String containing the FMAP created
 108    """
 109    def _FormatBlob(fmt, names, obj):
 110        params = [getattr(obj, name) for name in names]
 111        ConvertName(names, params)
 112        return struct.pack(fmt, *params)
 113
 114    values = FmapHeader(FMAP_SIGNATURE, 1, 0, 0, image_size, name, len(areas))
 115    blob = _FormatBlob(FMAP_HEADER_FORMAT, FMAP_HEADER_NAMES, values)
 116    for area in areas:
 117        blob += _FormatBlob(FMAP_AREA_FORMAT, FMAP_AREA_NAMES, area)
 118    return blob
 119