1# Copyright (c) 2020 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 common
8from autotest_lib.client.common_lib import error
9from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
10
11class firmware_RecoveryStress(FirmwareTest):
12    """This test checks the following FAFT hardware requirement:
13      - USB stick is plugged into Servo board, not DUT
14      - Recovery boot with USB stick using power_state:rec
15      - Recovery boot with USB stick using power_state:rec_force_mrc
16    """
17    version = 1
18    NEEDS_SERVO_USB = True
19
20    REBUILD_CACHE_MSG = "MRC: cache data 'RECOVERY_MRC_CACHE' needs update."
21    FIRMWARE_LOG_CMD = 'cbmem -1' + ' | grep ' + REBUILD_CACHE_MSG[:3]
22    RECOVERY_CACHE_SECTION = 'RECOVERY_MRC_CACHE'
23
24    def initialize(self, host, mode, cmdline_args):
25        super(firmware_RecoveryStress, self).initialize(
26                host, cmdline_args)
27        self.mode = mode
28        if self.mode not in ['rec', 'rec_force_mrc']:
29            raise error.TestFail('Wrong mode given. Not supported for this test.')
30        self.switcher.setup_mode('normal')
31        self.setup_usbkey(usbkey=True, host=False)
32
33    def check_cache_rebuilt(self):
34        """Checks the firmware log to ensure that the recovery cache was rebuilt
35        during recovery boot.
36
37        @return True if cache rebuilt
38        """
39        logging.info('Checking if cache was rebuilt.')
40
41        return self.faft_client.system.run_shell_command_check_output(
42                self.FIRMWARE_LOG_CMD, self.REBUILD_CACHE_MSG)
43
44    def cache_exist(self):
45        """Checks the firmware log to ensure that the recovery cache exists.
46
47        @return True if cache exists
48        """
49        logging.info("Checking if device has RECOVERY_MRC_CACHE")
50
51        # If flashrom can read the section, this means it exists.
52        command = ('flashrom -p host -r -i %s:/dev/null'
53                   % self.RECOVERY_CACHE_SECTION)
54        return self.faft_client.system.run_shell_command_check_output(
55            command, 'SUCCESS')
56
57    def run_once(self, reboot_iterations=1):
58        """Running recovery boot cycles to ensure booting through
59        USB successful."""
60
61        logging.info("Check DUT is booting into USB image through recovery mode")
62
63        if self.mode == "rec_force_mrc":
64            if not self.faft_config.rec_force_mrc:
65                raise error.TestNAError('DUT cannot force memory training.')
66
67            elif not self.cache_exist():
68                raise error.TestNAError('No RECOVERY_MRC_CACHE was found on DUT.')
69
70        for i in range(reboot_iterations):
71            logging.info('======== RUNNING RECOVERY BOOT ITERATION %d/%d '
72                    '========', i+1, reboot_iterations)
73            self.switcher.reboot_to_mode(to_mode=self.mode)
74            self.check_state((self.checkers.crossystem_checker, {
75                    'mainfw_type': 'recovery'
76            }))
77            if self.mode == "rec_force_mrc":
78                if not self.check_cache_rebuilt():
79                    raise error.TestFail('Recovery Cache was not rebuilt.')
80
81        logging.info("Simple reboot to boot into internal disk")
82        self.switcher.mode_aware_reboot()
83