| # Copyright 2018 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 re |
| import time |
| |
| from autotest_lib.client.common_lib import error, utils |
| from autotest_lib.client.common_lib.cros import cr50_utils |
| from autotest_lib.server.cros import filesystem_util |
| from autotest_lib.server.cros.faft.cr50_test import Cr50Test |
| |
| |
| class firmware_Cr50GetName(Cr50Test): |
| """Verify cr50-get-name.sh |
| |
| Verify cr50-get-name sets the correct board id and flags based on the |
| given stage. |
| """ |
| version = 1 |
| |
| GET_NAME_SCRIPT = '/usr/share/cros/cr50-get-name.sh' |
| # This translates to 'TEST' |
| TEST_BRAND = 0x54455354 |
| MAX_VAL = 0xffffffff |
| |
| |
| def initialize(self, host, cmdline_args, full_args={}): |
| # Restore the original image, rlz code, and board id during cleanup. |
| super(firmware_Cr50GetName, self).initialize(host, cmdline_args, |
| full_args, restore_cr50_image=True, restore_cr50_board_id=True) |
| |
| if not self.host.path_exists(self.GET_NAME_SCRIPT): |
| raise error.TestNAError('Device does not have "cr50-get-name"') |
| |
| efi_path = self.get_saved_eraseflashinfo_image_path() |
| |
| filesystem_util.make_rootfs_writable(self.host) |
| cr50_utils.InstallImage(self.host, efi_path, cr50_utils.CR50_PROD) |
| cr50_utils.InstallImage(self.host, efi_path, cr50_utils.CR50_PREPVT) |
| |
| # Update to the eraseflashinfo image so we can erase the board id after |
| # we set it. This test is verifying cr50-get-name, so it is ok if cr50 |
| # is running a non-prod image. |
| self.cr50_update(self.get_saved_dbg_image_path()) |
| self.cr50_update(efi_path, rollback=True) |
| |
| # Stop trunksd so it wont interfere with the update |
| cr50_utils.StopTrunksd(self.host) |
| |
| # Get the current cr50 update messages. The test will keep track of the |
| # last message and separate the current output from actual test results. |
| self.get_result() |
| |
| |
| def cleanup(self): |
| """Reset the DUT to restore trunksd.""" |
| try: |
| self.host.reset_via_servo() |
| finally: |
| super(firmware_Cr50GetName, self).cleanup() |
| |
| |
| def get_result(self): |
| """Return the new cr50 update messages from /var/log/messages""" |
| # Get the cr50 messages |
| result = self.host.run('grep cr50 /var/log/messages').stdout.strip() |
| |
| if hasattr(self, '_last_message'): |
| result = result.rsplit(self._last_message, 1)[-1] |
| |
| # Save the last line. It will be used to separate the current results |
| # from later runs. |
| self._last_message = result.rsplit('\n', 1)[-1] |
| logging.debug('last cr50 update message: "%s"', self._last_message) |
| return result |
| |
| |
| def get_expected_result_re(self, brand, flags, erased): |
| """Return the expected update message re given the test flags |
| |
| Args: |
| brand: The board id value to test. |
| flags: The flag value to test. |
| erased: True if the board id is erased |
| |
| Returns: |
| A string with info that must be found in /var/log/messages for valid |
| update results. |
| """ |
| expected_result = [] |
| |
| if erased: |
| board_id = 'ffffffff:ffffffff:ffffffff' |
| # If the board id is erased, the device should update to the prod |
| # image. |
| ext = 'prod' |
| expected_result.append('board ID is erased using prod image') |
| else: |
| board_id = '%08x:%08x:%08x' % (brand, brand ^ self.MAX_VAL, flags) |
| ext = 'prepvt' if flags & 0x10 else 'prod' |
| |
| flag_str = board_id.rsplit(':', 1)[-1] |
| |
| expected_result.append("board_id: '%s' board_flags: '0x%s', extension: " |
| "'%s'" % (board_id, flag_str, ext)) |
| expected_result.append('hashing /opt/google/cr50/firmware/cr50.bin.%s' % |
| ext) |
| return '(%s)' % '\n.*'.join(expected_result) |
| |
| |
| def check_result(self, brand, flags, erased): |
| """Verify the expected result string is found in the update messages |
| |
| Args: |
| brand: The board id value to test. |
| flags: The flag value to test. |
| erased: True if the board id is erased |
| |
| Raises: |
| TestFail if the expected result message did not match the update |
| output |
| """ |
| expected_result_re = self.get_expected_result_re(brand, flags, erased) |
| result = self.get_result() |
| match = re.search(expected_result_re, result) |
| |
| logging.debug('EXPECT: %s', expected_result_re) |
| logging.debug('GOT: %s', result) |
| |
| if not match: |
| raise error.TestFail('Unexpected result during update with %s' % |
| ('erased board id' if erased else '%x:%x' % (brand, flags))) |
| |
| logging.info('FOUND UPDATE RESULT:\n%s', match.groups()[0]) |
| |
| |
| def cr50_update_is_running(self): |
| """Returns True if cr50-update is running on the host""" |
| time.sleep(1) |
| status = self.host.run('status cr50-update').stdout |
| logging.info('cr50-update status: %s', status) |
| return 'running' in status |
| |
| |
| def run_update(self, brand, flags, clear_bid=False): |
| """Set the board id then run cr50-update |
| |
| Args: |
| brand: The board id int to test. |
| flags: The flag int to test. |
| clear_bid: True if the board id should be erased and not reset. |
| """ |
| if not self.cr50.eraseflashinfo(): |
| raise error.TestError('Unable to erase the board id') |
| |
| if not clear_bid: |
| cr50_utils.SetChipBoardId(self.host, brand, flags) |
| |
| # Get the current cr50 update messages. The test will keep track of the |
| # last message and separate the current output from actual test results. |
| self.get_result() |
| # Run the update script script |
| self.host.run('start cr50-update') |
| utils.wait_for_value(self.cr50_update_is_running, expected_value=False, |
| timeout_sec=30) |
| |
| # Make sure cr50 used the right image. |
| self.check_result(brand, flags, clear_bid) |
| |
| |
| def run_once(self): |
| """Verify cr50-get-name.sh""" |
| # Test the MP flags |
| self.run_update(self.TEST_BRAND, 0x7f00) |
| |
| # Test the pre-PVT flags |
| self.run_update(self.TEST_BRAND, 0x7f10) |
| |
| # Erase the board id |
| self.run_update(0, 0, clear_bid=True) |
| |
| # Make sure the script can tell the difference between an erased board |
| # id and one set to 0xffffffff:0xffffffff. |
| self.run_update(self.MAX_VAL, self.MAX_VAL) |