1# Copyright 2015 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6 7from autotest_lib.client.common_lib import error 8from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 9 10 11class firmware_FWupdateWP(FirmwareTest): 12 """RO+RW firmware update using chromeos-firmware, with WP=1 and with WP=0. 13 It modifies the FWIDs of the current firmware before flashing, and restores 14 the firmware after the test. 15 """ 16 17 # Region to use for flashrom wp-region commands 18 WP_REGION = 'WP_RO' 19 MODE = 'recovery' 20 21 def initialize(self, host, cmdline_args): 22 23 self.flashed = False 24 25 super(firmware_FWupdateWP, self).initialize(host, cmdline_args) 26 27 self._old_bios_wp = self.faft_client.bios.get_write_protect_status() 28 29 stripped_bios = self.faft_client.bios.strip_modified_fwids() 30 if stripped_bios: 31 logging.warning( 32 "Fixed the previously modified BIOS FWID(s): %s", 33 stripped_bios) 34 35 if self.faft_config.chrome_ec: 36 stripped_ec = self.faft_client.ec.strip_modified_fwids() 37 if stripped_ec: 38 logging.warning( 39 "Fixed the previously modified EC FWID(s): %s", 40 stripped_ec) 41 42 self.backup_firmware() 43 44 self.set_ap_write_protect_and_reboot(False) 45 self.faft_client.bios.set_write_protect_region(self.WP_REGION, True) 46 self.set_ap_write_protect_and_reboot(True) 47 48 def get_installed_versions(self): 49 """Get the installed versions of BIOS and EC firmware. 50 51 @return: A nested dict keyed by target ('bios' or 'ec') and then section 52 @rtype: dict 53 """ 54 vers = dict() 55 vers['bios'] = self.faft_client.updater.get_device_fwids('bios') 56 if self.faft_config.chrome_ec: 57 vers['ec'] = self.faft_client.updater.get_device_fwids('ec') 58 return vers 59 60 def run_case(self, append, write_protected, before_fwids, image_fwids): 61 """Run chromeos-firmwareupdate with given sub-case 62 63 @param append: additional piece to add to shellball name 64 @param write_protected: is the flash write protected (--wp)? 65 @param before_fwids: fwids before flashing ('bios' and 'ec' as keys) 66 @param image_fwids: fwids in image ('bios' and 'ec' as keys) 67 @return: a list of failure messages for the case 68 """ 69 70 cmd_desc = ('chromeos-firmwareupdate --mode=%s [wp=%s]' 71 % (self.MODE, write_protected)) 72 73 # Unlock the protection of the wp-enable and wp-range registers 74 self.set_ap_write_protect_and_reboot(False) 75 76 if write_protected: 77 self.faft_client.bios.set_write_protect_region(self.WP_REGION, True) 78 self.set_ap_write_protect_and_reboot(True) 79 else: 80 self.faft_client.bios.set_write_protect_region( 81 self.WP_REGION, False) 82 83 expected_written = {} 84 85 if write_protected: 86 bios_written = ['a', 'b'] 87 ec_written = [] # EC write is all-or-nothing 88 89 else: 90 bios_written = ['ro', 'a', 'b'] 91 ec_written = ['ro', 'rw'] 92 93 expected_written['bios'] = bios_written 94 95 if self.faft_config.chrome_ec and ec_written: 96 expected_written['ec'] = ec_written 97 98 # bios: [a, b], ec: [ro, rw] 99 written_desc = repr(expected_written).replace("'", "")[1:-1] 100 logging.debug('Before(%s): %s', append, before_fwids) 101 logging.debug('Image(%s): %s', append, image_fwids) 102 logging.info("Run %s (should write %s)", cmd_desc, written_desc) 103 104 # make sure we restore firmware after the test, if it tried to flash. 105 self.flashed = True 106 107 errors = [] 108 options = ['--quirks=ec_partial_recovery=0'] 109 result = self.run_chromeos_firmwareupdate( 110 self.MODE, append, options, ignore_status=True) 111 112 if result.exit_status == 255: 113 logging.info("DUT network dropped during update.") 114 elif result.exit_status != 0: 115 if (image_fwids == before_fwids and 116 'Good. It seems nothing was changed.' in result.stdout): 117 logging.info("DUT already matched the image; updater aborted.") 118 else: 119 errors.append('...updater: unexpectedly failed (rc=%s)' % 120 result.exit_status) 121 122 after_fwids = self.get_installed_versions() 123 logging.debug('After(%s): %s', append, after_fwids) 124 125 errors += self.check_fwids_written( 126 before_fwids, image_fwids, after_fwids, expected_written) 127 128 if errors: 129 logging.debug('%s', '\n'.join(errors)) 130 return ["%s (should write %s)\n%s" 131 % (cmd_desc, written_desc, '\n'.join(errors))] 132 else: 133 return [] 134 135 def run_once(self, host): 136 """Run chromeos-firmwareupdate with recovery or factory mode. 137 138 @param host: host to run on 139 """ 140 append = 'new' 141 have_ec = bool(self.faft_config.chrome_ec) 142 143 self.faft_client.updater.extract_shellball() 144 145 before_fwids = self.get_installed_versions() 146 147 # Modify the stock image 148 logging.info( 149 "Using the currently running firmware, with modified fwids") 150 self.setup_firmwareupdate_shellball() 151 self.faft_client.updater.reload_images() 152 self.modify_shellball(append, modify_ro=True, modify_ec=have_ec) 153 modded_fwids = self.identify_shellball(include_ec=have_ec) 154 155 fail_msg = "Section contents didn't show the expected changes." 156 157 errors = [] 158 # no args specified, so check both wp=1 and wp=0 159 errors += self.run_case(append, 1, before_fwids, modded_fwids) 160 errors += self.run_case(append, 0, before_fwids, modded_fwids) 161 162 if errors: 163 raise error.TestFail("%s\n%s" % (fail_msg, '\n'.join(errors))) 164 165 def cleanup(self): 166 """ 167 Restore firmware from the backup taken before flashing. 168 No EC reboot is needed, because the test doesn't actually reboot the EC 169 with the "new" firmware. 170 """ 171 self.set_ap_write_protect_and_reboot(False) 172 self.faft_client.bios.set_write_protect_range(0, 0, False) 173 174 if self.flashed: 175 logging.info("Restoring firmware") 176 self.restore_firmware() 177 178 # Restore the old write-protection value at the end of the test. 179 self.faft_client.bios.set_write_protect_range( 180 self._old_bios_wp['start'], 181 self._old_bios_wp['length'], 182 self._old_bios_wp['enabled']) 183 184 super(firmware_FWupdateWP, self).cleanup() 185