# Copyright (c) 2019 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 random import time from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.firmware_test import FirmwareTest # Serial number cannot contain vowels after the first character, so don't allow # any vowels in this test. VALID_CHARS = "BCDFGHJKLMNPQRSTVWXYZ0123456789" class firmware_SetSerialNumber(FirmwareTest): """ Servo based test to set serial number in firmware. Test that setting the serial number in firmware during an onsite RMA works. Mainboards for onsite RMA will have WP# asserted, flash WP bit cleared, the serial_number in VPD set to all spaces, and be in dev mode. After the serial number is set in firmware flash write protect will be enabled and the device will be in normal mode. """ version = 1 def start_serial_number_prompt(self): """Repeatedly press ctrl-s to bring up serial number prompt.""" logging.info("Pressing Ctrl-S.") timeout = time.time() + (self.faft_config.firmware_screen) while time.time() < timeout: self.servo.set_nocheck('ctrl_s', 'tab') time.sleep(1) def generate_serial_number_string(self): """Generate a valid serial number based on config""" return ''.join(random.choice(VALID_CHARS) for _ in range(self.faft_config.serial_number_length)) def send_string(self, keys): """Send a string over a servo""" for key in keys.lower(): self.servo.set_nocheck('arb_key_config', key) self.servo.set_nocheck('arb_key', 'tab') def initialize(self, host, cmdline_args): super(firmware_SetSerialNumber, self).initialize(host, cmdline_args) if self.faft_config.serial_number_length == 0: raise error.TestNAError("This test is only valid on devices where " "serial number can be set in firmware.") # This test is run on developer mode only. self.switcher.setup_mode('dev') # Disable fw wp to clear VPD value self.set_hardware_write_protect(False) self.faft_client.system.run_shell_command_get_output( 'flashrom -p host --wp-disable') self.faft_client.system.run_shell_command_get_output( 'vpd -i RO_VPD -s serial_number="%s"' % (' ' * self.faft_config.serial_number_length) ) self.set_hardware_write_protect(True) def run_once(self): """Run the test""" serial_number = self.generate_serial_number_string() logging.info("Setting serial number to '%s'.", serial_number) self.switcher.simple_reboot() if not self.faft_config.rma_entered_automatically: self.start_serial_number_prompt() else: time.sleep(self.faft_config.firmware_screen) self.send_string(serial_number) # Press enter on set self.servo.enter_key() # Press enter on confirm self.servo.enter_key() self.switcher.wait_for_client() # Check that device is no longer in dev mode self.checkers.mode_checker('normal') # Check that serial_number is correctly set result = self.faft_client.system.run_shell_command_get_output( 'vpd -i RO_VPD -g serial_number')[0] if result != serial_number: raise error.TestFail("Expected serial number '%s' but got '%s'" % ( serial_number, result)) # Check that write protect is correctly set result = self.faft_client.system.run_shell_command_get_output( 'flashrom -p host --wp-status') result = '\n'.join(result) if ('is disabled' in result or 'start=0x00000000' in result or 'len=0x00000000' in result): raise error.TestFail('Expected write protection to be enabled ' 'but output was:\n\n%s' % result) def cleanup(self): self.servo.set_nocheck('fw_wp_state', 'reset') super(firmware_SetSerialNumber, self).cleanup()