blob: f32d97f159a0863860a406b0aa68ba4031ca2241 [file] [log] [blame]
# Copyright (c) 2017 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.
"""Auto test for SiS firmware updater functionality and udev rule."""
from __future__ import print_function
import logging
import os
import re
import time
from autotest_lib.client.common_lib.cros import power_cycle_usb_util
from autotest_lib.client.common_lib import error
from autotest_lib.server import test
POWER_CYCLE_WAIT_TIME = 1 # seconds
UPDATER_WAIT_TIME = 80 # seconds
# This is the GPIO on guado.
FRONT_LEFT_USB_GPIO = 218
class enterprise_CFM_SiSFwUpdater(test.test):
"""
SiS firmware updater functionality test in Chrome Box.
The procedure of the test is:
1. flash old version FW to device,
2. power cycle usb port to simulate unplug and replug of device, which
should be able to trigger udev rule and run the updater,
3. wait for the updater to finish,
4. run fw updater again and verify that the FW in device is consistent with
latest FW within system by checking the output.
"""
version = 1
_LOG_FILE_PATH = '/tmp/sis-updater.log'
_FW_PATH = '/lib/firmware/sis/'
_OLD_FW_NAME = 'FW_Watchdog_0110.bin'
_NEW_FW_NAME = 'WYD_101_WYD_9255_A353_V04.bin'
_DUT_BOARD = 'guado'
_SIS_VID = '266e'
_SIS_PID = '0110'
def initialize(self, host):
self.host = host
self.log_file = self._LOG_FILE_PATH
self.old_fw_path = os.path.join(self._FW_PATH, self._OLD_FW_NAME)
self.new_fw_path = os.path.join(self._FW_PATH, self._NEW_FW_NAME)
self.usb_port_gpio_number = FRONT_LEFT_USB_GPIO
self.board = self._DUT_BOARD
self.vid = self._SIS_VID
self.pid = self._SIS_PID
# Open log file object.
self.log_file_obj = open(self.log_file, 'w')
def cleanup(self):
self.log_file_obj.close()
test.test.cleanup(self)
cmd = 'rm -f {}'.format(self.old_fw_path)
self._run_cmd(cmd)
def _run_cmd(self, command, str_compare='', print_output=False):
"""
Run command line on DUT.
Run commands on DUT. Wait for command to complete, then check the
output for expected string.
@param command: command line to run in dut.
@param str_compare: a piece of string we want to see in the output of
running the command.
@param print_output: if true, print command output in log.
@returns the command output and a bool value. If str_compare is in
command output, return true. Otherwise return false.
"""
logging.info('Execute: %s', command)
result = self.host.run(command, ignore_status=True)
if result.stderr:
output = result.stderr
else:
output = result.stdout
if print_output:
logging.info('Output: %s', ''.join(output))
if str_compare and str_compare not in ''.join(output):
return output, False
else:
return output, True
def convert_rootfs_writable(self):
"""Remove rootfs verification on DUT, reboot,
and remount the filesystem read-writable"""
logging.info('Disabling rootfs verification...')
self.remove_rootfs_verification()
logging.info('Rebooting...')
self.reboot()
logging.info('Remounting..')
cmd = 'mount -o remount,rw /'
self._run_cmd(cmd)
def remove_rootfs_verification(self):
"""Remove rootfs verification."""
# 2 & 4 are default partitions, and the system boots from one of them.
# Code from chromite/scripts/deploy_chrome.py
KERNEL_A_PARTITION = 2
KERNEL_B_PARTITION = 4
cmd_template = ('/usr/share/vboot/bin/make_dev_ssd.sh --partitions %d '
'--remove_rootfs_verification --force')
for partition in (KERNEL_A_PARTITION, KERNEL_B_PARTITION):
cmd = cmd_template % partition
self._run_cmd(cmd)
def reboot(self):
"""Reboots the DUT."""
self.host.reboot()
def is_filesystem_readwrite(self):
"""Check if the root file system is read-writable.
Query the DUT's filesystem /dev/root, often manifested as /dev/dm-0
or is mounted as read-only or not.
@returns True if the /dev/root is read-writable. False otherwise.
"""
cmd = 'cat /proc/mounts | grep "/dev/root"'
result, _ = self._run_cmd(cmd)
fields = re.split(' |,', result)
return True if fields.__len__() >= 4 and fields[3] == 'rw' else False
def copy_firmware(self):
"""Copy test firmware from server to DUT."""
current_dir = os.path.dirname(os.path.realpath(__file__))
src_firmware_path = os.path.join(current_dir, self._OLD_FW_NAME)
dst_firmware_path = self._FW_PATH
logging.info('Copy firmware from {} to {}.'.format(src_firmware_path,
dst_firmware_path))
self.host.send_file(src_firmware_path, dst_firmware_path,
delete_dest=True)
def triger_updater(self):
"""Triger udev rule to run fw updater."""
try:
power_cycle_usb_util.power_cycle_usb_vidpid(self.host, self.board,
self.vid, self.pid)
except KeyError:
raise error.TestFail('Counld\'t find target device: '
'vid:pid {}:{}'.format(self.vid, self.pid))
def flash_fw(self, fw_path, str_compare='', print_output=False):
"""
Flash certain firmware to device.
Run SiS firmware updater on DUT to flash the firmware given
by fw_path to target device (Mimo).
@param fw_path: the path to the firmware to flash.
@param str_compare, print_output: the same as function _run_cmd.
"""
cmd_run_updater = ('/usr/sbin/sis-updater '
'-ba -log_to=stdout {}'.format(fw_path))
output, succeed = self._run_cmd(
cmd_run_updater, str_compare=str_compare, print_output=print_output)
return output, succeed
def run_once(self):
"""Main test procedure."""
# Make the DUT filesystem writable.
if not self.is_filesystem_readwrite():
logging.info('DUT root file system is not read-writable. '
'Converting it read-writable...')
self.convert_rootfs_writable()
else:
logging.info('DUT is read-writable.')
# Copy old FW to device.
self.copy_firmware()
# Flash old FW to device.
expect_output = 'update firmware complete'
output, succeed = self.flash_fw(self.old_fw_path,
str_compare=expect_output)
self.log_file_obj.write('{}Log info for writing '
'old firmware{}\n'.format('-'*8, '-'*8))
self.log_file_obj.write(output)
if not succeed:
raise error.TestFail('Expect \'{}\' in output, '
'but didn\'t find it.'.format(expect_output))
# No need to manually triger udev to run FW updater here.
# Previous FW updating process will reset SiS after it finish.
# Wait for fw updater to finish.
time.sleep(UPDATER_WAIT_TIME)
# Try flash the new firmware, should detect same fw version.
expect_output = 'The device has the same FW as system'
output, succeed = self.flash_fw(self.new_fw_path,
str_compare=expect_output)
self.log_file_obj.write('{}Log info for writing '
'new firmware{}\n'.format('-'*8, '-'*8))
self.log_file_obj.write(output)
if not succeed:
raise error.TestFail('Expect {} in output '
'but didn\'t find it.'.format(expect_output))