xref: /aosp_15_r20/external/autotest/client/cros/faft/rpc_functions.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
3*9c5db199SXin Li# found in the LICENSE file.
4*9c5db199SXin Li"""Code to provide functions for FAFT tests.
5*9c5db199SXin Li
6*9c5db199SXin LiThese will be exposed via an xmlrpc server running on the DUT.
7*9c5db199SXin Li
8*9c5db199SXin Li@note: When adding categories, please also update server/cros/faft/rpc_proxy.pyi
9*9c5db199SXin Li"""
10*9c5db199SXin Li
11*9c5db199SXin Lifrom __future__ import print_function
12*9c5db199SXin Li
13*9c5db199SXin Liimport binascii
14*9c5db199SXin Lifrom six.moves import http_client as httplib
15*9c5db199SXin Liimport logging
16*9c5db199SXin Liimport os
17*9c5db199SXin Liimport signal
18*9c5db199SXin Liimport tempfile
19*9c5db199SXin Lifrom six.moves import xmlrpc_client as xmlrpclib
20*9c5db199SXin Li
21*9c5db199SXin Lifrom autotest_lib.client.common_lib import lsbrelease_utils
22*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import cros_config
23*9c5db199SXin Lifrom autotest_lib.client.cros import xmlrpc_server
24*9c5db199SXin Lifrom autotest_lib.client.cros.faft.utils import (
25*9c5db199SXin Li        cgpt_handler,
26*9c5db199SXin Li        os_interface,
27*9c5db199SXin Li        firmware_check_keys,
28*9c5db199SXin Li        firmware_updater,
29*9c5db199SXin Li        flashrom_handler,
30*9c5db199SXin Li        kernel_handler,
31*9c5db199SXin Li        rootfs_handler,
32*9c5db199SXin Li        tpm_handler,
33*9c5db199SXin Li)
34*9c5db199SXin Li
35*9c5db199SXin Li
36*9c5db199SXin Liclass FaftXmlRpcDelegate(xmlrpc_server.XmlRpcDelegate):
37*9c5db199SXin Li    """
38*9c5db199SXin Li    A class which routes RPC methods to the proper servicers.
39*9c5db199SXin Li
40*9c5db199SXin Li    Firmware tests are able to call an RPC method via:
41*9c5db199SXin Li        <FAFTClient>.[category].[method_name](params)
42*9c5db199SXin Li    When XML-RPC is being used, the RPC server routes the called method to:
43*9c5db199SXin Li        <XmlRpcDelegate>._dispatch('[category].[method_name]', params)
44*9c5db199SXin Li    The method is then dispatched to a Servicer class.
45*9c5db199SXin Li    """
46*9c5db199SXin Li
47*9c5db199SXin Li    def __init__(self, os_if):
48*9c5db199SXin Li        """Initialize the servicer for each category.
49*9c5db199SXin Li
50*9c5db199SXin Li        @type os_if: os_interface.OSInterface
51*9c5db199SXin Li        """
52*9c5db199SXin Li        self._ready = False
53*9c5db199SXin Li        self.bios = BiosServicer(os_if)
54*9c5db199SXin Li        self.cgpt = CgptServicer(os_if)
55*9c5db199SXin Li        self.ec = EcServicer(os_if)
56*9c5db199SXin Li        self.kernel = KernelServicer(os_if)
57*9c5db199SXin Li        self.minios_kernel = KernelServicer(os_if, is_minios=True)
58*9c5db199SXin Li        self.rootfs = RootfsServicer(os_if)
59*9c5db199SXin Li        self.rpc_settings = RpcSettingsServicer(os_if)
60*9c5db199SXin Li        self.system = SystemServicer(os_if)
61*9c5db199SXin Li        self.tpm = TpmServicer(os_if)
62*9c5db199SXin Li        self.updater = UpdaterServicer(os_if)
63*9c5db199SXin Li
64*9c5db199SXin Li        self._rpc_servicers = {
65*9c5db199SXin Li                'bios': self.bios,
66*9c5db199SXin Li                'cgpt': self.cgpt,
67*9c5db199SXin Li                'ec': self.ec,
68*9c5db199SXin Li                'kernel': self.kernel,
69*9c5db199SXin Li                'minios': self.minios_kernel,
70*9c5db199SXin Li                'rpc_settings': self.rpc_settings,
71*9c5db199SXin Li                'rootfs': self.rootfs,
72*9c5db199SXin Li                'system': self.system,
73*9c5db199SXin Li                'tpm': self.tpm,
74*9c5db199SXin Li                'updater': self.updater
75*9c5db199SXin Li        }
76*9c5db199SXin Li
77*9c5db199SXin Li        self._os_if = os_if
78*9c5db199SXin Li
79*9c5db199SXin Li    def __enter__(self):
80*9c5db199SXin Li        """Enter the the delegate context (when XmlRpcServer.run() starts).
81*9c5db199SXin Li
82*9c5db199SXin Li        The server is marked ready here, rather than immediately when created.
83*9c5db199SXin Li        """
84*9c5db199SXin Li        logging.debug("%s: Serving FAFT functions", self.__class__.__name__)
85*9c5db199SXin Li        self._ready = True
86*9c5db199SXin Li
87*9c5db199SXin Li    def __exit__(self, exception, value, traceback):
88*9c5db199SXin Li        """Exit the delegate context (when XmlRpcServer.run() finishes).
89*9c5db199SXin Li
90*9c5db199SXin Li        The server is marked not ready, to prevent the client from using
91*9c5db199SXin Li        the wrong server when quitting one instance and starting another.
92*9c5db199SXin Li        """
93*9c5db199SXin Li        self._ready = False
94*9c5db199SXin Li        logging.debug("%s: Done.", self.__class__.__name__)
95*9c5db199SXin Li
96*9c5db199SXin Li    def quit(self):
97*9c5db199SXin Li        """Exit the xmlrpc server."""
98*9c5db199SXin Li        self._ready = False
99*9c5db199SXin Li        os.kill(os.getpid(), signal.SIGINT)
100*9c5db199SXin Li
101*9c5db199SXin Li    def ready(self):
102*9c5db199SXin Li        """Is the RPC server ready to serve calls in a useful manner?
103*9c5db199SXin Li
104*9c5db199SXin Li        The server is only marked ready during the XmlRpcServer.run() loop.
105*9c5db199SXin Li        This method suppresses the extra logging of ready() from the superclass.
106*9c5db199SXin Li        """
107*9c5db199SXin Li        return self._ready
108*9c5db199SXin Li
109*9c5db199SXin Li    def _report_error(self, fault_code, message):
110*9c5db199SXin Li        """Raise the given RPC error text.
111*9c5db199SXin Li
112*9c5db199SXin Li        @param fault_code: the status code to use
113*9c5db199SXin Li        @param message: the string message to include before exception text
114*9c5db199SXin Li        @return the exception to raise
115*9c5db199SXin Li
116*9c5db199SXin Li        @type fault_code: int
117*9c5db199SXin Li        @type message: str
118*9c5db199SXin Li        @rtype: Exception
119*9c5db199SXin Li        """
120*9c5db199SXin Li        logging.error(message)
121*9c5db199SXin Li        return xmlrpclib.Fault(fault_code, message)
122*9c5db199SXin Li
123*9c5db199SXin Li    def _dispatch(self, called_method, params):
124*9c5db199SXin Li        """
125*9c5db199SXin Li        Send any RPC call to the appropriate servicer method.
126*9c5db199SXin Li
127*9c5db199SXin Li        @param called_method: The method of FAFTClient that was called.
128*9c5db199SXin Li                              Should take the form 'category.method'.
129*9c5db199SXin Li        @param params: The arguments passed into the method.
130*9c5db199SXin Li
131*9c5db199SXin Li        @type called_method: str
132*9c5db199SXin Li        @type params: tuple
133*9c5db199SXin Li
134*9c5db199SXin Li        @raise: xmlrpclib.Fault (using http error codes for fault codes)
135*9c5db199SXin Li        """
136*9c5db199SXin Li        logging.info('Called: %s%s', called_method, params)
137*9c5db199SXin Li
138*9c5db199SXin Li        name_pieces = called_method.split('.')
139*9c5db199SXin Li
140*9c5db199SXin Li        if not name_pieces:
141*9c5db199SXin Li            raise self._report_error(
142*9c5db199SXin Li                    httplib.BAD_REQUEST,
143*9c5db199SXin Li                    'RPC request is invalid (completely empty): "%s"' %
144*9c5db199SXin Li                    called_method)
145*9c5db199SXin Li
146*9c5db199SXin Li        method_name = name_pieces.pop()
147*9c5db199SXin Li        category = '.'.join(name_pieces)
148*9c5db199SXin Li
149*9c5db199SXin Li        if (method_name.startswith('_')
150*9c5db199SXin Li                and method_name not in ('__str__', '__repr__', '__call__')):
151*9c5db199SXin Li            # *._private() or *.__special__()
152*9c5db199SXin Li            # Forbid early, to prevent seeing which methods exist.
153*9c5db199SXin Li            raise self._report_error(
154*9c5db199SXin Li                    httplib.FORBIDDEN,
155*9c5db199SXin Li                    'RPC method name is private: %s%s[%s]' %
156*9c5db199SXin Li                    (category, '.' if category else '', method_name))
157*9c5db199SXin Li
158*9c5db199SXin Li        elif not method_name:
159*9c5db199SXin Li            # anything.()
160*9c5db199SXin Li            raise self._report_error(
161*9c5db199SXin Li                    httplib.BAD_REQUEST,
162*9c5db199SXin Li                    'RPC method name is empty: %s%s[%s]' %
163*9c5db199SXin Li                    (category, '.' if category else '', method_name))
164*9c5db199SXin Li
165*9c5db199SXin Li        if category in self._rpc_servicers:
166*9c5db199SXin Li            # system.func()
167*9c5db199SXin Li            holder = self._rpc_servicers[category]
168*9c5db199SXin Li            if not hasattr(holder, method_name):
169*9c5db199SXin Li                raise self._report_error(
170*9c5db199SXin Li                        httplib.NOT_FOUND,
171*9c5db199SXin Li                        'RPC method not found: %s.[%s]' %
172*9c5db199SXin Li                        (category, method_name))
173*9c5db199SXin Li
174*9c5db199SXin Li        elif category:
175*9c5db199SXin Li            # invalid.func()
176*9c5db199SXin Li            raise self._report_error(
177*9c5db199SXin Li                    httplib.NOT_FOUND,
178*9c5db199SXin Li                    'RPC category not found: [%s].%s' %
179*9c5db199SXin Li                    (category, method_name))
180*9c5db199SXin Li
181*9c5db199SXin Li        else:
182*9c5db199SXin Li            # .func() or .invalid()
183*9c5db199SXin Li            holder = self
184*9c5db199SXin Li            if not hasattr(holder, method_name):
185*9c5db199SXin Li                raise self._report_error(
186*9c5db199SXin Li                        httplib.NOT_FOUND,
187*9c5db199SXin Li                        'RPC method not found: [%s]' % method_name)
188*9c5db199SXin Li
189*9c5db199SXin Li        try:
190*9c5db199SXin Li            method = getattr(holder, method_name)
191*9c5db199SXin Li
192*9c5db199SXin Li        except AttributeError as e:
193*9c5db199SXin Li            logging.exception(e)
194*9c5db199SXin Li            raise
195*9c5db199SXin Li        try:
196*9c5db199SXin Li            return method(*params)
197*9c5db199SXin Li
198*9c5db199SXin Li        except Exception as e:
199*9c5db199SXin Li            logging.exception(e)
200*9c5db199SXin Li            raise
201*9c5db199SXin Li
202*9c5db199SXin Li
203*9c5db199SXin Liclass BiosServicer(object):
204*9c5db199SXin Li    """Class to service all BIOS RPCs"""
205*9c5db199SXin Li
206*9c5db199SXin Li    def __init__(self, os_if):
207*9c5db199SXin Li        """
208*9c5db199SXin Li        @type os_if: os_interface.OSInterface
209*9c5db199SXin Li        """
210*9c5db199SXin Li        self._os_if = os_if
211*9c5db199SXin Li
212*9c5db199SXin Li        # This attribute is accessed via a property, so it can load lazily
213*9c5db199SXin Li        # when actually used by the test.
214*9c5db199SXin Li        self._real_bios_handler = flashrom_handler.FlashromHandler(
215*9c5db199SXin Li                self._os_if, None, '/usr/share/vboot/devkeys', 'bios')
216*9c5db199SXin Li
217*9c5db199SXin Li    @property
218*9c5db199SXin Li    def _bios_handler(self):
219*9c5db199SXin Li        """Return the BIOS flashrom handler, after initializing it if necessary
220*9c5db199SXin Li
221*9c5db199SXin Li        @rtype: flashrom_handler.FlashromHandler
222*9c5db199SXin Li        """
223*9c5db199SXin Li        if not self._real_bios_handler.initialized:
224*9c5db199SXin Li            self._real_bios_handler.init()
225*9c5db199SXin Li        return self._real_bios_handler
226*9c5db199SXin Li
227*9c5db199SXin Li    def reload(self):
228*9c5db199SXin Li        """Reload the firmware image that may be changed."""
229*9c5db199SXin Li        self._bios_handler.new_image()
230*9c5db199SXin Li
231*9c5db199SXin Li    def get_gbb_flags(self):
232*9c5db199SXin Li        """Get the GBB flags.
233*9c5db199SXin Li
234*9c5db199SXin Li        @return: An integer of the GBB flags.
235*9c5db199SXin Li        """
236*9c5db199SXin Li        return self._bios_handler.get_gbb_flags()
237*9c5db199SXin Li
238*9c5db199SXin Li    def set_gbb_flags(self, flags):
239*9c5db199SXin Li        """Set the GBB flags.
240*9c5db199SXin Li
241*9c5db199SXin Li        @param flags: An integer of the GBB flags.
242*9c5db199SXin Li        """
243*9c5db199SXin Li        self._bios_handler.set_gbb_flags(flags, write_through=True)
244*9c5db199SXin Li
245*9c5db199SXin Li    def get_preamble_flags(self, section):
246*9c5db199SXin Li        """Get the preamble flags of a firmware section.
247*9c5db199SXin Li
248*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
249*9c5db199SXin Li        @return: An integer of the preamble flags.
250*9c5db199SXin Li        """
251*9c5db199SXin Li        return self._bios_handler.get_section_flags(section)
252*9c5db199SXin Li
253*9c5db199SXin Li    def set_preamble_flags(self, section, flags):
254*9c5db199SXin Li        """Set the preamble flags of a firmware section.
255*9c5db199SXin Li
256*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
257*9c5db199SXin Li        @param flags: An integer of preamble flags.
258*9c5db199SXin Li        """
259*9c5db199SXin Li        version = self.get_version(section)
260*9c5db199SXin Li        self._bios_handler.set_section_version(
261*9c5db199SXin Li                section, version, flags, write_through=True)
262*9c5db199SXin Li
263*9c5db199SXin Li    def get_body_sha(self, section):
264*9c5db199SXin Li        """Get SHA1 hash of BIOS RW firmware section.
265*9c5db199SXin Li
266*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
267*9c5db199SXin Li        @return: A string of the body SHA1 hash.
268*9c5db199SXin Li        """
269*9c5db199SXin Li        return self._bios_handler.get_section_sha(section)
270*9c5db199SXin Li
271*9c5db199SXin Li    def get_sig_sha(self, section):
272*9c5db199SXin Li        """Get SHA1 hash of firmware vblock in section.
273*9c5db199SXin Li
274*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
275*9c5db199SXin Li        @return: A string of the sig SHA1 hash.
276*9c5db199SXin Li        """
277*9c5db199SXin Li        return self._bios_handler.get_section_sig_sha(section)
278*9c5db199SXin Li
279*9c5db199SXin Li    def get_section_fwid(self, section=None):
280*9c5db199SXin Li        """Retrieve the RO or RW fwid.
281*9c5db199SXin Li
282*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
283*9c5db199SXin Li        @return: A string of the fwid
284*9c5db199SXin Li        """
285*9c5db199SXin Li        return self._bios_handler.get_section_fwid(section)
286*9c5db199SXin Li
287*9c5db199SXin Li    def get_sig_one_byte(self, section):
288*9c5db199SXin Li        """Get a specific byte of firmware signature of the section.
289*9c5db199SXin Li
290*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
291*9c5db199SXin Li        @return: Tuple of (offset, byte).
292*9c5db199SXin Li        """
293*9c5db199SXin Li        return self._bios_handler.get_firmware_sig_one_byte(section)
294*9c5db199SXin Li
295*9c5db199SXin Li    def modify_sig(self, section, offset, value):
296*9c5db199SXin Li        """Modify a byte of firmware signature of the section.
297*9c5db199SXin Li
298*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
299*9c5db199SXin Li        @offset: Offset of section to be modified.
300*9c5db199SXin Li        @value: The byte value.
301*9c5db199SXin Li        """
302*9c5db199SXin Li        return self._bios_handler.modify_firmware_sig(section, offset, value)
303*9c5db199SXin Li
304*9c5db199SXin Li    def get_body_one_byte(self, section):
305*9c5db199SXin Li        """Get a specific byte of firmware body of the section.
306*9c5db199SXin Li
307*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
308*9c5db199SXin Li        @return: Tuple of (offset, byte).
309*9c5db199SXin Li        """
310*9c5db199SXin Li        return self._bios_handler.get_firmware_body_one_byte(section)
311*9c5db199SXin Li
312*9c5db199SXin Li    def modify_body(self, section, offset, value):
313*9c5db199SXin Li        """Modify a byte of firmware body of the section.
314*9c5db199SXin Li
315*9c5db199SXin Li        @param section: A firmware section, either 'a' or 'b'.
316*9c5db199SXin Li        @offset: Offset of section to be modified.
317*9c5db199SXin Li        @value: The byte value.
318*9c5db199SXin Li        """
319*9c5db199SXin Li        return self._bios_handler.modify_firmware_body(section, offset, value)
320*9c5db199SXin Li
321*9c5db199SXin Li    def corrupt_mrc_cache(self):
322*9c5db199SXin Li        """Corrupt MRC cache.
323*9c5db199SXin Li
324*9c5db199SXin Li        NOTE: This method is not idempotent. A second call will still change the
325*9c5db199SXin Li        flashrom content of the client.
326*9c5db199SXin Li        """
327*9c5db199SXin Li        self._bios_handler.corrupt_mrc_cache()
328*9c5db199SXin Li
329*9c5db199SXin Li    def get_version(self, section):
330*9c5db199SXin Li        """Retrieve firmware version of a section."""
331*9c5db199SXin Li        return self._bios_handler.get_section_version(section)
332*9c5db199SXin Li
333*9c5db199SXin Li    def set_version(self, section, version):
334*9c5db199SXin Li        """Set firmware version of a section."""
335*9c5db199SXin Li        flags = self._bios_handler.get_section_flags(section)
336*9c5db199SXin Li        logging.info('Setting firmware section %s version to %d', section,
337*9c5db199SXin Li                     version)
338*9c5db199SXin Li        self._bios_handler.set_section_version(section,
339*9c5db199SXin Li                                               version,
340*9c5db199SXin Li                                               flags,
341*9c5db199SXin Li                                               write_through=True)
342*9c5db199SXin Li
343*9c5db199SXin Li    def get_datakey_version(self, section):
344*9c5db199SXin Li        """Return firmware data key version."""
345*9c5db199SXin Li        return self._bios_handler.get_section_datakey_version(section)
346*9c5db199SXin Li
347*9c5db199SXin Li    def get_kernel_subkey_version(self, section):
348*9c5db199SXin Li        """Return kernel subkey version."""
349*9c5db199SXin Li        return self._bios_handler.get_section_kernel_subkey_version(section)
350*9c5db199SXin Li
351*9c5db199SXin Li    def dump_whole(self, bios_path):
352*9c5db199SXin Li        """Dump the current BIOS firmware to a file, specified by bios_path.
353*9c5db199SXin Li
354*9c5db199SXin Li        @param bios_path: The path of the BIOS image to be written.
355*9c5db199SXin Li        """
356*9c5db199SXin Li        self._bios_handler.dump_whole(bios_path)
357*9c5db199SXin Li
358*9c5db199SXin Li    def write_whole(self, bios_path):
359*9c5db199SXin Li        """Write the firmware from bios_path to the current system.
360*9c5db199SXin Li
361*9c5db199SXin Li        @param bios_path: The path of the source BIOS image
362*9c5db199SXin Li        """
363*9c5db199SXin Li        self._bios_handler.new_image(bios_path)
364*9c5db199SXin Li        self._bios_handler.write_whole()
365*9c5db199SXin Li
366*9c5db199SXin Li    def strip_modified_fwids(self):
367*9c5db199SXin Li        """Strip trailing suffixes out of the FWIDs (see modify_image_fwids).
368*9c5db199SXin Li
369*9c5db199SXin Li        @return: a dict of any fwids that were adjusted, by section (ro, a, b)
370*9c5db199SXin Li        @rtype: dict
371*9c5db199SXin Li        """
372*9c5db199SXin Li        return self._bios_handler.strip_modified_fwids()
373*9c5db199SXin Li
374*9c5db199SXin Li    def set_write_protect_region(self, region, enabled=None):
375*9c5db199SXin Li        """Modify software write protect region and flag in one operation.
376*9c5db199SXin Li
377*9c5db199SXin Li        @param region: Region to set (usually WP_RO)
378*9c5db199SXin Li        @param enabled: If True, run --wp-enable; if False, run --wp-disable.
379*9c5db199SXin Li                        If None (default), don't specify either one.
380*9c5db199SXin Li        """
381*9c5db199SXin Li        self._bios_handler.set_write_protect_region(region, enabled)
382*9c5db199SXin Li
383*9c5db199SXin Li    def set_write_protect_range(self, start, length, enabled=None):
384*9c5db199SXin Li        """Modify software write protect range and flag in one operation.
385*9c5db199SXin Li
386*9c5db199SXin Li        @param start: offset (bytes) from start of flash to start of range
387*9c5db199SXin Li        @param length: offset (bytes) from start of range to end of range
388*9c5db199SXin Li        @param enabled: If True, run --wp-enable; if False, run --wp-disable.
389*9c5db199SXin Li                        If None (default), don't specify either one.
390*9c5db199SXin Li        """
391*9c5db199SXin Li        self._bios_handler.set_write_protect_range(start, length, enabled)
392*9c5db199SXin Li
393*9c5db199SXin Li    def get_write_protect_status(self):
394*9c5db199SXin Li        """Get a dict describing the status of the write protection
395*9c5db199SXin Li
396*9c5db199SXin Li        @return: {'enabled': True/False, 'start': '0x0', 'length': '0x0', ...}
397*9c5db199SXin Li        @rtype: dict
398*9c5db199SXin Li        """
399*9c5db199SXin Li        return self._bios_handler.get_write_protect_status()
400*9c5db199SXin Li
401*9c5db199SXin Li    def is_available(self):
402*9c5db199SXin Li        """Return True if available, False if not."""
403*9c5db199SXin Li        # Use the real handler, to avoid .init() raising an exception
404*9c5db199SXin Li        return self._real_bios_handler.is_available()
405*9c5db199SXin Li
406*9c5db199SXin Li    def get_write_cmd(self, image=None):
407*9c5db199SXin Li        """Get the command needed to write the whole image to the device.
408*9c5db199SXin Li
409*9c5db199SXin Li        @param image: the filename (empty to use current handler data)
410*9c5db199SXin Li        """
411*9c5db199SXin Li        if image:
412*9c5db199SXin Li            # Don't bother loading the usual image, since it's overridden.
413*9c5db199SXin Li            return self._real_bios_handler.get_write_cmd(image)
414*9c5db199SXin Li        else:
415*9c5db199SXin Li            return self._bios_handler.get_write_cmd()
416*9c5db199SXin Li
417*9c5db199SXin Liclass CgptServicer(object):
418*9c5db199SXin Li    """Class to service all CGPT RPCs"""
419*9c5db199SXin Li
420*9c5db199SXin Li    def __init__(self, os_if):
421*9c5db199SXin Li        """
422*9c5db199SXin Li        @type os_if: os_interface.OSInterface
423*9c5db199SXin Li        """
424*9c5db199SXin Li        self._os_if = os_if
425*9c5db199SXin Li        self._cgpt_handler = cgpt_handler.CgptHandler(self._os_if)
426*9c5db199SXin Li
427*9c5db199SXin Li    def get_attributes(self):
428*9c5db199SXin Li        """Get kernel attributes."""
429*9c5db199SXin Li        rootdev = self._os_if.get_root_dev()
430*9c5db199SXin Li        self._cgpt_handler.read_device_info(rootdev)
431*9c5db199SXin Li        return {
432*9c5db199SXin Li                'A': self._cgpt_handler.get_partition(rootdev, 'KERN-A'),
433*9c5db199SXin Li                'B': self._cgpt_handler.get_partition(rootdev, 'KERN-B')
434*9c5db199SXin Li        }
435*9c5db199SXin Li
436*9c5db199SXin Li    def set_attributes(self, a=None, b=None):
437*9c5db199SXin Li        """Set kernel attributes for either partition (or both)."""
438*9c5db199SXin Li        partitions = {'A': a, 'B': b}
439*9c5db199SXin Li        rootdev = self._os_if.get_root_dev()
440*9c5db199SXin Li        modifiable_attributes = list(self._cgpt_handler.ATTR_TO_COMMAND.keys())
441*9c5db199SXin Li        for partition_name in partitions.keys():
442*9c5db199SXin Li            partition = partitions[partition_name]
443*9c5db199SXin Li            if partition is None:
444*9c5db199SXin Li                continue
445*9c5db199SXin Li            attributes_to_set = {
446*9c5db199SXin Li                    key: partition[key]
447*9c5db199SXin Li                    for key in modifiable_attributes
448*9c5db199SXin Li            }
449*9c5db199SXin Li            if attributes_to_set:
450*9c5db199SXin Li                self._cgpt_handler.set_partition(
451*9c5db199SXin Li                        rootdev, 'KERN-%s' % partition_name, attributes_to_set)
452*9c5db199SXin Li
453*9c5db199SXin Li
454*9c5db199SXin Liclass EcServicer(object):
455*9c5db199SXin Li    """Class to service all EC RPCs"""
456*9c5db199SXin Li
457*9c5db199SXin Li    def __init__(self, os_if):
458*9c5db199SXin Li        """
459*9c5db199SXin Li        @type os_if: os_interface.OSInterface
460*9c5db199SXin Li        """
461*9c5db199SXin Li        self._os_if = os_if
462*9c5db199SXin Li
463*9c5db199SXin Li        # This attribute is accessed via a property, so it can load lazily
464*9c5db199SXin Li        # when actually used by the test.
465*9c5db199SXin Li        self._real_ec_handler = None
466*9c5db199SXin Li        ec_status = self._os_if.run_shell_command_get_status('mosys ec info')
467*9c5db199SXin Li        if ec_status == 0:
468*9c5db199SXin Li            self._real_ec_handler = flashrom_handler.FlashromHandler(
469*9c5db199SXin Li                    self._os_if, 'ec_root_key.vpubk',
470*9c5db199SXin Li                    '/usr/share/vboot/devkeys', 'ec')
471*9c5db199SXin Li
472*9c5db199SXin Li        else:
473*9c5db199SXin Li            logging.info('No EC is reported by mosys (rc=%s).', ec_status)
474*9c5db199SXin Li
475*9c5db199SXin Li    @property
476*9c5db199SXin Li    def _ec_handler(self):
477*9c5db199SXin Li        """Return the EC flashrom handler, after initializing it if necessary
478*9c5db199SXin Li
479*9c5db199SXin Li        @rtype: flashrom_handler.FlashromHandler
480*9c5db199SXin Li        """
481*9c5db199SXin Li        if not self._real_ec_handler:
482*9c5db199SXin Li            # No EC handler if board has no EC
483*9c5db199SXin Li            return None
484*9c5db199SXin Li
485*9c5db199SXin Li        if not self._real_ec_handler.initialized:
486*9c5db199SXin Li            self._real_ec_handler.init()
487*9c5db199SXin Li        return self._real_ec_handler
488*9c5db199SXin Li
489*9c5db199SXin Li    def reload(self):
490*9c5db199SXin Li        """Reload the firmware image that may be changed."""
491*9c5db199SXin Li        self._ec_handler.new_image()
492*9c5db199SXin Li
493*9c5db199SXin Li    def get_version(self, target=None):
494*9c5db199SXin Li        """Get the requested EC version.
495*9c5db199SXin Li
496*9c5db199SXin Li        @param target: 'ro'/'rw', or None to signify the active fw.
497*9c5db199SXin Li                       On a Wilco EC, this would be ignored, since Wilco
498*9c5db199SXin Li                       doesn't use ro/rw/active versions.
499*9c5db199SXin Li        @return: A string of the requested EC version, or '' if DUT has no EC.
500*9c5db199SXin Li        """
501*9c5db199SXin Li        CROS_EC_FILE = '/dev/cros_ec'
502*9c5db199SXin Li        WILCO_VERSION_FILE = '/sys/bus/platform/devices/GOOG000C:00/version'
503*9c5db199SXin Li
504*9c5db199SXin Li        # If DUT has a Chrome EC, parse `ectool version` for the target.
505*9c5db199SXin Li        if self._os_if.path_exists(CROS_EC_FILE):
506*9c5db199SXin Li            out = self._os_if.run_shell_command_get_output('ectool version')
507*9c5db199SXin Li            keyvals = dict([line.split(':', 1) for line in out])
508*9c5db199SXin Li            ro = keyvals['RO version'].strip()
509*9c5db199SXin Li            rw = keyvals['RW version'].strip()
510*9c5db199SXin Li            active = keyvals['Firmware copy'].strip()
511*9c5db199SXin Li            if target == None:
512*9c5db199SXin Li                if active == 'RO':
513*9c5db199SXin Li                    return ro
514*9c5db199SXin Li                elif active == 'RW':
515*9c5db199SXin Li                    return rw
516*9c5db199SXin Li                raise ValueError(
517*9c5db199SXin Li                        'Unexpected active FW type: want RO/RW; got ' + active)
518*9c5db199SXin Li            elif target.lower() == 'ro':
519*9c5db199SXin Li                return ro
520*9c5db199SXin Li            elif target.lower() == 'rw':
521*9c5db199SXin Li                return rw
522*9c5db199SXin Li            raise ValueError(
523*9c5db199SXin Li                    'Invalid EC version target: want ro/rw/None; got ' +
524*9c5db199SXin Li                    target)
525*9c5db199SXin Li        # If DUT has a Wilco EC read sysfs for the EC version.
526*9c5db199SXin Li        # Wilco doesn't use RO/RW/active, so ignore target.
527*9c5db199SXin Li        elif self._os_if.path_exists(WILCO_VERSION_FILE):
528*9c5db199SXin Li            with open(WILCO_VERSION_FILE, "r") as f:
529*9c5db199SXin Li                return f.read().strip()
530*9c5db199SXin Li        # If DUT doesn't have an EC, return the empty string.
531*9c5db199SXin Li        else:
532*9c5db199SXin Li            return ''
533*9c5db199SXin Li
534*9c5db199SXin Li    def get_active_hash(self):
535*9c5db199SXin Li        """Get hash of active EC RW firmware."""
536*9c5db199SXin Li        return self._os_if.run_shell_command_get_output(
537*9c5db199SXin Li                'ectool echash | grep hash: | sed "s/hash:\s\+//"')[0]
538*9c5db199SXin Li
539*9c5db199SXin Li    def dump_whole(self, ec_path):
540*9c5db199SXin Li        """Dump the current EC firmware to a file, specified by ec_path.
541*9c5db199SXin Li
542*9c5db199SXin Li        @param ec_path: The path of the EC image to be written.
543*9c5db199SXin Li        """
544*9c5db199SXin Li        self._ec_handler.dump_whole(ec_path)
545*9c5db199SXin Li
546*9c5db199SXin Li    def write_whole(self, ec_path):
547*9c5db199SXin Li        """Write the firmware from ec_path to the current system.
548*9c5db199SXin Li
549*9c5db199SXin Li        @param ec_path: The path of the source EC image.
550*9c5db199SXin Li        """
551*9c5db199SXin Li        self._ec_handler.new_image(ec_path)
552*9c5db199SXin Li        self._ec_handler.write_whole()
553*9c5db199SXin Li
554*9c5db199SXin Li    def corrupt_body(self, section):
555*9c5db199SXin Li        """Corrupt the requested EC section body.
556*9c5db199SXin Li
557*9c5db199SXin Li        NOTE: This method is not idempotent. A second call will still change the
558*9c5db199SXin Li        flashrom content of the client.
559*9c5db199SXin Li
560*9c5db199SXin Li        @param section: An EC section, either 'a' or 'b'.
561*9c5db199SXin Li        """
562*9c5db199SXin Li        self._ec_handler.corrupt_firmware_body(section)
563*9c5db199SXin Li
564*9c5db199SXin Li    def dump_firmware(self, ec_path):
565*9c5db199SXin Li        """Dump the current EC firmware to a file, specified by ec_path.
566*9c5db199SXin Li
567*9c5db199SXin Li        @param ec_path: The path of the EC image to be written.
568*9c5db199SXin Li        """
569*9c5db199SXin Li        self._ec_handler.dump_whole(ec_path)
570*9c5db199SXin Li
571*9c5db199SXin Li    def set_write_protect(self, enable):
572*9c5db199SXin Li        """Enable write protect of the EC flash chip.
573*9c5db199SXin Li
574*9c5db199SXin Li        @param enable: True if activating EC write protect. Otherwise, False.
575*9c5db199SXin Li        """
576*9c5db199SXin Li        if enable:
577*9c5db199SXin Li            self._ec_handler.enable_write_protect()
578*9c5db199SXin Li        else:
579*9c5db199SXin Li            self._ec_handler.disable_write_protect()
580*9c5db199SXin Li
581*9c5db199SXin Li    def get_write_protect_status(self):
582*9c5db199SXin Li        """Get a dict describing the status of the write protection
583*9c5db199SXin Li
584*9c5db199SXin Li        @return: {'enabled': True/False, 'start': '0x0', 'length': '0x0', ...}
585*9c5db199SXin Li        @rtype: dict
586*9c5db199SXin Li        """
587*9c5db199SXin Li        logging.debug("Calling self._ec_handler.get_write_protect_status")
588*9c5db199SXin Li        rec = self._ec_handler.get_write_protect_status()
589*9c5db199SXin Li        logging.debug("Returning %s", rec)
590*9c5db199SXin Li        return rec
591*9c5db199SXin Li
592*9c5db199SXin Li    def is_efs(self):
593*9c5db199SXin Li        """Return True if the EC supports EFS."""
594*9c5db199SXin Li        return self._ec_handler.has_section_body('rw_b')
595*9c5db199SXin Li
596*9c5db199SXin Li    def copy_rw(self, from_section, to_section):
597*9c5db199SXin Li        """Copy EC RW from from_section to to_section."""
598*9c5db199SXin Li        self._ec_handler.copy_from_to(from_section, to_section)
599*9c5db199SXin Li
600*9c5db199SXin Li    def reboot_to_switch_slot(self):
601*9c5db199SXin Li        """Reboot EC to switch the active RW slot."""
602*9c5db199SXin Li        self._os_if.run_shell_command(
603*9c5db199SXin Li                'ectool reboot_ec cold switch-slot', modifies_device=True)
604*9c5db199SXin Li
605*9c5db199SXin Li    def strip_modified_fwids(self):
606*9c5db199SXin Li        """Strip trailing suffixes out of the FWIDs (see modify_image_fwids)."""
607*9c5db199SXin Li        return self._ec_handler.strip_modified_fwids()
608*9c5db199SXin Li
609*9c5db199SXin Li    def get_write_cmd(self, image=None):
610*9c5db199SXin Li        """Get the command needed to write the whole image to the device.
611*9c5db199SXin Li
612*9c5db199SXin Li        @param image: the filename (empty to use current handler data)
613*9c5db199SXin Li        """
614*9c5db199SXin Li        if image:
615*9c5db199SXin Li            # Don't bother loading the usual image, since it's overridden.
616*9c5db199SXin Li            return self._real_ec_handler.get_write_cmd(image)
617*9c5db199SXin Li        else:
618*9c5db199SXin Li            return self._ec_handler.get_write_cmd()
619*9c5db199SXin Li
620*9c5db199SXin Li
621*9c5db199SXin Liclass KernelServicer(object):
622*9c5db199SXin Li    """Class to service all Kernel RPCs"""
623*9c5db199SXin Li
624*9c5db199SXin Li    def __init__(self, os_if, is_minios=False):
625*9c5db199SXin Li        """
626*9c5db199SXin Li        @type os_if: os_interface.OSInterface
627*9c5db199SXin Li        @type is_minios: True if it is a MiniOS kernel; otherwise, False.
628*9c5db199SXin Li        """
629*9c5db199SXin Li        self._os_if = os_if
630*9c5db199SXin Li        self._real_kernel_handler = kernel_handler.KernelHandler(
631*9c5db199SXin Li                self._os_if, is_minios)
632*9c5db199SXin Li
633*9c5db199SXin Li    @property
634*9c5db199SXin Li    def _kernel_handler(self):
635*9c5db199SXin Li        """Return the kernel handler, after initializing it if necessary
636*9c5db199SXin Li
637*9c5db199SXin Li        @rtype: kernel_handler.KernelHandler
638*9c5db199SXin Li        """
639*9c5db199SXin Li        if not self._real_kernel_handler.initialized:
640*9c5db199SXin Li            self._real_kernel_handler.init(
641*9c5db199SXin Li                    dev_key_path='/usr/share/vboot/devkeys',
642*9c5db199SXin Li                    internal_disk=True)
643*9c5db199SXin Li        return self._real_kernel_handler
644*9c5db199SXin Li
645*9c5db199SXin Li    def corrupt_sig(self, section):
646*9c5db199SXin Li        """Corrupt the requested kernel section.
647*9c5db199SXin Li
648*9c5db199SXin Li        @param section: A kernel section, either 'a' or 'b'.
649*9c5db199SXin Li        """
650*9c5db199SXin Li        self._kernel_handler.corrupt_kernel(section)
651*9c5db199SXin Li
652*9c5db199SXin Li    def restore_sig(self, section):
653*9c5db199SXin Li        """Restore the requested kernel section (previously corrupted).
654*9c5db199SXin Li
655*9c5db199SXin Li        @param section: A kernel section, either 'a' or 'b'.
656*9c5db199SXin Li        """
657*9c5db199SXin Li        self._kernel_handler.restore_kernel(section)
658*9c5db199SXin Li
659*9c5db199SXin Li    def _modify_version(self, section, delta):
660*9c5db199SXin Li        """Modify kernel version for the requested section, by adding delta.
661*9c5db199SXin Li
662*9c5db199SXin Li        The passed in delta, a positive or a negative number, is added to the
663*9c5db199SXin Li        original kernel version.
664*9c5db199SXin Li        """
665*9c5db199SXin Li        original_version = self._kernel_handler.get_version(section)
666*9c5db199SXin Li        new_version = original_version + delta
667*9c5db199SXin Li        logging.info('Setting kernel section %s version from %d to %d',
668*9c5db199SXin Li                     section, original_version, new_version)
669*9c5db199SXin Li        self._kernel_handler.set_version(section, new_version)
670*9c5db199SXin Li
671*9c5db199SXin Li    def move_version_backward(self, section):
672*9c5db199SXin Li        """Decrement kernel version for the requested section."""
673*9c5db199SXin Li        self._modify_version(section, -1)
674*9c5db199SXin Li
675*9c5db199SXin Li    def move_version_forward(self, section):
676*9c5db199SXin Li        """Increase kernel version for the requested section."""
677*9c5db199SXin Li        self._modify_version(section, 1)
678*9c5db199SXin Li
679*9c5db199SXin Li    def get_version(self, section):
680*9c5db199SXin Li        """Return kernel version."""
681*9c5db199SXin Li        return self._kernel_handler.get_version(section)
682*9c5db199SXin Li
683*9c5db199SXin Li    def get_datakey_version(self, section):
684*9c5db199SXin Li        """Return kernel datakey version."""
685*9c5db199SXin Li        return self._kernel_handler.get_datakey_version(section)
686*9c5db199SXin Li
687*9c5db199SXin Li    def diff_a_b(self):
688*9c5db199SXin Li        """Compare kernel A with B.
689*9c5db199SXin Li
690*9c5db199SXin Li        @return: True: if kernel A is different with B.
691*9c5db199SXin Li                 False: if kernel A is the same as B.
692*9c5db199SXin Li        """
693*9c5db199SXin Li        rootdev = self._os_if.get_root_dev()
694*9c5db199SXin Li        kernel_a = self._os_if.join_part(rootdev, '2')
695*9c5db199SXin Li        kernel_b = self._os_if.join_part(rootdev, '4')
696*9c5db199SXin Li
697*9c5db199SXin Li        # The signature (some kind of hash) for the kernel body is stored in
698*9c5db199SXin Li        # the beginning. So compare the first 64KB (including header, preamble,
699*9c5db199SXin Li        # and signature) should be enough to check them identical.
700*9c5db199SXin Li        header_a = self._os_if.read_partition(kernel_a, 0x10000)
701*9c5db199SXin Li        header_b = self._os_if.read_partition(kernel_b, 0x10000)
702*9c5db199SXin Li
703*9c5db199SXin Li        return header_a != header_b
704*9c5db199SXin Li
705*9c5db199SXin Li    def resign_with_keys(self, section, key_path=None):
706*9c5db199SXin Li        """Resign kernel with temporary key."""
707*9c5db199SXin Li        self._kernel_handler.resign_kernel(section, key_path)
708*9c5db199SXin Li
709*9c5db199SXin Li    def dump(self, section, kernel_path):
710*9c5db199SXin Li        """Dump the specified kernel to a file.
711*9c5db199SXin Li
712*9c5db199SXin Li        @param section: The kernel to dump. May be A or B.
713*9c5db199SXin Li        @param kernel_path: The path to the kernel image to be written.
714*9c5db199SXin Li        """
715*9c5db199SXin Li        self._kernel_handler.dump_kernel(section, kernel_path)
716*9c5db199SXin Li
717*9c5db199SXin Li    def write(self, section, kernel_path):
718*9c5db199SXin Li        """Write a kernel image to the specified section.
719*9c5db199SXin Li
720*9c5db199SXin Li        @param section: The kernel to dump. May be A or B.
721*9c5db199SXin Li        @param kernel_path: The path to the kernel image.
722*9c5db199SXin Li        """
723*9c5db199SXin Li        self._kernel_handler.write_kernel(section, kernel_path)
724*9c5db199SXin Li
725*9c5db199SXin Li    def get_sha(self, section):
726*9c5db199SXin Li        """Return the SHA1 hash of the specified kernel section."""
727*9c5db199SXin Li        return self._kernel_handler.get_sha(section)
728*9c5db199SXin Li
729*9c5db199SXin Li
730*9c5db199SXin Liclass RootfsServicer(object):
731*9c5db199SXin Li    """Class to service all RootFS RPCs"""
732*9c5db199SXin Li
733*9c5db199SXin Li    def __init__(self, os_if):
734*9c5db199SXin Li        """
735*9c5db199SXin Li        @type os_if: os_interface.OSInterface
736*9c5db199SXin Li        """
737*9c5db199SXin Li        self._os_if = os_if
738*9c5db199SXin Li        self._real_rootfs_handler = rootfs_handler.RootfsHandler(self._os_if)
739*9c5db199SXin Li
740*9c5db199SXin Li    @property
741*9c5db199SXin Li    def _rootfs_handler(self):
742*9c5db199SXin Li        """Return the rootfs handler, after initializing it if necessary
743*9c5db199SXin Li
744*9c5db199SXin Li        @rtype: rootfs_handler.RootfsHandler
745*9c5db199SXin Li        """
746*9c5db199SXin Li        if not self._real_rootfs_handler.initialized:
747*9c5db199SXin Li            self._real_rootfs_handler.init()
748*9c5db199SXin Li        return self._real_rootfs_handler
749*9c5db199SXin Li
750*9c5db199SXin Li    def verify_rootfs(self, section):
751*9c5db199SXin Li        """Verifies the integrity of the root FS.
752*9c5db199SXin Li
753*9c5db199SXin Li        @param section: The rootfs to verify. May be A or B.
754*9c5db199SXin Li        """
755*9c5db199SXin Li        return self._rootfs_handler.verify_rootfs(section)
756*9c5db199SXin Li
757*9c5db199SXin Li
758*9c5db199SXin Liclass RpcSettingsServicer(object):
759*9c5db199SXin Li    """Class to service RPCs for settings of the RPC server itself"""
760*9c5db199SXin Li
761*9c5db199SXin Li    def __init__(self, os_if):
762*9c5db199SXin Li        """
763*9c5db199SXin Li        @type os_if: os_interface.OSInterface
764*9c5db199SXin Li        """
765*9c5db199SXin Li        self._os_if = os_if
766*9c5db199SXin Li
767*9c5db199SXin Li    def enable_test_mode(self):
768*9c5db199SXin Li        """Enable test mode (avoids writing to flash or gpt)"""
769*9c5db199SXin Li        self._os_if.test_mode = True
770*9c5db199SXin Li
771*9c5db199SXin Li    def disable_test_mode(self):
772*9c5db199SXin Li        """Disable test mode and return to normal operation"""
773*9c5db199SXin Li        self._os_if.test_mode = False
774*9c5db199SXin Li
775*9c5db199SXin Li
776*9c5db199SXin Liclass SystemServicer(object):
777*9c5db199SXin Li    """Class to service all System RPCs"""
778*9c5db199SXin Li
779*9c5db199SXin Li    def __init__(self, os_if):
780*9c5db199SXin Li        """
781*9c5db199SXin Li        @type os_if: os_interface.OSInterface
782*9c5db199SXin Li        """
783*9c5db199SXin Li        self._os_if = os_if
784*9c5db199SXin Li        self._key_checker = firmware_check_keys.firmwareCheckKeys()
785*9c5db199SXin Li
786*9c5db199SXin Li    def is_available(self):
787*9c5db199SXin Li        """Function for polling the RPC server availability.
788*9c5db199SXin Li
789*9c5db199SXin Li        @return: Always True.
790*9c5db199SXin Li        """
791*9c5db199SXin Li        return True
792*9c5db199SXin Li
793*9c5db199SXin Li    def run_shell_command(self, command, block=True):
794*9c5db199SXin Li        """Run shell command.
795*9c5db199SXin Li
796*9c5db199SXin Li        @param command: A shell command to be run.
797*9c5db199SXin Li        @param block: if True (default), wait for command to finish
798*9c5db199SXin Li        """
799*9c5db199SXin Li        self._os_if.run_shell_command(command, block=block)
800*9c5db199SXin Li
801*9c5db199SXin Li    def run_shell_command_check_output(self, command, success_token):
802*9c5db199SXin Li        """Run shell command and check its stdout for a string.
803*9c5db199SXin Li
804*9c5db199SXin Li        @param command: A shell command to be run.
805*9c5db199SXin Li        @param success_token: A string to search the output for.
806*9c5db199SXin Li        @return: A Boolean indicating whether the success_token was found in
807*9c5db199SXin Li                the command output.
808*9c5db199SXin Li        """
809*9c5db199SXin Li        return self._os_if.run_shell_command_check_output(
810*9c5db199SXin Li                command, success_token)
811*9c5db199SXin Li
812*9c5db199SXin Li    def run_shell_command_get_output(self, command, include_stderr=False):
813*9c5db199SXin Li        """Run shell command and get its console output.
814*9c5db199SXin Li
815*9c5db199SXin Li        @param command: A shell command to be run.
816*9c5db199SXin Li        @return: A list of strings stripped of the newline characters.
817*9c5db199SXin Li        """
818*9c5db199SXin Li        return self._os_if.run_shell_command_get_output(command, include_stderr)
819*9c5db199SXin Li
820*9c5db199SXin Li    def run_shell_command_get_status(self, command):
821*9c5db199SXin Li        """Run shell command and get its console status.
822*9c5db199SXin Li
823*9c5db199SXin Li        @param command: A shell command to be run.
824*9c5db199SXin Li        @return: The returncode of the process
825*9c5db199SXin Li        @rtype: int
826*9c5db199SXin Li        """
827*9c5db199SXin Li        return self._os_if.run_shell_command_get_status(command)
828*9c5db199SXin Li
829*9c5db199SXin Li    def get_platform_name(self):
830*9c5db199SXin Li        """Get the platform name of the current system.
831*9c5db199SXin Li
832*9c5db199SXin Li        @return: A string of the platform name.
833*9c5db199SXin Li        """
834*9c5db199SXin Li        return lsbrelease_utils.get_current_board()
835*9c5db199SXin Li
836*9c5db199SXin Li    def get_model_name(self):
837*9c5db199SXin Li        """Get the model name of the current system.
838*9c5db199SXin Li
839*9c5db199SXin Li        @return: A string of the model name.
840*9c5db199SXin Li        """
841*9c5db199SXin Li        model = cros_config.call_cros_config_get_output(
842*9c5db199SXin Li                '/ name', self._os_if.run_shell_command_get_result)
843*9c5db199SXin Li        if not model:
844*9c5db199SXin Li            raise Exception('Failed getting model name from cros_config')
845*9c5db199SXin Li        return model
846*9c5db199SXin Li
847*9c5db199SXin Li    def dev_tpm_present(self):
848*9c5db199SXin Li        """Check if /dev/tpm0 is present.
849*9c5db199SXin Li
850*9c5db199SXin Li        @return: Boolean true or false.
851*9c5db199SXin Li        """
852*9c5db199SXin Li        return os.path.exists('/dev/tpm0')
853*9c5db199SXin Li
854*9c5db199SXin Li    def get_crossystem_value(self, key):
855*9c5db199SXin Li        """Get crossystem value of the requested key.
856*9c5db199SXin Li
857*9c5db199SXin Li        @param key: A crossystem key.
858*9c5db199SXin Li        @return: A string of the requested crossystem value.
859*9c5db199SXin Li        """
860*9c5db199SXin Li        return self._os_if.run_shell_command_get_output(
861*9c5db199SXin Li                'crossystem %s' % key)[0]
862*9c5db199SXin Li
863*9c5db199SXin Li    def get_boot_mode(self):
864*9c5db199SXin Li        """Get the current firmware boot mode.
865*9c5db199SXin Li
866*9c5db199SXin Li        @return: Either 'normal', 'dev', or 'rec'.
867*9c5db199SXin Li        @raise: ValueError if mainfw_type and devsw_boot do not correspond to
868*9c5db199SXin Li                an expected boot mode combination.
869*9c5db199SXin Li        """
870*9c5db199SXin Li        mainfw_type = self._os_if.cs.mainfw_type
871*9c5db199SXin Li        devsw_boot = self._os_if.cs.devsw_boot
872*9c5db199SXin Li        if mainfw_type == 'normal' and devsw_boot == '0':
873*9c5db199SXin Li            return 'normal'
874*9c5db199SXin Li        elif mainfw_type == 'developer' and devsw_boot == '1':
875*9c5db199SXin Li            return 'dev'
876*9c5db199SXin Li        elif mainfw_type == 'recovery':
877*9c5db199SXin Li            return 'rec'
878*9c5db199SXin Li        else:
879*9c5db199SXin Li            raise ValueError('Unexpected mainfw_type/devsw_boot combination: '
880*9c5db199SXin Li                             'mainfw_type=%s, devsw_boot=%s' %
881*9c5db199SXin Li                             (mainfw_type, devsw_boot))
882*9c5db199SXin Li
883*9c5db199SXin Li    def get_root_dev(self):
884*9c5db199SXin Li        """Get the name of root device without partition number.
885*9c5db199SXin Li
886*9c5db199SXin Li        @return: A string of the root device without partition number.
887*9c5db199SXin Li        """
888*9c5db199SXin Li        return self._os_if.get_root_dev()
889*9c5db199SXin Li
890*9c5db199SXin Li    def get_root_part(self):
891*9c5db199SXin Li        """Get the name of root device with partition number.
892*9c5db199SXin Li
893*9c5db199SXin Li        @return: A string of the root device with partition number.
894*9c5db199SXin Li        """
895*9c5db199SXin Li        return self._os_if.get_root_part()
896*9c5db199SXin Li
897*9c5db199SXin Li    def set_try_fw_b(self, count=1):
898*9c5db199SXin Li        """Set 'Try Firmware B' flag in crossystem.
899*9c5db199SXin Li
900*9c5db199SXin Li        @param count: # times to try booting into FW B
901*9c5db199SXin Li        """
902*9c5db199SXin Li        self._os_if.cs.fwb_tries = count
903*9c5db199SXin Li
904*9c5db199SXin Li    def set_fw_try_next(self, next, count=0):
905*9c5db199SXin Li        """Set fw_try_next to A or B.
906*9c5db199SXin Li
907*9c5db199SXin Li        @param next: Next FW to reboot to (A or B)
908*9c5db199SXin Li        @param count: # of times to try booting into FW <next>
909*9c5db199SXin Li        """
910*9c5db199SXin Li        self._os_if.cs.fw_try_next = next
911*9c5db199SXin Li        if count:
912*9c5db199SXin Li            self._os_if.cs.fw_try_count = count
913*9c5db199SXin Li
914*9c5db199SXin Li    def get_minios_priority(self):
915*9c5db199SXin Li        """Get minios_priority value, which denotes the minios image to try
916*9c5db199SXin Li        first. (A or B)
917*9c5db199SXin Li
918*9c5db199SXin Li        @return: 'A' or 'B'
919*9c5db199SXin Li        """
920*9c5db199SXin Li        return self._os_if.cs.minios_priority
921*9c5db199SXin Li
922*9c5db199SXin Li    def set_minios_priority(self, priority):
923*9c5db199SXin Li        """Set minios_priority to A or B.
924*9c5db199SXin Li
925*9c5db199SXin Li        @param priority: MiniOS partition to try first (A or B)
926*9c5db199SXin Li        """
927*9c5db199SXin Li        self._os_if.cs.minios_priority = priority
928*9c5db199SXin Li
929*9c5db199SXin Li    def get_fw_vboot2(self):
930*9c5db199SXin Li        """Get fw_vboot2."""
931*9c5db199SXin Li        try:
932*9c5db199SXin Li            return self._os_if.cs.fw_vboot2 == '1'
933*9c5db199SXin Li        except os_interface.OSInterfaceError:
934*9c5db199SXin Li            return False
935*9c5db199SXin Li
936*9c5db199SXin Li    def request_recovery_boot(self):
937*9c5db199SXin Li        """Request running in recovery mode on the restart."""
938*9c5db199SXin Li        self._os_if.cs.request_recovery()
939*9c5db199SXin Li
940*9c5db199SXin Li    def get_dev_boot_usb(self):
941*9c5db199SXin Li        """Get dev_boot_usb value which controls developer mode boot from USB.
942*9c5db199SXin Li
943*9c5db199SXin Li        @return: True if enable, False if disable.
944*9c5db199SXin Li        """
945*9c5db199SXin Li        return self._os_if.cs.dev_boot_usb == '1'
946*9c5db199SXin Li
947*9c5db199SXin Li    def set_dev_boot_usb(self, value):
948*9c5db199SXin Li        """Set dev_boot_usb value which controls developer mode boot from USB.
949*9c5db199SXin Li
950*9c5db199SXin Li        @param value: True to enable, False to disable.
951*9c5db199SXin Li        """
952*9c5db199SXin Li        self._os_if.cs.dev_boot_usb = 1 if value else 0
953*9c5db199SXin Li
954*9c5db199SXin Li    def get_dev_default_boot(self):
955*9c5db199SXin Li        """Get dev_default_boot value, which selects the default boot device.
956*9c5db199SXin Li
957*9c5db199SXin Li        @return: 'disk' or 'usb' or 'legacy'
958*9c5db199SXin Li        """
959*9c5db199SXin Li        return self._os_if.cs.dev_default_boot
960*9c5db199SXin Li
961*9c5db199SXin Li    def set_dev_default_boot(self, device='disk'):
962*9c5db199SXin Li        """Set dev_default_boot value, which selects the default boot device.
963*9c5db199SXin Li
964*9c5db199SXin Li        @param device: 'disk' or 'usb' or 'legacy' (default: 'disk')
965*9c5db199SXin Li        """
966*9c5db199SXin Li        self._os_if.cs.dev_default_boot = device
967*9c5db199SXin Li
968*9c5db199SXin Li    def is_removable_device_boot(self):
969*9c5db199SXin Li        """Check the current boot device is removable.
970*9c5db199SXin Li
971*9c5db199SXin Li        @return: True: if a removable device boots.
972*9c5db199SXin Li                 False: if a non-removable device boots.
973*9c5db199SXin Li        """
974*9c5db199SXin Li        root_part = self._os_if.get_root_part()
975*9c5db199SXin Li        return self._os_if.is_removable_device(root_part)
976*9c5db199SXin Li
977*9c5db199SXin Li    def get_internal_device(self):
978*9c5db199SXin Li        """Get the internal disk by given the current disk."""
979*9c5db199SXin Li        root_part = self._os_if.get_root_part()
980*9c5db199SXin Li        return self._os_if.get_internal_disk(root_part)
981*9c5db199SXin Li
982*9c5db199SXin Li    def create_temp_dir(self, prefix='backup_', dir=None):
983*9c5db199SXin Li        """Create a temporary directory and return the path."""
984*9c5db199SXin Li        return tempfile.mkdtemp(prefix=prefix, dir=dir)
985*9c5db199SXin Li
986*9c5db199SXin Li    def remove_file(self, file_path):
987*9c5db199SXin Li        """Remove the file."""
988*9c5db199SXin Li        return self._os_if.remove_file(file_path)
989*9c5db199SXin Li
990*9c5db199SXin Li    def remove_dir(self, dir_path):
991*9c5db199SXin Li        """Remove the directory."""
992*9c5db199SXin Li        return self._os_if.remove_dir(dir_path)
993*9c5db199SXin Li
994*9c5db199SXin Li    def check_keys(self, expected_sequence):
995*9c5db199SXin Li        """Check the keys sequence was as expected.
996*9c5db199SXin Li
997*9c5db199SXin Li        @param expected_sequence: A list of expected key sequences.
998*9c5db199SXin Li        """
999*9c5db199SXin Li        return self._key_checker.check_keys(expected_sequence)
1000*9c5db199SXin Li
1001*9c5db199SXin Li
1002*9c5db199SXin Liclass TpmServicer(object):
1003*9c5db199SXin Li    """Class to service all TPM RPCs"""
1004*9c5db199SXin Li
1005*9c5db199SXin Li    def __init__(self, os_if):
1006*9c5db199SXin Li        """
1007*9c5db199SXin Li        @type os_if: os_interface.OSInterface
1008*9c5db199SXin Li        """
1009*9c5db199SXin Li        self._os_if = os_if
1010*9c5db199SXin Li
1011*9c5db199SXin Li        # This attribute is accessed via a property, so it can load lazily
1012*9c5db199SXin Li        # when actually used by the test.
1013*9c5db199SXin Li        self._real_tpm_handler = tpm_handler.TpmHandler(self._os_if)
1014*9c5db199SXin Li
1015*9c5db199SXin Li    @property
1016*9c5db199SXin Li    def _tpm_handler(self):
1017*9c5db199SXin Li        """Handler for the TPM
1018*9c5db199SXin Li
1019*9c5db199SXin Li        @rtype: tpm_handler.TpmHandler
1020*9c5db199SXin Li        """
1021*9c5db199SXin Li        if not self._real_tpm_handler.initialized:
1022*9c5db199SXin Li            self._real_tpm_handler.init()
1023*9c5db199SXin Li        return self._real_tpm_handler
1024*9c5db199SXin Li
1025*9c5db199SXin Li    def get_firmware_version(self):
1026*9c5db199SXin Li        """Retrieve tpm firmware body version."""
1027*9c5db199SXin Li        return self._tpm_handler.get_fw_version()
1028*9c5db199SXin Li
1029*9c5db199SXin Li    def get_firmware_datakey_version(self):
1030*9c5db199SXin Li        """Retrieve tpm firmware data key version."""
1031*9c5db199SXin Li        return self._tpm_handler.get_fw_key_version()
1032*9c5db199SXin Li
1033*9c5db199SXin Li    def get_kernel_version(self):
1034*9c5db199SXin Li        """Retrieve tpm kernel body version."""
1035*9c5db199SXin Li        return self._tpm_handler.get_kernel_version()
1036*9c5db199SXin Li
1037*9c5db199SXin Li    def get_kernel_datakey_version(self):
1038*9c5db199SXin Li        """Retrieve tpm kernel data key version."""
1039*9c5db199SXin Li        return self._tpm_handler.get_kernel_key_version()
1040*9c5db199SXin Li
1041*9c5db199SXin Li    def get_tpm_version(self):
1042*9c5db199SXin Li        """Returns '1.2' or '2.0' as a string."""
1043*9c5db199SXin Li        # tpmc can return this without stopping daemons, so access real handler.
1044*9c5db199SXin Li        return self._real_tpm_handler.get_tpm_version()
1045*9c5db199SXin Li
1046*9c5db199SXin Li    def stop_daemon(self):
1047*9c5db199SXin Li        """Stop tpm related daemon."""
1048*9c5db199SXin Li        return self._tpm_handler.stop_daemon()
1049*9c5db199SXin Li
1050*9c5db199SXin Li    def restart_daemon(self):
1051*9c5db199SXin Li        """Restart tpm related daemon which was stopped by stop_daemon()."""
1052*9c5db199SXin Li        return self._tpm_handler.restart_daemon()
1053*9c5db199SXin Li
1054*9c5db199SXin Li
1055*9c5db199SXin Liclass UpdaterServicer(object):
1056*9c5db199SXin Li    """Class to service all Updater RPCs"""
1057*9c5db199SXin Li
1058*9c5db199SXin Li    def __init__(self, os_if):
1059*9c5db199SXin Li        """
1060*9c5db199SXin Li        @type os_if: os_interface.OSInterface
1061*9c5db199SXin Li        """
1062*9c5db199SXin Li        self._os_if = os_if
1063*9c5db199SXin Li        self._real_updater = firmware_updater.FirmwareUpdater(self._os_if)
1064*9c5db199SXin Li
1065*9c5db199SXin Li    @property
1066*9c5db199SXin Li    def _updater(self):
1067*9c5db199SXin Li        """Handler for the updater
1068*9c5db199SXin Li
1069*9c5db199SXin Li        @rtype: firmware_updater.FirmwareUpdater
1070*9c5db199SXin Li        """
1071*9c5db199SXin Li        if not self._real_updater.initialized:
1072*9c5db199SXin Li            self._real_updater.init()
1073*9c5db199SXin Li        return self._real_updater
1074*9c5db199SXin Li
1075*9c5db199SXin Li    def cleanup(self):
1076*9c5db199SXin Li        """Clean up the temporary directory"""
1077*9c5db199SXin Li        # Use the updater directly, to avoid initializing it just to clean it up
1078*9c5db199SXin Li        self._real_updater.cleanup_temp_dir()
1079*9c5db199SXin Li
1080*9c5db199SXin Li    def stop_daemon(self):
1081*9c5db199SXin Li        """Stop update-engine daemon."""
1082*9c5db199SXin Li        return self._real_updater.stop_daemon()
1083*9c5db199SXin Li
1084*9c5db199SXin Li    def start_daemon(self):
1085*9c5db199SXin Li        """Start update-engine daemon."""
1086*9c5db199SXin Li        return self._real_updater.start_daemon()
1087*9c5db199SXin Li
1088*9c5db199SXin Li    def get_section_fwid(self, target='bios', section=None):
1089*9c5db199SXin Li        """Retrieve shellball's RW or RO fwid."""
1090*9c5db199SXin Li        return self._updater.get_section_fwid(target, section)
1091*9c5db199SXin Li
1092*9c5db199SXin Li    def get_device_fwids(self, target='bios'):
1093*9c5db199SXin Li        """Retrieve flash device's fwids for the target."""
1094*9c5db199SXin Li        return self._updater.get_device_fwids(target)
1095*9c5db199SXin Li
1096*9c5db199SXin Li    def get_image_fwids(self, target='bios', filename=None):
1097*9c5db199SXin Li        """Retrieve image file's fwids for the target."""
1098*9c5db199SXin Li        return self._updater.get_image_fwids(target, filename)
1099*9c5db199SXin Li
1100*9c5db199SXin Li    def modify_image_fwids(self, target='bios', sections=None):
1101*9c5db199SXin Li        """Modify the fwid in the image, but don't flash it."""
1102*9c5db199SXin Li        return self._updater.modify_image_fwids(target, sections)
1103*9c5db199SXin Li
1104*9c5db199SXin Li    def modify_ecid_and_flash_to_bios(self):
1105*9c5db199SXin Li        """Modify ecid, put it to AP firmware, and flash it to the system."""
1106*9c5db199SXin Li        self._updater.modify_ecid_and_flash_to_bios()
1107*9c5db199SXin Li
1108*9c5db199SXin Li    def corrupt_diagnostics_image(self, local_filename):
1109*9c5db199SXin Li        """Corrupts a diagnostics image in the CBFS working directory.
1110*9c5db199SXin Li
1111*9c5db199SXin Li        @param local_filename: Filename for storing the diagnostics image in the
1112*9c5db199SXin Li            CBFS working directory
1113*9c5db199SXin Li        """
1114*9c5db199SXin Li        self._updater.corrupt_diagnostics_image(local_filename)
1115*9c5db199SXin Li
1116*9c5db199SXin Li    def get_ec_hash(self):
1117*9c5db199SXin Li        """Return the hex string of the EC hash."""
1118*9c5db199SXin Li        blob = self._updater.get_ec_hash()
1119*9c5db199SXin Li        # Format it to a hex string
1120*9c5db199SXin Li        return binascii.hexlify(blob)
1121*9c5db199SXin Li
1122*9c5db199SXin Li    def resign_firmware(self, version):
1123*9c5db199SXin Li        """Resign firmware with version.
1124*9c5db199SXin Li
1125*9c5db199SXin Li        @param version: new version number.
1126*9c5db199SXin Li        """
1127*9c5db199SXin Li        self._updater.resign_firmware(version)
1128*9c5db199SXin Li
1129*9c5db199SXin Li    def extract_shellball(self, append=None):
1130*9c5db199SXin Li        """Extract shellball with the given append suffix.
1131*9c5db199SXin Li
1132*9c5db199SXin Li        @param append: use for the shellball name.
1133*9c5db199SXin Li        """
1134*9c5db199SXin Li        return self._updater.extract_shellball(append)
1135*9c5db199SXin Li
1136*9c5db199SXin Li    def repack_shellball(self, append=None):
1137*9c5db199SXin Li        """Repack shellball with new fwid.
1138*9c5db199SXin Li
1139*9c5db199SXin Li        @param append: use for the shellball name.
1140*9c5db199SXin Li        """
1141*9c5db199SXin Li        return self._updater.repack_shellball(append)
1142*9c5db199SXin Li
1143*9c5db199SXin Li    def reset_shellball(self):
1144*9c5db199SXin Li        """Revert to the stock shellball"""
1145*9c5db199SXin Li        self._updater.reset_shellball()
1146*9c5db199SXin Li
1147*9c5db199SXin Li    def reload_images(self):
1148*9c5db199SXin Li        """Reload handlers from the on-disk images, in case they've changed."""
1149*9c5db199SXin Li        self._updater.reload_images()
1150*9c5db199SXin Li
1151*9c5db199SXin Li    def get_firmwareupdate_command(self, mode, append=None, options=()):
1152*9c5db199SXin Li        """Get the command needed to run updater with the given options.
1153*9c5db199SXin Li
1154*9c5db199SXin Li        The client should run it via ssh, in case the update resets USB network.
1155*9c5db199SXin Li
1156*9c5db199SXin Li        @param mode: mode for the updater
1157*9c5db199SXin Li        @param append: extra string appended to shellball filename to run
1158*9c5db199SXin Li        @param options: options for chromeos-firmwareupdate
1159*9c5db199SXin Li        @return: returncode of the updater
1160*9c5db199SXin Li        @rtype: str
1161*9c5db199SXin Li        """
1162*9c5db199SXin Li        return self._updater.get_firmwareupdate_command(mode, append, options)
1163*9c5db199SXin Li
1164*9c5db199SXin Li    def run_firmwareupdate(self, mode, append=None, options=()):
1165*9c5db199SXin Li        """Run updater with the given options
1166*9c5db199SXin Li
1167*9c5db199SXin Li        @param mode: mode for the updater
1168*9c5db199SXin Li        @param append: extra string appended to shellball filename to run
1169*9c5db199SXin Li        @param options: options for chromeos-firmwareupdate
1170*9c5db199SXin Li        @return: returncode of the updater
1171*9c5db199SXin Li        @rtype: int
1172*9c5db199SXin Li        """
1173*9c5db199SXin Li        return self._updater.run_firmwareupdate(mode, append, options)
1174*9c5db199SXin Li
1175*9c5db199SXin Li    def run_autoupdate(self, append):
1176*9c5db199SXin Li        """Run chromeos-firmwareupdate with autoupdate mode."""
1177*9c5db199SXin Li        options = ['--noupdate_ec', '--wp=1']
1178*9c5db199SXin Li        self._updater.run_firmwareupdate(
1179*9c5db199SXin Li                mode='autoupdate', append=append, options=options)
1180*9c5db199SXin Li
1181*9c5db199SXin Li    def run_factory_install(self):
1182*9c5db199SXin Li        """Run chromeos-firmwareupdate with factory_install mode."""
1183*9c5db199SXin Li        options = ['--noupdate_ec', '--wp=0']
1184*9c5db199SXin Li        self._updater.run_firmwareupdate(
1185*9c5db199SXin Li                mode='factory_install', options=options)
1186*9c5db199SXin Li
1187*9c5db199SXin Li    def run_bootok(self, append):
1188*9c5db199SXin Li        """Run chromeos-firmwareupdate with bootok mode."""
1189*9c5db199SXin Li        self._updater.run_firmwareupdate(mode='bootok', append=append)
1190*9c5db199SXin Li
1191*9c5db199SXin Li    def run_recovery(self):
1192*9c5db199SXin Li        """Run chromeos-firmwareupdate with recovery mode."""
1193*9c5db199SXin Li        options = ['--noupdate_ec', '--nocheck_keys', '--force', '--wp=1']
1194*9c5db199SXin Li        self._updater.run_firmwareupdate(mode='recovery', options=options)
1195*9c5db199SXin Li
1196*9c5db199SXin Li    def cbfs_setup_work_dir(self):
1197*9c5db199SXin Li        """Sets up cbfstool work directory."""
1198*9c5db199SXin Li        return self._updater.cbfs_setup_work_dir()
1199*9c5db199SXin Li
1200*9c5db199SXin Li    def cbfs_extract_chip(self,
1201*9c5db199SXin Li                          fw_name,
1202*9c5db199SXin Li                          extension='.bin',
1203*9c5db199SXin Li                          hash_extension='.hash'):
1204*9c5db199SXin Li        """Runs cbfstool to extract chip firmware.
1205*9c5db199SXin Li
1206*9c5db199SXin Li        @param fw_name: Name of chip firmware to extract.
1207*9c5db199SXin Li        @return: Boolean success status.
1208*9c5db199SXin Li        """
1209*9c5db199SXin Li        return self._updater.cbfs_extract_chip(fw_name, extension,
1210*9c5db199SXin Li                                               hash_extension)
1211*9c5db199SXin Li
1212*9c5db199SXin Li    def cbfs_extract_diagnostics(self, diag_name, local_filename):
1213*9c5db199SXin Li        """Runs cbfstool to extract a diagnostics image.
1214*9c5db199SXin Li
1215*9c5db199SXin Li        @param diag_name: Name of the diagnostics image in CBFS
1216*9c5db199SXin Li        @param local_filename: Filename for storing the diagnostics image in the
1217*9c5db199SXin Li            CBFS working directory
1218*9c5db199SXin Li        """
1219*9c5db199SXin Li        self._updater.cbfs_extract_diagnostics(diag_name, local_filename)
1220*9c5db199SXin Li
1221*9c5db199SXin Li    def cbfs_replace_diagnostics(self, diag_name, local_filename):
1222*9c5db199SXin Li        """Runs cbfstool to replace a diagnostics image in the firmware image.
1223*9c5db199SXin Li
1224*9c5db199SXin Li        @param diag_name: Name of the diagnostics image in CBFS
1225*9c5db199SXin Li        @param local_filename: Filename for storing the diagnostics image in the
1226*9c5db199SXin Li            CBFS working directory
1227*9c5db199SXin Li        """
1228*9c5db199SXin Li        self._updater.cbfs_replace_diagnostics(diag_name, local_filename)
1229*9c5db199SXin Li
1230*9c5db199SXin Li    def cbfs_get_chip_hash(self, fw_name, hash_extension='.hash'):
1231*9c5db199SXin Li        """Gets the chip firmware hash blob.
1232*9c5db199SXin Li
1233*9c5db199SXin Li        The hash data is returned as a list of stringified two-byte pieces:
1234*9c5db199SXin Li        \x12\x34...\xab\xcd\xef -> ['0x12', '0x34', ..., '0xab', '0xcd', '0xef']
1235*9c5db199SXin Li
1236*9c5db199SXin Li        @param fw_name: Name of chip firmware whose hash blob to return.
1237*9c5db199SXin Li        @return: Hex string of hash blob.
1238*9c5db199SXin Li        """
1239*9c5db199SXin Li        return self._updater.cbfs_get_chip_hash(fw_name, hash_extension)
1240*9c5db199SXin Li
1241*9c5db199SXin Li    def cbfs_replace_chip(self,
1242*9c5db199SXin Li                          fw_name,
1243*9c5db199SXin Li                          extension='.bin',
1244*9c5db199SXin Li                          hash_extension='.hash',
1245*9c5db199SXin Li                          regions=('a', 'b')):
1246*9c5db199SXin Li        """Runs cbfstool to replace chip firmware.
1247*9c5db199SXin Li
1248*9c5db199SXin Li        @param fw_name: Name of chip firmware to extract.
1249*9c5db199SXin Li        @return: Boolean success status.
1250*9c5db199SXin Li        """
1251*9c5db199SXin Li        return self._updater.cbfs_replace_chip(fw_name, extension,
1252*9c5db199SXin Li                                               hash_extension, regions)
1253*9c5db199SXin Li
1254*9c5db199SXin Li    def cbfs_sign_and_flash(self):
1255*9c5db199SXin Li        """Runs cbfs signer and flash it.
1256*9c5db199SXin Li
1257*9c5db199SXin Li        @param fw_name: Name of chip firmware to extract.
1258*9c5db199SXin Li        @return: Boolean success status.
1259*9c5db199SXin Li        """
1260*9c5db199SXin Li        return self._updater.cbfs_sign_and_flash()
1261*9c5db199SXin Li
1262*9c5db199SXin Li    def cbfs_extract(self,
1263*9c5db199SXin Li                     filename,
1264*9c5db199SXin Li                     extension,
1265*9c5db199SXin Li                     regions,
1266*9c5db199SXin Li                     local_filename=None,
1267*9c5db199SXin Li                     arch=None,
1268*9c5db199SXin Li                     bios=None):
1269*9c5db199SXin Li        """Extracts an arbitrary file from cbfs.
1270*9c5db199SXin Li
1271*9c5db199SXin Li        Note that extracting from
1272*9c5db199SXin Li        @param filename: Filename in cbfs, including extension
1273*9c5db199SXin Li        @param extension: Extension of the file, including '.'
1274*9c5db199SXin Li        @param regions: Tuple of regions (the default is just 'a')
1275*9c5db199SXin Li        @param arch: Specific machine architecture to extract (default unset)
1276*9c5db199SXin Li        @param local_filename: Path to use on the DUT, overriding the default in
1277*9c5db199SXin Li                           the cbfs work dir.
1278*9c5db199SXin Li        @param bios: Image from which the cbfs file to be extracted
1279*9c5db199SXin Li        @return: The full path of the extracted file, or None
1280*9c5db199SXin Li        """
1281*9c5db199SXin Li        return self._updater.cbfs_extract(filename,
1282*9c5db199SXin Li                                      extension, regions,
1283*9c5db199SXin Li                                      local_filename,
1284*9c5db199SXin Li                                      arch,
1285*9c5db199SXin Li                                      bios)
1286*9c5db199SXin Li
1287*9c5db199SXin Li    def get_temp_path(self):
1288*9c5db199SXin Li        """Get updater's temp directory path."""
1289*9c5db199SXin Li        return self._updater.get_temp_path()
1290*9c5db199SXin Li
1291*9c5db199SXin Li    def get_keys_path(self):
1292*9c5db199SXin Li        """Get updater's keys directory path."""
1293*9c5db199SXin Li        return self._updater.get_keys_path()
1294*9c5db199SXin Li
1295*9c5db199SXin Li    def get_work_path(self):
1296*9c5db199SXin Li        """Get updater's work directory path."""
1297*9c5db199SXin Li        return self._updater.get_work_path()
1298*9c5db199SXin Li
1299*9c5db199SXin Li    def get_bios_relative_path(self):
1300*9c5db199SXin Li        """Gets the relative path of the bios image in the shellball."""
1301*9c5db199SXin Li        return self._updater.get_bios_relative_path()
1302*9c5db199SXin Li
1303*9c5db199SXin Li    def get_ec_relative_path(self):
1304*9c5db199SXin Li        """Gets the relative path of the ec image in the shellball."""
1305*9c5db199SXin Li        return self._updater.get_ec_relative_path()
1306*9c5db199SXin Li
1307*9c5db199SXin Li    def copy_bios(self, filename):
1308*9c5db199SXin Li        """Make a copy of the shellball bios.bin"""
1309*9c5db199SXin Li        return self._updater.copy_bios(filename)
1310*9c5db199SXin Li
1311*9c5db199SXin Li    def get_image_gbb_flags(self, filename=None):
1312*9c5db199SXin Li        """Get the GBB flags in the given image (shellball image if unspecified)
1313*9c5db199SXin Li
1314*9c5db199SXin Li        @param filename: the image path to act on (None to use shellball image)
1315*9c5db199SXin Li        @return: An integer of the GBB flags.
1316*9c5db199SXin Li        """
1317*9c5db199SXin Li        return self._updater.get_image_gbb_flags(filename)
1318*9c5db199SXin Li
1319*9c5db199SXin Li    def set_image_gbb_flags(self, flags, filename=None):
1320*9c5db199SXin Li        """Set the GBB flags in the given image (shellball image if unspecified)
1321*9c5db199SXin Li
1322*9c5db199SXin Li        @param flags: the flags to set
1323*9c5db199SXin Li        @param filename: the image path to act on (None to use shellball image)
1324*9c5db199SXin Li
1325*9c5db199SXin Li        @type flags: int
1326*9c5db199SXin Li        @type filename: str | None
1327*9c5db199SXin Li        """
1328*9c5db199SXin Li        return self._updater.set_image_gbb_flags(flags, filename)
1329