| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| |
| import logging, os, time |
| |
| from autotest_lib.client.common_lib import error, utils |
| from autotest_lib.server.cros import vboot_constants as vboot |
| from autotest_lib.server.cros.faft.faft_classes import FAFTSequence |
| |
| |
| class firmware_UpdateECBin(FAFTSequence): |
| """ |
| This test verified the EC software sync. The EC binary is embedded in |
| the BIOS image. On AP startup, AP verifies the EC by comparing the |
| hash of the current EC with the hash of the embedded EC image. So |
| updating EC is simple and we just need to change the EC binary on |
| the BIOS image. |
| |
| This test requires a new EC image for update. The new EC image should |
| be different with the existing EC image on the current BIOS. In normal |
| cases, we use the ec_autest_image.bin from firmware_from_source.tar.bz2. |
| The ec_autest_image.bin is the same binary as ec.bin but shift'ed and its |
| version string has the "_shift" suffix. |
| |
| The new EC image should be specified by the new_ec argument, like: |
| run_remote_tests.sh --args "new_ec=ec_autest_image.bin" ... |
| |
| The test covers RONORMAL->TWOSTOP, TWOSTOP->TWOSTOP, and |
| TWOSTOP->RONORMAL updates. |
| """ |
| version = 1 |
| |
| |
| def initialize(self, host, cmdline_args): |
| # Parse arguments from command line |
| dict_args = utils.args_to_dict(cmdline_args) |
| if 'new_ec' not in dict_args or not os.path.isfile(dict_args['new_ec']): |
| raise error.TestError( |
| 'Should specify a valid new_ec image for update, like: ' |
| 'run_remote_tests.sh --args "new_ec=/path/to/' |
| 'ec_autest_image.bin". The ec_autest_image.bin file is ' |
| 'included in the firmware_from_source.tar.bz2.') |
| self.arg_new_ec = dict_args['new_ec'] |
| logging.info('The EC image to-be-updated is: %s', self.arg_new_ec) |
| super(firmware_UpdateECBin, self).initialize(host, cmdline_args) |
| self.backup_firmware() |
| self.setup_dev_mode(dev_mode) |
| self.setup_usbkey(usbkey=False) |
| |
| temp_path = self.faft_client.updater.get_temp_path() |
| self.faft_client.updater.setup() |
| |
| self.old_bios_path = os.path.join(temp_path, 'old_bios.bin') |
| self.faft_client.bios.dump_whole(self.old_bios_path) |
| |
| self.new_ec_path = os.path.join(temp_path, 'new_ec.bin') |
| host.send_file(self.arg_new_ec, self.new_ec_path) |
| |
| |
| def cleanup(self): |
| self.restore_firmware() |
| self.faft_client.updater.cleanup() |
| super(firmware_UpdateECBin, self).cleanup() |
| |
| |
| def do_ronormal_update(self): |
| self.faft_client.bios.setup_EC_image(self.new_ec_path) |
| self.new_ec_sha = self.faft_client.bios.get_EC_image_sha() |
| self.faft_client.bios.update_EC_from_image('a', 0) |
| |
| |
| def do_twostop_update(self): |
| # We update the original BIOS image back. This BIOS image contains |
| # the original EC binary. But set RW boot. So it is a TWOSTOP -> |
| # TWOSTOP update. |
| self.faft_client.bios.write_whole(self.old_bios_path) |
| self.faft_client.bios.set_preamble_flags('a', 0) |
| |
| |
| def ec_checker(self, use_new_ec): |
| ro_normal_checker = self.checkers.ro_normal_checker('A', twostop=True) |
| sha_now = self.faft_client.ec.get_firmware_sha() |
| if use_new_ec: |
| sha_checker = (sha_now == self.new_ec_sha) |
| else: |
| sha_checker = (sha_now != self.new_ec_sha) |
| return (ro_normal_checker and sha_checker) |
| |
| |
| def software_sync_and_ctrl_d(self): |
| time.sleep(self.faft_config.software_sync) |
| self.wait_dev_screen_and_ctrl_d() |
| |
| |
| def run_once(self, dev_mode=False): |
| if not self.check_ec_capability(): |
| raise error.TestNAError("Nothing needs to be tested on this device") |
| |
| flags = self.faft_client.bios.get_preamble_flags('a') |
| if flags & vboot.PREAMBLE_USE_RO_NORMAL == 0: |
| logging.info('The firmware USE_RO_NORMAL flag is disabled.') |
| return |
| |
| self.register_faft_sequence(( |
| { # Step 1, expected EC RO boot, update EC and disable RO flag |
| 'state_checker': (self.checkers.ro_normal_checker, 'A'), |
| 'userspace_action': self.do_ronormal_update, |
| 'reboot_action': self.sync_and_warm_reboot, |
| 'firmware_action': self.software_sync_and_ctrl_d if dev_mode |
| else None |
| }, |
| { # Step 2, expected new EC and RW boot, restore the original BIOS |
| 'state_checker': (self.ec_checker, True), |
| 'userspace_action': self.do_twostop_update, |
| # We use warm reboot here to test the following EC behavior: |
| # If EC is already into RW before powering on the AP, the AP |
| # will need to get the EC into RO first. It does this by |
| # telling the EC to wait for the AP to shut down, reboot |
| # into RO, then power on the AP automatically. |
| 'reboot_action': self.sync_and_warm_reboot, |
| 'firmware_action': self.software_sync_and_ctrl_d if dev_mode |
| else None |
| }, |
| { # Step 3, expected different EC and RW boot, enable RO flag |
| 'state_checker': (self.ec_checker, False), |
| 'userspace_action': (self.faft_client.bios.set_preamble_flags, |
| ('a', flags)), |
| 'reboot_action': self.sync_and_warm_reboot, |
| }, |
| { # Step 4, expected EC RO boot, done |
| 'state_checker': (self.checkers.ro_normal_checker, 'A'), |
| }, |
| )) |
| self.run_faft_sequence() |