1# Copyright (c) 2012 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
6from autotest_lib.server import utils
7from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
8from autotest_lib.client.common_lib import error
9
10
11class firmware_UpdateFirmwareVersion(FirmwareTest):
12    """
13    Servo based firmware update test which checks the firmware version.
14
15    This test requires a USB test image plugged in. The firmware id of
16    the current running firmware must matches the system shellball's, or user
17    can provide a shellball to do this test. In this way, the client will be
18    update with the given shellball first. On runtime, this test modifies the
19    firmware version of the shellball and runs autoupdate. Check firmware
20    version after boot with firmware B, and then recover firmware A and B to
21    original shellball.
22    """
23    version = 1
24    NEEDS_SERVO_USB = True
25
26    def check_firmware_version(self, expected_ver):
27        """Checks the firmware version."""
28        actual_ver = self.faft_client.bios.get_version(
29                'b' if self.fw_vboot2 else 'a')
30        actual_tpm_fwver = self.faft_client.tpm.get_firmware_version()
31        if actual_ver != expected_ver or actual_tpm_fwver != expected_ver:
32            raise error.TestFail(
33                'Firmware version should be %s,'
34                'but got (fwver, tpm_fwver) = (%s, %s).' %
35                (expected_ver, actual_ver, actual_tpm_fwver))
36        else:
37            logging.info(
38                'Update success, now version is %s',
39                actual_ver)
40
41    def initialize(self, host, cmdline_args):
42        """Setup the test"""
43        dict_args = utils.args_to_dict(cmdline_args)
44        shellball_path = dict_args.get('shellball', None)
45        super(firmware_UpdateFirmwareVersion, self).initialize(
46            host, cmdline_args)
47        self.switcher.setup_mode('normal')
48        self.backup_firmware()
49        self.setup_firmwareupdate_shellball(shellball_path)
50
51        # Update firmware if needed
52        if shellball_path:
53            self.set_ap_write_protect_and_reboot(enable=False)
54            self.faft_client.updater.run_factory_install()
55            self.switcher.mode_aware_reboot()
56
57        self.setup_usbkey(usbkey=True)
58
59        self._fwid = self.faft_client.updater.get_section_fwid()
60
61        self.fw_ver_tpm = self.faft_client.tpm.get_firmware_version()
62        actual_ver = self.faft_client.bios.get_version('a')
63        logging.info('Origin version is %s', actual_ver)
64        self._update_version = actual_ver + 1
65        logging.info('Firmware version will update to version %s',
66                     self._update_version)
67
68        self.faft_client.updater.resign_firmware(self._update_version)
69        self.faft_client.updater.repack_shellball('test')
70
71    def cleanup(self):
72        """Cleanup after the test"""
73        try:
74            if self.faft_client.tpm.get_firmware_version() != self.fw_ver_tpm:
75                self.reboot_and_reset_tpm()
76            self.restore_firmware()
77            self.invalidate_firmware_setup()
78        except Exception as e:
79            logging.error("Caught exception: %s", str(e))
80        super(firmware_UpdateFirmwareVersion, self).cleanup()
81
82    def run_once(self):
83        """Runs a single iteration of the test."""
84        logging.info("Update firmware with new version.")
85        self.check_state((self.checkers.crossystem_checker, {
86                          'fwid': self._fwid
87                          }))
88        self.check_state((self.checkers.fw_tries_checker, 'A'))
89        self.faft_client.updater.run_autoupdate('test')
90        self.switcher.mode_aware_reboot()
91
92        logging.info("Copy firmware form B to A.")
93        self.faft_client.updater.run_bootok('test')
94        self.check_state((self.checkers.fw_tries_checker, 'B'))
95        self.switcher.mode_aware_reboot()
96
97        logging.info("Check firmware and TPM version, then recovery.")
98        self.check_state((self.checkers.fw_tries_checker,
99                          'B' if self.fw_vboot2 else 'A'))
100        self.check_firmware_version(self._update_version)
101        self.faft_client.updater.run_recovery()
102        self.reboot_and_reset_tpm()
103
104        logging.info("Check Rollback version.")
105        self.check_state((self.checkers.crossystem_checker, {
106                          'fwid': self._fwid
107                          }))
108        self.check_state((self.checkers.fw_tries_checker,
109                          'B' if self.fw_vboot2 else 'A'))
110        self.check_firmware_version(self._update_version - 1)
111