| # Copyright 2016 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. |
| |
| import logging |
| import os |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib import utils |
| from autotest_lib.server.cros.faft.firmware_test import FirmwareTest |
| |
| |
| class platform_Flashrom(FirmwareTest): |
| """ |
| Test flashrom works correctly by calling |
| chromeos-firmwareupdate --mode=factory. |
| """ |
| version = 1 |
| |
| |
| def initialize(self, host, cmdline_args): |
| # This test assume the system already have the latest RW from |
| # shellball. If you not sure, run chromeos-firmware --mode=factory. |
| # Device should have WP disable. |
| |
| # Parse arguments from command line |
| dict_args = utils.args_to_dict(cmdline_args) |
| super(platform_Flashrom, self).initialize(host, cmdline_args) |
| |
| def run_cmd(self, command, checkfor=''): |
| """ |
| Log and execute command and return the output. |
| |
| @param command: Command to execute on device. |
| @param checkfor: If not emmpty, fail test if checkfor not in output. |
| @returns the output of command. |
| """ |
| command = command + ' 2>&1' |
| logging.info('Execute %s', command) |
| output = self.faft_client.system.run_shell_command_get_output(command) |
| logging.info('Output >>> %s <<<', output) |
| if checkfor and checkfor not in '\n'.join(output): |
| raise error.TestFail('Expect %s in output of %s' % |
| (checkfor, '\n'.join(output))) |
| return output |
| |
| def _check_wp_disable(self): |
| """Check firmware is write protect disabled.""" |
| self.run_cmd('flashrom -p host --wp-status', checkfor='is disabled') |
| if self.faft_config.chrome_ec: |
| self.run_cmd('flashrom -p ec --wp-status', checkfor='is disabled') |
| if self.faft_config.chrome_usbpd: |
| self.run_cmd('flashrom -p ec:type=pd --wp-status', |
| checkfor='is disabled') |
| |
| def _get_region(self, fmap_filename, region): |
| """Get region start and size from fmap. |
| |
| @param fmap_filename: Path to dump of FMAP. |
| @param region: The region name. |
| @return tuple of start and size for the region. |
| """ |
| output = self.run_cmd('dump_fmap -p %s %s' % (fmap_filename, region)) |
| _, start, size = output[0].split() |
| return int(start), int(size) |
| |
| def run_once(self, dev_mode=True): |
| """Main test logic""" |
| # 1) Check SW WP is disabled. |
| self._check_wp_disable() |
| |
| # Output location on DUT. |
| # Set if you want to preserve output content for debug. |
| tmpdir = os.getenv('DUT_TMPDIR') |
| if not tmpdir: tmpdir = '/tmp' |
| |
| # 2) Erase RW section B. Needed CL 329549 starting with R51-7989.0.0. |
| # before this change -E erase everything. |
| self.run_cmd('flashrom -E -i RW_SECTION_B', 'SUCCESS') |
| |
| # 3) Reinstall RW B (Test flashrom) |
| self.run_cmd('chromeos-firmwareupdate --mode=factory', 'SUCCESS') |
| |
| # 4) Check that device can be rebooted. |
| self.switcher.mode_aware_reboot() |
| |
| # 5) Compare flash section B vs shellball section B |
| # 5.1) Extract shellball RW section B form the appropriate bios.bin |
| # found the firmware tarball on the DUT. |
| self.faft_client.updater.extract_shellball() |
| shball_bios = os.path.join( |
| self.faft_client.updater.get_work_path(), |
| self.faft_client.updater.get_bios_relative_path()) |
| # Temp file to store a section read from the chip. |
| shball_rw_b = os.path.join( |
| self.faft_client.updater.get_work_path(), |
| 'shball_rw_b.bin') |
| logging.info('Using fw image %s, temp file %s', |
| shball_bios, shball_rw_b) |
| |
| # Extract FMAP |
| fmap = os.path.join(tmpdir, 'fmap.bin') |
| self.run_cmd('flashrom -r -i FMAP:%s' % fmap, 'SUCCESS') |
| |
| # Extract RW B, offset detail |
| # Figure out section B start byte and size. |
| (Bstart, Blen) = self._get_region(fmap, 'RW_SECTION_B') |
| self.run_cmd('dd bs=1 skip=%d count=%d if=%s of=%s 2>&1' |
| % (Bstart, Blen, shball_bios, shball_rw_b), '%d bytes' % Blen) |
| |
| # 5.2) Extract flash RW section B. |
| # skylake cannot read only section B, see http://crosbug.com/p/52061 |
| rw_b2 = os.path.join(tmpdir, 'rw_b2.bin') |
| self.run_cmd('flashrom -r -i RW_SECTION_B:%s' % rw_b2, 'SUCCESS') |
| |
| # 5.3) Compare output of 5.1 vs 5.2 |
| result_output = self.run_cmd('cmp %s %s' % (shball_rw_b, rw_b2)) |
| logging.info('cmp %s %s == %s', shball_rw_b, rw_b2, result_output) |
| |
| # 6) Report result. |
| if ''.join(result_output) != '': |
| raise error.TestFail('Mismatch between %s and %s' % (shball_rw_b, rw_b2)) |