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