blob: 15b4a69b80153f9fda93f11a469860437442c9e5 [file] [log] [blame]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001# Copyright (c) 2011 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
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +08005import ctypes
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08006import logging
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +08007import os
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08008import re
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +08009import subprocess
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080010import time
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080011
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +080012from autotest_lib.client.bin import utils
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080013from autotest_lib.client.common_lib import error
J. Richard Barnette75487572013-03-08 12:47:50 -080014from autotest_lib.server import hosts
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +080015from autotest_lib.server.cros import vboot_constants as vboot
Vic Yangf93f7022012-10-31 09:40:36 +080016from autotest_lib.server.cros.faft_checkers import FAFTCheckers
Vic Yangebd6de62012-06-26 14:25:57 +080017from autotest_lib.server.cros.faft_client_attribute import FAFTClientAttribute
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +080018from autotest_lib.server.cros.faft_delay_constants import FAFTDelayConstants
J. Richard Barnette75487572013-03-08 12:47:50 -080019from autotest_lib.server.cros.servo import chrome_ec
Tom Wai-Hong Tam22b77302011-11-03 13:03:48 +080020from autotest_lib.server.cros.servo_test import ServoTest
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080021
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080022class FAFTSequence(ServoTest):
23 """
24 The base class of Fully Automated Firmware Test Sequence.
25
26 Many firmware tests require several reboot cycles and verify the resulted
27 system states. To do that, an Autotest test case should detailly handle
28 every action on each step. It makes the test case hard to read and many
29 duplicated code. The base class FAFTSequence is to solve this problem.
30
31 The actions of one reboot cycle is defined in a dict, namely FAFT_STEP.
32 There are four functions in the FAFT_STEP dict:
33 state_checker: a function to check the current is valid or not,
34 returning True if valid, otherwise, False to break the whole
35 test sequence.
36 userspace_action: a function to describe the action ran in userspace.
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +080037 reboot_action: a function to do reboot, default: sync_and_warm_reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080038 firmware_action: a function to describe the action ran after reboot.
39
Tom Wai-Hong Tam7c17ff22011-10-26 09:44:09 +080040 And configurations:
41 install_deps_after_boot: if True, install the Autotest dependency after
42 boot; otherwise, do nothing. It is for the cases of recovery mode
43 test. The test boots a USB/SD image instead of an internal image.
44 The previous installed Autotest dependency on the internal image
45 is lost. So need to install it again.
46
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080047 The default FAFT_STEP checks nothing in state_checker and does nothing in
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +080048 userspace_action and firmware_action. Its reboot_action is a hardware
49 reboot. You can change the default FAFT_STEP by calling
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080050 self.register_faft_template(FAFT_STEP).
51
52 A FAFT test case consists of several FAFT_STEP's, namely FAFT_SEQUENCE.
53 FAFT_SEQUENCE is an array of FAFT_STEP's. Any missing fields on FAFT_STEP
54 fall back to default.
55
56 In the run_once(), it should register and run FAFT_SEQUENCE like:
57 def run_once(self):
58 self.register_faft_sequence(FAFT_SEQUENCE)
59 self.run_faft_sequnce()
60
61 Note that in the last step, we only run state_checker. The
62 userspace_action, reboot_action, and firmware_action are not executed.
63
64 Attributes:
65 _faft_template: The default FAFT_STEP of each step. The actions would
66 be over-written if the registered FAFT_SEQUENCE is valid.
67 _faft_sequence: The registered FAFT_SEQUENCE.
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080068 _install_image_path: The URL or the path on the host to the Chrome OS
69 test image to be installed.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080070 _firmware_update: Boolean. True if firmware update needed after
71 installing the image.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080072 """
73 version = 1
74
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +080075 # Mapping of partition number of kernel and rootfs.
76 KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
77 ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
78 OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
79 OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
80
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +080081 CHROMEOS_MAGIC = "CHROMEOS"
82 CORRUPTED_MAGIC = "CORRUPTD"
83
Vadim Bendebury89ec24e2012-12-17 12:54:18 -080084 _ROOTFS_PARTITION_NUMBER = 3
85
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080086 _HTTP_PREFIX = 'http://'
87 _DEVSERVER_PORT = '8090'
88
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +080089 _faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080090 _faft_sequence = ()
91
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080092 _install_image_path = None
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080093 _firmware_update = False
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +080094
ctchang38ae4922012-09-03 17:01:16 +080095 _backup_firmware_sha = ()
96
Ismail Noorbasha07fdb612013-02-14 14:13:31 -080097
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +080098 # Class level variable, keep track the states of one time setup.
99 # This variable is preserved across tests which inherit this class.
100 _global_setup_done = {
101 'gbb_flags': False,
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800102 'reimage': False,
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800103 'usb_check': False,
104 }
Vic Yang54f70572012-10-19 17:05:26 +0800105
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800106 @classmethod
107 def check_setup_done(cls, label):
108 """Check if the given setup is done.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800109
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800110 Args:
111 label: The label of the setup.
112 """
113 return cls._global_setup_done[label]
114
115
116 @classmethod
117 def mark_setup_done(cls, label):
118 """Mark the given setup done.
119
120 Args:
121 label: The label of the setup.
122 """
123 cls._global_setup_done[label] = True
124
125
126 @classmethod
127 def unmark_setup_done(cls, label):
128 """Mark the given setup not done.
129
130 Args:
131 label: The label of the setup.
132 """
133 cls._global_setup_done[label] = False
Vic Yang54f70572012-10-19 17:05:26 +0800134
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800135
136 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
137 # Parse arguments from command line
138 args = {}
Ismail Noorbasha07fdb612013-02-14 14:13:31 -0800139 self.power_control = host.POWER_CONTROL_RPM
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800140 for arg in cmdline_args:
141 match = re.search("^(\w+)=(.+)", arg)
142 if match:
143 args[match.group(1)] = match.group(2)
Ismail Noorbasha07fdb612013-02-14 14:13:31 -0800144 if 'power_control' in args:
145 self.power_control = args['power_control']
146 if self.power_control not in host.POWER_CONTROL_VALID_ARGS:
147 raise error.TestError('Valid values for --args=power_control '
148 'are %s. But you entered wrong argument '
149 'as "%s".'
150 % (host.POWER_CONTROL_VALID_ARGS,
151 self.power_control))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800152 if 'image' in args:
153 self._install_image_path = args['image']
Vic Yang772df8a2012-10-31 10:10:49 +0800154 logging.info('Install Chrome OS test image path: %s',
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800155 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800156 if 'firmware_update' in args and args['firmware_update'].lower() \
157 not in ('0', 'false', 'no'):
158 if self._install_image_path:
159 self._firmware_update = True
160 logging.info('Also update firmware after installing.')
161 else:
162 logging.warning('Firmware update will not not performed '
163 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800164
165 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
166 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800167 if use_faft:
168 self.client_attr = FAFTClientAttribute(
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800169 self.faft_client.system.get_platform_name())
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800170 self.delay = FAFTDelayConstants(
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800171 self.faft_client.system.get_platform_name())
Vic Yangf93f7022012-10-31 09:40:36 +0800172 self.checkers = FAFTCheckers(self, self.faft_client)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800173
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800174 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800175 self.ec = chrome_ec.ChromeEC(self.servo)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800176
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800177 if not self.client_attr.has_keyboard:
178 # The environment variable USBKM232_UART_DEVICE should point
179 # to the USB-KM232 UART device.
180 if ('USBKM232_UART_DEVICE' not in os.environ or
181 not os.path.exists(os.environ['USBKM232_UART_DEVICE'])):
182 raise error.TestError('Must set a valid environment '
183 'variable USBKM232_UART_DEVICE.')
184
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700185 # Setting up key matrix mapping
186 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
187
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800188
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800189 def setup(self, ec_wp=None):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800190 """Autotest setup function."""
191 super(FAFTSequence, self).setup()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800192 self.register_faft_template({
193 'state_checker': (None),
194 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800195 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800196 'firmware_action': (None)
197 })
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800198 self.install_test_image(self._install_image_path, self._firmware_update)
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800199 self.record_system_info()
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800200 self.setup_gbb_flags()
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800201 self.setup_ec_write_protect(ec_wp)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800202
203
204 def cleanup(self):
205 """Autotest cleanup function."""
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800206 self.restore_ec_write_protect()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800207 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800208 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800209 super(FAFTSequence, self).cleanup()
210
211
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800212 def record_system_info(self):
213 """Record some critical system info to the attr keyval.
214
215 This info is used by generate_test_report and local_dash later.
216 """
217 self.write_attr_keyval({
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800218 'fw_version': self.faft_client.ec.get_version(),
219 'hwid': self.faft_client.system.get_crossystem_value('hwid'),
220 'fwid': self.faft_client.system.get_crossystem_value('fwid'),
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800221 })
222
223
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800224 def invalidate_firmware_setup(self):
225 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800226
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800227 This method is called when the firmware is re-flashed. It resets all
228 firmware related setup states so that the next test setup properly
229 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800230 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800231 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800232
233
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800234 def _retrieve_recovery_reason_from_trap(self):
235 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800236
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800237 Returns:
238 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800239 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800240 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800241 logging.info('Try to retrieve recovery reason...')
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800242 if self.servo.get_usbkey_direction() == 'dut':
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800243 self.wait_fw_screen_and_plug_usb()
244 else:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800245 self.servo.switch_usbkey('dut')
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800246
247 try:
248 self.wait_for_client(install_deps=True)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800249 lines = self.faft_client.system.run_shell_command_get_output(
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800250 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800251 recovery_reason = int(lines[0])
252 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800253 except AssertionError:
254 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800255 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800256
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800257
258 def _reset_client(self):
259 """Reset client to a workable state.
260
261 This method is called when the client is not responsive. It may be
262 caused by the following cases:
263 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
264 - corrupted firmware;
265 - corrutped OS image.
266 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800267 # DUT may halt on a firmware screen. Try cold reboot.
268 logging.info('Try cold reboot...')
269 self.cold_reboot()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800270 self.wait_for_client_offline()
271 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800272 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800273 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800274 return
275 except AssertionError:
276 pass
277
278 # DUT may be broken by a corrupted firmware. Restore firmware.
279 # We assume the recovery boot still works fine. Since the recovery
280 # code is in RO region and all FAFT tests don't change the RO region
281 # except GBB.
282 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800283 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800284 logging.info('Try restore the original firmware...')
285 if self.is_firmware_changed():
286 try:
287 self.restore_firmware()
288 return
289 except AssertionError:
290 logging.info('Restoring firmware doesn\'t help.')
291
292 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800293 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800294 logging.info('Try restore the OS image...')
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800295 self.faft_client.system.run_shell_command('chromeos-install --yes')
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800296 self.sync_and_warm_reboot()
297 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800298 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800299 try:
300 self.wait_for_client(install_deps=True)
301 logging.info('Successfully restore OS image.')
302 return
303 except AssertionError:
304 logging.info('Restoring OS image doesn\'t help.')
305
306
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800307 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800308 """Ensure client in recovery boot; reboot into it if necessary.
309
310 Raises:
311 error.TestError: if failed to boot the USB image.
312 """
313 # DUT works fine and is already in recovery boot, done.
314 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800315 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800316 return
317
318 logging.info('Try boot into USB image...')
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800319 self.servo.switch_usbkey('host')
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800320 self.enable_rec_mode_and_reboot()
321 self.wait_fw_screen_and_plug_usb()
322 try:
323 self.wait_for_client(install_deps=True)
324 except AssertionError:
325 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800326
327
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800328 def _restore_routine_from_timeout(self, next_step=None):
329 """A routine to try to restore the system from a timeout error.
330
331 This method is called when FAFT failed to connect DUT after reboot.
332
333 Args:
334 next_step: Optional, a FAFT_STEP dict of the next step, which is used
335 for diagnostic.
336
337 Raises:
338 error.TestFail: This exception is already raised, with a decription
339 why it failed.
340 """
341 next_checker_matched = False
342 if next_step is not None:
343 next_test = {}
344 next_test.update(self._faft_template)
345 next_test.update(next_step)
346
347 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
348 # identify if it is a network flaky.
349
350 recovery_reason = self._retrieve_recovery_reason_from_trap()
351 if next_step is not None and recovery_reason:
352 if self._call_action(next_test['state_checker']):
353 # Repluging the USB can pass the state_checker of the next step,
354 # meaning that the firmware failed to boot into USB directly.
355 next_checker_matched = True
356
357 # Reset client to a workable state.
358 self._reset_client()
359
360 # Raise the proper TestFail exception.
361 if next_checker_matched:
362 raise error.TestFail('Firmware failed to auto-boot USB in the '
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800363 'recovery boot (reason: %d)' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800364 elif recovery_reason:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800365 raise error.TestFail('Trapped in the recovery screen (reason: %d) '
366 'and timed out' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800367 else:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800368 raise error.TestFail('Timed out waiting for DUT reboot')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800369
370
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800371 def assert_test_image_in_usb_disk(self, usb_dev=None, install_shim=False):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800372 """Assert an USB disk plugged-in on servo and a test image inside.
373
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800374 Args:
375 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
376 If None, it is detected automatically.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800377 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800378
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800379 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800380 error.TestError: if USB disk not detected or not a test (install shim)
381 image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800382 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800383 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800384 return
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800385 if usb_dev:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800386 assert self.servo.get_usbkey_direction() == 'host'
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800387 else:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800388 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800389 usb_dev = self.servo.probe_host_usb_dev()
390 if not usb_dev:
391 raise error.TestError(
392 'An USB disk should be plugged in the servo board.')
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800393
394 rootfs = '%s%s' % (usb_dev, self._ROOTFS_PARTITION_NUMBER)
395 logging.info('usb dev is %s', usb_dev)
396 tmpd = self.servo.system_output('mktemp -d -t usbcheck.XXXX')
397 self.servo.system('mount -o ro %s %s' % (rootfs, tmpd))
398
399 if install_shim:
400 dir_list = self.servo.system_output('ls -a %s' %
401 os.path.join(tmpd, 'root'))
402 check_passed = '.factory_installer' in dir_list
403 else:
404 check_passed = self.servo.system_output(
405 'grep -i "CHROMEOS_RELEASE_DESCRIPTION=.*test" %s' %
406 os.path.join(tmpd, 'etc/lsb-release'),
407 ignore_status=True)
408 for cmd in ('umount %s' % rootfs, 'sync', 'rm -rf %s' % tmpd):
409 self.servo.system(cmd)
410
411 if not check_passed:
412 raise error.TestError(
413 'No Chrome OS %s found on the USB flash plugged into servo' %
414 'install shim' if install_shim else 'test')
415
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800416 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800417
418
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800419 def setup_usbkey(self, usbkey, host=None, install_shim=False):
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800420 """Setup the USB disk for the test.
421
422 It checks the setup of USB disk and a valid ChromeOS test image inside.
423 It also muxes the USB disk to either the host or DUT by request.
424
425 Args:
426 usbkey: True if the USB disk is required for the test, False if not
427 required.
428 host: Optional, True to mux the USB disk to host, False to mux it
429 to DUT, default to do nothing.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800430 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800431 """
432 if usbkey:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800433 self.assert_test_image_in_usb_disk(install_shim=install_shim)
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800434 elif host is None:
435 # USB disk is not required for the test. Better to mux it to host.
436 host = True
437
438 if host is True:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800439 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800440 elif host is False:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800441 self.servo.switch_usbkey('dut')
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800442
443
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800444 def get_server_address(self):
445 """Get the server address seen from the client.
446
447 Returns:
448 A string of the server address.
449 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800450 r = self.faft_client.system.run_shell_command_get_output(
451 "echo $SSH_CLIENT")
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800452 return r[0].split()[0]
453
454
Simran Basi741b5d42012-05-18 11:27:15 -0700455 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800456 """Install the test image specied by the path onto the USB and DUT disk.
457
458 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500459 recovery mode. Then runs 'chromeos-install' (and possible
460 chromeos-firmwareupdate') to install it to DUT disk.
461
462 Sample command line:
463
464 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
465 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
466 server/site_tests/firmware_XXXX/control
467
468 This test requires an automated recovery to occur while simulating
469 inserting and removing the usb key from the servo. To allow this the
470 following hardware setup is required:
471 1. servo2 board connected via servoflex.
472 2. USB key inserted in the servo2.
473 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
474 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800475
476 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800477 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800478 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800479
480 Raises:
481 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800482 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800483 if not image_path:
484 return
485
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800486 if self.check_setup_done('reimage'):
487 return
488
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800489 if image_path.startswith(self._HTTP_PREFIX):
490 # TODO(waihong@chromium.org): Add the check of the URL to ensure
491 # it is a test image.
492 devserver = None
493 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800494 elif self.servo.is_localhost():
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800495 # If servod is localhost, i.e. both servod and FAFT see the same
496 # file system, do nothing.
497 devserver = None
498 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800499 else:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800500 image_dir, image_base = os.path.split(image_path)
501 logging.info('Starting devserver to serve the image...')
502 # The following stdout and stderr arguments should not be None,
503 # even we don't use them. Otherwise, the socket of devserve is
504 # created as fd 1 (as no stdout) but it still thinks stdout is fd
505 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800506 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800507 '--archive_dir=%s' % image_dir,
508 '--port=%s' % self._DEVSERVER_PORT],
509 stdout=subprocess.PIPE,
510 stderr=subprocess.PIPE)
511 image_url = '%s%s:%s/static/archive/%s' % (
512 self._HTTP_PREFIX,
513 self.get_server_address(),
514 self._DEVSERVER_PORT,
515 image_base)
516
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800517 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800518 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800519 # devserver is a service running forever. If it is terminated,
520 # some error does happen.
521 if devserver.poll():
522 raise error.TestError('Starting devserver failed, '
523 'returning %d.' % devserver.returncode)
524
Vic Yang772df8a2012-10-31 10:10:49 +0800525 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800526 self.servo.image_to_servo_usb(image_url)
527
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800528 self.assert_test_image_in_usb_disk()
529
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800530 if devserver and devserver.poll() is None:
531 logging.info('Shutting down devserver...')
532 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500533
534 # DUT is powered off while imaging servo USB.
535 # Now turn it on.
536 self.servo.power_short_press()
537 self.wait_for_client()
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800538 self.servo.switch_usbkey('dut')
Mike Truty49153d82012-08-21 22:27:30 -0500539
540 install_cmd = 'chromeos-install --yes'
541 if firmware_update:
542 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800543 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500544
545 self.register_faft_sequence((
546 { # Step 1, request recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800547 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500548 'mainfw_type': ('developer', 'normal'),
549 }),
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800550 'userspace_action': (
551 self.faft_client.system.request_recovery_boot),
Mike Truty49153d82012-08-21 22:27:30 -0500552 'firmware_action': self.wait_fw_screen_and_plug_usb,
553 'install_deps_after_boot': True,
554 },
555 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800556 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500557 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800558 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500559 }),
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800560 'userspace_action': (self.faft_client.system.run_shell_command,
Mike Truty49153d82012-08-21 22:27:30 -0500561 install_cmd),
562 'reboot_action': self.cold_reboot,
563 'install_deps_after_boot': True,
564 },
565 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800566 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500567 'mainfw_type': ('developer', 'normal')
568 }),
569 },
570 ))
571 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800572
573 if firmware_update:
574 self.clear_saved_firmware()
575
Mike Truty49153d82012-08-21 22:27:30 -0500576 # 'Unplug' any USB keys in the servo from the dut.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800577 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800578 # Mark usb_check done so it won't check a test image in USB anymore.
579 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800580 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800581
582
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800583 def clear_set_gbb_flags(self, clear_mask, set_mask):
584 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800585
586 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800587 clear_mask: A mask of flags to be cleared.
588 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800589 """
Tom Wai-Hong Tamc1a569f2012-12-04 15:07:25 +0800590 gbb_flags = self.faft_client.bios.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800591 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
592
593 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800594 logging.info('Change the GBB flags from 0x%x to 0x%x.',
595 gbb_flags, new_flags)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800596 self.faft_client.system.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800597 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800598 self.faft_client.bios.reload()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800599 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800600 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800601 self.run_faft_step({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800602 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800603 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800604
605
Vic Yang772df8a2012-10-31 10:10:49 +0800606 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800607 """Check if current platform has required EC capabilities.
608
609 Args:
610 required_cap: A list containing required EC capabilities. Pass in
611 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800612 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800613
614 Returns:
615 True if requirements are met. Otherwise, False.
616 """
617 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800618 if not suppress_warning:
619 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800620 return False
621
Vic Yang772df8a2012-10-31 10:10:49 +0800622 if not required_cap:
623 return True
624
Vic Yang4d72cb62012-07-24 11:51:09 +0800625 for cap in required_cap:
626 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800627 if not suppress_warning:
628 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800629 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800630 return False
631
632 return True
633
634
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800635 def check_root_part_on_non_recovery(self, part):
636 """Check the partition number of root device and on normal/dev boot.
637
638 Returns:
639 True if the root device matched and on normal/dev boot;
640 otherwise, False.
641 """
Vic Yangf93f7022012-10-31 09:40:36 +0800642 return self.checkers.root_part_checker(part) and \
643 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800644 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800645 })
646
647
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800648 def _join_part(self, dev, part):
649 """Return a concatenated string of device and partition number.
650
651 Args:
652 dev: A string of device, e.g.'/dev/sda'.
653 part: A string of partition number, e.g.'3'.
654
655 Returns:
656 A concatenated string of device and partition number, e.g.'/dev/sda3'.
657
658 >>> seq = FAFTSequence()
659 >>> seq._join_part('/dev/sda', '3')
660 '/dev/sda3'
661 >>> seq._join_part('/dev/mmcblk0', '2')
662 '/dev/mmcblk0p2'
663 """
664 if 'mmcblk' in dev:
665 return dev + 'p' + part
666 else:
667 return dev + part
668
669
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800670 def copy_kernel_and_rootfs(self, from_part, to_part):
671 """Copy kernel and rootfs from from_part to to_part.
672
673 Args:
674 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800675 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800676 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800677 root_dev = self.faft_client.system.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800678 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800679 from_part, to_part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800680 self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800681 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
682 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800683 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800684 from_part, to_part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800685 self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800686 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
687 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800688
689
690 def ensure_kernel_boot(self, part):
691 """Ensure the request kernel boot.
692
693 If not, it duplicates the current kernel to the requested kernel
694 and sets the requested higher priority to ensure it boot.
695
696 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800697 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800698 """
Vic Yangf93f7022012-10-31 09:40:36 +0800699 if not self.checkers.root_part_checker(part):
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800700 if self.faft_client.kernel.diff_a_b():
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800701 self.copy_kernel_and_rootfs(
702 from_part=self.OTHER_KERNEL_MAP[part],
703 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800704 self.run_faft_step({
705 'userspace_action': (self.reset_and_prioritize_kernel, part),
706 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800707
708
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800709 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800710 """Set hardware write protect pin.
711
712 Args:
713 enable: True if asserting write protect pin. Otherwise, False.
714 """
715 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
716 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800717 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800718
719
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800720 def set_ec_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800721 """Set EC write protect status and reboot to take effect.
722
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800723 The write protect state is only activated if both hardware write
724 protect pin is asserted and software write protect flag is set.
Vic Yang416f2032012-08-28 10:18:03 +0800725 This method asserts/deasserts hardware write protect pin first, and
726 set corresponding EC software write protect flag.
727
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800728 If the device uses non-Chrome EC, set the software write protect via
729 flashrom.
730
731 If the device uses Chrome EC, a reboot is required for write protect
732 to take effect. Since the software write protect flag cannot be unset
733 if hardware write protect pin is asserted, we need to deasserted the
734 pin first if we are deactivating write protect. Similarly, a reboot
735 is required before we can modify the software flag.
736
Vic Yang416f2032012-08-28 10:18:03 +0800737 Args:
738 enable: True if activating EC write protect. Otherwise, False.
739 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800740 self.set_hardware_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800741 if self.client_attr.chrome_ec:
742 self.set_chrome_ec_write_protect_and_reboot(enable)
743 else:
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800744 self.faft_client.ec.set_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800745 self.sync_and_warm_reboot()
746
747
748 def set_chrome_ec_write_protect_and_reboot(self, enable):
749 """Set Chrome EC write protect status and reboot to take effect.
750
751 Args:
752 enable: True if activating EC write protect. Otherwise, False.
753 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800754 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800755 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800756 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800757 self.sync_and_ec_reboot()
758 else:
759 # Reboot after deasserting hardware write protect pin to deactivate
760 # write protect. And then remove software write protect flag.
761 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800762 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800763
764
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800765 def setup_ec_write_protect(self, ec_wp):
766 """Setup for EC write-protection.
767
768 It makes sure the EC in the requested write-protection state. If not, it
769 flips the state. Flipping the write-protection requires DUT reboot.
770
771 Args:
772 ec_wp: True to request EC write-protected; False to request EC not
773 write-protected; None to do nothing.
774 """
775 if ec_wp is None:
776 self._old_ec_wp = None
777 return
778 self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
779 if ec_wp != self._old_ec_wp:
780 logging.info('The test required EC is %swrite-protected. Reboot '
781 'and flip the state.', '' if ec_wp else 'not ')
782 self.run_faft_step({
Tom Wai-Hong Tamdd830982013-01-16 10:31:05 +0800783 'reboot_action': (self.set_ec_write_protect_and_reboot, ec_wp),
784 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800785 })
786
787
788 def restore_ec_write_protect(self):
789 """Restore the original EC write-protection."""
790 if self._old_ec_wp is None:
791 return
792 if not self.checkers.crossystem_checker(
793 {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
794 logging.info('Restore the original EC write protection and reboot.')
795 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800796 'reboot_action': (self.set_ec_write_protect_and_reboot,
Tom Wai-Hong Tamdd830982013-01-16 10:31:05 +0800797 self._old_ec_wp),
798 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800799 })
800
801
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800802 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800803 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800804 if not self.client_attr.has_keyboard:
805 logging.info('Running usbkm232-ctrld...')
806 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800807 else:
808 self.servo.ctrl_d()
809
810
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800811 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800812 """Send Ctrl-U key to DUT.
813
814 Raises:
815 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
816 on a no-build-in-keyboard device.
817 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800818 if not self.client_attr.has_keyboard:
819 logging.info('Running usbkm232-ctrlu...')
820 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800821 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
822 self.ec.key_down('<ctrl_l>')
823 self.ec.key_down('u')
824 self.ec.key_up('u')
825 self.ec.key_up('<ctrl_l>')
826 elif self.client_attr.has_keyboard:
827 raise error.TestError(
828 "Can't send Ctrl-U to DUT without using Chrome EC.")
829 else:
830 raise error.TestError(
831 "Should specify the ctrl_u_cmd argument.")
832
833
Vic Yang701a59e2013-05-02 05:10:22 +0800834 def press_enter(self, press_secs=None):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800835 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800836 if not self.client_attr.has_keyboard:
837 logging.info('Running usbkm232-enter...')
838 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800839 else:
Vic Yang701a59e2013-05-02 05:10:22 +0800840 self.servo.enter_key(press_secs)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800841
842
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800843 def wait_dev_screen_and_ctrl_d(self):
844 """Wait for firmware warning screen and press Ctrl-D."""
845 time.sleep(self.delay.dev_screen)
846 self.press_ctrl_d()
847
848
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800849 def wait_fw_screen_and_ctrl_d(self):
850 """Wait for firmware warning screen and press Ctrl-D."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800851 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800852 self.press_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800853
854
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800855 def wait_fw_screen_and_ctrl_u(self):
856 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800857 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800858 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800859
860
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800861 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
862 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800863 time.sleep(self.delay.firmware_screen)
Vic Yang701a59e2013-05-02 05:10:22 +0800864
865 # Pressing Enter for too long triggers a second key press.
866 # Let's press it without delay
867 self.press_enter(press_secs=0)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800868
869 # For Alex/ZGB, there is a dev warning screen in text mode.
870 # Skip it by pressing Ctrl-D.
871 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800872 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800873 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800874
875
Mike Truty49153d82012-08-21 22:27:30 -0500876 def wait_fw_screen_and_unplug_usb(self):
877 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800878 time.sleep(self.delay.load_usb)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800879 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800880 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500881
882
883 def wait_fw_screen_and_plug_usb(self):
884 """Wait for firmware warning screen and then unplug and plug the USB."""
885 self.wait_fw_screen_and_unplug_usb()
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800886 self.servo.switch_usbkey('dut')
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800887
888
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800889 def wait_fw_screen_and_press_power(self):
890 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800891 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800892 # While the firmware screen, the power button probing loop sleeps
893 # 0.25 second on every scan. Use the normal delay (1.2 second) for
894 # power press.
895 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800896
897
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800898 def wait_longer_fw_screen_and_press_power(self):
899 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800900 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800901 self.wait_fw_screen_and_press_power()
902
903
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800904 def wait_fw_screen_and_close_lid(self):
905 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800906 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800907 self.servo.lid_close()
908
909
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800910 def wait_longer_fw_screen_and_close_lid(self):
911 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800912 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800913 self.wait_fw_screen_and_close_lid()
914
915
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800916 def setup_gbb_flags(self):
917 """Setup the GBB flags for FAFT test."""
Tom Wai-Hong Tamee835002013-02-05 11:50:15 +0800918 if self.client_attr.gbb_version < 1.1:
919 logging.info('Skip modifying GBB on versions older than 1.1.')
920 return
921
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800922 if self.check_setup_done('gbb_flags'):
923 return
924
925 logging.info('Set proper GBB flags for test.')
926 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
927 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
928 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
929 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800930 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
931 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800932 self.mark_setup_done('gbb_flags')
933
934
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800935 def setup_tried_fwb(self, tried_fwb):
936 """Setup for fw B tried state.
937
938 It makes sure the system in the requested fw B tried state. If not, it
939 tries to do so.
940
941 Args:
942 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
943 """
944 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800945 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800946 logging.info(
947 'Firmware is not booted with tried_fwb. Reboot into it.')
948 self.run_faft_step({
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800949 'userspace_action': self.faft_client.system.set_try_fw_b,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800950 })
951 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800952 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800953 logging.info(
954 'Firmware is booted with tried_fwb. Reboot to clear.')
955 self.run_faft_step({})
956
957
Ismail Noorbasha07fdb612013-02-14 14:13:31 -0800958 def power_on(self):
959 """Switch DUT AC power on."""
960 self._client.power_on(self.power_control)
961
962
963 def power_off(self):
964 """Switch DUT AC power off."""
965 self._client.power_off(self.power_control)
966
967
968 def power_cycle(self):
969 """Power cycle DUT AC power."""
970 self._client.power_cycle(self.power_control)
971
972
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800973 def enable_rec_mode_and_reboot(self):
974 """Switch to rec mode and reboot.
975
976 This method emulates the behavior of the old physical recovery switch,
977 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
978 recovery mode, i.e. just press Power + Esc + Refresh.
979 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800980 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800981 # Reset twice to emulate a long recovery-key-combo hold.
982 cold_reset_num = 2 if self.client_attr.long_rec_combo else 1
Tom Wai-Hong Tam4c9684a2012-12-11 10:48:05 +0800983 for i in range(cold_reset_num):
984 if i:
985 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800986 # Cold reset to clear EC_IN_RW signal
987 self.servo.set('cold_reset', 'on')
988 time.sleep(self.delay.hold_cold_reset)
989 self.servo.set('cold_reset', 'off')
Vic Yang49799792013-05-01 08:17:02 +0800990 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800991 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800992 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800993 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800994 self.servo.power_short_press()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800995 elif self.client_attr.broken_rec_mode:
Ismail Noorbasha07fdb612013-02-14 14:13:31 -0800996 self.power_cycle()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800997 logging.info('Booting to recovery mode.')
998 self.servo.custom_recovery_mode()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800999 else:
1000 self.servo.enable_recovery_mode()
1001 self.cold_reboot()
Tom Wai-Hong Tamad4aaae2012-12-12 11:02:06 +08001002 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +08001003 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +08001004
1005
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +08001006 def enable_dev_mode_and_reboot(self):
1007 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +08001008 if self.client_attr.keyboard_dev:
1009 self.enable_keyboard_dev_mode()
1010 else:
1011 self.servo.enable_development_mode()
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001012 self.faft_client.system.run_shell_command(
Vic Yange7553162012-06-20 16:20:47 +08001013 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001014
1015
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +08001016 def enable_normal_mode_and_reboot(self):
1017 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +08001018 if self.client_attr.keyboard_dev:
1019 self.disable_keyboard_dev_mode()
1020 else:
1021 self.servo.disable_development_mode()
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001022 self.faft_client.system.run_shell_command(
Vic Yange7553162012-06-20 16:20:47 +08001023 'chromeos-firmwareupdate --mode tonormal && reboot')
1024
1025
1026 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
1027 """Wait for firmware screen and then switch into or out of dev mode.
1028
1029 Args:
1030 dev: True if switching into dev mode. Otherwise, False.
1031 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001032 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +08001033 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001034 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +08001035 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001036 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +08001037 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001038 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +08001039
1040
1041 def enable_keyboard_dev_mode(self):
1042 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +08001043 # Plug out USB disk for preventing recovery boot without warning
Vadim Bendeburye7bd9362012-12-19 14:35:20 -08001044 self.servo.switch_usbkey('host')
Vic Yange7553162012-06-20 16:20:47 +08001045 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +08001046 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001047 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001048 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +08001049
Gediminas Ramanauskas9da80f22012-11-14 12:59:43 -08001050 # TODO (crosbug.com/p/16231) remove this conditional completely if/when
1051 # issue is resolved.
1052 if self.client_attr.platform == 'Parrot':
1053 self.wait_for_client_offline()
1054 self.cold_reboot()
1055
Vic Yange7553162012-06-20 16:20:47 +08001056
1057 def disable_keyboard_dev_mode(self):
1058 logging.info("Disabling keyboard controlled developer mode")
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -08001059 if (not self.client_attr.chrome_ec and
1060 not self.client_attr.broken_rec_mode):
Vic Yang611dd852012-08-02 15:36:31 +08001061 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001062 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001063 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001064 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001065
1066
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001067 def setup_dev_mode(self, dev_mode):
1068 """Setup for development mode.
1069
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001070 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001071 tries to do so.
1072
1073 Args:
1074 dev_mode: True if requested in dev mode; False if normal mode.
1075 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001076 # Change the default firmware_action for dev mode passing the fw screen.
1077 self.register_faft_template({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +08001078 'firmware_action': (self.wait_dev_screen_and_ctrl_d if dev_mode
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001079 else None),
1080 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001081 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +08001082 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001083 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001084 logging.info('Dev switch is not on. Now switch it on.')
1085 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001086 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001087 'mainfw_type': 'developer'}):
1088 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001089 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001090 'userspace_action': None if self.client_attr.keyboard_dev
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001091 else (self.faft_client.system.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001092 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001093 'reboot_action': self.enable_keyboard_dev_mode if
1094 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001095 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001096 else:
Vic Yange7553162012-06-20 16:20:47 +08001097 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001098 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001099 logging.info('Dev switch is not off. Now switch it off.')
1100 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001101 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001102 'mainfw_type': 'normal'}):
1103 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001104 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001105 'userspace_action': None if self.client_attr.keyboard_dev
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001106 else (self.faft_client.system.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001107 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001108 'reboot_action': self.disable_keyboard_dev_mode if
1109 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001110 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001111
1112
Tom Wai-Hong Tam4c153fa2013-01-22 13:56:06 +08001113 def setup_rw_boot(self, section='a'):
1114 """Make sure firmware is in RW-boot mode.
1115
1116 If the given firmware section is in RO-boot mode, turn off the RO-boot
1117 flag and reboot DUT into RW-boot mode.
1118
1119 Args:
1120 section: A firmware section, either 'a' or 'b'.
1121 """
1122 flags = self.faft_client.bios.get_preamble_flags(section)
1123 if flags & vboot.PREAMBLE_USE_RO_NORMAL:
1124 flags = flags ^ vboot.PREAMBLE_USE_RO_NORMAL
1125 self.run_faft_step({
1126 'userspace_action': (self.faft_client.bios.set_preamble_flags,
1127 (section, flags))
1128 })
1129
1130
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001131 def setup_kernel(self, part):
1132 """Setup for kernel test.
1133
1134 It makes sure both kernel A and B bootable and the current boot is
1135 the requested kernel part.
1136
1137 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001138 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001139 """
1140 self.ensure_kernel_boot(part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001141 if self.faft_client.kernel.diff_a_b():
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001142 self.copy_kernel_and_rootfs(from_part=part,
1143 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001144 self.reset_and_prioritize_kernel(part)
1145
1146
1147 def reset_and_prioritize_kernel(self, part):
1148 """Make the requested partition highest priority.
1149
1150 This function also reset kerenl A and B to bootable.
1151
1152 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001153 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001154 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001155 root_dev = self.faft_client.system.get_root_dev()
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001156 # Reset kernel A and B to bootable.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001157 self.faft_client.system.run_shell_command(
1158 'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['a'], root_dev))
1159 self.faft_client.system.run_shell_command(
1160 'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['b'], root_dev))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001161 # Set kernel part highest priority.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001162 self.faft_client.system.run_shell_command('cgpt prioritize -i%s %s' %
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001163 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001164 # Safer to sync and wait until the cgpt status written to the disk.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001165 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001166 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001167
1168
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001169 def warm_reboot(self):
1170 """Request a warm reboot.
1171
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001172 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001173 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001174 # Use cold reset if the warm reset is broken.
1175 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001176 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1177 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001178 else:
J. Richard Barnette75136b32013-03-26 13:38:44 -07001179 self.servo.get_power_state_controller().warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001180
1181
1182 def cold_reboot(self):
1183 """Request a cold reboot.
1184
1185 A wrapper for underlying servo cold reset.
1186 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001187 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001188 self.servo.set('pwr_button', 'press')
1189 self.servo.set('cold_reset', 'on')
1190 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001191 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001192 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001193 else:
J. Richard Barnette75136b32013-03-26 13:38:44 -07001194 self.servo.get_power_state_controller().cold_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001195
1196
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001197 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001198 """Request the client sync and do a warm reboot.
1199
1200 This is the default reboot action on FAFT.
1201 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001202 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001203 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001204 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001205
1206
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001207 def sync_and_cold_reboot(self):
1208 """Request the client sync and do a cold reboot.
1209
1210 This reboot action is used to reset EC for recovery mode.
1211 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001212 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001213 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001214 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001215
1216
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001217 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001218 """Request the client sync and do a EC triggered reboot.
1219
1220 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001221 flags: Optional, a space-separated string of flags passed to EC
1222 reboot command, including:
1223 default: EC soft reboot;
1224 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001225 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001226 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001227 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001228 self.ec.reboot(flags)
Tom Wai-Hong Tamad4aaae2012-12-12 11:02:06 +08001229 time.sleep(self.delay.ec_boot_to_console)
Vic Yangf86728a2012-07-30 10:44:07 +08001230 self.check_lid_and_power_on()
1231
1232
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001233 def reboot_with_factory_install_shim(self):
1234 """Request reboot with factory install shim to reset TPM.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001235
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001236 Factory install shim requires dev mode enabled. So this method switches
1237 firmware to dev mode first and reboot. The client uses factory install
1238 shim to reset TPM values.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001239 """
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001240 # Unplug USB first to avoid the complicated USB autoboot cases.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -08001241 self.servo.switch_usbkey('host')
Vic Yangf93f7022012-10-31 09:40:36 +08001242 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001243 if not is_dev:
1244 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001245 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001246 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001247 self.wait_fw_screen_and_plug_usb()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001248 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001249 self.warm_reboot()
1250
1251
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001252 def full_power_off_and_on(self):
1253 """Shutdown the device by pressing power button and power on again."""
1254 # Press power button to trigger Chrome OS normal shutdown process.
Tom Wai-Hong Tambe464992012-12-12 10:54:07 +08001255 # We use a customized delay since the normal-press 1.2s is not enough.
1256 self.servo.power_key(self.delay.hold_pwr_button)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001257 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001258 # Short press power button to boot DUT again.
1259 self.servo.power_short_press()
1260
1261
Vic Yangf86728a2012-07-30 10:44:07 +08001262 def check_lid_and_power_on(self):
1263 """
1264 On devices with EC software sync, system powers on after EC reboots if
1265 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1266 This method checks lid switch state and presses power button if
1267 necessary.
1268 """
1269 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001270 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001271 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001272
1273
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001274 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1275 """Modify the kernel header magic in USB stick.
1276
1277 The kernel header magic is the first 8-byte of kernel partition.
1278 We modify it to make it fail on kernel verification check.
1279
1280 Args:
1281 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1282 from_magic: A string of magic which we change it from.
1283 to_magic: A string of magic which we change it to.
1284
1285 Raises:
1286 error.TestError: if failed to change magic.
1287 """
Vadim Bendeburyb0b0b832013-02-04 22:08:40 -08001288 assert len(from_magic) == 8
1289 assert len(to_magic) == 8
1290 # USB image only contains one kernel.
1291 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
1292 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1293 current_magic = self.servo.system_output(read_cmd)
1294 if current_magic == to_magic:
1295 logging.info("The kernel magic is already %s.", current_magic)
1296 return
1297 if current_magic != from_magic:
1298 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1299
1300 logging.info('Modify the kernel magic in USB, from %s to %s.',
1301 from_magic, to_magic)
1302 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1303 " 2>/dev/null" % (to_magic, kernel_part))
1304 self.servo.system(write_cmd)
1305
1306 if self.servo.system_output(read_cmd) != to_magic:
1307 raise error.TestError("Failed to write new magic.")
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001308
1309
1310 def corrupt_usb_kernel(self, usb_dev):
1311 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1312
1313 Args:
1314 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1315 """
1316 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1317 self.CORRUPTED_MAGIC)
1318
1319
1320 def restore_usb_kernel(self, usb_dev):
1321 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1322
1323 Args:
1324 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1325 """
1326 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1327 self.CHROMEOS_MAGIC)
1328
1329
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001330 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001331 """Call the action function with/without arguments.
1332
1333 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001334 action_tuple: A function, or a tuple (function, args, error_msg),
1335 in which, args and error_msg are optional. args is
1336 either a value or a tuple if multiple arguments.
Vic Yang52116d42012-11-05 16:22:34 +08001337 This can also be a list containing multiple function
1338 or tuple. In this case, these actions are called in
1339 sequence.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001340 check_status: Check the return value of action function. If not
1341 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001342
1343 Returns:
1344 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001345
1346 Raises:
1347 error.TestError: An error when the action function is not callable.
1348 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001349 """
Vic Yang52116d42012-11-05 16:22:34 +08001350 if isinstance(action_tuple, list):
1351 return all([self._call_action(action, check_status=check_status)
1352 for action in action_tuple])
1353
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001354 action = action_tuple
1355 args = ()
1356 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001357 if isinstance(action_tuple, tuple):
1358 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001359 if len(action_tuple) >= 2:
1360 args = action_tuple[1]
1361 if not isinstance(args, tuple):
1362 args = (args,)
1363 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001364 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001365
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001366 if action is None:
1367 return
1368
1369 if not callable(action):
1370 raise error.TestError('action is not callable!')
1371
1372 info_msg = 'calling %s' % str(action)
1373 if args:
1374 info_msg += ' with args %s' % str(args)
1375 logging.info(info_msg)
1376 ret = action(*args)
1377
1378 if check_status and not ret:
1379 raise error.TestFail('%s: %s returning %s' %
1380 (error_msg, info_msg, str(ret)))
1381 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001382
1383
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001384 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
Tom Wai-Hong Tam8da40de2012-12-12 12:15:54 +08001385 post_power_action=None, shutdown_timeout=None):
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001386 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1387
1388 Args:
1389 shutdown_action: a function which makes DUT shutdown, like pressing
1390 power key.
1391 pre_power_action: a function which is called before next power on.
1392 post_power_action: a function which is called after next power on.
Tom Wai-Hong Tam8da40de2012-12-12 12:15:54 +08001393 shutdown_timeout: a timeout to confirm DUT shutdown.
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001394
1395 Raises:
1396 error.TestFail: if the shutdown_action() failed to turn DUT off.
1397 """
1398 self._call_action(shutdown_action)
1399 logging.info('Wait to ensure DUT shut down...')
1400 try:
Tom Wai-Hong Tam8da40de2012-12-12 12:15:54 +08001401 if shutdown_timeout is None:
1402 shutdown_timeout = self.delay.shutdown_timeout
1403 self.wait_for_client(timeout=shutdown_timeout)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001404 raise error.TestFail(
1405 'Should shut the device down after calling %s.' %
1406 str(shutdown_action))
1407 except AssertionError:
1408 logging.info(
1409 'DUT is surely shutdown. We are going to power it on again...')
1410
1411 if pre_power_action:
1412 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001413 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001414 if post_power_action:
1415 self._call_action(post_power_action)
1416
1417
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001418 def register_faft_template(self, template):
1419 """Register FAFT template, the default FAFT_STEP of each step.
1420
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001421 Any missing field falls back to the original faft_template.
1422
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001423 Args:
1424 template: A FAFT_STEP dict.
1425 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001426 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001427
1428
1429 def register_faft_sequence(self, sequence):
1430 """Register FAFT sequence.
1431
1432 Args:
1433 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1434 """
1435 self._faft_sequence = sequence
1436
1437
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001438 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001439 """Run a single FAFT step.
1440
1441 Any missing field falls back to faft_template. An empty step means
1442 running the default faft_template.
1443
1444 Args:
1445 step: A FAFT_STEP dict.
1446 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001447 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1448 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001449
1450 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001451 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001452 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001453 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001454 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1455 'firmware_action', 'install_deps_after_boot')
1456
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001457 test = {}
1458 test.update(self._faft_template)
1459 test.update(step)
1460
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001461 for key in test:
1462 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001463 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001464
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001465 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001466 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001467
1468 self._call_action(test['userspace_action'])
1469
1470 # Don't run reboot_action and firmware_action if no_reboot is True.
1471 if not no_reboot:
Tom Wai-Hong Tam12636062013-04-09 17:14:15 +08001472 boot_id = self._client.get_boot_id()
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001473 self._call_action(test['reboot_action'])
Tom Wai-Hong Tam12636062013-04-09 17:14:15 +08001474 self.wait_for_client_offline(orig_boot_id=boot_id)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001475 self._call_action(test['firmware_action'])
1476
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001477 try:
1478 if 'install_deps_after_boot' in test:
1479 self.wait_for_client(
1480 install_deps=test['install_deps_after_boot'])
1481 else:
1482 self.wait_for_client()
1483 except AssertionError:
Yusuf Mohsinally928f8c72012-12-11 15:27:02 -08001484 logging.error('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001485 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001486
1487
1488 def run_faft_sequence(self):
1489 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001490 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001491 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001492 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001493 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001494 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001495 if index == len(sequence) - 1:
1496 self.run_faft_step(step, no_reboot=True)
1497 else:
1498 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001499
1500
ctchang38ae4922012-09-03 17:01:16 +08001501 def get_current_firmware_sha(self):
1502 """Get current firmware sha of body and vblock.
1503
1504 Returns:
1505 Current firmware sha follows the order (
1506 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1507 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001508 current_firmware_sha = (self.faft_client.bios.get_sig_sha('a'),
1509 self.faft_client.bios.get_body_sha('a'),
1510 self.faft_client.bios.get_sig_sha('b'),
1511 self.faft_client.bios.get_body_sha('b'))
ctchang38ae4922012-09-03 17:01:16 +08001512 return current_firmware_sha
1513
1514
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001515 def is_firmware_changed(self):
1516 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001517
1518 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001519 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001520 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001521 # Device may not be rebooted after test.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001522 self.faft_client.bios.reload()
ctchang38ae4922012-09-03 17:01:16 +08001523
1524 current_sha = self.get_current_firmware_sha()
1525
1526 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001527 return False
ctchang38ae4922012-09-03 17:01:16 +08001528 else:
ctchang38ae4922012-09-03 17:01:16 +08001529 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1530 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1531 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1532 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001533 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001534 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1535 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1536 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1537 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001538 return True
ctchang38ae4922012-09-03 17:01:16 +08001539
1540
1541 def backup_firmware(self, suffix='.original'):
1542 """Backup firmware to file, and then send it to host.
1543
1544 Args:
1545 suffix: a string appended to backup file name
1546 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001547 remote_temp_dir = self.faft_client.system.create_temp_dir()
1548 self.faft_client.bios.dump_whole(os.path.join(remote_temp_dir, 'bios'))
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001549 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1550 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001551
1552 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001553 logging.info('Backup firmware stored in %s with suffix %s',
1554 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001555
1556
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001557 def is_firmware_saved(self):
1558 """Check if a firmware saved (called backup_firmware before).
1559
1560 Returns:
1561 True if the firmware is backuped; otherwise False.
1562 """
1563 return self._backup_firmware_sha != ()
1564
1565
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001566 def clear_saved_firmware(self):
1567 """Clear the firmware saved by the method backup_firmware."""
1568 self._backup_firmware_sha = ()
1569
1570
ctchang38ae4922012-09-03 17:01:16 +08001571 def restore_firmware(self, suffix='.original'):
1572 """Restore firmware from host in resultsdir.
1573
1574 Args:
1575 suffix: a string appended to backup file name
1576 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001577 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001578 return
1579
1580 # Backup current corrupted firmware.
1581 self.backup_firmware(suffix='.corrupt')
1582
1583 # Restore firmware.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001584 remote_temp_dir = self.faft_client.system.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001585 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1586 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001587
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001588 self.faft_client.bios.write_whole(
1589 os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001590 self.sync_and_warm_reboot()
1591 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +08001592 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001593 self.wait_for_client()
1594
ctchang38ae4922012-09-03 17:01:16 +08001595 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001596
1597
1598 def setup_firmwareupdate_shellball(self, shellball=None):
1599 """Deside a shellball to use in firmware update test.
1600
1601 Check if there is a given shellball, and it is a shell script. Then,
1602 send it to the remote host. Otherwise, use
1603 /usr/sbin/chromeos-firmwareupdate.
1604
1605 Args:
1606 shellball: path of a shellball or default to None.
1607
1608 Returns:
1609 Path of shellball in remote host.
1610 If use default shellball, reutrn None.
1611 """
1612 updater_path = None
1613 if shellball:
1614 # Determine the firmware file is a shellball or a raw binary.
1615 is_shellball = (utils.system_output("file %s" % shellball).find(
1616 "shell script") != -1)
1617 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001618 logging.info('Device will update firmware with shellball %s',
1619 shellball)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001620 temp_dir = self.faft_client.system.create_temp_dir(
1621 'shellball_')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001622 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1623 self._client.send_file(shellball, temp_shellball)
1624 updater_path = temp_shellball
1625 else:
1626 raise error.TestFail(
1627 'The given shellball is not a shell script.')
1628 return updater_path