| Index: client/common_lib/site_fmap.py
|
| diff --git a/client/common_lib/site_fmap.py b/client/common_lib/site_fmap.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..87e87ffdffc250d808535e93a9039004c5b03fd7
|
| --- /dev/null
|
| +++ b/client/common_lib/site_fmap.py
|
| @@ -0,0 +1,154 @@
|
| +#!/usr/bin/env python
|
| +# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +"""
|
| +This module provides basic encode and decode functionality to the flashrom
|
| +memory map (FMAP) structure.
|
| +
|
| +Usage:
|
| + (decode)
|
| + obj = fmap_decode(blob)
|
| + print obj
|
| +
|
| + (encode)
|
| + blob = fmap_encode(obj)
|
| + open('output.bin', 'w').write(blob)
|
| +
|
| + The object returned by fmap_decode is a dictionary with names defined in
|
| + fmap.h. A special property 'FLAGS' is provided as a readable and read-only
|
| + tuple of decoded area flags.
|
| +"""
|
| +
|
| +import struct
|
| +import sys
|
| +
|
| +# constants imported from lib/fmap.h
|
| +FMAP_SIGNATURE = "__FMAP__"
|
| +FMAP_VER_MAJOR = 1
|
| +FMAP_VER_MINOR = 0
|
| +FMAP_STRLEN = 32
|
| +
|
| +FMAP_FLAGS = {
|
| + 'FMAP_AREA_STATIC': 1 << 0,
|
| + 'FMAP_AREA_COMPRESSED': 1 << 1,
|
| +}
|
| +
|
| +FMAP_HEADER_NAMES = (
|
| + 'signature',
|
| + 'ver_major',
|
| + 'ver_minor',
|
| + 'base',
|
| + 'size',
|
| + 'name',
|
| + 'nareas',
|
| +)
|
| +
|
| +FMAP_AREA_NAMES = (
|
| + 'offset',
|
| + 'size',
|
| + 'name',
|
| + 'flags',
|
| +)
|
| +
|
| +# format string
|
| +FMAP_HEADER_FORMAT = "<8sBBQI%dsH" % (FMAP_STRLEN)
|
| +FMAP_AREA_FORMAT = "<II%dsH" % (FMAP_STRLEN)
|
| +
|
| +
|
| +def _fmap_decode_header(blob, offset):
|
| + """ (internal) Decodes a FMAP header from blob by offset"""
|
| + header = {}
|
| + for (name, value) in zip(FMAP_HEADER_NAMES,
|
| + struct.unpack_from(FMAP_HEADER_FORMAT,
|
| + blob,
|
| + offset)):
|
| + header[name] = value
|
| +
|
| + if header['signature'] != FMAP_SIGNATURE:
|
| + raise struct.error('Invalid signature')
|
| + if header['ver_major'] != FMAP_VER_MAJOR or \
|
| + header['ver_minor'] != FMAP_VER_MINOR:
|
| + raise struct.error('Incompatible version')
|
| +
|
| + # convert null-terminated names
|
| + header['name'] = header['name'].strip(chr(0))
|
| + return (header, struct.calcsize(FMAP_HEADER_FORMAT))
|
| +
|
| +
|
| +def _fmap_decode_area(blob, offset):
|
| + """ (internal) Decodes a FMAP area record from blob by offset """
|
| + area = {}
|
| + for (name, value) in zip(FMAP_AREA_NAMES,
|
| + struct.unpack_from(FMAP_AREA_FORMAT, blob, offset)):
|
| + area[name] = value
|
| + # convert null-terminated names
|
| + area['name'] = area['name'].strip(chr(0))
|
| + # add a (readonly) readable FLAGS
|
| + area['FLAGS'] = _fmap_decode_area_flags(area['flags'])
|
| + return (area, struct.calcsize(FMAP_AREA_FORMAT))
|
| +
|
| +
|
| +def _fmap_decode_area_flags(area_flags):
|
| + """ (internal) Decodes a FMAP flags property """
|
| + return tuple([name for name in FMAP_FLAGS if area_flags & FMAP_FLAGS[name]])
|
| +
|
| +
|
| +def fmap_decode(blob, offset=None):
|
| + """ Decodes a blob to FMAP dictionary object.
|
| +
|
| + Arguments:
|
| + blob: a binary data containing FMAP structure.
|
| + offset: starting offset of FMAP. When omitted, fmap_decode will search in
|
| + the blob.
|
| + """
|
| + fmap = {}
|
| + if offset == None:
|
| + # try search magic in fmap
|
| + offset = blob.find(FMAP_SIGNATURE)
|
| + (fmap, size) = _fmap_decode_header(blob, offset)
|
| + fmap['areas'] = []
|
| + offset = offset + size
|
| + for i in range(fmap['nareas']):
|
| + (area, size) = _fmap_decode_area(blob, offset)
|
| + offset = offset + size
|
| + fmap['areas'].append(area)
|
| + return fmap
|
| +
|
| +
|
| +def _fmap_encode_header(obj):
|
| + """ (internal) Encodes a FMAP header """
|
| + values = [obj[name] for name in FMAP_HEADER_NAMES]
|
| + return struct.pack(FMAP_HEADER_FORMAT, *values)
|
| +
|
| +
|
| +def _fmap_encode_area(obj):
|
| + """ (internal) Encodes a FMAP area entry """
|
| + values = [obj[name] for name in FMAP_AREA_NAMES]
|
| + return struct.pack(FMAP_AREA_FORMAT, *values)
|
| +
|
| +
|
| +def fmap_encode(obj):
|
| + """ Encodes a FMAP dictionary object to blob.
|
| +
|
| + Arguments
|
| + obj: a FMAP dictionary object.
|
| + """
|
| + # fix up values
|
| + obj['nareas'] = len(obj['areas'])
|
| + # TODO(hungte) re-assign signature / version?
|
| + blob = _fmap_encode_header(obj)
|
| + for area in obj['areas']:
|
| + blob = blob + _fmap_encode_area(area)
|
| + return blob
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + # main entry, do a unit test
|
| + blob = open('bin/example.bin').read()
|
| + obj = fmap_decode(blob)
|
| + print obj
|
| + blob2 = fmap_encode(obj)
|
| + obj2 = fmap_decode(blob2)
|
| + print obj2
|
| + assert obj == obj2
|
|
|