saft_flashrom_util.py revision 8086f96b61050d813db785f8a416d884bd0b2225
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 Tamimport os
25c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport re
26c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport stat
27c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport subprocess
28c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport sys
29c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport tempfile
30c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport types
31c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
32c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport chromeos_interface
33c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
34c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass TestError(Exception):
35c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    pass
36c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
37c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
38c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass LayoutScraper(object):
39be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    """Object of this class is used to retrieve layout from a BIOS file."""
40c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
41c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    # The default conversion table for mosys.
42c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    DEFAULT_CHROMEOS_FMAP_CONVERSION = {
43c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Boot Stub": "FV_BSTUB",
44c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "GBB Area": "FV_GBB",
45c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Recovery Firmware": "FVDEV",
46c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "RO VPD": "RO_VPD",
47c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware A Key": "VBOOTA",
48c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware A Data": "FVMAIN",
49c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware B Key": "VBOOTB",
50c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Firmware B Data": "FVMAINB",
51c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "Log Volume": "FV_LOG",
52c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # New layout in Chrome OS Main Processor Firmware Specification,
53c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # used by all newer (>2011) platforms except Mario.
54c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "BOOT_STUB": "FV_BSTUB",
55c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "GBB": "FV_GBB",
56c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "RECOVERY": "FVDEV",
57c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "VBLOCK_A": "VBOOTA",
58c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "VBLOCK_B": "VBOOTB",
59c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "FW_MAIN_A": "FVMAIN",
60c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "FW_MAIN_B": "FVMAINB",
618086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        # New sections in Depthcharge.
628086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        "EC_MAIN_A": "ECMAINA",
638086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        "EC_MAIN_B": "ECMAINB",
64c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # EC firmware layout
65c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "EC_RW": "EC_RW",
66c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        }
67c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
68c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def __init__(self, os_if):
69c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.image = None
70c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if = os_if
71c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
72c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _get_text_layout(self, file_name):
73be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Retrieve text layout from a firmware image file.
74c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
75c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        This function uses the 'mosys' utility to scan the firmware image and
76c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        retrieve the section layout information.
77c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
78c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The layout is reported as a set of lines with multiple
79c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        "<name>"="value" pairs, all this output is passed to the caller.
80be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
81c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
82c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        mosys_cmd = 'mosys -f -k eeprom map %s' % file_name
83c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return self.os_if.run_shell_command_get_output(mosys_cmd)
84c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
85c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _line_to_dictionary(self, line):
86be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Convert a text layout line into a dictionary.
87c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
88c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Get a string consisting of single space separated "<name>"="value>"
89c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        pairs and convert it into a dictionary where keys are the <name>
90c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        fields, and values are the corresponding <value> fields.
91c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
92c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Return the dictionary to the caller.
93be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
94c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
95c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        rv = {}
96c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
97c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        items = line.replace('" ', '"^').split('^')
98c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for item in items:
99c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            pieces = item.split('=')
100c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if len(pieces) != 2:
101c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                continue
102c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            rv[pieces[0]] = pieces[1].strip('"')
103c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return rv
104c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
105c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def check_layout(self, layout, file_size):
106be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Verify the layout to be consistent.
107c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
108c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        The layout is consistent if there is no overlapping sections and the
109c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        section boundaries do not exceed the file size.
110c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
111c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Inputs:
112c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          layout: a dictionary keyed by a string (the section name) with
113c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                  values being two integers tuples, the first and the last
114c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                  bites' offset in the file.
115c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          file_size: and integer, the size of the file the layout describes
116c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                     the sections in.
117c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
118c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Raises:
119c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          TestError in case the layout is not consistent.
120be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
121c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
122c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # Generate a list of section range tuples.
123c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ost = sorted([layout[section] for section in layout])
124c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        base = -1
125c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for section_base, section_end in ost:
126c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if section_base <= base or section_end + 1 < section_base:
127c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                raise TestError('bad section at 0x%x..0x%x' % (
128c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                        section_base, section_end))
129c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            base = section_end
130c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if base > file_size:
131c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise TestError('Section end 0x%x exceeds file size %x' % (
132c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                    base, file_size))
133c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
134c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_layout(self, file_name):
135be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Generate layout for a firmware file.
136c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
137c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        First retrieve the text layout as reported by 'mosys' and then convert
138c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        it into a dictionary, replacing section names reported by mosys into
139c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        matching names from DEFAULT_CHROMEOS_FMAP_CONVERSION dictionary above,
140c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        using the names as keys in the layout dictionary. The elements of the
141c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout dictionary are the offsets of the first ans last bytes of the
142c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        section in the firmware file.
143c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
144c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Then verify the generated layout's consistency and return it to the
145c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        caller.
146be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
147c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
148c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_data = {} # keyed by the section name, elements - tuples of
149c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                         # (<section start addr>, <section end addr>)
150c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
151c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        for line in self._get_text_layout(file_name):
152c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            d = self._line_to_dictionary(line)
153c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            try:
154c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                name = self.DEFAULT_CHROMEOS_FMAP_CONVERSION[d['area_name']]
155c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            except KeyError:
156c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                continue  # This line does not contain an area of interest.
157c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
158c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            if name in layout_data:
159c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                raise TestError('%s duplicated in the layout' % area_name)
160c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
161c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            offset = int(d['area_offset'], 0)
162c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            size = int(d['area_size'], 0)
163c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            layout_data[name] = (offset, offset + size - 1)
164c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
165c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.check_layout(layout_data, os.stat(file_name)[stat.ST_SIZE])
166c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return layout_data
167c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
168c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# flashrom utility wrapper
169c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass flashrom_util(object):
170c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    """ a wrapper for "flashrom" utility.
171c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
172c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    You can read, write, or query flash ROM size with this utility.
173c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Although you can do "partial-write", the tools always takes a
174c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    full ROM image as input parameter.
175c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
176c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    NOTE before accessing flash ROM, you may need to first "select"
177c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    your target - usually BIOS or EC. That part is not handled by
178c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    this utility. Please find other external script to do it.
179c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
180c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    To perform a read, you need to:
181c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     1. Prepare a flashrom_util object
182c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: flashrom = flashrom_util.flashrom_util()
183c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     2. Perform read operation
184c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: image = flashrom.read_whole()
185c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
186c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        When the contents of the flashrom is read off the target, it's map
187c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        gets created automatically (read from the flashrom image using
188c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        'mosys'). If the user wants this object to operate on some other file,
189c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        he could either have the map for the file created explicitly by
190c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        invoking flashrom.set_firmware_layout(filename), or supply his own map
191c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        (which is a dictionary where keys are section names, and values are
192c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        tuples of integers, base address of the section and the last address
193c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        of the section).
194c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
195c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    By default this object operates on the map retrieved from the image and
196c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    stored locally, this map can be overwritten by an explicitly passed user
197c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    map.
198c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
199c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam   To perform a (partial) write:
200c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
201c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     1. Prepare a buffer storing an image to be written into the flashrom.
202c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     2. Have the map generated automatically or prepare your own, for instance:
203c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: layout_map_all = { 'all': (0, rom_size - 1) }
204c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex: layout_map = { 'ro': (0, 0xFFF), 'rw': (0x1000, rom_size-1) }
205c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam     4. Perform write operation
206c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
207c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex using default map:
208c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          flashrom.write_partial(new_image, (<section_name>, ...))
209c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        ex using explicitly provided map:
210c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam          flashrom.write_partial(new_image, layout_map_all, ('all',))
211c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
212c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    Attributes:
213c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        verbose:    print debug and helpful messages
214c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        keep_temp_files: boolean flag to control cleaning of temporary files
215c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    """
216c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
217be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam    def __init__(self, verbose=False, keep_temp_files=False,
218be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam                 target_is_ec=False):
219c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """ constructor of flashrom_util. help(flashrom_util) for more info """
220c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.verbose = verbose
221c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.keep_temp_files = keep_temp_files
222c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.firmware_layout = {}
223c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if = chromeos_interface.ChromeOSInterface(True)
224c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if.init(tempfile.gettempdir())
225c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self._target_command = ''
226c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if target_is_ec:
227c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self._enable_ec_access()
228c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
229c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            self._enable_bios_access()
230c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
231c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _enable_bios_access(self):
232c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.os_if.target_hosted():
233c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
234c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self._target_command = '-p internal:bus=spi'
235c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
236c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def _enable_ec_access(self):
237c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if not self.os_if.target_hosted():
238c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
239c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self._target_command = '-p internal:bus=lpc'
240c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
241c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_temp_filename(self, prefix):
242be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """ (internal) Returns name of a temporary file in self.tmp_root """
243c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        (fd, name) = tempfile.mkstemp(prefix=prefix)
244c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        os.close(fd)
245c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return name
246c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
247c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def remove_temp_file(self, filename):
248c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """ (internal) Removes a temp file if self.keep_temp_files is false. """
249c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.keep_temp_files:
250c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            return
251c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if os.path.exists(filename):
252c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            os.remove(filename)
253c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
254c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def create_layout_file(self, layout_map):
255be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
256c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        (internal) Creates a layout file based on layout_map.
257c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns the file name containing layout information.
258be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
259c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_text = ['0x%08lX:0x%08lX %s' % (v[0], v[1], k)
260c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            for k, v in layout_map.items()]
261c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_text.sort()  # XXX unstable if range exceeds 2^32
262c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        tmpfn = self.get_temp_filename('lay')
263c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        open(tmpfn, 'wb').write('\n'.join(layout_text) + '\n')
264c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return tmpfn
265c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
266c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_section(self, base_image, section_name):
267be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
268c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Retrieves a section of data based on section_name in layout_map.
269c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Raises error if unknown section or invalid layout_map.
270be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
2718086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        if section_name not in self.firmware_layout:
2728086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam            return []
273c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        pos = self.firmware_layout[section_name]
274c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if pos[0] >= pos[1] or pos[1] >= len(base_image):
275c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise TestError('INTERNAL ERROR: invalid layout map: %s.' %
276c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                            section_name)
277eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        blob = base_image[pos[0] : pos[1] + 1]
278eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        # Trim down the main firmware body to its actual size since the
279eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        # signing utility uses the size of the input file as the size of
280eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        # the data to sign. Make it the same way as firmware creation.
2818086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam        if section_name in ('FVMAIN', 'FVMAINB', 'ECMAINA', 'ECMAINB'):
282eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            align = 4
283eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            pad = blob[-1]
284eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            blob = blob.rstrip(pad)
285eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            blob = blob + ((align - 1) - (len(blob) - 1) % align) * pad
286eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam        return blob
287c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
288c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def put_section(self, base_image, section_name, data):
289be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
290c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Updates a section of data based on section_name in firmware_layout.
291c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Raises error if unknown section.
292c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns the full updated image data.
293be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
294c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        pos = self.firmware_layout[section_name]
295c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if pos[0] >= pos[1] or pos[1] >= len(base_image):
296c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            raise TestError('INTERNAL ERROR: invalid layout map.')
297c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if len(data) != pos[1] - pos[0] + 1:
298eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            # Pad the main firmware body since we trimed it down before.
2998086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam            if (len(data) < pos[1] - pos[0] + 1 and section_name in
3008086f96b61050d813db785f8a416d884bd0b2225Tom Wai-Hong Tam                    ('FVMAIN', 'FVMAINB', 'ECMAINA', 'ECMAINB')):
301eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam                pad = base_image[pos[1]]
302eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam                data = data + pad * (pos[1] - pos[0] + 1 - len(data))
303eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam            else:
304eac7acffc449b41455a2ae57ed5df9a6fa83f352Tom Wai-Hong Tam                raise TestError('INTERNAL ERROR: unmatched data size.')
305c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return base_image[0 : pos[0]] + data + base_image[pos[1] + 1 :]
306c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
307c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def get_size(self):
308c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """ Gets size of current flash ROM """
309c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # TODO(hungte) Newer version of tool (flashrom) may support --get-size
310c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # command which is faster in future. Right now we use back-compatible
311c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # method: read whole and then get length.
312c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        image = self.read_whole()
313c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return len(image)
314c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
315c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def set_firmware_layout(self, file_name):
316c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        """get layout read from the BIOS """
317c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
318c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        scraper = LayoutScraper(self.os_if)
319c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.firmware_layout = scraper.get_layout(file_name)
320c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
32144204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam    def enable_write_protect(self):
32244204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        """Enable the write pretection of the flash chip."""
32344204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        cmd = 'flashrom %s --wp-enable' % self._target_command
32444204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
32544204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam
32644204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam    def disable_write_protect(self):
32744204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        """Disable the write pretection of the flash chip."""
32844204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        cmd = 'flashrom %s --wp-disable' % self._target_command
32944204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
33044204b3e74e1ee85a19e330894e731ef554c0a6dTom Wai-Hong Tam
331c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def read_whole(self):
332be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
333c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Reads whole flash ROM data.
334c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Returns the data read from flash ROM, or empty string for other error.
335be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
336c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        tmpfn = self.get_temp_filename('rd_')
337c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        cmd = 'flashrom %s -r "%s"' % (self._target_command, tmpfn)
338c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.verbose:
339c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            print 'flashrom_util.read_whole(): ', cmd
340c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
341c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
342c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        result = open(tmpfn, 'rb').read()
343c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.set_firmware_layout(tmpfn)
344c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
345c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # clean temporary resources
346c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.remove_temp_file(tmpfn)
347c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        return result
348c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
349c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def write_partial(self, base_image, write_list, write_layout_map=None):
350be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
351c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        Writes data in sections of write_list to flash ROM.
352c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        An exception is raised if write operation fails.
353be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """
354c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
355c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if write_layout_map:
356c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            layout_map = write_layout_map
357c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        else:
358c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            layout_map = self.firmware_layout
359c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
360c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        tmpfn = self.get_temp_filename('wr_')
361c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        open(tmpfn, 'wb').write(base_image)
362c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_fn = self.create_layout_file(layout_map)
363c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
364c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        cmd = 'flashrom %s -l "%s" -i %s -w "%s"' % (
365c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam                self._target_command, layout_fn, ' -i '.join(write_list), tmpfn)
366c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        if self.verbose:
367c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam            print 'flashrom.write_partial(): ', cmd
368c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
369c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.os_if.run_shell_command(cmd)
370c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
371c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        # clean temporary resources
372c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.remove_temp_file(tmpfn)
373c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.remove_temp_file(layout_fn)
374c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam
375c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam    def write_whole(self, base_image):
376be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam        """Write the whole base image. """
377c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        layout_map = { 'all': (0, len(base_image) - 1) }
378c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam        self.write_partial(base_image, ('all',), layout_map)
379