Home | History | Annotate | Download | only in firmware_FWupdate
      1 # Copyright 2015 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 
      5 import logging
      6 import os
      7 import shutil
      8 import tempfile
      9 
     10 from chromite.lib import remote_access
     11 from autotest_lib.client.common_lib import error
     12 from autotest_lib.client.common_lib import utils
     13 from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
     14 
     15 
     16 class firmware_FWupdate(FirmwareTest):
     17     """RO+RW firmware update using chromeos-firmware --mode=[recovery|factory]
     18 
     19     Setup Steps:
     20     1. Check the device is in normal mode for recovery or
     21        Check the device is in dev mode for factory
     22 
     23     Test Steps:
     24     2. extract shellball and repack with new bios.bin and ec.bin
     25     3. run --mode=recovery
     26     4. reboot
     27 
     28     Verification Steps:
     29     1. Step 3 should result into a success message
     30     2. Run crossystem and check fwid and ro_fwid should display the new bios
     31        firmware version string.
     32     4. Run ectool version to check ec version. The RO version and RW version
     33        strings should display new ec firmware strings.
     34     """
     35 
     36     version = 1
     37 
     38     SHELLBALL_ORG = '/usr/sbin/chromeos-firmwareupdate'
     39     SHELLBALL_COPY = '/home/root/chromeos-firmwareupdate'
     40 
     41     def initialize(self, host, cmdline_args):
     42         dict_args = utils.args_to_dict(cmdline_args)
     43         super(firmware_FWupdate, self).initialize(host, cmdline_args)
     44         if not set(('new_ec', 'new_bios')).issubset(set(dict_args)):
     45           raise error.TestError('Missing new_ec and/or new_bios argument')
     46         self.new_ec = dict_args['new_ec']
     47         self.new_bios = dict_args['new_bios']
     48         if not os.path.isfile(self.new_ec) or not os.path.isfile(self.new_bios):
     49           raise error.TestError('Failed to locate ec or bios file')
     50         self.new_pd = ''
     51         if 'new_pd' in dict_args:
     52           self.new_pd = dict_args['new_pd']
     53           if not os.path.isfile(self.new_pd):
     54             raise error.TestError('Failed to locate pd file')
     55         logging.info('EC=%s BIOS=%s PD=%s',
     56                      self.new_ec, self.new_bios, self.new_pd)
     57         self.mode = 'recovery'
     58         if 'mode' in dict_args:
     59           self.mode = dict_args['mode']
     60           if self.mode == 'recovery':
     61             self.switcher.setup_mode('normal')  # Set device to normal mode
     62           elif self.mode == 'factory':
     63             self.switcher.setup_mode('dev')   # Set device to dev mode
     64           else:
     65             raise error.TestError('Unknown mode:%s' % self.mode)
     66 
     67     def local_run_cmd(self, command):
     68         """Execute command on local system.
     69 
     70         @param command: shell command to be executed on local system.
     71         @returns command output.
     72         """
     73         logging.info('Execute %s', command)
     74         output = utils.system_output(command)
     75         logging.info('Output %s', output)
     76         return output
     77 
     78     def dut_run_cmd(self, command):
     79         """Execute command on DUT.
     80 
     81         @param command: shell command to be executed on DUT.
     82         @returns command output.
     83         """
     84         logging.info('Execute %s', command)
     85         output = self.faft_client.system.run_shell_command_get_output(command)
     86         logging.info('Output %s', output)
     87         return output
     88 
     89     def get_pd_version(self):
     90         """Get pd firmware version.
     91 
     92         @returns pd firmware version string if available.
     93         """
     94         if self.new_pd:
     95             return self.dut_run_cmd('mosys -k pd info')[0].split('"')[5]
     96         return ''
     97 
     98     def get_system_setup(self):
     99         """Get and return DUT system params.
    100 
    101         @returns DUT system params needed for this test.
    102         """
    103         return {
    104           'pd_version': self.get_pd_version(),
    105           'ec_version': self.faft_client.ec.get_version(),
    106           'mainfw_type':
    107             self.faft_client.system.get_crossystem_value('mainfw_type'),
    108           'ro_fwid':
    109             self.faft_client.system.get_crossystem_value('ro_fwid'),
    110           'fwid':
    111             self.faft_client.system.get_crossystem_value('fwid'),
    112         }
    113 
    114     def repack_shellball(self, hostname):
    115         """Repack DUT shellball and replace on DUT.
    116 
    117         @param hostname: hostname of DUT.
    118         """
    119         extract_dir = tempfile.mkdtemp(prefix='extract', dir='/tmp')
    120 
    121         self.dut_run_cmd('mkdir %s' % extract_dir)
    122         self.dut_run_cmd('cp %s %s' % (self.SHELLBALL_ORG, self.SHELLBALL_COPY))
    123         self.dut_run_cmd('%s --sb_extract %s' % (self.SHELLBALL_COPY,
    124                                                  extract_dir))
    125 
    126         dut_access = remote_access.RemoteDevice(hostname, username='root')
    127         self.dut_run_cmd('cp %s %s' % (self.SHELLBALL_ORG, self.SHELLBALL_COPY))
    128 
    129         # Replace bin files.
    130         target_file = '%s/%s' % (extract_dir, 'ec.bin')
    131         dut_access.CopyToDevice(self.new_ec, target_file, mode='scp')
    132         target_file = '%s/%s' % (extract_dir, 'bios.bin')
    133         dut_access.CopyToDevice(self.new_bios, target_file,  mode='scp')
    134 
    135         if self.new_pd:
    136           target_file = '%s/%s' % (extract_dir, 'pd.bin')
    137           dut_access.CopyToDevice(self.new_pd, target_file,  mode='scp')
    138 
    139         self.dut_run_cmd('%s --sb_repack %s' % (self.SHELLBALL_COPY,
    140                                                 extract_dir))
    141 
    142         # Call to "shar" in chromeos-firmwareupdate might fail and the repack
    143         # ignore failure and exit with 0 status (http://crosbug.com/p/33719).
    144         # Add additional check to ensure the repack is successful.
    145         command = 'tail -1 %s' % self.SHELLBALL_COPY
    146         output = self.dut_run_cmd(command)
    147         if 'exit 0' not in output:
    148           raise error.TestError('Failed to repack %s' % self.SHELLBALL_COPY)
    149 
    150     def get_fw_bin_version(self):
    151         """Get firmwware version from binary file.
    152 
    153         @returns verions for bios, ec, pd
    154         """
    155         bios_version = self.local_run_cmd('strings %s|grep Google_|head -1'
    156                                               % self.new_bios)
    157         ec_version = self.local_run_cmd('strings %s|head -1' % self.new_ec)
    158         pd_version = ''
    159         if self.new_pd:
    160             pd_version = self.local_run_cmd('strings %s|head -1' % self.new_pd)
    161         return (bios_version, ec_version, pd_version)
    162 
    163     def run_once(self, host):
    164         """Run chromeos-firmwareupdate with recovery or factory mode.
    165 
    166         @param host: host to run on
    167         """
    168         crossystem_before = self.get_system_setup()
    169         (bios_version, ec_version, pd_version) = self.get_fw_bin_version()
    170 
    171         # Repack shellball with new ec and bios.
    172         self.repack_shellball(host.hostname)
    173 
    174         # Flash DUT with new bios/ec.
    175         command = '%s --mode=%s' % (self.SHELLBALL_COPY, self.mode)
    176         self.dut_run_cmd(command)
    177         host.reboot()
    178 
    179         # Extract and verify DUT state.
    180         crossystem_after = self.get_system_setup()
    181         logging.info('crossystem BEFORE: %s', crossystem_before)
    182         logging.info('crossystem AFTER: %s', crossystem_after)
    183         logging.info('Expects bios %s', bios_version)
    184         logging.info('Expects ec %s', ec_version)
    185         logging.info('Expects pd %s', pd_version)
    186         assert bios_version == crossystem_after['fwid']
    187         assert bios_version == crossystem_after['ro_fwid']
    188         assert ec_version == crossystem_after['ec_version']
    189         assert pd_version == crossystem_after['pd_version']
    190