1c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Use of this source code is governed by a BSD-style license that can be
3c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# found in the LICENSE file.
4c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
5c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam""" This module provides convenience routines to access Flash ROM (EEPROM)
6c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
7c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamsaft_flashrom_util is based on utility 'flashrom'.
8c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
9c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamOriginal tool syntax:
10c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    (read ) flashrom -r <file>
11c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    (write) flashrom -l <layout_fn> [-i <image_name> ...] -w <file>
12c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
13c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamThe layout_fn is in format of
14c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    address_begin:address_end image_name
15c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    which defines a region between (address_begin, address_end) and can
16c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    be accessed by the name image_name.
17c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
18c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamCurrently the tool supports multiple partial write but not partial read.
19c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
20c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamIn the saft_flashrom_util, we provide read and partial write abilities.
21c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong TamFor more information, see help(saft_flashrom_util.flashrom_util).
22c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam"""
23c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
24c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass TestError(Exception):
25c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    pass
26c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
27c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
28c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass LayoutScraper(object):
29be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    """Object of this class is used to retrieve layout from a BIOS file."""
30c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
31c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    # The default conversion table for mosys.
32c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    DEFAULT_CHROMEOS_FMAP_CONVERSION = {
33c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Boot Stub": "FV_BSTUB",
34c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "GBB Area": "FV_GBB",
35c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Recovery Firmware": "FVDEV",
36c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "RO VPD": "RO_VPD",
37c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware A Key": "VBOOTA",
38c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware A Data": "FVMAIN",
39c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware B Key": "VBOOTB",
40c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware B Data": "FVMAINB",
41c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Log Volume": "FV_LOG",
42c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # New layout in Chrome OS Main Processor Firmware Specification,
43c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # used by all newer (>2011) platforms except Mario.
44c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "BOOT_STUB": "FV_BSTUB",
45c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "GBB": "FV_GBB",
46c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "RECOVERY": "FVDEV",
47c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "VBLOCK_A": "VBOOTA",
48c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "VBLOCK_B": "VBOOTB",
49c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "FW_MAIN_A": "FVMAIN",
50c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "FW_MAIN_B": "FVMAINB",
51dcff84266ccf29d474e902b597225a1e07cb765dTyler Reid        # Memory Training data cache for recovery boots
52dcff84266ccf29d474e902b597225a1e07cb765dTyler Reid        # Added on Nov 09, 2016
53dcff84266ccf29d474e902b597225a1e07cb765dTyler Reid        "RECOVERY_MRC_CACHE": "RECOVERY_MRC_CACHE",
548086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        # New sections in Depthcharge.
558086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        "EC_MAIN_A": "ECMAINA",
568086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        "EC_MAIN_B": "ECMAINB",
57c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # EC firmware layout
58c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "EC_RW": "EC_RW",
59c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        }
60c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
61c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __init__(self, os_if):
62c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.image = None
63c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if = os_if
64c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
65c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _get_text_layout(self, file_name):
66be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Retrieve text layout from a firmware image file.
67c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
68c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        This function uses the 'mosys' utility to scan the firmware image and
69c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        retrieve the section layout information.
70c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
71c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The layout is reported as a set of lines with multiple
72c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "<name>"="value" pairs, all this output is passed to the caller.
73be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
74c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
7564161b4d52c8d313ade6427cd290b90ff1e26581David Hendricks        mosys_cmd = 'mosys -k eeprom map %s' % file_name
76c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.os_if.run_shell_command_get_output(mosys_cmd)
77c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
78c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _line_to_dictionary(self, line):
79be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Convert a text layout line into a dictionary.
80c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
81c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Get a string consisting of single space separated "<name>"="value>"
82c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        pairs and convert it into a dictionary where keys are the <name>
83c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        fields, and values are the corresponding <value> fields.
84c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
85c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Return the dictionary to the caller.
86be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
87c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
88c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        rv = {}
89c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
90c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        items = line.replace('" ', '"^').split('^')
91c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for item in items:
92c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            pieces = item.split('=')
93c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if len(pieces) != 2:
94c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                continue
95c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            rv[pieces[0]] = pieces[1].strip('"')
96c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return rv
97c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
98c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def check_layout(self, layout, file_size):
99be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Verify the layout to be consistent.
100c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
101c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The layout is consistent if there is no overlapping sections and the
102c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        section boundaries do not exceed the file size.
103c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
104c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Inputs:
105c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          layout: a dictionary keyed by a string (the section name) with
106c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                  values being two integers tuples, the first and the last
107c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                  bites' offset in the file.
108c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          file_size: and integer, the size of the file the layout describes
109c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                     the sections in.
110c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
111c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Raises:
112c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          TestError in case the layout is not consistent.
113be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
114c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
115c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # Generate a list of section range tuples.
116c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ost = sorted([layout[section] for section in layout])
117c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        base = -1
118c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for section_base, section_end in ost:
119c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if section_base <= base or section_end + 1 < section_base:
120c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                raise TestError('bad section at 0x%x..0x%x' % (
121c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                        section_base, section_end))
122c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            base = section_end
123c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if base > file_size:
124c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise TestError('Section end 0x%x exceeds file size %x' % (
125c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    base, file_size))
126c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
127c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_layout(self, file_name):
128be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Generate layout for a firmware file.
129c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
130c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        First retrieve the text layout as reported by 'mosys' and then convert
131c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        it into a dictionary, replacing section names reported by mosys into
132c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        matching names from DEFAULT_CHROMEOS_FMAP_CONVERSION dictionary above,
133c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        using the names as keys in the layout dictionary. The elements of the
134c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout dictionary are the offsets of the first ans last bytes of the
135c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        section in the firmware file.
136c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
137c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Then verify the generated layout's consistency and return it to the
138c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        caller.
139be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
140c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
141c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_data = {} # keyed by the section name, elements - tuples of
142c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                         # (<section start addr>, <section end addr>)
143c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
144c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for line in self._get_text_layout(file_name):
145c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            d = self._line_to_dictionary(line)
146c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            try:
147c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                name = self.DEFAULT_CHROMEOS_FMAP_CONVERSION[d['area_name']]
148c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            except KeyError:
149c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                continue  # This line does not contain an area of interest.
150c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
151c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if name in layout_data:
1529999730bc117c6a6363b616d3da5dbf0eb6b4d50Tom Wai-Hong Tam                raise TestError('%s duplicated in the layout' % name)
153c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
154c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            offset = int(d['area_offset'], 0)
155c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            size = int(d['area_size'], 0)
156c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            layout_data[name] = (offset, offset + size - 1)
157c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
15838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        self.check_layout(layout_data, self.os_if.get_file_size(file_name))
159c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return layout_data
160c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
161c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# flashrom utility wrapper
162c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass flashrom_util(object):
163c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    """ a wrapper for "flashrom" utility.
164c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
165c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    You can read, write, or query flash ROM size with this utility.
166c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Although you can do "partial-write", the tools always takes a
167c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    full ROM image as input parameter.
168c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
169c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    NOTE before accessing flash ROM, you may need to first "select"
170c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    your target - usually BIOS or EC. That part is not handled by
171c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    this utility. Please find other external script to do it.
172c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
173c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    To perform a read, you need to:
174c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     1. Prepare a flashrom_util object
175c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: flashrom = flashrom_util.flashrom_util()
176c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     2. Perform read operation
177c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: image = flashrom.read_whole()
178c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
179c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        When the contents of the flashrom is read off the target, it's map
180c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        gets created automatically (read from the flashrom image using
181c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        'mosys'). If the user wants this object to operate on some other file,
182c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        he could either have the map for the file created explicitly by
183c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        invoking flashrom.set_firmware_layout(filename), or supply his own map
184c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        (which is a dictionary where keys are section names, and values are
185c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        tuples of integers, base address of the section and the last address
186c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        of the section).
187c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
188c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    By default this object operates on the map retrieved from the image and
189c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    stored locally, this map can be overwritten by an explicitly passed user
190c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    map.
191c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
192c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam   To perform a (partial) write:
193c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
194c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     1. Prepare a buffer storing an image to be written into the flashrom.
195c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     2. Have the map generated automatically or prepare your own, for instance:
196c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: layout_map_all = { 'all': (0, rom_size - 1) }
197c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: layout_map = { 'ro': (0, 0xFFF), 'rw': (0x1000, rom_size-1) }
198c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     4. Perform write operation
199c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
200c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex using default map:
201c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          flashrom.write_partial(new_image, (<section_name>, ...))
202c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex using explicitly provided map:
203c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          flashrom.write_partial(new_image, layout_map_all, ('all',))
204c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
205c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Attributes:
206c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        keep_temp_files: boolean flag to control cleaning of temporary files
207c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    """
208c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
209ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam    def __init__(self, os_if, keep_temp_files=False,
210be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam                 target_is_ec=False):
211c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """ constructor of flashrom_util. help(flashrom_util) for more info """
212ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam        self.os_if = os_if
213c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.keep_temp_files = keep_temp_files
214c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.firmware_layout = {}
215c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self._target_command = ''
216c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if target_is_ec:
217c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self._enable_ec_access()
218c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
219c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self._enable_bios_access()
220c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
221c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _enable_bios_access(self):
222c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.os_if.target_hosted():
223c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
22437bcc951d328d064255426a10ec6fd855c0eaeb4David Hendricks        self._target_command = '-p host'
225c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
226c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _enable_ec_access(self):
227c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.os_if.target_hosted():
228c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
22937bcc951d328d064255426a10ec6fd855c0eaeb4David Hendricks        self._target_command = '-p ec'
230c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
23138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam    def _get_temp_filename(self, prefix):
23238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        """Returns name of a temporary file in /tmp."""
23338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        return self.os_if.create_temp_file(prefix)
234c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
23538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam    def _remove_temp_file(self, filename):
23638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        """Removes a temp file if self.keep_temp_files is false."""
237c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.keep_temp_files:
238c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
23938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        if self.os_if.path_exists(filename):
24038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam            self.os_if.remove_file(filename)
24138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam
24238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam    def _create_layout_file(self, layout_map):
24338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        """Creates a layout file based on layout_map.
244c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
245c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns the file name containing layout information.
246be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
247c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_text = ['0x%08lX:0x%08lX %s' % (v[0], v[1], k)
248c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            for k, v in layout_map.items()]
249c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_text.sort()  # XXX unstable if range exceeds 2^32
25038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        tmpfn = self._get_temp_filename('lay_')
25138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        self.os_if.write_file(tmpfn, '\n'.join(layout_text) + '\n')
252c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return tmpfn
253c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
254c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_section(self, base_image, section_name):
255be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
256c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Retrieves a section of data based on section_name in layout_map.
257c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Raises error if unknown section or invalid layout_map.
258be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
2598086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        if section_name not in self.firmware_layout:
2608086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam            return []
261c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        pos = self.firmware_layout[section_name]
262c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if pos[0] >= pos[1] or pos[1] >= len(base_image):
263c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise TestError('INTERNAL ERROR: invalid layout map: %s.' %
264c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                            section_name)
265eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        blob = base_image[pos[0] : pos[1] + 1]
266eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        # Trim down the main firmware body to its actual size since the
267eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        # signing utility uses the size of the input file as the size of
268eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        # the data to sign. Make it the same way as firmware creation.
2698086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        if section_name in ('FVMAIN', 'FVMAINB', 'ECMAINA', 'ECMAINB'):
270eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            align = 4
271eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            pad = blob[-1]
272eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            blob = blob.rstrip(pad)
273eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            blob = blob + ((align - 1) - (len(blob) - 1) % align) * pad
274eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        return blob
275c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
276c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def put_section(self, base_image, section_name, data):
277be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
278c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Updates a section of data based on section_name in firmware_layout.
279c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Raises error if unknown section.
280c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns the full updated image data.
281be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
282c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        pos = self.firmware_layout[section_name]
283c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if pos[0] >= pos[1] or pos[1] >= len(base_image):
284c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise TestError('INTERNAL ERROR: invalid layout map.')
285c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if len(data) != pos[1] - pos[0] + 1:
286eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            # Pad the main firmware body since we trimed it down before.
2878086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam            if (len(data) < pos[1] - pos[0] + 1 and section_name in
2888086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam                    ('FVMAIN', 'FVMAINB', 'ECMAINA', 'ECMAINB')):
289eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam                pad = base_image[pos[1]]
290eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam                data = data + pad * (pos[1] - pos[0] + 1 - len(data))
291eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            else:
292eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam                raise TestError('INTERNAL ERROR: unmatched data size.')
293c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return base_image[0 : pos[0]] + data + base_image[pos[1] + 1 :]
294c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
295c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_size(self):
296c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """ Gets size of current flash ROM """
297c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # TODO(hungte) Newer version of tool (flashrom) may support --get-size
298c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # command which is faster in future. Right now we use back-compatible
299c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # method: read whole and then get length.
300c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        image = self.read_whole()
301c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return len(image)
302c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
303c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def set_firmware_layout(self, file_name):
304c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """get layout read from the BIOS """
305c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
306c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        scraper = LayoutScraper(self.os_if)
307c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.firmware_layout = scraper.get_layout(file_name)
308c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
30944204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam    def enable_write_protect(self):
31044204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        """Enable the write pretection of the flash chip."""
31144204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        cmd = 'flashrom %s --wp-enable' % self._target_command
31244204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
31344204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam
31444204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam    def disable_write_protect(self):
31544204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        """Disable the write pretection of the flash chip."""
31644204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        cmd = 'flashrom %s --wp-disable' % self._target_command
31744204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
31844204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam
319c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def read_whole(self):
320be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
321c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Reads whole flash ROM data.
322c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns the data read from flash ROM, or empty string for other error.
323be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
32438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        tmpfn = self._get_temp_filename('rd_')
325c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        cmd = 'flashrom %s -r "%s"' % (self._target_command, tmpfn)
32622331b87b470527c17309695a07560d67cb9ddd1Tom Wai-Hong Tam        self.os_if.log('flashrom_util.read_whole(): %s' % cmd)
327c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
32838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        result = self.os_if.read_file(tmpfn)
329c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.set_firmware_layout(tmpfn)
330c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
331c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # clean temporary resources
33238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        self._remove_temp_file(tmpfn)
333c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return result
334c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
335c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def write_partial(self, base_image, write_list, write_layout_map=None):
336be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
337c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Writes data in sections of write_list to flash ROM.
338c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        An exception is raised if write operation fails.
339be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
340c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
341c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if write_layout_map:
342c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            layout_map = write_layout_map
343c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
344c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            layout_map = self.firmware_layout
345c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
34638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        tmpfn = self._get_temp_filename('wr_')
34738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        self.os_if.write_file(tmpfn, base_image)
34838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        layout_fn = self._create_layout_file(layout_map)
349c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
350c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        cmd = 'flashrom %s -l "%s" -i %s -w "%s"' % (
351c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                self._target_command, layout_fn, ' -i '.join(write_list), tmpfn)
35222331b87b470527c17309695a07560d67cb9ddd1Tom Wai-Hong Tam        self.os_if.log('flashrom.write_partial(): %s' % cmd)
353c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
354c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
3556dd5843d5526bd472d61bc4a3dd38d1a8e5fe24bShelley Chen        # flashrom write will reboot the ec after corruption
3566dd5843d5526bd472d61bc4a3dd38d1a8e5fe24bShelley Chen        # For Android, need to make sure ec is back online
3576dd5843d5526bd472d61bc4a3dd38d1a8e5fe24bShelley Chen        # before continuing, or adb command will cause test failure
3586dd5843d5526bd472d61bc4a3dd38d1a8e5fe24bShelley Chen        if self.os_if.is_android:
3596dd5843d5526bd472d61bc4a3dd38d1a8e5fe24bShelley Chen            self.os_if.wait_for_device(60)
3606dd5843d5526bd472d61bc4a3dd38d1a8e5fe24bShelley Chen
361c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # clean temporary resources
36238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        self._remove_temp_file(tmpfn)
36338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam        self._remove_temp_file(layout_fn)
364c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
365c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def write_whole(self, base_image):
366be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Write the whole base image. """
367c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_map = { 'all': (0, len(base_image) - 1) }
368c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.write_partial(base_image, ('all',), layout_map)
369