| 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:
 | 
| 
 |