| Index: client/common_lib/flashrom_util.py
|
| diff --git a/client/common_lib/flashrom_util.py b/client/common_lib/flashrom_util.py
|
| index 4cf4f1da3009f6f5e9fdad028995181fa8e82d94..ae5cdeebfda8097f83009b41f26f55a59312de7a 100644
|
| --- a/client/common_lib/flashrom_util.py
|
| +++ b/client/common_lib/flashrom_util.py
|
| @@ -67,6 +67,19 @@ DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS = {
|
| """,
|
| }
|
|
|
| +# The default conversion table for fmap_decode.
|
| +DEFAULT_CHROMEOS_FMAP_CONVERSION = {
|
| + "Boot Stub": "FV_BSTUB",
|
| + "GBB Area": "FV_GBB",
|
| + "Recovery Firmware": "FVDEV",
|
| + "RO VPD": "RO_VPD",
|
| + "Firmware A Key": "VBOOTA",
|
| + "Firmware A Data": "FVMAIN",
|
| + "Firmware B Key": "VBOOTB",
|
| + "Firmware B Data": "FVMAINB",
|
| + "Log Volume": "FV_LOG",
|
| +}
|
| +
|
| # Default "skip" sections when verifying section data.
|
| # This is required because some flashrom chip may create timestamps (or checksum
|
| # values) when (or immediately after) we change flashrom content.
|
| @@ -180,6 +193,75 @@ def compile_layout(desc, size):
|
| return layout
|
|
|
|
|
| +def _convert_fmap_layout(conversion_map, fmap_areas):
|
| + """
|
| + (internal utility) Converts a FMAP areas structure to flashrom layout format
|
| + by conversion_map.
|
| + Args:
|
| + conversion_map: dictionary of names to convert.
|
| + fmap_areas: a list of {name, offset, size} dictionary.
|
| +
|
| + Returns: layout structure for flashrom_util, or empty for failure.
|
| + """
|
| + layout = {}
|
| + for entry in fmap_areas:
|
| + name = entry['name']
|
| + offset = entry['offset']
|
| + size = entry['size']
|
| + if name in conversion_map:
|
| + name = conversion_map[name]
|
| + name = name.replace(' ', '%20')
|
| + layout[name] = (offset, offset + size - 1)
|
| + return layout
|
| +
|
| +
|
| +def decode_fmap_layout_external(conversion_map, image_file_name):
|
| + """
|
| + (Utility) Decodes layout by an external fmap_decode command provided by
|
| + system PATH.
|
| + Args:
|
| + conversion_map: dictionary for FMAP area name conversion
|
| + image_file_name: file name of firmware image with FMAP structure for
|
| + parsing layout.
|
| +
|
| + Returns: layout structure for flashrom_util, or empty for failure.
|
| + """
|
| + if os.system('type fmap_decode 2>/dev/null') != 0:
|
| + # print 'error: no fmap_decode in system.'
|
| + return {}
|
| + fmap_object = []
|
| + fmap = os.popen("fmap_decode %s 2>/dev/null" % image_file_name).readlines()
|
| + for entry in fmap:
|
| + if 'area_name' not in entry:
|
| + continue
|
| + # format: area_offset="HEX" area_size="HEX" area_name="NAME" ...
|
| + offset = int(re.findall('area_offset="([^"]*)"', entry)[0], 0)
|
| + size = int(re.findall('area_size="([^"]*)"', entry)[0], 0)
|
| + name = re.findall('area_name="([^"]*)"', entry)[0]
|
| + # print 'off=%s, size=%s, name=%s' % (offset, size, name)
|
| + fmap_object.append({'offset':offset, 'size':size, 'name':name})
|
| + return _convert_fmap_layout(conversion_map, fmap_object)
|
| +
|
| +
|
| +def decode_fmap_layout(conversion_map, image_blob):
|
| + """
|
| + (Utility) Uses fmap_decode to retrieve embedded layout of a prepared
|
| + firmware image.
|
| + Args:
|
| + conversion_map: dictionary for FMAP area name conversion
|
| + image_blob: binary data of firmware image containing FMAP
|
| +
|
| + Returns: layout structure for flashrom_util, or empty for failure.
|
| + """
|
| + try:
|
| + import site_fmap
|
| + fmap_object = site_fmap.fmap_decode(image_blob)['areas']
|
| + except:
|
| + # print 'decode_fmap_layout: failed to decode from image blob'
|
| + fmap_object = []
|
| + return _convert_fmap_layout(conversion_map, fmap_object)
|
| +
|
| +
|
| def csv_to_list(csv, delimiter=','):
|
| """
|
| (Utility) Converts a comma-separated-value (or list) to a list.
|
| @@ -265,6 +347,7 @@ class flashrom_util(object):
|
| self.verbose = verbose
|
| self.keep_temp_files = keep_temp_files
|
| self.target_map = target_map
|
| + self.is_debug = False
|
| # detect bbs map if target_map is None.
|
| # NOTE when target_map == {}, that means "do not execute commands",
|
| # different to default value.
|
| @@ -342,41 +425,63 @@ class flashrom_util(object):
|
| return target_map
|
| raise TestError('INTERNAL ERROR: unknown architecture, need target_map')
|
|
|
| - def detect_layout(self, layout_desciption, size=None):
|
| + def detect_layout(self, layout_desciption, size, image):
|
| """
|
| Detects and builds layout according to current flash ROM size
|
| - and a simple layout description language.
|
| - If parameter 'size' is omitted, self.get_size() will be called.
|
| + (or image) and a simple layout description language.
|
| +
|
| + NOTE: if you don't trust any available FMAP layout information in
|
| + flashrom image, pass image = None.
|
|
|
| - See help(flashrom_util.compile_layout) for the syntax of description.
|
| + Args:
|
| + layout_description: Pre-defined layout description. See
|
| + help(flashrom_util.compile_layout) for syntax detail.
|
| + size: Size of flashrom. If size is None, self.get_size()
|
| + will be called.
|
| + image: (optional) Flash ROM image that contains FMAP layout info.
|
| + If image is None, layout will be calculated by size only.
|
|
|
| Returns the layout map (empty if any error).
|
| """
|
| - if not size:
|
| - size = self.get_size()
|
| - return compile_layout(layout_desciption, size)
|
| + ret = None
|
| + if image:
|
| + if self.is_debug:
|
| + print " * detect_layout: try FMAP"
|
| + ret = decode_fmap_layout(DEFAULT_CHROMEOS_FMAP_CONVERSION, image)
|
| + if not ret:
|
| + if not size:
|
| + size = self.get_size()
|
| + ret = compile_layout(layout_desciption, size)
|
| + if self.is_debug:
|
| + print " * detect_layout: using pre-defined memory layout"
|
| + elif self.is_debug:
|
| + print " * detect_layout: using FMAP layout in firmware image."
|
| + return ret
|
|
|
| - def detect_chromeos_layout(self, target, size=None):
|
| + def detect_chromeos_layout(self, target, size, image):
|
| """
|
| Detects and builds ChromeOS firmware layout according to current flash
|
| - ROM size. If parameter 'size' is None, self.get_size() will be called.
|
| + ROM size. Currently supported targets are: 'bios' or 'ec'.
|
|
|
| - Currently supported targets are: 'bios' or 'ec'.
|
| + See help(flashrom_util.flashrom_util.detect_layout) for detail
|
| + information of argument size and image.
|
|
|
| Returns the layout map (empty if any error).
|
| """
|
| assert target in DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS, \
|
| 'unknown layout target: ' + test
|
| chromeos_target = DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS[target]
|
| - return self.detect_layout(chromeos_target, size)
|
| + return self.detect_layout(chromeos_target, size, image)
|
|
|
| - def detect_chromeos_bios_layout(self, size=None):
|
| - """ Detects standard ChromeOS BIOS layout """
|
| - return self.detect_chromeos_layout(self.TARGET_BIOS, size)
|
| + def detect_chromeos_bios_layout(self, size, image):
|
| + """ Detects standard ChromeOS BIOS layout.
|
| + A short cut to detect_chromeos_layout(TARGET_BIOS, size, image). """
|
| + return self.detect_chromeos_layout(self.TARGET_BIOS, size, image)
|
|
|
| - def detect_chromeos_ec_layout(self, size=None):
|
| - """ Detects standard ChromeOS Embedded Controller layout """
|
| - return self.detect_chromeos_layout(self.TARGET_EC, size)
|
| + def detect_chromeos_ec_layout(self, size, image):
|
| + """ Detects standard ChromeOS Embedded Controller layout.
|
| + A short cut to detect_chromeos_layout(TARGET_EC, size, image). """
|
| + return self.detect_chromeos_layout(self.TARGET_EC, size, image)
|
|
|
| def read_whole(self):
|
| '''
|
| @@ -550,7 +655,7 @@ class FlashromUtility(object):
|
|
|
| Arguments:
|
| flashrom_util_instance: An instance of existing flashrom_util. If
|
| - not provided, FirmwareUpdater will create
|
| + not provided, FlashromUtility will create
|
| one with all default values.
|
| is_verbose: Flag to control outputting verbose messages.
|
| """
|
| @@ -565,21 +670,43 @@ class FlashromUtility(object):
|
| self.is_verbose = is_verbose
|
| self.is_debug = False
|
|
|
| - def initialize(self, target, layout_desc=None, skip_verify=None):
|
| - """ Starts flashrom initialization with given target. """
|
| + def initialize(self, target, layout_image=None, layout_desc=None,
|
| + use_fmap_layout=True, skip_verify=None):
|
| + """
|
| + Starts flashrom initialization with given target.
|
| +
|
| + Args:
|
| + target: Name of the target you are dealing with (check TARGET_*)
|
| + layout_desc: (optional) Description of pre-defined layout
|
| + layout_image: (optional) A image blob containing FMAP for building
|
| + layout. None if you want to use current system flash content
|
| + use_fmap_layout: Use True (default) if you trust the FMAP in
|
| + layout_image.
|
| + skip_verify: Description of what data must be skipped when
|
| + doing comparison / verification.
|
| + """
|
| flashrom = self.flashrom
|
| if not flashrom.select_target(target):
|
| raise TestError("Cannot Select Target. Abort.")
|
| +
|
| if self.is_verbose:
|
| print " - reading current content"
|
| self.current_image = flashrom.read_whole()
|
| if not self.current_image:
|
| raise TestError("Cannot read flashrom image. Abort.")
|
| flashrom_size = len(self.current_image)
|
| +
|
| + if not use_fmap_layout:
|
| + layout_image = None
|
| + elif not layout_image:
|
| + layout_image = current_image
|
| +
|
| if layout_desc:
|
| - layout = flashrom.detect_layout(layout_desc, flashrom_size)
|
| + layout = flashrom.detect_layout(
|
| + layout_desc, flashrom_size, layout_image)
|
| else:
|
| - layout = flashrom.detect_chromeos_layout(target, flashrom_size)
|
| + layout = flashrom.detect_chromeos_layout(
|
| + target, flashrom_size, layout_image)
|
| self.layout = layout
|
| self.whole_flash_layout = flashrom.detect_layout('all', flashrom_size)
|
| if not skip_verify:
|
|
|