blob: cbe538367a50c99d44803cebce38d5627401fd99 [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 Tam40fd9472012-01-09 17:11:02 +080010import sys
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080011import time
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080012
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +080013from autotest_lib.client.bin import utils
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080014from autotest_lib.client.common_lib import error
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +080015from autotest_lib.server.cros import vboot_constants as vboot
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +080016from autotest_lib.server.cros import chrome_ec
Vic Yangf93f7022012-10-31 09:40:36 +080017from autotest_lib.server.cros.faft_checkers import FAFTCheckers
Vic Yangebd6de62012-06-26 14:25:57 +080018from autotest_lib.server.cros.faft_client_attribute import FAFTClientAttribute
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +080019from autotest_lib.server.cros.faft_delay_constants import FAFTDelayConstants
Tom Wai-Hong Tam22b77302011-11-03 13:03:48 +080020from autotest_lib.server.cros.servo_test import ServoTest
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080021from autotest_lib.site_utils import lab_test
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +080022from autotest_lib.site_utils.chromeos_test.common_util import ChromeOSTestError
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080023
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080024class FAFTSequence(ServoTest):
25 """
26 The base class of Fully Automated Firmware Test Sequence.
27
28 Many firmware tests require several reboot cycles and verify the resulted
29 system states. To do that, an Autotest test case should detailly handle
30 every action on each step. It makes the test case hard to read and many
31 duplicated code. The base class FAFTSequence is to solve this problem.
32
33 The actions of one reboot cycle is defined in a dict, namely FAFT_STEP.
34 There are four functions in the FAFT_STEP dict:
35 state_checker: a function to check the current is valid or not,
36 returning True if valid, otherwise, False to break the whole
37 test sequence.
38 userspace_action: a function to describe the action ran in userspace.
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +080039 reboot_action: a function to do reboot, default: sync_and_warm_reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080040 firmware_action: a function to describe the action ran after reboot.
41
Tom Wai-Hong Tam7c17ff22011-10-26 09:44:09 +080042 And configurations:
43 install_deps_after_boot: if True, install the Autotest dependency after
44 boot; otherwise, do nothing. It is for the cases of recovery mode
45 test. The test boots a USB/SD image instead of an internal image.
46 The previous installed Autotest dependency on the internal image
47 is lost. So need to install it again.
48
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080049 The default FAFT_STEP checks nothing in state_checker and does nothing in
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +080050 userspace_action and firmware_action. Its reboot_action is a hardware
51 reboot. You can change the default FAFT_STEP by calling
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080052 self.register_faft_template(FAFT_STEP).
53
54 A FAFT test case consists of several FAFT_STEP's, namely FAFT_SEQUENCE.
55 FAFT_SEQUENCE is an array of FAFT_STEP's. Any missing fields on FAFT_STEP
56 fall back to default.
57
58 In the run_once(), it should register and run FAFT_SEQUENCE like:
59 def run_once(self):
60 self.register_faft_sequence(FAFT_SEQUENCE)
61 self.run_faft_sequnce()
62
63 Note that in the last step, we only run state_checker. The
64 userspace_action, reboot_action, and firmware_action are not executed.
65
66 Attributes:
67 _faft_template: The default FAFT_STEP of each step. The actions would
68 be over-written if the registered FAFT_SEQUENCE is valid.
69 _faft_sequence: The registered FAFT_SEQUENCE.
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080070 _install_image_path: The URL or the path on the host to the Chrome OS
71 test image to be installed.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080072 _firmware_update: Boolean. True if firmware update needed after
73 installing the image.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080074 """
75 version = 1
76
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +080077 # Mapping of partition number of kernel and rootfs.
78 KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
79 ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
80 OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
81 OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
82
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +080083 CHROMEOS_MAGIC = "CHROMEOS"
84 CORRUPTED_MAGIC = "CORRUPTD"
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
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +080097 # Class level variable, keep track the states of one time setup.
98 # This variable is preserved across tests which inherit this class.
99 _global_setup_done = {
100 'gbb_flags': False,
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800101 'reimage': False,
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800102 'usb_check': False,
103 }
Vic Yang54f70572012-10-19 17:05:26 +0800104
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800105 @classmethod
106 def check_setup_done(cls, label):
107 """Check if the given setup is done.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800108
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800109 Args:
110 label: The label of the setup.
111 """
112 return cls._global_setup_done[label]
113
114
115 @classmethod
116 def mark_setup_done(cls, label):
117 """Mark the given setup done.
118
119 Args:
120 label: The label of the setup.
121 """
122 cls._global_setup_done[label] = True
123
124
125 @classmethod
126 def unmark_setup_done(cls, label):
127 """Mark the given setup not done.
128
129 Args:
130 label: The label of the setup.
131 """
132 cls._global_setup_done[label] = False
Vic Yang54f70572012-10-19 17:05:26 +0800133
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800134
135 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
136 # Parse arguments from command line
137 args = {}
138 for arg in cmdline_args:
139 match = re.search("^(\w+)=(.+)", arg)
140 if match:
141 args[match.group(1)] = match.group(2)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800142 if 'image' in args:
143 self._install_image_path = args['image']
Vic Yang772df8a2012-10-31 10:10:49 +0800144 logging.info('Install Chrome OS test image path: %s',
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800145 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800146 if 'firmware_update' in args and args['firmware_update'].lower() \
147 not in ('0', 'false', 'no'):
148 if self._install_image_path:
149 self._firmware_update = True
150 logging.info('Also update firmware after installing.')
151 else:
152 logging.warning('Firmware update will not not performed '
153 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800154
155 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
156 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800157 if use_faft:
158 self.client_attr = FAFTClientAttribute(
159 self.faft_client.get_platform_name())
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800160 self.delay = FAFTDelayConstants(
161 self.faft_client.get_platform_name())
Vic Yangf93f7022012-10-31 09:40:36 +0800162 self.checkers = FAFTCheckers(self, self.faft_client)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800163
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800164 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800165 self.ec = chrome_ec.ChromeEC(self.servo)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800166
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800167 if not self.client_attr.has_keyboard:
168 # The environment variable USBKM232_UART_DEVICE should point
169 # to the USB-KM232 UART device.
170 if ('USBKM232_UART_DEVICE' not in os.environ or
171 not os.path.exists(os.environ['USBKM232_UART_DEVICE'])):
172 raise error.TestError('Must set a valid environment '
173 'variable USBKM232_UART_DEVICE.')
174
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700175 # Setting up key matrix mapping
176 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
177
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800178
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800179 def setup(self, ec_wp=None):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800180 """Autotest setup function."""
181 super(FAFTSequence, self).setup()
182 if not self._remote_infos['faft']['used']:
183 raise error.TestError('The use_faft flag should be enabled.')
184 self.register_faft_template({
185 'state_checker': (None),
186 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800187 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800188 'firmware_action': (None)
189 })
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800190 self.install_test_image(self._install_image_path, self._firmware_update)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800191 self.setup_gbb_flags()
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800192 self.setup_ec_write_protect(ec_wp)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800193
194
195 def cleanup(self):
196 """Autotest cleanup function."""
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800197 self.restore_ec_write_protect()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800198 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800199 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800200 super(FAFTSequence, self).cleanup()
201
202
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800203 def invalidate_firmware_setup(self):
204 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800205
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800206 This method is called when the firmware is re-flashed. It resets all
207 firmware related setup states so that the next test setup properly
208 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800209 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800210 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800211
212
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800213 def _retrieve_recovery_reason_from_trap(self):
214 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800215
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800216 Returns:
217 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800218 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800219 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800220 logging.info('Try to retrieve recovery reason...')
221 if self.servo.get('usb_mux_sel1') == 'dut_sees_usbkey':
222 self.wait_fw_screen_and_plug_usb()
223 else:
224 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
225
226 try:
227 self.wait_for_client(install_deps=True)
228 lines = self.faft_client.run_shell_command_get_output(
229 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800230 recovery_reason = int(lines[0])
231 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800232 except AssertionError:
233 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800234 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800235
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800236
237 def _reset_client(self):
238 """Reset client to a workable state.
239
240 This method is called when the client is not responsive. It may be
241 caused by the following cases:
242 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
243 - corrupted firmware;
244 - corrutped OS image.
245 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800246 # DUT may halt on a firmware screen. Try cold reboot.
247 logging.info('Try cold reboot...')
248 self.cold_reboot()
249 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800250 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800251 return
252 except AssertionError:
253 pass
254
255 # DUT may be broken by a corrupted firmware. Restore firmware.
256 # We assume the recovery boot still works fine. Since the recovery
257 # code is in RO region and all FAFT tests don't change the RO region
258 # except GBB.
259 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800260 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800261 logging.info('Try restore the original firmware...')
262 if self.is_firmware_changed():
263 try:
264 self.restore_firmware()
265 return
266 except AssertionError:
267 logging.info('Restoring firmware doesn\'t help.')
268
269 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800270 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800271 logging.info('Try restore the OS image...')
272 self.faft_client.run_shell_command('chromeos-install --yes')
273 self.sync_and_warm_reboot()
274 self.wait_for_client_offline()
275 try:
276 self.wait_for_client(install_deps=True)
277 logging.info('Successfully restore OS image.')
278 return
279 except AssertionError:
280 logging.info('Restoring OS image doesn\'t help.')
281
282
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800283 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800284 """Ensure client in recovery boot; reboot into it if necessary.
285
286 Raises:
287 error.TestError: if failed to boot the USB image.
288 """
289 # DUT works fine and is already in recovery boot, done.
290 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800291 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800292 return
293
294 logging.info('Try boot into USB image...')
295 self.servo.enable_usb_hub(host=True)
296 self.enable_rec_mode_and_reboot()
297 self.wait_fw_screen_and_plug_usb()
298 try:
299 self.wait_for_client(install_deps=True)
300 except AssertionError:
301 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800302
303
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800304 def _restore_routine_from_timeout(self, next_step=None):
305 """A routine to try to restore the system from a timeout error.
306
307 This method is called when FAFT failed to connect DUT after reboot.
308
309 Args:
310 next_step: Optional, a FAFT_STEP dict of the next step, which is used
311 for diagnostic.
312
313 Raises:
314 error.TestFail: This exception is already raised, with a decription
315 why it failed.
316 """
317 next_checker_matched = False
318 if next_step is not None:
319 next_test = {}
320 next_test.update(self._faft_template)
321 next_test.update(next_step)
322
323 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
324 # identify if it is a network flaky.
325
326 recovery_reason = self._retrieve_recovery_reason_from_trap()
327 if next_step is not None and recovery_reason:
328 if self._call_action(next_test['state_checker']):
329 # Repluging the USB can pass the state_checker of the next step,
330 # meaning that the firmware failed to boot into USB directly.
331 next_checker_matched = True
332
333 # Reset client to a workable state.
334 self._reset_client()
335
336 # Raise the proper TestFail exception.
337 if next_checker_matched:
338 raise error.TestFail('Firmware failed to auto-boot USB in the '
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800339 'recovery boot (reason: %d)' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800340 elif recovery_reason:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800341 raise error.TestFail('Trapped in the recovery screen (reason: %d) '
342 'and timed out' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800343 else:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800344 raise error.TestFail('Timed out waiting for DUT reboot')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800345
346
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800347 def assert_test_image_in_path(self, image_path):
348 """Assert the image of image_path be a Chrome OS test image.
349
350 Args:
351 image_path: A path on the host to the test image.
352
353 Raises:
354 error.TestError: if the image is not a test image.
355 """
356 try:
Tom Wai-Hong Tam5929b1e2012-11-07 09:40:42 +0800357 build_ver, build_hash = lab_test.VerifyImageAndGetId(
358 os.environ['CROS_WORKON_SRCROOT'],
359 image_path)
Vic Yang772df8a2012-10-31 10:10:49 +0800360 logging.info('Build of image: %s %s', build_ver, build_hash)
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800361 except ChromeOSTestError:
362 raise error.TestError(
363 'An USB disk containning a test image should be plugged '
364 'in the servo board.')
365
366
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800367 def assert_test_image_in_usb_disk(self, usb_dev=None):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800368 """Assert an USB disk plugged-in on servo and a test image inside.
369
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800370 Args:
371 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
372 If None, it is detected automatically.
373
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800374 Raises:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800375 error.TestError: if USB disk not detected or not a test image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800376 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800377 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800378 return
379
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800380 # TODO(waihong@chromium.org): We skip the check when servod runs in
381 # a different host since no easy way to access the servo host so far.
382 # Should find a way to work-around it.
383 if not self.servo.is_localhost():
384 logging.info('Skip checking Chrome OS test image in USB as servod '
385 'runs in a different host.')
386 return
387
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800388 if usb_dev:
389 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
390 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700391 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800392 usb_dev = self.servo.probe_host_usb_dev()
393 if not usb_dev:
394 raise error.TestError(
395 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800396 self.assert_test_image_in_path(usb_dev)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800397 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800398
399
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800400 def setup_usbkey(self, usbkey, host=None):
401 """Setup the USB disk for the test.
402
403 It checks the setup of USB disk and a valid ChromeOS test image inside.
404 It also muxes the USB disk to either the host or DUT by request.
405
406 Args:
407 usbkey: True if the USB disk is required for the test, False if not
408 required.
409 host: Optional, True to mux the USB disk to host, False to mux it
410 to DUT, default to do nothing.
411 """
412 if usbkey:
413 self.assert_test_image_in_usb_disk()
414 elif host is None:
415 # USB disk is not required for the test. Better to mux it to host.
416 host = True
417
418 if host is True:
419 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
420 elif host is False:
421 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
422
423
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800424 def get_server_address(self):
425 """Get the server address seen from the client.
426
427 Returns:
428 A string of the server address.
429 """
430 r = self.faft_client.run_shell_command_get_output("echo $SSH_CLIENT")
431 return r[0].split()[0]
432
433
Simran Basi741b5d42012-05-18 11:27:15 -0700434 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800435 """Install the test image specied by the path onto the USB and DUT disk.
436
437 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500438 recovery mode. Then runs 'chromeos-install' (and possible
439 chromeos-firmwareupdate') to install it to DUT disk.
440
441 Sample command line:
442
443 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
444 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
445 server/site_tests/firmware_XXXX/control
446
447 This test requires an automated recovery to occur while simulating
448 inserting and removing the usb key from the servo. To allow this the
449 following hardware setup is required:
450 1. servo2 board connected via servoflex.
451 2. USB key inserted in the servo2.
452 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
453 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800454
455 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800456 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800457 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800458
459 Raises:
460 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800461 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800462 if not image_path:
463 return
464
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800465 if self.check_setup_done('reimage'):
466 return
467
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800468 if image_path.startswith(self._HTTP_PREFIX):
469 # TODO(waihong@chromium.org): Add the check of the URL to ensure
470 # it is a test image.
471 devserver = None
472 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800473 elif self.servo.is_localhost():
474 self.assert_test_image_in_path(image_path)
475 # If servod is localhost, i.e. both servod and FAFT see the same
476 # file system, do nothing.
477 devserver = None
478 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800479 else:
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800480 self.assert_test_image_in_path(image_path)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800481 image_dir, image_base = os.path.split(image_path)
482 logging.info('Starting devserver to serve the image...')
483 # The following stdout and stderr arguments should not be None,
484 # even we don't use them. Otherwise, the socket of devserve is
485 # created as fd 1 (as no stdout) but it still thinks stdout is fd
486 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800487 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800488 '--archive_dir=%s' % image_dir,
489 '--port=%s' % self._DEVSERVER_PORT],
490 stdout=subprocess.PIPE,
491 stderr=subprocess.PIPE)
492 image_url = '%s%s:%s/static/archive/%s' % (
493 self._HTTP_PREFIX,
494 self.get_server_address(),
495 self._DEVSERVER_PORT,
496 image_base)
497
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800498 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800499 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800500 # devserver is a service running forever. If it is terminated,
501 # some error does happen.
502 if devserver.poll():
503 raise error.TestError('Starting devserver failed, '
504 'returning %d.' % devserver.returncode)
505
Vic Yang772df8a2012-10-31 10:10:49 +0800506 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800507 self.servo.image_to_servo_usb(image_url)
508
509 if devserver and devserver.poll() is None:
510 logging.info('Shutting down devserver...')
511 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500512
513 # DUT is powered off while imaging servo USB.
514 # Now turn it on.
515 self.servo.power_short_press()
516 self.wait_for_client()
517 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
518
519 install_cmd = 'chromeos-install --yes'
520 if firmware_update:
521 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800522 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500523
524 self.register_faft_sequence((
525 { # Step 1, request recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800526 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500527 'mainfw_type': ('developer', 'normal'),
528 }),
529 'userspace_action': self.faft_client.request_recovery_boot,
530 'firmware_action': self.wait_fw_screen_and_plug_usb,
531 'install_deps_after_boot': True,
532 },
533 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800534 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500535 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800536 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500537 }),
538 'userspace_action': (self.faft_client.run_shell_command,
539 install_cmd),
540 'reboot_action': self.cold_reboot,
541 'install_deps_after_boot': True,
542 },
543 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800544 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500545 'mainfw_type': ('developer', 'normal')
546 }),
547 },
548 ))
549 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800550
551 if firmware_update:
552 self.clear_saved_firmware()
553
Mike Truty49153d82012-08-21 22:27:30 -0500554 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800555 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800556 # Mark usb_check done so it won't check a test image in USB anymore.
557 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800558 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800559
560
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800561 def clear_set_gbb_flags(self, clear_mask, set_mask):
562 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800563
564 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800565 clear_mask: A mask of flags to be cleared.
566 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800567 """
568 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800569 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
570
571 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800572 logging.info('Change the GBB flags from 0x%x to 0x%x.',
573 gbb_flags, new_flags)
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800574 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800575 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800576 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800577 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800578 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800579 self.run_faft_step({
580 'firmware_action': self.wait_fw_screen_and_ctrl_d,
581 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800582
583
Vic Yang772df8a2012-10-31 10:10:49 +0800584 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800585 """Check if current platform has required EC capabilities.
586
587 Args:
588 required_cap: A list containing required EC capabilities. Pass in
589 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800590 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800591
592 Returns:
593 True if requirements are met. Otherwise, False.
594 """
595 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800596 if not suppress_warning:
597 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800598 return False
599
Vic Yang772df8a2012-10-31 10:10:49 +0800600 if not required_cap:
601 return True
602
Vic Yang4d72cb62012-07-24 11:51:09 +0800603 for cap in required_cap:
604 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800605 if not suppress_warning:
606 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800607 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800608 return False
609
610 return True
611
612
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800613 def check_root_part_on_non_recovery(self, part):
614 """Check the partition number of root device and on normal/dev boot.
615
616 Returns:
617 True if the root device matched and on normal/dev boot;
618 otherwise, False.
619 """
Vic Yangf93f7022012-10-31 09:40:36 +0800620 return self.checkers.root_part_checker(part) and \
621 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800622 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800623 })
624
625
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800626 def _join_part(self, dev, part):
627 """Return a concatenated string of device and partition number.
628
629 Args:
630 dev: A string of device, e.g.'/dev/sda'.
631 part: A string of partition number, e.g.'3'.
632
633 Returns:
634 A concatenated string of device and partition number, e.g.'/dev/sda3'.
635
636 >>> seq = FAFTSequence()
637 >>> seq._join_part('/dev/sda', '3')
638 '/dev/sda3'
639 >>> seq._join_part('/dev/mmcblk0', '2')
640 '/dev/mmcblk0p2'
641 """
642 if 'mmcblk' in dev:
643 return dev + 'p' + part
644 else:
645 return dev + part
646
647
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800648 def copy_kernel_and_rootfs(self, from_part, to_part):
649 """Copy kernel and rootfs from from_part to to_part.
650
651 Args:
652 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800653 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800654 """
655 root_dev = self.faft_client.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800656 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800657 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800658 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800659 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
660 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800661 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800662 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800663 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800664 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
665 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800666
667
668 def ensure_kernel_boot(self, part):
669 """Ensure the request kernel boot.
670
671 If not, it duplicates the current kernel to the requested kernel
672 and sets the requested higher priority to ensure it boot.
673
674 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800675 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800676 """
Vic Yangf93f7022012-10-31 09:40:36 +0800677 if not self.checkers.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800678 if self.faft_client.diff_kernel_a_b():
679 self.copy_kernel_and_rootfs(
680 from_part=self.OTHER_KERNEL_MAP[part],
681 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800682 self.run_faft_step({
683 'userspace_action': (self.reset_and_prioritize_kernel, part),
684 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800685
686
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800687 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800688 """Set hardware write protect pin.
689
690 Args:
691 enable: True if asserting write protect pin. Otherwise, False.
692 """
693 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
694 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800695 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800696
697
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800698 def set_EC_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800699 """Set EC write protect status and reboot to take effect.
700
701 EC write protect is only activated if both hardware write protect pin
702 is asserted and software write protect flag is set. Also, a reboot is
703 required for write protect to take effect.
704
705 Since the software write protect flag cannot be unset if hardware write
706 protect pin is asserted, we need to deasserted the pin first if we are
707 deactivating write protect. Similarly, a reboot is required before we
708 can modify the software flag.
709
710 This method asserts/deasserts hardware write protect pin first, and
711 set corresponding EC software write protect flag.
712
713 Args:
714 enable: True if activating EC write protect. Otherwise, False.
715 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800716 self.set_hardware_write_protect(enable)
717 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800718 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800719 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800720 self.sync_and_ec_reboot()
721 else:
722 # Reboot after deasserting hardware write protect pin to deactivate
723 # write protect. And then remove software write protect flag.
724 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800725 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800726
727
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800728 def setup_ec_write_protect(self, ec_wp):
729 """Setup for EC write-protection.
730
731 It makes sure the EC in the requested write-protection state. If not, it
732 flips the state. Flipping the write-protection requires DUT reboot.
733
734 Args:
735 ec_wp: True to request EC write-protected; False to request EC not
736 write-protected; None to do nothing.
737 """
738 if ec_wp is None:
739 self._old_ec_wp = None
740 return
741 self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
742 if ec_wp != self._old_ec_wp:
743 logging.info('The test required EC is %swrite-protected. Reboot '
744 'and flip the state.', '' if ec_wp else 'not ')
745 self.run_faft_step({
746 'reboot_action': (self.set_EC_write_protect_and_reboot, ec_wp)
747 })
748
749
750 def restore_ec_write_protect(self):
751 """Restore the original EC write-protection."""
752 if self._old_ec_wp is None:
753 return
754 if not self.checkers.crossystem_checker(
755 {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
756 logging.info('Restore the original EC write protection and reboot.')
757 self.run_faft_step({
758 'reboot_action': (self.set_EC_write_protect_and_reboot,
759 self._old_ec_wp)
760 })
761
762
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800763 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800764 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800765 if not self.client_attr.has_keyboard:
766 logging.info('Running usbkm232-ctrld...')
767 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800768 else:
769 self.servo.ctrl_d()
770
771
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800772 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800773 """Send Ctrl-U key to DUT.
774
775 Raises:
776 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
777 on a no-build-in-keyboard device.
778 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800779 if not self.client_attr.has_keyboard:
780 logging.info('Running usbkm232-ctrlu...')
781 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800782 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
783 self.ec.key_down('<ctrl_l>')
784 self.ec.key_down('u')
785 self.ec.key_up('u')
786 self.ec.key_up('<ctrl_l>')
787 elif self.client_attr.has_keyboard:
788 raise error.TestError(
789 "Can't send Ctrl-U to DUT without using Chrome EC.")
790 else:
791 raise error.TestError(
792 "Should specify the ctrl_u_cmd argument.")
793
794
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800795 def press_enter(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800796 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800797 if not self.client_attr.has_keyboard:
798 logging.info('Running usbkm232-enter...')
799 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800800 else:
801 self.servo.enter_key()
802
803
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800804 def wait_fw_screen_and_ctrl_d(self):
805 """Wait for firmware warning screen and press Ctrl-D."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800806 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800807 self.press_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800808
809
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800810 def wait_fw_screen_and_ctrl_u(self):
811 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800812 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800813 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800814
815
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800816 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
817 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800818 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800819 self.press_enter()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800820
821 # For Alex/ZGB, there is a dev warning screen in text mode.
822 # Skip it by pressing Ctrl-D.
823 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800824 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800825 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800826
827
Mike Truty49153d82012-08-21 22:27:30 -0500828 def wait_fw_screen_and_unplug_usb(self):
829 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800830 time.sleep(self.delay.load_usb)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800831 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800832 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500833
834
835 def wait_fw_screen_and_plug_usb(self):
836 """Wait for firmware warning screen and then unplug and plug the USB."""
837 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800838 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
839
840
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800841 def wait_fw_screen_and_press_power(self):
842 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800843 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800844 # While the firmware screen, the power button probing loop sleeps
845 # 0.25 second on every scan. Use the normal delay (1.2 second) for
846 # power press.
847 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800848
849
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800850 def wait_longer_fw_screen_and_press_power(self):
851 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800852 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800853 self.wait_fw_screen_and_press_power()
854
855
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800856 def wait_fw_screen_and_close_lid(self):
857 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800858 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800859 self.servo.lid_close()
860
861
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800862 def wait_longer_fw_screen_and_close_lid(self):
863 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800864 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800865 self.wait_fw_screen_and_close_lid()
866
867
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800868 def setup_gbb_flags(self):
869 """Setup the GBB flags for FAFT test."""
870 if self.check_setup_done('gbb_flags'):
871 return
872
873 logging.info('Set proper GBB flags for test.')
874 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
875 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
876 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
877 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
878 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM)
879 self.mark_setup_done('gbb_flags')
880
881
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800882 def setup_tried_fwb(self, tried_fwb):
883 """Setup for fw B tried state.
884
885 It makes sure the system in the requested fw B tried state. If not, it
886 tries to do so.
887
888 Args:
889 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
890 """
891 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800892 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800893 logging.info(
894 'Firmware is not booted with tried_fwb. Reboot into it.')
895 self.run_faft_step({
896 'userspace_action': self.faft_client.set_try_fw_b,
897 })
898 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800899 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800900 logging.info(
901 'Firmware is booted with tried_fwb. Reboot to clear.')
902 self.run_faft_step({})
903
904
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800905 def enable_rec_mode_and_reboot(self):
906 """Switch to rec mode and reboot.
907
908 This method emulates the behavior of the old physical recovery switch,
909 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
910 recovery mode, i.e. just press Power + Esc + Refresh.
911 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800912 if self.client_attr.chrome_ec:
Vic Yang81273092012-08-21 15:57:09 +0800913 # Cold reset to clear EC_IN_RW signal
Vic Yanga7250662012-08-31 04:00:08 +0800914 self.servo.set('cold_reset', 'on')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800915 time.sleep(self.delay.hold_cold_reset)
Vic Yanga7250662012-08-31 04:00:08 +0800916 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800917 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800918 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800919 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800920 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800921 self.servo.power_short_press()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800922 else:
923 self.servo.enable_recovery_mode()
924 self.cold_reboot()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800925 time.sleep(self.delay.ec_reboot_cmd)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800926 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800927
928
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800929 def enable_dev_mode_and_reboot(self):
930 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800931 if self.client_attr.keyboard_dev:
932 self.enable_keyboard_dev_mode()
933 else:
934 self.servo.enable_development_mode()
935 self.faft_client.run_shell_command(
936 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800937
938
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800939 def enable_normal_mode_and_reboot(self):
940 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800941 if self.client_attr.keyboard_dev:
942 self.disable_keyboard_dev_mode()
943 else:
944 self.servo.disable_development_mode()
945 self.faft_client.run_shell_command(
946 'chromeos-firmwareupdate --mode tonormal && reboot')
947
948
949 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
950 """Wait for firmware screen and then switch into or out of dev mode.
951
952 Args:
953 dev: True if switching into dev mode. Otherwise, False.
954 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800955 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +0800956 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800957 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +0800958 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800959 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +0800960 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800961 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +0800962
963
964 def enable_keyboard_dev_mode(self):
965 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +0800966 # Plug out USB disk for preventing recovery boot without warning
967 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +0800968 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800969 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800970 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800971 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +0800972
973
974 def disable_keyboard_dev_mode(self):
975 logging.info("Disabling keyboard controlled developer mode")
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800976 if not self.client_attr.chrome_ec:
Vic Yang611dd852012-08-02 15:36:31 +0800977 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +0800978 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800979 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800980 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800981
982
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800983 def setup_dev_mode(self, dev_mode):
984 """Setup for development mode.
985
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800986 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800987 tries to do so.
988
989 Args:
990 dev_mode: True if requested in dev mode; False if normal mode.
991 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800992 # Change the default firmware_action for dev mode passing the fw screen.
993 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800994 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
995 else None),
996 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800997 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +0800998 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +0800999 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001000 logging.info('Dev switch is not on. Now switch it on.')
1001 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001002 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001003 'mainfw_type': 'developer'}):
1004 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001005 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001006 'userspace_action': None if self.client_attr.keyboard_dev
1007 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001008 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001009 'reboot_action': self.enable_keyboard_dev_mode if
1010 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001011 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001012 else:
Vic Yange7553162012-06-20 16:20:47 +08001013 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001014 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001015 logging.info('Dev switch is not off. Now switch it off.')
1016 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001017 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001018 'mainfw_type': 'normal'}):
1019 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001020 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001021 'userspace_action': None if self.client_attr.keyboard_dev
1022 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001023 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001024 'reboot_action': self.disable_keyboard_dev_mode if
1025 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001026 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001027
1028
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001029 def setup_kernel(self, part):
1030 """Setup for kernel test.
1031
1032 It makes sure both kernel A and B bootable and the current boot is
1033 the requested kernel part.
1034
1035 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001036 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001037 """
1038 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001039 if self.faft_client.diff_kernel_a_b():
1040 self.copy_kernel_and_rootfs(from_part=part,
1041 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001042 self.reset_and_prioritize_kernel(part)
1043
1044
1045 def reset_and_prioritize_kernel(self, part):
1046 """Make the requested partition highest priority.
1047
1048 This function also reset kerenl A and B to bootable.
1049
1050 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001051 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001052 """
1053 root_dev = self.faft_client.get_root_dev()
1054 # Reset kernel A and B to bootable.
1055 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1056 (self.KERNEL_MAP['a'], root_dev))
1057 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1058 (self.KERNEL_MAP['b'], root_dev))
1059 # Set kernel part highest priority.
1060 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1061 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001062 # Safer to sync and wait until the cgpt status written to the disk.
1063 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001064 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001065
1066
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001067 def warm_reboot(self):
1068 """Request a warm reboot.
1069
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001070 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001071 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001072 # Use cold reset if the warm reset is broken.
1073 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001074 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1075 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001076 else:
1077 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001078
1079
1080 def cold_reboot(self):
1081 """Request a cold reboot.
1082
1083 A wrapper for underlying servo cold reset.
1084 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001085 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001086 self.servo.set('pwr_button', 'press')
1087 self.servo.set('cold_reset', 'on')
1088 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001089 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001090 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001091 else:
1092 self.servo.cold_reset()
1093
1094
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001095 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001096 """Request the client sync and do a warm reboot.
1097
1098 This is the default reboot action on FAFT.
1099 """
1100 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001101 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001102 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001103
1104
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001105 def sync_and_cold_reboot(self):
1106 """Request the client sync and do a cold reboot.
1107
1108 This reboot action is used to reset EC for recovery mode.
1109 """
1110 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001111 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001112 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001113
1114
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001115 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001116 """Request the client sync and do a EC triggered reboot.
1117
1118 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001119 flags: Optional, a space-separated string of flags passed to EC
1120 reboot command, including:
1121 default: EC soft reboot;
1122 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001123 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001124 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001125 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001126 self.ec.reboot(flags)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001127 time.sleep(self.delay.ec_reboot_cmd)
Vic Yangf86728a2012-07-30 10:44:07 +08001128 self.check_lid_and_power_on()
1129
1130
Chun-ting Changa4f65532012-10-17 16:57:28 +08001131 def sync_and_reboot_with_factory_install_shim(self):
1132 """Request the client sync and do a warm reboot to recovery mode.
1133
1134 After reboot, the client will use factory install shim to reset TPM
1135 values. The client ignore TPM rollback, so here forces it to recovery
1136 mode.
1137 """
Vic Yangf93f7022012-10-31 09:40:36 +08001138 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001139 if not is_dev:
1140 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001141 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001142 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001143 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001144 self.warm_reboot()
1145
1146
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001147 def full_power_off_and_on(self):
1148 """Shutdown the device by pressing power button and power on again."""
1149 # Press power button to trigger Chrome OS normal shutdown process.
1150 self.servo.power_normal_press()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001151 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001152 # Short press power button to boot DUT again.
1153 self.servo.power_short_press()
1154
1155
Vic Yangf86728a2012-07-30 10:44:07 +08001156 def check_lid_and_power_on(self):
1157 """
1158 On devices with EC software sync, system powers on after EC reboots if
1159 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1160 This method checks lid switch state and presses power button if
1161 necessary.
1162 """
1163 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001164 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001165 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001166
1167
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001168 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1169 """Modify the kernel header magic in USB stick.
1170
1171 The kernel header magic is the first 8-byte of kernel partition.
1172 We modify it to make it fail on kernel verification check.
1173
1174 Args:
1175 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1176 from_magic: A string of magic which we change it from.
1177 to_magic: A string of magic which we change it to.
1178
1179 Raises:
1180 error.TestError: if failed to change magic.
1181 """
1182 assert len(from_magic) == 8
1183 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001184 # USB image only contains one kernel.
1185 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001186 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1187 current_magic = utils.system_output(read_cmd)
1188 if current_magic == to_magic:
Vic Yang772df8a2012-10-31 10:10:49 +08001189 logging.info("The kernel magic is already %s.", current_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001190 return
1191 if current_magic != from_magic:
1192 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1193
Vic Yang772df8a2012-10-31 10:10:49 +08001194 logging.info('Modify the kernel magic in USB, from %s to %s.',
1195 from_magic, to_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001196 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1197 " 2>/dev/null" % (to_magic, kernel_part))
1198 utils.system(write_cmd)
1199
1200 if utils.system_output(read_cmd) != to_magic:
1201 raise error.TestError("Failed to write new magic.")
1202
1203
1204 def corrupt_usb_kernel(self, usb_dev):
1205 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1206
1207 Args:
1208 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1209 """
1210 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1211 self.CORRUPTED_MAGIC)
1212
1213
1214 def restore_usb_kernel(self, usb_dev):
1215 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1216
1217 Args:
1218 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1219 """
1220 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1221 self.CHROMEOS_MAGIC)
1222
1223
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001224 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001225 """Call the action function with/without arguments.
1226
1227 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001228 action_tuple: A function, or a tuple (function, args, error_msg),
1229 in which, args and error_msg are optional. args is
1230 either a value or a tuple if multiple arguments.
Vic Yang52116d42012-11-05 16:22:34 +08001231 This can also be a list containing multiple function
1232 or tuple. In this case, these actions are called in
1233 sequence.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001234 check_status: Check the return value of action function. If not
1235 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001236
1237 Returns:
1238 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001239
1240 Raises:
1241 error.TestError: An error when the action function is not callable.
1242 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001243 """
Vic Yang52116d42012-11-05 16:22:34 +08001244 if isinstance(action_tuple, list):
1245 return all([self._call_action(action, check_status=check_status)
1246 for action in action_tuple])
1247
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001248 action = action_tuple
1249 args = ()
1250 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001251 if isinstance(action_tuple, tuple):
1252 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001253 if len(action_tuple) >= 2:
1254 args = action_tuple[1]
1255 if not isinstance(args, tuple):
1256 args = (args,)
1257 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001258 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001259
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001260 if action is None:
1261 return
1262
1263 if not callable(action):
1264 raise error.TestError('action is not callable!')
1265
1266 info_msg = 'calling %s' % str(action)
1267 if args:
1268 info_msg += ' with args %s' % str(args)
1269 logging.info(info_msg)
1270 ret = action(*args)
1271
1272 if check_status and not ret:
1273 raise error.TestFail('%s: %s returning %s' %
1274 (error_msg, info_msg, str(ret)))
1275 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001276
1277
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001278 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1279 post_power_action=None):
1280 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1281
1282 Args:
1283 shutdown_action: a function which makes DUT shutdown, like pressing
1284 power key.
1285 pre_power_action: a function which is called before next power on.
1286 post_power_action: a function which is called after next power on.
1287
1288 Raises:
1289 error.TestFail: if the shutdown_action() failed to turn DUT off.
1290 """
1291 self._call_action(shutdown_action)
1292 logging.info('Wait to ensure DUT shut down...')
1293 try:
1294 self.wait_for_client()
1295 raise error.TestFail(
1296 'Should shut the device down after calling %s.' %
1297 str(shutdown_action))
1298 except AssertionError:
1299 logging.info(
1300 'DUT is surely shutdown. We are going to power it on again...')
1301
1302 if pre_power_action:
1303 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001304 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001305 if post_power_action:
1306 self._call_action(post_power_action)
1307
1308
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001309 def register_faft_template(self, template):
1310 """Register FAFT template, the default FAFT_STEP of each step.
1311
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001312 Any missing field falls back to the original faft_template.
1313
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001314 Args:
1315 template: A FAFT_STEP dict.
1316 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001317 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001318
1319
1320 def register_faft_sequence(self, sequence):
1321 """Register FAFT sequence.
1322
1323 Args:
1324 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1325 """
1326 self._faft_sequence = sequence
1327
1328
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001329 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001330 """Run a single FAFT step.
1331
1332 Any missing field falls back to faft_template. An empty step means
1333 running the default faft_template.
1334
1335 Args:
1336 step: A FAFT_STEP dict.
1337 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001338 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1339 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001340
1341 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001342 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001343 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001344 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001345 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1346 'firmware_action', 'install_deps_after_boot')
1347
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001348 test = {}
1349 test.update(self._faft_template)
1350 test.update(step)
1351
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001352 for key in test:
1353 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001354 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001355
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001356 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001357 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001358
1359 self._call_action(test['userspace_action'])
1360
1361 # Don't run reboot_action and firmware_action if no_reboot is True.
1362 if not no_reboot:
1363 self._call_action(test['reboot_action'])
1364 self.wait_for_client_offline()
1365 self._call_action(test['firmware_action'])
1366
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001367 try:
1368 if 'install_deps_after_boot' in test:
1369 self.wait_for_client(
1370 install_deps=test['install_deps_after_boot'])
1371 else:
1372 self.wait_for_client()
1373 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001374 logging.info('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001375 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001376
1377
1378 def run_faft_sequence(self):
1379 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001380 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001381 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001382 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001383 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001384 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001385 if index == len(sequence) - 1:
1386 self.run_faft_step(step, no_reboot=True)
1387 else:
1388 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001389
1390
ctchang38ae4922012-09-03 17:01:16 +08001391 def get_current_firmware_sha(self):
1392 """Get current firmware sha of body and vblock.
1393
1394 Returns:
1395 Current firmware sha follows the order (
1396 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1397 """
1398 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1399 self.faft_client.get_firmware_sha('a'),
1400 self.faft_client.get_firmware_sig_sha('b'),
1401 self.faft_client.get_firmware_sha('b'))
1402 return current_firmware_sha
1403
1404
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001405 def is_firmware_changed(self):
1406 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001407
1408 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001409 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001410 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001411 # Device may not be rebooted after test.
1412 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001413
1414 current_sha = self.get_current_firmware_sha()
1415
1416 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001417 return False
ctchang38ae4922012-09-03 17:01:16 +08001418 else:
ctchang38ae4922012-09-03 17:01:16 +08001419 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1420 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1421 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1422 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001423 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001424 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1425 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1426 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1427 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001428 return True
ctchang38ae4922012-09-03 17:01:16 +08001429
1430
1431 def backup_firmware(self, suffix='.original'):
1432 """Backup firmware to file, and then send it to host.
1433
1434 Args:
1435 suffix: a string appended to backup file name
1436 """
1437 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001438 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1439 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1440 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001441
1442 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001443 logging.info('Backup firmware stored in %s with suffix %s',
1444 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001445
1446
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001447 def is_firmware_saved(self):
1448 """Check if a firmware saved (called backup_firmware before).
1449
1450 Returns:
1451 True if the firmware is backuped; otherwise False.
1452 """
1453 return self._backup_firmware_sha != ()
1454
1455
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001456 def clear_saved_firmware(self):
1457 """Clear the firmware saved by the method backup_firmware."""
1458 self._backup_firmware_sha = ()
1459
1460
ctchang38ae4922012-09-03 17:01:16 +08001461 def restore_firmware(self, suffix='.original'):
1462 """Restore firmware from host in resultsdir.
1463
1464 Args:
1465 suffix: a string appended to backup file name
1466 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001467 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001468 return
1469
1470 # Backup current corrupted firmware.
1471 self.backup_firmware(suffix='.corrupt')
1472
1473 # Restore firmware.
1474 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001475 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1476 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001477
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001478 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001479 self.sync_and_warm_reboot()
1480 self.wait_for_client_offline()
1481 self.wait_for_client()
1482
ctchang38ae4922012-09-03 17:01:16 +08001483 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001484
1485
1486 def setup_firmwareupdate_shellball(self, shellball=None):
1487 """Deside a shellball to use in firmware update test.
1488
1489 Check if there is a given shellball, and it is a shell script. Then,
1490 send it to the remote host. Otherwise, use
1491 /usr/sbin/chromeos-firmwareupdate.
1492
1493 Args:
1494 shellball: path of a shellball or default to None.
1495
1496 Returns:
1497 Path of shellball in remote host.
1498 If use default shellball, reutrn None.
1499 """
1500 updater_path = None
1501 if shellball:
1502 # Determine the firmware file is a shellball or a raw binary.
1503 is_shellball = (utils.system_output("file %s" % shellball).find(
1504 "shell script") != -1)
1505 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001506 logging.info('Device will update firmware with shellball %s',
1507 shellball)
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001508 temp_dir = self.faft_client.create_temp_dir('shellball_')
1509 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1510 self._client.send_file(shellball, temp_shellball)
1511 updater_path = temp_shellball
1512 else:
1513 raise error.TestFail(
1514 'The given shellball is not a shell script.')
1515 return updater_path