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 time 6 7from autotest_lib.client.common_lib import error 8from autotest_lib.client.common_lib.cros import cr50_utils 9from autotest_lib.server.cros.faft.cr50_test import Cr50Test 10 11 12class firmware_Cr50RejectUpdate(Cr50Test): 13 """Verify cr50 rejects certain updates.""" 14 version = 1 15 OLD_IMAGE_VER = '0.0.18' 16 # We dont care that it actually matches the device devid. It will be 17 # rejected before the update. This is just one that I picked from google 18 # storage 19 IMAGE_DEVID = '0x1000d059 0x04657208' 20 # No boards use the bid TEST. Use this image to verify cr50 rejects images 21 # with the wrong board id. 22 BID = 'TEST:0000ffff:0000ff00' 23 TEST_PATH = '/tmp/test_image.bin' 24 25 26 def initialize(self, host, cmdline_args, full_args): 27 """Initialize servo and download images""" 28 super(firmware_Cr50RejectUpdate, self).initialize(host, cmdline_args, 29 full_args, restore_cr50_state=True) 30 31 if not hasattr(self, 'cr50'): 32 raise error.TestNAError('Test can only be run on devices with ' 33 'access to the Cr50 console') 34 35 if 'DBG' in self.cr50.get_version(): 36 raise error.TestNAError('Update rules are wonky on DBG images') 37 38 if cr50_utils.GetChipBoardId(host) == cr50_utils.ERASED_CHIP_BID: 39 raise error.TestNAError('Set Cr50 board id to run test') 40 41 self.bid_path = self.download_cr50_debug_image(self.IMAGE_DEVID, 42 self.BID)[0] 43 self.old_path = self.download_cr50_release_image(self.OLD_IMAGE_VER)[0] 44 self.original_path = self.get_saved_cr50_original_path() 45 self.host = host 46 # Wait until cr50 can accept an update, so cr50 update rate limiting 47 # won't interfere with the test. 48 self.cr50.wait_until_update_is_allowed() 49 50 51 def try_update(self, arg, path, err=0, stdout='', wait=True): 52 """Run gsctool with the given image and args. Verify the result 53 54 Args: 55 arg: strings with the gsctool args 56 path: local path to the test image 57 err: The error number 58 stdout: a string that must be included in the cmd stdout 59 wait: Wait for cr50 to have been up for 60 seconds before attempting 60 the update. 61 62 Raises: 63 TestFail if there is an unexpected result. 64 """ 65 # Copy the image to the DUT 66 self.host.send_file(path, self.TEST_PATH) 67 68 # Wait for cr50 to have been up for 60 seconds, so it won't 69 # automatically reject the image. 70 if wait: 71 self.cr50.wait_until_update_is_allowed() 72 73 # Try to update 74 result = self.host.run('gsctool -a %s %s' % (arg, self.TEST_PATH), 75 ignore_status=True, ignore_timeout=True, timeout=60) 76 77 # Check the result 78 stderr = 'Error %d' % err 79 if err and stderr not in result.stderr: 80 raise error.TestFail('"%s" not in "%s"' % (stderr, result.stderr)) 81 if stdout and stdout not in result.stdout: 82 raise error.TestFail('"%s" not in "%s"' % (stdout, result.stdout)) 83 84 85 def run_once(self): 86 """Verify cr50 rejects certain updates""" 87 # Cr50 rejects a mismatched board id no matter what 88 self.try_update('-u', self.bid_path, err=12) 89 self.try_update('', self.bid_path, err=12) 90 91 # With the '-u' option cr50 rejects any images with old/same header 92 # with 'nothing to do' 93 self.try_update('-u', self.old_path, stdout='nothing to do') 94 self.try_update('-u', self.original_path, stdout='nothing to do') 95 96 # Without '-u' cr50 rejects old headers 97 self.try_update('', self.old_path, err=8) 98 99 # Cr50 will accept images with the same header version if -u is omitted. 100 # original_path is the image already on cr50, so this won't have any 101 # real effect. It will just reboot the device. 102 self.try_update('', self.original_path, stdout='image updated') 103 # After reboot, if the DUT hasn't responded within 45 seconds, it's not 104 # going to. 105 time.sleep(45) 106 if not self.host.is_up_fast(): 107 raise error.TestError('DUT did not respond') 108 # Wait for the host to respond to ping. Make sure it responded within 109 # 60 seconds. The whole point of this case is that cr50 will reject 110 # images in the first 60 seconds of boot, so it won't work if cr50 111 # has been up for a while. 112 if self.cr50.gettime() >= 60: 113 raise error.TestError('Cannot complete test. Took >60 seconds for ' 114 'DUT to come back online') 115 # After any reboot, cr50 will reject images for 60 seconds 116 self.try_update('', self.original_path, err=9, wait=False) 117