Home | History | Annotate | Download | only in enterprise_CFM_SiSFwUpdater
      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 
      6 from __future__ import print_function
      7 import logging
      8 import os
      9 import re
     10 import time
     11 
     12 from autotest_lib.client.common_lib.cros import power_cycle_usb_util
     13 
     14 from autotest_lib.client.common_lib import error
     15 from autotest_lib.server import test
     16 
     17 POWER_CYCLE_WAIT_TIME = 1   # seconds
     18 UPDATER_WAIT_TIME = 80      # seconds
     19 # This is the GPIO on guado.
     20 FRONT_LEFT_USB_GPIO = 218
     21 
     22 
     23 class 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_V03.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