blob: 3cea48e2a13af80d06b9a7ef02c773800bca52cf [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 Tam40fd9472012-01-09 17:11:02 +080024dirname = os.path.dirname(sys.modules[__name__].__file__)
25autotest_dir = os.path.abspath(os.path.join(dirname, "..", ".."))
26cros_dir = os.path.join(autotest_dir, "..", "..", "..", "..")
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080027
28class FAFTSequence(ServoTest):
29 """
30 The base class of Fully Automated Firmware Test Sequence.
31
32 Many firmware tests require several reboot cycles and verify the resulted
33 system states. To do that, an Autotest test case should detailly handle
34 every action on each step. It makes the test case hard to read and many
35 duplicated code. The base class FAFTSequence is to solve this problem.
36
37 The actions of one reboot cycle is defined in a dict, namely FAFT_STEP.
38 There are four functions in the FAFT_STEP dict:
39 state_checker: a function to check the current is valid or not,
40 returning True if valid, otherwise, False to break the whole
41 test sequence.
42 userspace_action: a function to describe the action ran in userspace.
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +080043 reboot_action: a function to do reboot, default: sync_and_warm_reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080044 firmware_action: a function to describe the action ran after reboot.
45
Tom Wai-Hong Tam7c17ff22011-10-26 09:44:09 +080046 And configurations:
47 install_deps_after_boot: if True, install the Autotest dependency after
48 boot; otherwise, do nothing. It is for the cases of recovery mode
49 test. The test boots a USB/SD image instead of an internal image.
50 The previous installed Autotest dependency on the internal image
51 is lost. So need to install it again.
52
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080053 The default FAFT_STEP checks nothing in state_checker and does nothing in
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +080054 userspace_action and firmware_action. Its reboot_action is a hardware
55 reboot. You can change the default FAFT_STEP by calling
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080056 self.register_faft_template(FAFT_STEP).
57
58 A FAFT test case consists of several FAFT_STEP's, namely FAFT_SEQUENCE.
59 FAFT_SEQUENCE is an array of FAFT_STEP's. Any missing fields on FAFT_STEP
60 fall back to default.
61
62 In the run_once(), it should register and run FAFT_SEQUENCE like:
63 def run_once(self):
64 self.register_faft_sequence(FAFT_SEQUENCE)
65 self.run_faft_sequnce()
66
67 Note that in the last step, we only run state_checker. The
68 userspace_action, reboot_action, and firmware_action are not executed.
69
70 Attributes:
71 _faft_template: The default FAFT_STEP of each step. The actions would
72 be over-written if the registered FAFT_SEQUENCE is valid.
73 _faft_sequence: The registered FAFT_SEQUENCE.
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080074 _install_image_path: The URL or the path on the host to the Chrome OS
75 test image to be installed.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080076 _firmware_update: Boolean. True if firmware update needed after
77 installing the image.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080078 """
79 version = 1
80
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +080081 # Mapping of partition number of kernel and rootfs.
82 KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
83 ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
84 OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
85 OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
86
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +080087 CHROMEOS_MAGIC = "CHROMEOS"
88 CORRUPTED_MAGIC = "CORRUPTD"
89
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080090 _HTTP_PREFIX = 'http://'
91 _DEVSERVER_PORT = '8090'
92
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +080093 _faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080094 _faft_sequence = ()
95
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080096 _install_image_path = None
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080097 _firmware_update = False
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +080098
ctchang38ae4922012-09-03 17:01:16 +080099 _backup_firmware_sha = ()
100
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800101 # Class level variable, keep track the states of one time setup.
102 # This variable is preserved across tests which inherit this class.
103 _global_setup_done = {
104 'gbb_flags': False,
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800105 'reimage': False,
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800106 'usb_check': False,
107 }
Vic Yang54f70572012-10-19 17:05:26 +0800108
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800109 @classmethod
110 def check_setup_done(cls, label):
111 """Check if the given setup is done.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800112
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800113 Args:
114 label: The label of the setup.
115 """
116 return cls._global_setup_done[label]
117
118
119 @classmethod
120 def mark_setup_done(cls, label):
121 """Mark the given setup done.
122
123 Args:
124 label: The label of the setup.
125 """
126 cls._global_setup_done[label] = True
127
128
129 @classmethod
130 def unmark_setup_done(cls, label):
131 """Mark the given setup not done.
132
133 Args:
134 label: The label of the setup.
135 """
136 cls._global_setup_done[label] = False
Vic Yang54f70572012-10-19 17:05:26 +0800137
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800138
139 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
140 # Parse arguments from command line
141 args = {}
142 for arg in cmdline_args:
143 match = re.search("^(\w+)=(.+)", arg)
144 if match:
145 args[match.group(1)] = match.group(2)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800146 if 'image' in args:
147 self._install_image_path = args['image']
Vic Yang772df8a2012-10-31 10:10:49 +0800148 logging.info('Install Chrome OS test image path: %s',
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800149 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800150 if 'firmware_update' in args and args['firmware_update'].lower() \
151 not in ('0', 'false', 'no'):
152 if self._install_image_path:
153 self._firmware_update = True
154 logging.info('Also update firmware after installing.')
155 else:
156 logging.warning('Firmware update will not not performed '
157 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800158
159 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
160 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800161 if use_faft:
162 self.client_attr = FAFTClientAttribute(
163 self.faft_client.get_platform_name())
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800164 self.delay = FAFTDelayConstants(
165 self.faft_client.get_platform_name())
Vic Yangf93f7022012-10-31 09:40:36 +0800166 self.checkers = FAFTCheckers(self, self.faft_client)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800167
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800168 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800169 self.ec = chrome_ec.ChromeEC(self.servo)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800170
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800171 if not self.client_attr.has_keyboard:
172 # The environment variable USBKM232_UART_DEVICE should point
173 # to the USB-KM232 UART device.
174 if ('USBKM232_UART_DEVICE' not in os.environ or
175 not os.path.exists(os.environ['USBKM232_UART_DEVICE'])):
176 raise error.TestError('Must set a valid environment '
177 'variable USBKM232_UART_DEVICE.')
178
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700179 # Setting up key matrix mapping
180 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
181
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800182
183 def setup(self):
184 """Autotest setup function."""
185 super(FAFTSequence, self).setup()
186 if not self._remote_infos['faft']['used']:
187 raise error.TestError('The use_faft flag should be enabled.')
188 self.register_faft_template({
189 'state_checker': (None),
190 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800191 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800192 'firmware_action': (None)
193 })
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800194 self.install_test_image(self._install_image_path, self._firmware_update)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800195 self.setup_gbb_flags()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800196
197
198 def cleanup(self):
199 """Autotest cleanup function."""
200 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800201 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800202 super(FAFTSequence, self).cleanup()
203
204
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800205 def invalidate_firmware_setup(self):
206 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800207
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800208 This method is called when the firmware is re-flashed. It resets all
209 firmware related setup states so that the next test setup properly
210 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800211 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800212 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800213
214
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800215 def _retrieve_recovery_reason_from_trap(self):
216 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800217
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800218 Returns:
219 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800220 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800221 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800222 logging.info('Try to retrieve recovery reason...')
223 if self.servo.get('usb_mux_sel1') == 'dut_sees_usbkey':
224 self.wait_fw_screen_and_plug_usb()
225 else:
226 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
227
228 try:
229 self.wait_for_client(install_deps=True)
230 lines = self.faft_client.run_shell_command_get_output(
231 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800232 recovery_reason = int(lines[0])
233 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800234 except AssertionError:
235 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800236 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800237
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800238
239 def _reset_client(self):
240 """Reset client to a workable state.
241
242 This method is called when the client is not responsive. It may be
243 caused by the following cases:
244 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
245 - corrupted firmware;
246 - corrutped OS image.
247 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800248 # DUT may halt on a firmware screen. Try cold reboot.
249 logging.info('Try cold reboot...')
250 self.cold_reboot()
251 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800252 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800253 return
254 except AssertionError:
255 pass
256
257 # DUT may be broken by a corrupted firmware. Restore firmware.
258 # We assume the recovery boot still works fine. Since the recovery
259 # code is in RO region and all FAFT tests don't change the RO region
260 # except GBB.
261 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800262 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800263 logging.info('Try restore the original firmware...')
264 if self.is_firmware_changed():
265 try:
266 self.restore_firmware()
267 return
268 except AssertionError:
269 logging.info('Restoring firmware doesn\'t help.')
270
271 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800272 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800273 logging.info('Try restore the OS image...')
274 self.faft_client.run_shell_command('chromeos-install --yes')
275 self.sync_and_warm_reboot()
276 self.wait_for_client_offline()
277 try:
278 self.wait_for_client(install_deps=True)
279 logging.info('Successfully restore OS image.')
280 return
281 except AssertionError:
282 logging.info('Restoring OS image doesn\'t help.')
283
284
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800285 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800286 """Ensure client in recovery boot; reboot into it if necessary.
287
288 Raises:
289 error.TestError: if failed to boot the USB image.
290 """
291 # DUT works fine and is already in recovery boot, done.
292 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800293 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800294 return
295
296 logging.info('Try boot into USB image...')
297 self.servo.enable_usb_hub(host=True)
298 self.enable_rec_mode_and_reboot()
299 self.wait_fw_screen_and_plug_usb()
300 try:
301 self.wait_for_client(install_deps=True)
302 except AssertionError:
303 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800304
305
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800306 def _restore_routine_from_timeout(self, next_step=None):
307 """A routine to try to restore the system from a timeout error.
308
309 This method is called when FAFT failed to connect DUT after reboot.
310
311 Args:
312 next_step: Optional, a FAFT_STEP dict of the next step, which is used
313 for diagnostic.
314
315 Raises:
316 error.TestFail: This exception is already raised, with a decription
317 why it failed.
318 """
319 next_checker_matched = False
320 if next_step is not None:
321 next_test = {}
322 next_test.update(self._faft_template)
323 next_test.update(next_step)
324
325 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
326 # identify if it is a network flaky.
327
328 recovery_reason = self._retrieve_recovery_reason_from_trap()
329 if next_step is not None and recovery_reason:
330 if self._call_action(next_test['state_checker']):
331 # Repluging the USB can pass the state_checker of the next step,
332 # meaning that the firmware failed to boot into USB directly.
333 next_checker_matched = True
334
335 # Reset client to a workable state.
336 self._reset_client()
337
338 # Raise the proper TestFail exception.
339 if next_checker_matched:
340 raise error.TestFail('Firmware failed to auto-boot USB in the '
341 'recovery reason: %d.' % recovery_reason)
342 elif recovery_reason:
343 raise error.TestFail('Trapped in the recovery reason: %d' %
344 recovery_reason)
345 else:
346 raise error.TestFail('Timed out waiting for DUT reboot.')
347
348
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800349 def assert_test_image_in_path(self, image_path):
350 """Assert the image of image_path be a Chrome OS test image.
351
352 Args:
353 image_path: A path on the host to the test image.
354
355 Raises:
356 error.TestError: if the image is not a test image.
357 """
358 try:
359 build_ver, build_hash = lab_test.VerifyImageAndGetId(cros_dir,
360 image_path)
Vic Yang772df8a2012-10-31 10:10:49 +0800361 logging.info('Build of image: %s %s', build_ver, build_hash)
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800362 except ChromeOSTestError:
363 raise error.TestError(
364 'An USB disk containning a test image should be plugged '
365 'in the servo board.')
366
367
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800368 def assert_test_image_in_usb_disk(self, usb_dev=None):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800369 """Assert an USB disk plugged-in on servo and a test image inside.
370
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800371 Args:
372 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
373 If None, it is detected automatically.
374
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800375 Raises:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800376 error.TestError: if USB disk not detected or not a test image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800377 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800378 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800379 return
380
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800381 # TODO(waihong@chromium.org): We skip the check when servod runs in
382 # a different host since no easy way to access the servo host so far.
383 # Should find a way to work-around it.
384 if not self.servo.is_localhost():
385 logging.info('Skip checking Chrome OS test image in USB as servod '
386 'runs in a different host.')
387 return
388
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800389 if usb_dev:
390 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
391 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700392 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800393 usb_dev = self.servo.probe_host_usb_dev()
394 if not usb_dev:
395 raise error.TestError(
396 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800397 self.assert_test_image_in_path(usb_dev)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800398 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800399
400
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800401 def setup_usbkey(self, usbkey, host=None):
402 """Setup the USB disk for the test.
403
404 It checks the setup of USB disk and a valid ChromeOS test image inside.
405 It also muxes the USB disk to either the host or DUT by request.
406
407 Args:
408 usbkey: True if the USB disk is required for the test, False if not
409 required.
410 host: Optional, True to mux the USB disk to host, False to mux it
411 to DUT, default to do nothing.
412 """
413 if usbkey:
414 self.assert_test_image_in_usb_disk()
415 elif host is None:
416 # USB disk is not required for the test. Better to mux it to host.
417 host = True
418
419 if host is True:
420 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
421 elif host is False:
422 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
423
424
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800425 def get_server_address(self):
426 """Get the server address seen from the client.
427
428 Returns:
429 A string of the server address.
430 """
431 r = self.faft_client.run_shell_command_get_output("echo $SSH_CLIENT")
432 return r[0].split()[0]
433
434
Simran Basi741b5d42012-05-18 11:27:15 -0700435 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800436 """Install the test image specied by the path onto the USB and DUT disk.
437
438 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500439 recovery mode. Then runs 'chromeos-install' (and possible
440 chromeos-firmwareupdate') to install it to DUT disk.
441
442 Sample command line:
443
444 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
445 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
446 server/site_tests/firmware_XXXX/control
447
448 This test requires an automated recovery to occur while simulating
449 inserting and removing the usb key from the servo. To allow this the
450 following hardware setup is required:
451 1. servo2 board connected via servoflex.
452 2. USB key inserted in the servo2.
453 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
454 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800455
456 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800457 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800458 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800459
460 Raises:
461 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800462 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800463 if not image_path:
464 return
465
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800466 if self.check_setup_done('reimage'):
467 return
468
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800469 if image_path.startswith(self._HTTP_PREFIX):
470 # TODO(waihong@chromium.org): Add the check of the URL to ensure
471 # it is a test image.
472 devserver = None
473 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800474 elif self.servo.is_localhost():
475 self.assert_test_image_in_path(image_path)
476 # If servod is localhost, i.e. both servod and FAFT see the same
477 # file system, do nothing.
478 devserver = None
479 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800480 else:
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800481 self.assert_test_image_in_path(image_path)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800482 image_dir, image_base = os.path.split(image_path)
483 logging.info('Starting devserver to serve the image...')
484 # The following stdout and stderr arguments should not be None,
485 # even we don't use them. Otherwise, the socket of devserve is
486 # created as fd 1 (as no stdout) but it still thinks stdout is fd
487 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800488 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800489 '--archive_dir=%s' % image_dir,
490 '--port=%s' % self._DEVSERVER_PORT],
491 stdout=subprocess.PIPE,
492 stderr=subprocess.PIPE)
493 image_url = '%s%s:%s/static/archive/%s' % (
494 self._HTTP_PREFIX,
495 self.get_server_address(),
496 self._DEVSERVER_PORT,
497 image_base)
498
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800499 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800500 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800501 # devserver is a service running forever. If it is terminated,
502 # some error does happen.
503 if devserver.poll():
504 raise error.TestError('Starting devserver failed, '
505 'returning %d.' % devserver.returncode)
506
Vic Yang772df8a2012-10-31 10:10:49 +0800507 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800508 self.servo.image_to_servo_usb(image_url)
509
510 if devserver and devserver.poll() is None:
511 logging.info('Shutting down devserver...')
512 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500513
514 # DUT is powered off while imaging servo USB.
515 # Now turn it on.
516 self.servo.power_short_press()
517 self.wait_for_client()
518 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
519
520 install_cmd = 'chromeos-install --yes'
521 if firmware_update:
522 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800523 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500524
525 self.register_faft_sequence((
526 { # Step 1, request recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800527 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500528 'mainfw_type': ('developer', 'normal'),
529 }),
530 'userspace_action': self.faft_client.request_recovery_boot,
531 'firmware_action': self.wait_fw_screen_and_plug_usb,
532 'install_deps_after_boot': True,
533 },
534 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800535 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500536 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800537 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500538 }),
539 'userspace_action': (self.faft_client.run_shell_command,
540 install_cmd),
541 'reboot_action': self.cold_reboot,
542 'install_deps_after_boot': True,
543 },
544 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800545 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500546 'mainfw_type': ('developer', 'normal')
547 }),
548 },
549 ))
550 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800551
552 if firmware_update:
553 self.clear_saved_firmware()
554
Mike Truty49153d82012-08-21 22:27:30 -0500555 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800556 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800557 # Mark usb_check done so it won't check a test image in USB anymore.
558 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800559 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800560
561
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800562 def clear_set_gbb_flags(self, clear_mask, set_mask):
563 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800564
565 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800566 clear_mask: A mask of flags to be cleared.
567 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800568 """
569 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800570 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
571
572 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800573 logging.info('Change the GBB flags from 0x%x to 0x%x.',
574 gbb_flags, new_flags)
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800575 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800576 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800577 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800578 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800579 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800580 self.run_faft_step({
581 'firmware_action': self.wait_fw_screen_and_ctrl_d,
582 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800583
584
Vic Yang772df8a2012-10-31 10:10:49 +0800585 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800586 """Check if current platform has required EC capabilities.
587
588 Args:
589 required_cap: A list containing required EC capabilities. Pass in
590 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800591 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800592
593 Returns:
594 True if requirements are met. Otherwise, False.
595 """
596 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800597 if not suppress_warning:
598 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800599 return False
600
Vic Yang772df8a2012-10-31 10:10:49 +0800601 if not required_cap:
602 return True
603
Vic Yang4d72cb62012-07-24 11:51:09 +0800604 for cap in required_cap:
605 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800606 if not suppress_warning:
607 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800608 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800609 return False
610
611 return True
612
613
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800614 def check_root_part_on_non_recovery(self, part):
615 """Check the partition number of root device and on normal/dev boot.
616
617 Returns:
618 True if the root device matched and on normal/dev boot;
619 otherwise, False.
620 """
Vic Yangf93f7022012-10-31 09:40:36 +0800621 return self.checkers.root_part_checker(part) and \
622 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800623 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800624 })
625
626
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800627 def _join_part(self, dev, part):
628 """Return a concatenated string of device and partition number.
629
630 Args:
631 dev: A string of device, e.g.'/dev/sda'.
632 part: A string of partition number, e.g.'3'.
633
634 Returns:
635 A concatenated string of device and partition number, e.g.'/dev/sda3'.
636
637 >>> seq = FAFTSequence()
638 >>> seq._join_part('/dev/sda', '3')
639 '/dev/sda3'
640 >>> seq._join_part('/dev/mmcblk0', '2')
641 '/dev/mmcblk0p2'
642 """
643 if 'mmcblk' in dev:
644 return dev + 'p' + part
645 else:
646 return dev + part
647
648
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800649 def copy_kernel_and_rootfs(self, from_part, to_part):
650 """Copy kernel and rootfs from from_part to to_part.
651
652 Args:
653 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800654 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800655 """
656 root_dev = self.faft_client.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800657 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800658 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800659 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800660 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
661 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800662 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800663 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800664 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800665 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
666 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800667
668
669 def ensure_kernel_boot(self, part):
670 """Ensure the request kernel boot.
671
672 If not, it duplicates the current kernel to the requested kernel
673 and sets the requested higher priority to ensure it boot.
674
675 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800676 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800677 """
Vic Yangf93f7022012-10-31 09:40:36 +0800678 if not self.checkers.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800679 if self.faft_client.diff_kernel_a_b():
680 self.copy_kernel_and_rootfs(
681 from_part=self.OTHER_KERNEL_MAP[part],
682 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800683 self.run_faft_step({
684 'userspace_action': (self.reset_and_prioritize_kernel, part),
685 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800686
687
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800688 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800689 """Set hardware write protect pin.
690
691 Args:
692 enable: True if asserting write protect pin. Otherwise, False.
693 """
694 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
695 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800696 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800697
698
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800699 def set_EC_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800700 """Set EC write protect status and reboot to take effect.
701
702 EC write protect is only activated if both hardware write protect pin
703 is asserted and software write protect flag is set. Also, a reboot is
704 required for write protect to take effect.
705
706 Since the software write protect flag cannot be unset if hardware write
707 protect pin is asserted, we need to deasserted the pin first if we are
708 deactivating write protect. Similarly, a reboot is required before we
709 can modify the software flag.
710
711 This method asserts/deasserts hardware write protect pin first, and
712 set corresponding EC software write protect flag.
713
714 Args:
715 enable: True if activating EC write protect. Otherwise, False.
716 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800717 self.set_hardware_write_protect(enable)
718 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800719 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800720 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800721 self.sync_and_ec_reboot()
722 else:
723 # Reboot after deasserting hardware write protect pin to deactivate
724 # write protect. And then remove software write protect flag.
725 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800726 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800727
728
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800729 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800730 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800731 if not self.client_attr.has_keyboard:
732 logging.info('Running usbkm232-ctrld...')
733 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800734 else:
735 self.servo.ctrl_d()
736
737
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800738 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800739 """Send Ctrl-U key to DUT.
740
741 Raises:
742 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
743 on a no-build-in-keyboard device.
744 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800745 if not self.client_attr.has_keyboard:
746 logging.info('Running usbkm232-ctrlu...')
747 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800748 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
749 self.ec.key_down('<ctrl_l>')
750 self.ec.key_down('u')
751 self.ec.key_up('u')
752 self.ec.key_up('<ctrl_l>')
753 elif self.client_attr.has_keyboard:
754 raise error.TestError(
755 "Can't send Ctrl-U to DUT without using Chrome EC.")
756 else:
757 raise error.TestError(
758 "Should specify the ctrl_u_cmd argument.")
759
760
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800761 def press_enter(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800762 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800763 if not self.client_attr.has_keyboard:
764 logging.info('Running usbkm232-enter...')
765 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800766 else:
767 self.servo.enter_key()
768
769
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800770 def wait_fw_screen_and_ctrl_d(self):
771 """Wait for firmware warning screen and press Ctrl-D."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800772 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800773 self.press_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800774
775
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800776 def wait_fw_screen_and_ctrl_u(self):
777 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800778 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800779 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800780
781
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800782 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
783 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800784 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800785 self.press_enter()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800786
787 # For Alex/ZGB, there is a dev warning screen in text mode.
788 # Skip it by pressing Ctrl-D.
789 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800790 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800791 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800792
793
Mike Truty49153d82012-08-21 22:27:30 -0500794 def wait_fw_screen_and_unplug_usb(self):
795 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800796 time.sleep(self.delay.load_usb)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800797 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800798 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500799
800
801 def wait_fw_screen_and_plug_usb(self):
802 """Wait for firmware warning screen and then unplug and plug the USB."""
803 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800804 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
805
806
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800807 def wait_fw_screen_and_press_power(self):
808 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800809 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800810 # While the firmware screen, the power button probing loop sleeps
811 # 0.25 second on every scan. Use the normal delay (1.2 second) for
812 # power press.
813 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800814
815
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800816 def wait_longer_fw_screen_and_press_power(self):
817 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800818 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800819 self.wait_fw_screen_and_press_power()
820
821
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800822 def wait_fw_screen_and_close_lid(self):
823 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800824 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800825 self.servo.lid_close()
826
827
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800828 def wait_longer_fw_screen_and_close_lid(self):
829 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800830 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800831 self.wait_fw_screen_and_close_lid()
832
833
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800834 def setup_gbb_flags(self):
835 """Setup the GBB flags for FAFT test."""
836 if self.check_setup_done('gbb_flags'):
837 return
838
839 logging.info('Set proper GBB flags for test.')
840 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
841 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
842 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
843 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
844 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM)
845 self.mark_setup_done('gbb_flags')
846
847
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800848 def setup_tried_fwb(self, tried_fwb):
849 """Setup for fw B tried state.
850
851 It makes sure the system in the requested fw B tried state. If not, it
852 tries to do so.
853
854 Args:
855 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
856 """
857 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800858 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800859 logging.info(
860 'Firmware is not booted with tried_fwb. Reboot into it.')
861 self.run_faft_step({
862 'userspace_action': self.faft_client.set_try_fw_b,
863 })
864 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800865 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800866 logging.info(
867 'Firmware is booted with tried_fwb. Reboot to clear.')
868 self.run_faft_step({})
869
870
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800871 def enable_rec_mode_and_reboot(self):
872 """Switch to rec mode and reboot.
873
874 This method emulates the behavior of the old physical recovery switch,
875 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
876 recovery mode, i.e. just press Power + Esc + Refresh.
877 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800878 if self.client_attr.chrome_ec:
Vic Yang81273092012-08-21 15:57:09 +0800879 # Cold reset to clear EC_IN_RW signal
Vic Yanga7250662012-08-31 04:00:08 +0800880 self.servo.set('cold_reset', 'on')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800881 time.sleep(self.delay.hold_cold_reset)
Vic Yanga7250662012-08-31 04:00:08 +0800882 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800883 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800884 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800885 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800886 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800887 self.servo.power_short_press()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800888 else:
889 self.servo.enable_recovery_mode()
890 self.cold_reboot()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800891 time.sleep(self.delay.ec_reboot_cmd)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800892 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800893
894
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800895 def enable_dev_mode_and_reboot(self):
896 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800897 if self.client_attr.keyboard_dev:
898 self.enable_keyboard_dev_mode()
899 else:
900 self.servo.enable_development_mode()
901 self.faft_client.run_shell_command(
902 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800903
904
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800905 def enable_normal_mode_and_reboot(self):
906 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800907 if self.client_attr.keyboard_dev:
908 self.disable_keyboard_dev_mode()
909 else:
910 self.servo.disable_development_mode()
911 self.faft_client.run_shell_command(
912 'chromeos-firmwareupdate --mode tonormal && reboot')
913
914
915 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
916 """Wait for firmware screen and then switch into or out of dev mode.
917
918 Args:
919 dev: True if switching into dev mode. Otherwise, False.
920 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800921 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +0800922 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800923 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +0800924 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800925 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +0800926 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800927 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +0800928
929
930 def enable_keyboard_dev_mode(self):
931 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +0800932 # Plug out USB disk for preventing recovery boot without warning
933 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +0800934 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800935 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800936 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800937 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +0800938
939
940 def disable_keyboard_dev_mode(self):
941 logging.info("Disabling keyboard controlled developer mode")
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800942 if not self.client_attr.chrome_ec:
Vic Yang611dd852012-08-02 15:36:31 +0800943 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +0800944 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800945 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800946 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800947
948
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800949 def setup_dev_mode(self, dev_mode):
950 """Setup for development mode.
951
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800952 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800953 tries to do so.
954
955 Args:
956 dev_mode: True if requested in dev mode; False if normal mode.
957 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800958 # Change the default firmware_action for dev mode passing the fw screen.
959 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800960 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
961 else None),
962 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800963 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +0800964 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +0800965 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800966 logging.info('Dev switch is not on. Now switch it on.')
967 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +0800968 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800969 'mainfw_type': 'developer'}):
970 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800971 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800972 'userspace_action': None if self.client_attr.keyboard_dev
973 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800974 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800975 'reboot_action': self.enable_keyboard_dev_mode if
976 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800977 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800978 else:
Vic Yange7553162012-06-20 16:20:47 +0800979 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +0800980 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800981 logging.info('Dev switch is not off. Now switch it off.')
982 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +0800983 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800984 'mainfw_type': 'normal'}):
985 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800986 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800987 'userspace_action': None if self.client_attr.keyboard_dev
988 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800989 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800990 'reboot_action': self.disable_keyboard_dev_mode if
991 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800992 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800993
994
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800995 def setup_kernel(self, part):
996 """Setup for kernel test.
997
998 It makes sure both kernel A and B bootable and the current boot is
999 the requested kernel part.
1000
1001 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001002 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001003 """
1004 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001005 if self.faft_client.diff_kernel_a_b():
1006 self.copy_kernel_and_rootfs(from_part=part,
1007 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001008 self.reset_and_prioritize_kernel(part)
1009
1010
1011 def reset_and_prioritize_kernel(self, part):
1012 """Make the requested partition highest priority.
1013
1014 This function also reset kerenl A and B to bootable.
1015
1016 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001017 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001018 """
1019 root_dev = self.faft_client.get_root_dev()
1020 # Reset kernel A and B to bootable.
1021 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1022 (self.KERNEL_MAP['a'], root_dev))
1023 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1024 (self.KERNEL_MAP['b'], root_dev))
1025 # Set kernel part highest priority.
1026 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1027 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001028 # Safer to sync and wait until the cgpt status written to the disk.
1029 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001030 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001031
1032
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001033 def warm_reboot(self):
1034 """Request a warm reboot.
1035
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001036 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001037 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001038 # Use cold reset if the warm reset is broken.
1039 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001040 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1041 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001042 else:
1043 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001044
1045
1046 def cold_reboot(self):
1047 """Request a cold reboot.
1048
1049 A wrapper for underlying servo cold reset.
1050 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001051 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001052 self.servo.set('pwr_button', 'press')
1053 self.servo.set('cold_reset', 'on')
1054 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001055 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001056 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +08001057 elif self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001058 # We don't use servo.cold_reset() here because software sync is
1059 # not yet finished, and device may or may not come up after cold
1060 # reset. Pressing power button before firmware comes up solves this.
1061 #
1062 # The correct behavior should be (not work now):
1063 # - If rebooting EC with rec mode on, power on AP and it boots
1064 # into recovery mode.
1065 # - If rebooting EC with rec mode off, power on AP for software
1066 # sync. Then AP checks if lid open or not. If lid open, continue;
1067 # otherwise, shut AP down and need servo for a power button
1068 # press.
1069 self.servo.set('cold_reset', 'on')
1070 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001071 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001072 self.servo.power_short_press()
1073 else:
1074 self.servo.cold_reset()
1075
1076
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001077 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001078 """Request the client sync and do a warm reboot.
1079
1080 This is the default reboot action on FAFT.
1081 """
1082 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001083 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001084 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001085
1086
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001087 def sync_and_cold_reboot(self):
1088 """Request the client sync and do a cold reboot.
1089
1090 This reboot action is used to reset EC for recovery mode.
1091 """
1092 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001093 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001094 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001095
1096
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001097 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001098 """Request the client sync and do a EC triggered reboot.
1099
1100 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001101 flags: Optional, a space-separated string of flags passed to EC
1102 reboot command, including:
1103 default: EC soft reboot;
1104 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001105 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001106 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001107 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001108 self.ec.reboot(flags)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001109 time.sleep(self.delay.ec_reboot_cmd)
Vic Yangf86728a2012-07-30 10:44:07 +08001110 self.check_lid_and_power_on()
1111
1112
Chun-ting Changa4f65532012-10-17 16:57:28 +08001113 def sync_and_reboot_with_factory_install_shim(self):
1114 """Request the client sync and do a warm reboot to recovery mode.
1115
1116 After reboot, the client will use factory install shim to reset TPM
1117 values. The client ignore TPM rollback, so here forces it to recovery
1118 mode.
1119 """
Vic Yangf93f7022012-10-31 09:40:36 +08001120 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001121 if not is_dev:
1122 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001123 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001124 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001125 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001126 self.warm_reboot()
1127
1128
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001129 def full_power_off_and_on(self):
1130 """Shutdown the device by pressing power button and power on again."""
1131 # Press power button to trigger Chrome OS normal shutdown process.
1132 self.servo.power_normal_press()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001133 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001134 # Short press power button to boot DUT again.
1135 self.servo.power_short_press()
1136
1137
Vic Yangf86728a2012-07-30 10:44:07 +08001138 def check_lid_and_power_on(self):
1139 """
1140 On devices with EC software sync, system powers on after EC reboots if
1141 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1142 This method checks lid switch state and presses power button if
1143 necessary.
1144 """
1145 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001146 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001147 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001148
1149
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001150 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1151 """Modify the kernel header magic in USB stick.
1152
1153 The kernel header magic is the first 8-byte of kernel partition.
1154 We modify it to make it fail on kernel verification check.
1155
1156 Args:
1157 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1158 from_magic: A string of magic which we change it from.
1159 to_magic: A string of magic which we change it to.
1160
1161 Raises:
1162 error.TestError: if failed to change magic.
1163 """
1164 assert len(from_magic) == 8
1165 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001166 # USB image only contains one kernel.
1167 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001168 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1169 current_magic = utils.system_output(read_cmd)
1170 if current_magic == to_magic:
Vic Yang772df8a2012-10-31 10:10:49 +08001171 logging.info("The kernel magic is already %s.", current_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001172 return
1173 if current_magic != from_magic:
1174 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1175
Vic Yang772df8a2012-10-31 10:10:49 +08001176 logging.info('Modify the kernel magic in USB, from %s to %s.',
1177 from_magic, to_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001178 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1179 " 2>/dev/null" % (to_magic, kernel_part))
1180 utils.system(write_cmd)
1181
1182 if utils.system_output(read_cmd) != to_magic:
1183 raise error.TestError("Failed to write new magic.")
1184
1185
1186 def corrupt_usb_kernel(self, usb_dev):
1187 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1188
1189 Args:
1190 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1191 """
1192 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1193 self.CORRUPTED_MAGIC)
1194
1195
1196 def restore_usb_kernel(self, usb_dev):
1197 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1198
1199 Args:
1200 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1201 """
1202 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1203 self.CHROMEOS_MAGIC)
1204
1205
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001206 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001207 """Call the action function with/without arguments.
1208
1209 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001210 action_tuple: A function, or a tuple (function, args, error_msg),
1211 in which, args and error_msg are optional. args is
1212 either a value or a tuple if multiple arguments.
1213 check_status: Check the return value of action function. If not
1214 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001215
1216 Returns:
1217 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001218
1219 Raises:
1220 error.TestError: An error when the action function is not callable.
1221 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001222 """
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001223 action = action_tuple
1224 args = ()
1225 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001226 if isinstance(action_tuple, tuple):
1227 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001228 if len(action_tuple) >= 2:
1229 args = action_tuple[1]
1230 if not isinstance(args, tuple):
1231 args = (args,)
1232 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001233 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001234
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001235 if action is None:
1236 return
1237
1238 if not callable(action):
1239 raise error.TestError('action is not callable!')
1240
1241 info_msg = 'calling %s' % str(action)
1242 if args:
1243 info_msg += ' with args %s' % str(args)
1244 logging.info(info_msg)
1245 ret = action(*args)
1246
1247 if check_status and not ret:
1248 raise error.TestFail('%s: %s returning %s' %
1249 (error_msg, info_msg, str(ret)))
1250 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001251
1252
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001253 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1254 post_power_action=None):
1255 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1256
1257 Args:
1258 shutdown_action: a function which makes DUT shutdown, like pressing
1259 power key.
1260 pre_power_action: a function which is called before next power on.
1261 post_power_action: a function which is called after next power on.
1262
1263 Raises:
1264 error.TestFail: if the shutdown_action() failed to turn DUT off.
1265 """
1266 self._call_action(shutdown_action)
1267 logging.info('Wait to ensure DUT shut down...')
1268 try:
1269 self.wait_for_client()
1270 raise error.TestFail(
1271 'Should shut the device down after calling %s.' %
1272 str(shutdown_action))
1273 except AssertionError:
1274 logging.info(
1275 'DUT is surely shutdown. We are going to power it on again...')
1276
1277 if pre_power_action:
1278 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001279 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001280 if post_power_action:
1281 self._call_action(post_power_action)
1282
1283
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001284 def register_faft_template(self, template):
1285 """Register FAFT template, the default FAFT_STEP of each step.
1286
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001287 Any missing field falls back to the original faft_template.
1288
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001289 Args:
1290 template: A FAFT_STEP dict.
1291 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001292 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001293
1294
1295 def register_faft_sequence(self, sequence):
1296 """Register FAFT sequence.
1297
1298 Args:
1299 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1300 """
1301 self._faft_sequence = sequence
1302
1303
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001304 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001305 """Run a single FAFT step.
1306
1307 Any missing field falls back to faft_template. An empty step means
1308 running the default faft_template.
1309
1310 Args:
1311 step: A FAFT_STEP dict.
1312 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001313 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1314 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001315
1316 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001317 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001318 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001319 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001320 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1321 'firmware_action', 'install_deps_after_boot')
1322
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001323 test = {}
1324 test.update(self._faft_template)
1325 test.update(step)
1326
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001327 for key in test:
1328 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001329 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001330
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001331 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001332 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001333
1334 self._call_action(test['userspace_action'])
1335
1336 # Don't run reboot_action and firmware_action if no_reboot is True.
1337 if not no_reboot:
1338 self._call_action(test['reboot_action'])
1339 self.wait_for_client_offline()
1340 self._call_action(test['firmware_action'])
1341
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001342 try:
1343 if 'install_deps_after_boot' in test:
1344 self.wait_for_client(
1345 install_deps=test['install_deps_after_boot'])
1346 else:
1347 self.wait_for_client()
1348 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001349 logging.info('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001350 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001351
1352
1353 def run_faft_sequence(self):
1354 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001355 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001356 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001357 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001358 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001359 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001360 if index == len(sequence) - 1:
1361 self.run_faft_step(step, no_reboot=True)
1362 else:
1363 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001364
1365
ctchang38ae4922012-09-03 17:01:16 +08001366 def get_current_firmware_sha(self):
1367 """Get current firmware sha of body and vblock.
1368
1369 Returns:
1370 Current firmware sha follows the order (
1371 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1372 """
1373 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1374 self.faft_client.get_firmware_sha('a'),
1375 self.faft_client.get_firmware_sig_sha('b'),
1376 self.faft_client.get_firmware_sha('b'))
1377 return current_firmware_sha
1378
1379
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001380 def is_firmware_changed(self):
1381 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001382
1383 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001384 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001385 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001386 # Device may not be rebooted after test.
1387 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001388
1389 current_sha = self.get_current_firmware_sha()
1390
1391 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001392 return False
ctchang38ae4922012-09-03 17:01:16 +08001393 else:
ctchang38ae4922012-09-03 17:01:16 +08001394 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1395 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1396 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1397 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001398 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001399 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1400 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1401 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1402 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001403 return True
ctchang38ae4922012-09-03 17:01:16 +08001404
1405
1406 def backup_firmware(self, suffix='.original'):
1407 """Backup firmware to file, and then send it to host.
1408
1409 Args:
1410 suffix: a string appended to backup file name
1411 """
1412 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001413 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1414 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1415 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001416
1417 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001418 logging.info('Backup firmware stored in %s with suffix %s',
1419 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001420
1421
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001422 def is_firmware_saved(self):
1423 """Check if a firmware saved (called backup_firmware before).
1424
1425 Returns:
1426 True if the firmware is backuped; otherwise False.
1427 """
1428 return self._backup_firmware_sha != ()
1429
1430
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001431 def clear_saved_firmware(self):
1432 """Clear the firmware saved by the method backup_firmware."""
1433 self._backup_firmware_sha = ()
1434
1435
ctchang38ae4922012-09-03 17:01:16 +08001436 def restore_firmware(self, suffix='.original'):
1437 """Restore firmware from host in resultsdir.
1438
1439 Args:
1440 suffix: a string appended to backup file name
1441 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001442 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001443 return
1444
1445 # Backup current corrupted firmware.
1446 self.backup_firmware(suffix='.corrupt')
1447
1448 # Restore firmware.
1449 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001450 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1451 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001452
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001453 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001454 self.sync_and_warm_reboot()
1455 self.wait_for_client_offline()
1456 self.wait_for_client()
1457
ctchang38ae4922012-09-03 17:01:16 +08001458 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001459
1460
1461 def setup_firmwareupdate_shellball(self, shellball=None):
1462 """Deside a shellball to use in firmware update test.
1463
1464 Check if there is a given shellball, and it is a shell script. Then,
1465 send it to the remote host. Otherwise, use
1466 /usr/sbin/chromeos-firmwareupdate.
1467
1468 Args:
1469 shellball: path of a shellball or default to None.
1470
1471 Returns:
1472 Path of shellball in remote host.
1473 If use default shellball, reutrn None.
1474 """
1475 updater_path = None
1476 if shellball:
1477 # Determine the firmware file is a shellball or a raw binary.
1478 is_shellball = (utils.system_output("file %s" % shellball).find(
1479 "shell script") != -1)
1480 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001481 logging.info('Device will update firmware with shellball %s',
1482 shellball)
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001483 temp_dir = self.faft_client.create_temp_dir('shellball_')
1484 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1485 self._client.send_file(shellball, temp_shellball)
1486 updater_path = temp_shellball
1487 else:
1488 raise error.TestFail(
1489 'The given shellball is not a shell script.')
1490 return updater_path