1# Copyright (c) 2019 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 random 7import time 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 11 12# Serial number cannot contain vowels after the first character, so don't allow 13# any vowels in this test. 14VALID_CHARS = "BCDFGHJKLMNPQRSTVWXYZ0123456789" 15 16class firmware_SetSerialNumber(FirmwareTest): 17 """ 18 Servo based test to set serial number in firmware. 19 20 Test that setting the serial number in firmware during an onsite RMA works. 21 Mainboards for onsite RMA will have WP# asserted, flash WP bit cleared, 22 the serial_number in VPD set to all spaces, and be in dev mode. After the 23 serial number is set in firmware flash write protect will be enabled and 24 the device will be in normal mode. 25 """ 26 version = 1 27 28 def start_serial_number_prompt(self): 29 """Repeatedly press ctrl-s to bring up serial number prompt.""" 30 logging.info("Pressing Ctrl-S.") 31 timeout = time.time() + (self.faft_config.firmware_screen) 32 while time.time() < timeout: 33 self.servo.set_nocheck('ctrl_s', 'tab') 34 time.sleep(1) 35 36 def generate_serial_number_string(self): 37 """Generate a valid serial number based on config""" 38 return ''.join(random.choice(VALID_CHARS) 39 for _ in range(self.faft_config.serial_number_length)) 40 41 def send_string(self, keys): 42 """Send a string over a servo""" 43 for key in keys.lower(): 44 self.servo.set_nocheck('arb_key_config', key) 45 self.servo.set_nocheck('arb_key', 'tab') 46 47 def initialize(self, host, cmdline_args): 48 super(firmware_SetSerialNumber, self).initialize(host, cmdline_args) 49 50 if self.faft_config.serial_number_length == 0: 51 raise error.TestNAError("This test is only valid on devices where " 52 "serial number can be set in firmware.") 53 54 # This test is run on developer mode only. 55 self.switcher.setup_mode('dev') 56 57 # Disable fw wp to clear VPD value 58 self.set_hardware_write_protect(False) 59 60 self.faft_client.system.run_shell_command_get_output( 61 'flashrom -p host --wp-disable') 62 63 self.faft_client.system.run_shell_command_get_output( 64 'vpd -i RO_VPD -s serial_number="%s"' % 65 (' ' * self.faft_config.serial_number_length) 66 ) 67 68 self.set_hardware_write_protect(True) 69 70 def run_once(self): 71 """Run the test""" 72 serial_number = self.generate_serial_number_string() 73 logging.info("Setting serial number to '%s'.", serial_number) 74 75 self.switcher.simple_reboot() 76 if not self.faft_config.rma_entered_automatically: 77 self.start_serial_number_prompt() 78 else: 79 time.sleep(self.faft_config.firmware_screen) 80 self.send_string(serial_number) 81 # Press enter on set 82 self.servo.enter_key() 83 # Press enter on confirm 84 self.servo.enter_key() 85 self.switcher.wait_for_client() 86 87 # Check that device is no longer in dev mode 88 self.checkers.mode_checker('normal') 89 90 # Check that serial_number is correctly set 91 result = self.faft_client.system.run_shell_command_get_output( 92 'vpd -i RO_VPD -g serial_number')[0] 93 94 if result != serial_number: 95 raise error.TestFail("Expected serial number '%s' but got '%s'" % ( 96 serial_number, result)) 97 98 # Check that write protect is correctly set 99 result = self.faft_client.system.run_shell_command_get_output( 100 'flashrom -p host --wp-status') 101 102 result = '\n'.join(result) 103 104 if ('is disabled' in result or 105 'start=0x00000000' in result or 106 'len=0x00000000' in result): 107 raise error.TestFail('Expected write protection to be enabled ' 108 'but output was:\n\n%s' % result) 109 110 def cleanup(self): 111 self.servo.set_nocheck('fw_wp_state', 'reset') 112 super(firmware_SetSerialNumber, self).cleanup() 113