• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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
5import logging
6import os
7
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.common_lib import utils
10from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
11
12
13class platform_Flashrom(FirmwareTest):
14    """
15    Test flashrom works correctly by calling
16    chromeos-firmwareupdate --mode=factory.
17    """
18    version = 1
19
20
21    def initialize(self, host, cmdline_args):
22        # This test assume the system already have the latest RW from
23        # shellball.  If you not sure, run chromeos-firmware --mode=factory.
24        # Device should have WP disable.
25
26        # Parse arguments from command line
27        dict_args = utils.args_to_dict(cmdline_args)
28        super(platform_Flashrom, self).initialize(host, cmdline_args)
29
30    def run_cmd(self, command, checkfor=''):
31        """
32        Log and execute command and return the output.
33
34        @param command: Command to execute on device.
35        @param checkfor: If not emmpty, fail test if checkfor not in output.
36        @returns the output of command.
37        """
38        command = command + ' 2>&1'
39        logging.info('Execute %s', command)
40        output = self.faft_client.system.run_shell_command_get_output(command)
41        logging.info('Output >>> %s <<<', output)
42        if checkfor and checkfor not in '\n'.join(output):
43            raise error.TestFail('Expect %s in output of %s' %
44                                 (checkfor, '\n'.join(output)))
45        return output
46
47    def _check_wp_disable(self):
48        """Check firmware is write protect disabled."""
49        self.run_cmd('flashrom -p host --wp-status', checkfor='is disabled')
50        if self.faft_config.chrome_ec:
51            self.run_cmd('flashrom -p ec --wp-status', checkfor='is disabled')
52        if self.faft_config.chrome_usbpd:
53            self.run_cmd('flashrom -p ec:type=pd --wp-status',
54                         checkfor='is disabled')
55
56    def _get_region(self, fmap_filename, region):
57        """Get region start and size from fmap.
58
59        @param fmap_filename: Path to dump of FMAP.
60        @param region: The region name.
61        @return tuple of start and size for the region.
62        """
63        output = self.run_cmd('dump_fmap -p %s %s' % (fmap_filename, region))
64        _, start, size = output[0].split()
65        return int(start), int(size)
66
67    def run_once(self, dev_mode=True):
68        """Main test logic"""
69        # 1) Check SW WP is disabled.
70        self._check_wp_disable()
71
72        # Output location on DUT.
73        # Set if you want to preserve output content for debug.
74        tmpdir = os.getenv('DUT_TMPDIR')
75        if not tmpdir: tmpdir = '/tmp'
76
77        # 2) Erase RW section B.  Needed CL 329549 starting with R51-7989.0.0.
78        # before this change -E erase everything.
79        self.run_cmd('flashrom -E -i RW_SECTION_B', 'SUCCESS')
80
81        # 3) Reinstall RW B (Test flashrom)
82        self.run_cmd('chromeos-firmwareupdate --mode=factory', 'SUCCESS')
83
84        # 4) Check that device can be rebooted.
85        self.switcher.mode_aware_reboot()
86
87        # 5) Compare flash section B vs shellball section B
88        # 5.1) Extract shellball RW section B form the appropriate bios.bin
89        # found the firmware tarball on the DUT.
90        self.faft_client.updater.extract_shellball()
91        shball_bios = os.path.join(
92            self.faft_client.updater.get_work_path(),
93            self.faft_client.updater.get_bios_relative_path())
94        # Temp file to store a section read from the chip.
95        shball_rw_b = os.path.join(
96            self.faft_client.updater.get_work_path(),
97            'shball_rw_b.bin')
98        logging.info('Using fw image %s, temp file %s',
99                     shball_bios, shball_rw_b)
100
101        # Extract FMAP
102        fmap = os.path.join(tmpdir, 'fmap.bin')
103        self.run_cmd('flashrom -r -i FMAP:%s' % fmap, 'SUCCESS')
104
105        # Extract RW B, offset detail
106        # Figure out section B start byte and size.
107        (Bstart, Blen) = self._get_region(fmap, 'RW_SECTION_B')
108        self.run_cmd('dd bs=1 skip=%d count=%d if=%s of=%s 2>&1'
109                     % (Bstart, Blen, shball_bios, shball_rw_b), '%d bytes' % Blen)
110
111        # 5.2) Extract flash RW section B.
112        # skylake cannot read only section B, see http://crosbug.com/p/52061
113        rw_b2 = os.path.join(tmpdir, 'rw_b2.bin')
114        self.run_cmd('flashrom -r -i RW_SECTION_B:%s' % rw_b2, 'SUCCESS')
115
116        # 5.3) Compare output of 5.1 vs 5.2
117        result_output = self.run_cmd('cmp %s %s' % (shball_rw_b, rw_b2))
118        logging.info('cmp %s %s == %s', shball_rw_b, rw_b2, result_output)
119
120        # 6) Report result.
121        if ''.join(result_output) != '':
122            raise error.TestFail('Mismatch between %s and %s' % (shball_rw_b, rw_b2))
123