• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 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 re
7import time
8
9from autotest_lib.client.common_lib import error, utils
10from autotest_lib.client.common_lib.cros import cr50_utils
11from autotest_lib.server.cros import filesystem_util
12from autotest_lib.server.cros.faft.cr50_test import Cr50Test
13
14
15class firmware_Cr50GetName(Cr50Test):
16    """Verify cr50-get-name.sh
17
18    Verify cr50-get-name sets the correct board id and flags based on the
19    given stage.
20    """
21    version = 1
22
23    GET_NAME_SCRIPT = '/usr/share/cros/cr50-get-name.sh'
24    # This translates to 'TEST'
25    TEST_BRAND = 0x54455354
26    MAX_VAL = 0xffffffff
27
28
29    def initialize(self, host, cmdline_args, full_args={}):
30        # Restore the original image, rlz code, and board id during cleanup.
31        super(firmware_Cr50GetName, self).initialize(host, cmdline_args,
32            full_args, restore_cr50_image=True, restore_cr50_board_id=True)
33
34        if not self.host.path_exists(self.GET_NAME_SCRIPT):
35            raise error.TestNAError('Device does not have "cr50-get-name"')
36
37        efi_path = self.get_saved_eraseflashinfo_image_path()
38
39        filesystem_util.make_rootfs_writable(self.host)
40        cr50_utils.InstallImage(self.host, efi_path, cr50_utils.CR50_PROD)
41        cr50_utils.InstallImage(self.host, efi_path, cr50_utils.CR50_PREPVT)
42
43        # Update to the eraseflashinfo image so we can erase the board id after
44        # we set it. This test is verifying cr50-get-name, so it is ok if cr50
45        # is running a non-prod image.
46        self.cr50_update(self.get_saved_dbg_image_path())
47        self.cr50_update(efi_path, rollback=True)
48
49        # Stop trunksd so it wont interfere with the update
50        cr50_utils.StopTrunksd(self.host)
51
52        # Get the current cr50 update messages. The test will keep track of the
53        # last message and separate the current output from actual test results.
54        self.get_result()
55
56
57    def cleanup(self):
58        """Reset the DUT to restore trunksd."""
59        try:
60            self.host.reset_via_servo()
61        finally:
62            super(firmware_Cr50GetName, self).cleanup()
63
64
65    def get_result(self):
66        """Return the new cr50 update messages from /var/log/messages"""
67        # Get the cr50 messages
68        result = self.host.run('grep cr50 /var/log/messages').stdout.strip()
69
70        if hasattr(self, '_last_message'):
71            result = result.rsplit(self._last_message, 1)[-1]
72
73        # Save the last line. It will be used to separate the current results
74        # from later runs.
75        self._last_message = result.rsplit('\n', 1)[-1]
76        logging.debug('last cr50 update message: "%s"', self._last_message)
77        return result
78
79
80    def get_expected_result_re(self, brand, flags, erased):
81        """Return the expected update message re given the test flags
82
83        Args:
84            brand: The board id value to test.
85            flags: The flag value to test.
86            erased: True if the board id is erased
87
88        Returns:
89            A string with info that must be found in /var/log/messages for valid
90            update results.
91        """
92        expected_result = []
93
94        if erased:
95            board_id = 'ffffffff:ffffffff:ffffffff'
96            # If the board id is erased, the device should update to the prod
97            # image.
98            ext = 'prod'
99            expected_result.append('board ID is erased using prod image')
100        else:
101            board_id = '%08x:%08x:%08x' % (brand, brand ^ self.MAX_VAL, flags)
102            ext = 'prepvt' if flags & 0x10 else 'prod'
103
104        flag_str = board_id.rsplit(':', 1)[-1]
105
106        expected_result.append("board_id: '%s' board_flags: '0x%s', extension: "
107                "'%s'" % (board_id, flag_str, ext))
108        expected_result.append('hashing /opt/google/cr50/firmware/cr50.bin.%s' %
109                ext)
110        return '(%s)' % '\n.*'.join(expected_result)
111
112
113    def check_result(self, brand, flags, erased):
114        """Verify the expected result string is found in the update messages
115
116        Args:
117            brand: The board id value to test.
118            flags: The flag value to test.
119            erased: True if the board id is erased
120
121        Raises:
122            TestFail if the expected result message did not match the update
123            output
124        """
125        expected_result_re = self.get_expected_result_re(brand, flags, erased)
126        result = self.get_result()
127        match = re.search(expected_result_re, result)
128
129        logging.debug('EXPECT: %s', expected_result_re)
130        logging.debug('GOT: %s', result)
131
132        if not match:
133            raise error.TestFail('Unexpected result during update with %s' %
134                    ('erased board id' if erased else '%x:%x' % (brand, flags)))
135
136        logging.info('FOUND UPDATE RESULT:\n%s', match.groups()[0])
137
138
139    def cr50_update_is_running(self):
140        """Returns True if cr50-update is running on the host"""
141        time.sleep(1)
142        status = self.host.run('status cr50-update').stdout
143        logging.info('cr50-update status: %s', status)
144        return 'running' in status
145
146
147    def run_update(self, brand, flags, clear_bid=False):
148        """Set the board id then run cr50-update
149
150        Args:
151            brand: The board id int to test.
152            flags: The flag int to test.
153            clear_bid: True if the board id should be erased and not reset.
154        """
155        if not self.cr50.eraseflashinfo():
156            raise error.TestError('Unable to erase the board id')
157
158        if not clear_bid:
159            cr50_utils.SetChipBoardId(self.host, brand, flags)
160
161        # Get the current cr50 update messages. The test will keep track of the
162        # last message and separate the current output from actual test results.
163        self.get_result()
164        # Run the update script script
165        self.host.run('start cr50-update')
166        utils.wait_for_value(self.cr50_update_is_running, expected_value=False,
167                             timeout_sec=30)
168
169        # Make sure cr50 used the right image.
170        self.check_result(brand, flags, clear_bid)
171
172
173    def run_once(self):
174        """Verify cr50-get-name.sh"""
175        # Test the MP flags
176        self.run_update(self.TEST_BRAND, 0x7f00)
177
178        # Test the pre-PVT flags
179        self.run_update(self.TEST_BRAND, 0x7f10)
180
181        # Erase the board id
182        self.run_update(0, 0, clear_bid=True)
183
184        # Make sure the script can tell the difference between an erased board
185        # id and one set to 0xffffffff:0xffffffff.
186        self.run_update(self.MAX_VAL, self.MAX_VAL)
187