• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2017 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"""Auto test for SiS firmware updater functionality and udev rule."""
5
6from __future__ import print_function
7import logging
8import os
9import re
10import time
11
12from autotest_lib.client.common_lib.cros import power_cycle_usb_util
13
14from autotest_lib.client.common_lib import error
15from autotest_lib.server import test
16
17POWER_CYCLE_WAIT_TIME = 1   # seconds
18UPDATER_WAIT_TIME = 80      # seconds
19# This is the GPIO on guado.
20FRONT_LEFT_USB_GPIO = 218
21
22
23class enterprise_CFM_SiSFwUpdater(test.test):
24    """
25    SiS firmware updater functionality test in Chrome Box.
26
27    The procedure of the test is:
28    1. flash old version FW to device,
29    2. power cycle usb port to simulate unplug and replug of device, which
30         should be able to trigger udev rule and run the updater,
31    3. wait for the updater to finish,
32    4. run fw updater again and verify that the FW in device is consistent with
33         latest FW within system by checking the output.
34    """
35
36    version = 1
37
38    _LOG_FILE_PATH = '/tmp/sis-updater.log'
39    _FW_PATH = '/lib/firmware/sis/'
40    _OLD_FW_NAME = 'FW_Watchdog_0110.bin'
41    _NEW_FW_NAME = 'WYD_101_WYD_9255_A353_V04.bin'
42    _DUT_BOARD = 'guado'
43    _SIS_VID = '266e'
44    _SIS_PID = '0110'
45
46    def initialize(self, host):
47        self.host = host
48        self.log_file = self._LOG_FILE_PATH
49        self.old_fw_path = os.path.join(self._FW_PATH, self._OLD_FW_NAME)
50        self.new_fw_path = os.path.join(self._FW_PATH, self._NEW_FW_NAME)
51        self.usb_port_gpio_number = FRONT_LEFT_USB_GPIO
52        self.board = self._DUT_BOARD
53        self.vid = self._SIS_VID
54        self.pid = self._SIS_PID
55        # Open log file object.
56        self.log_file_obj = open(self.log_file, 'w')
57
58    def cleanup(self):
59        self.log_file_obj.close()
60        test.test.cleanup(self)
61        cmd = 'rm -f {}'.format(self.old_fw_path)
62        self._run_cmd(cmd)
63
64    def _run_cmd(self, command, str_compare='', print_output=False):
65        """
66        Run command line on DUT.
67
68        Run commands on DUT. Wait for command to complete, then check the
69        output for expected string.
70
71        @param command: command line to run in dut.
72        @param str_compare: a piece of string we want to see in the output of
73                running the command.
74        @param print_output: if true, print command output in log.
75
76        @returns the command output and a bool value. If str_compare is in
77              command output, return true. Otherwise return false.
78
79        """
80
81        logging.info('Execute: %s', command)
82        result = self.host.run(command, ignore_status=True)
83        if result.stderr:
84            output = result.stderr
85        else:
86            output = result.stdout
87        if print_output:
88            logging.info('Output: %s', ''.join(output))
89        if str_compare and str_compare not in ''.join(output):
90            return output, False
91        else:
92            return output, True
93
94    def convert_rootfs_writable(self):
95        """Remove rootfs verification on DUT, reboot,
96        and remount the filesystem read-writable"""
97
98        logging.info('Disabling rootfs verification...')
99        self.remove_rootfs_verification()
100
101        logging.info('Rebooting...')
102        self.reboot()
103
104        logging.info('Remounting..')
105        cmd = 'mount -o remount,rw /'
106        self._run_cmd(cmd)
107
108    def remove_rootfs_verification(self):
109        """Remove rootfs verification."""
110
111        # 2 & 4 are default partitions, and the system boots from one of them.
112        # Code from chromite/scripts/deploy_chrome.py
113        KERNEL_A_PARTITION = 2
114        KERNEL_B_PARTITION = 4
115
116        cmd_template = ('/usr/share/vboot/bin/make_dev_ssd.sh --partitions %d '
117                        '--remove_rootfs_verification --force')
118        for partition in (KERNEL_A_PARTITION, KERNEL_B_PARTITION):
119            cmd = cmd_template % partition
120            self._run_cmd(cmd)
121
122    def reboot(self):
123        """Reboots the DUT."""
124
125        self.host.reboot()
126
127    def is_filesystem_readwrite(self):
128        """Check if the root file system is read-writable.
129
130        Query the DUT's filesystem /dev/root, often manifested as /dev/dm-0
131        or  is mounted as read-only or not.
132
133        @returns True if the /dev/root is read-writable. False otherwise.
134        """
135
136        cmd = 'cat /proc/mounts | grep "/dev/root"'
137        result, _ = self._run_cmd(cmd)
138        fields = re.split(' |,', result)
139        return True if fields.__len__() >= 4 and fields[3] == 'rw' else False
140
141    def copy_firmware(self):
142        """Copy test firmware from server to DUT."""
143
144        current_dir = os.path.dirname(os.path.realpath(__file__))
145        src_firmware_path = os.path.join(current_dir, self._OLD_FW_NAME)
146        dst_firmware_path = self._FW_PATH
147        logging.info('Copy firmware from {} to {}.'.format(src_firmware_path,
148                                                           dst_firmware_path))
149        self.host.send_file(src_firmware_path, dst_firmware_path,
150                            delete_dest=True)
151
152    def triger_updater(self):
153        """Triger udev rule to run fw updater."""
154
155        try:
156            power_cycle_usb_util.power_cycle_usb_vidpid(self.host, self.board,
157                                                        self.vid, self.pid)
158        except KeyError:
159            raise error.TestFail('Counld\'t find target device: '
160                                 'vid:pid {}:{}'.format(self.vid, self.pid))
161
162    def flash_fw(self, fw_path, str_compare='', print_output=False):
163        """
164        Flash certain firmware to device.
165
166        Run SiS firmware updater on DUT to flash the firmware given
167        by fw_path to target device (Mimo).
168
169        @param fw_path: the path to the firmware to flash.
170        @param str_compare, print_output: the same as function _run_cmd.
171
172        """
173        cmd_run_updater = ('/usr/sbin/sis-updater '
174                           '-ba -log_to=stdout {}'.format(fw_path))
175        output, succeed = self._run_cmd(
176            cmd_run_updater, str_compare=str_compare, print_output=print_output)
177        return output, succeed
178
179    def run_once(self):
180        """Main test procedure."""
181
182        # Make the DUT filesystem writable.
183        if not self.is_filesystem_readwrite():
184            logging.info('DUT root file system is not read-writable. '
185                         'Converting it read-writable...')
186            self.convert_rootfs_writable()
187        else:
188            logging.info('DUT is read-writable.')
189
190        # Copy old FW to device.
191        self.copy_firmware()
192
193        # Flash old FW to device.
194        expect_output = 'update firmware complete'
195        output, succeed = self.flash_fw(self.old_fw_path,
196                                        str_compare=expect_output)
197        self.log_file_obj.write('{}Log info for writing '
198                                'old firmware{}\n'.format('-'*8, '-'*8))
199        self.log_file_obj.write(output)
200        if not succeed:
201            raise error.TestFail('Expect \'{}\' in output, '
202                                 'but didn\'t find it.'.format(expect_output))
203
204        # No need to manually triger udev to run FW updater here.
205        # Previous FW updating process will reset SiS after it finish.
206
207        # Wait for fw updater to finish.
208        time.sleep(UPDATER_WAIT_TIME)
209
210        # Try flash the new firmware, should detect same fw version.
211        expect_output = 'The device has the same FW as system'
212        output, succeed = self.flash_fw(self.new_fw_path,
213                                        str_compare=expect_output)
214        self.log_file_obj.write('{}Log info for writing '
215                                'new firmware{}\n'.format('-'*8, '-'*8))
216        self.log_file_obj.write(output)
217        if not succeed:
218            raise error.TestFail('Expect {} in output '
219                                 'but didn\'t find it.'.format(expect_output))
220
221