blob: 9ae46568de29f4f42f1aba79876c7c1cb10518f3 [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
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -080021from autotest_lib.server import hosts
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080022from autotest_lib.site_utils import lab_test
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +080023from autotest_lib.site_utils.chromeos_test.common_util import ChromeOSTestError
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080024
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080025class FAFTSequence(ServoTest):
26 """
27 The base class of Fully Automated Firmware Test Sequence.
28
29 Many firmware tests require several reboot cycles and verify the resulted
30 system states. To do that, an Autotest test case should detailly handle
31 every action on each step. It makes the test case hard to read and many
32 duplicated code. The base class FAFTSequence is to solve this problem.
33
34 The actions of one reboot cycle is defined in a dict, namely FAFT_STEP.
35 There are four functions in the FAFT_STEP dict:
36 state_checker: a function to check the current is valid or not,
37 returning True if valid, otherwise, False to break the whole
38 test sequence.
39 userspace_action: a function to describe the action ran in userspace.
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +080040 reboot_action: a function to do reboot, default: sync_and_warm_reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080041 firmware_action: a function to describe the action ran after reboot.
42
Tom Wai-Hong Tam7c17ff22011-10-26 09:44:09 +080043 And configurations:
44 install_deps_after_boot: if True, install the Autotest dependency after
45 boot; otherwise, do nothing. It is for the cases of recovery mode
46 test. The test boots a USB/SD image instead of an internal image.
47 The previous installed Autotest dependency on the internal image
48 is lost. So need to install it again.
49
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080050 The default FAFT_STEP checks nothing in state_checker and does nothing in
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +080051 userspace_action and firmware_action. Its reboot_action is a hardware
52 reboot. You can change the default FAFT_STEP by calling
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080053 self.register_faft_template(FAFT_STEP).
54
55 A FAFT test case consists of several FAFT_STEP's, namely FAFT_SEQUENCE.
56 FAFT_SEQUENCE is an array of FAFT_STEP's. Any missing fields on FAFT_STEP
57 fall back to default.
58
59 In the run_once(), it should register and run FAFT_SEQUENCE like:
60 def run_once(self):
61 self.register_faft_sequence(FAFT_SEQUENCE)
62 self.run_faft_sequnce()
63
64 Note that in the last step, we only run state_checker. The
65 userspace_action, reboot_action, and firmware_action are not executed.
66
67 Attributes:
68 _faft_template: The default FAFT_STEP of each step. The actions would
69 be over-written if the registered FAFT_SEQUENCE is valid.
70 _faft_sequence: The registered FAFT_SEQUENCE.
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080071 _install_image_path: The URL or the path on the host to the Chrome OS
72 test image to be installed.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080073 _firmware_update: Boolean. True if firmware update needed after
74 installing the image.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080075 """
76 version = 1
77
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +080078 # Mapping of partition number of kernel and rootfs.
79 KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
80 ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
81 OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
82 OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
83
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +080084 CHROMEOS_MAGIC = "CHROMEOS"
85 CORRUPTED_MAGIC = "CORRUPTD"
86
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080087 _HTTP_PREFIX = 'http://'
88 _DEVSERVER_PORT = '8090'
89
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +080090 _faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080091 _faft_sequence = ()
92
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080093 _install_image_path = None
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080094 _firmware_update = False
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +080095
ctchang38ae4922012-09-03 17:01:16 +080096 _backup_firmware_sha = ()
97
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +080098 # Class level variable, keep track the states of one time setup.
99 # This variable is preserved across tests which inherit this class.
100 _global_setup_done = {
101 'gbb_flags': False,
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800102 'reimage': False,
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800103 'usb_check': False,
104 }
Vic Yang54f70572012-10-19 17:05:26 +0800105
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800106 @classmethod
107 def check_setup_done(cls, label):
108 """Check if the given setup is done.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800109
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800110 Args:
111 label: The label of the setup.
112 """
113 return cls._global_setup_done[label]
114
115
116 @classmethod
117 def mark_setup_done(cls, label):
118 """Mark the given setup done.
119
120 Args:
121 label: The label of the setup.
122 """
123 cls._global_setup_done[label] = True
124
125
126 @classmethod
127 def unmark_setup_done(cls, label):
128 """Mark the given setup not done.
129
130 Args:
131 label: The label of the setup.
132 """
133 cls._global_setup_done[label] = False
Vic Yang54f70572012-10-19 17:05:26 +0800134
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800135
136 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
137 # Parse arguments from command line
138 args = {}
139 for arg in cmdline_args:
140 match = re.search("^(\w+)=(.+)", arg)
141 if match:
142 args[match.group(1)] = match.group(2)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800143 if 'image' in args:
144 self._install_image_path = args['image']
Vic Yang772df8a2012-10-31 10:10:49 +0800145 logging.info('Install Chrome OS test image path: %s',
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800146 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800147 if 'firmware_update' in args and args['firmware_update'].lower() \
148 not in ('0', 'false', 'no'):
149 if self._install_image_path:
150 self._firmware_update = True
151 logging.info('Also update firmware after installing.')
152 else:
153 logging.warning('Firmware update will not not performed '
154 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800155
156 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
157 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800158 if use_faft:
159 self.client_attr = FAFTClientAttribute(
160 self.faft_client.get_platform_name())
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800161 self.delay = FAFTDelayConstants(
162 self.faft_client.get_platform_name())
Vic Yangf93f7022012-10-31 09:40:36 +0800163 self.checkers = FAFTCheckers(self, self.faft_client)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800164
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800165 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800166 self.ec = chrome_ec.ChromeEC(self.servo)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800167
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800168 if not self.client_attr.has_keyboard:
169 # The environment variable USBKM232_UART_DEVICE should point
170 # to the USB-KM232 UART device.
171 if ('USBKM232_UART_DEVICE' not in os.environ or
172 not os.path.exists(os.environ['USBKM232_UART_DEVICE'])):
173 raise error.TestError('Must set a valid environment '
174 'variable USBKM232_UART_DEVICE.')
175
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700176 # Setting up key matrix mapping
177 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
178
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800179 self._host = hosts.create_host(self.servo.get_target_hostname())
180
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800181
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800182 def setup(self, ec_wp=None):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800183 """Autotest setup function."""
184 super(FAFTSequence, self).setup()
185 if not self._remote_infos['faft']['used']:
186 raise error.TestError('The use_faft flag should be enabled.')
187 self.register_faft_template({
188 'state_checker': (None),
189 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800190 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800191 'firmware_action': (None)
192 })
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800193 self.install_test_image(self._install_image_path, self._firmware_update)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800194 self.setup_gbb_flags()
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800195 self.setup_ec_write_protect(ec_wp)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800196
197
198 def cleanup(self):
199 """Autotest cleanup function."""
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800200 self.restore_ec_write_protect()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800201 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800202 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800203 super(FAFTSequence, self).cleanup()
204
205
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800206 def invalidate_firmware_setup(self):
207 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800208
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800209 This method is called when the firmware is re-flashed. It resets all
210 firmware related setup states so that the next test setup properly
211 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800212 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800213 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800214
215
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800216 def _retrieve_recovery_reason_from_trap(self):
217 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800218
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800219 Returns:
220 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800221 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800222 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800223 logging.info('Try to retrieve recovery reason...')
224 if self.servo.get('usb_mux_sel1') == 'dut_sees_usbkey':
225 self.wait_fw_screen_and_plug_usb()
226 else:
227 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
228
229 try:
230 self.wait_for_client(install_deps=True)
231 lines = self.faft_client.run_shell_command_get_output(
232 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800233 recovery_reason = int(lines[0])
234 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800235 except AssertionError:
236 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800237 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800238
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800239
240 def _reset_client(self):
241 """Reset client to a workable state.
242
243 This method is called when the client is not responsive. It may be
244 caused by the following cases:
245 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
246 - corrupted firmware;
247 - corrutped OS image.
248 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800249 # DUT may halt on a firmware screen. Try cold reboot.
250 logging.info('Try cold reboot...')
251 self.cold_reboot()
252 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800253 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800254 return
255 except AssertionError:
256 pass
257
258 # DUT may be broken by a corrupted firmware. Restore firmware.
259 # We assume the recovery boot still works fine. Since the recovery
260 # code is in RO region and all FAFT tests don't change the RO region
261 # except GBB.
262 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800263 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800264 logging.info('Try restore the original firmware...')
265 if self.is_firmware_changed():
266 try:
267 self.restore_firmware()
268 return
269 except AssertionError:
270 logging.info('Restoring firmware doesn\'t help.')
271
272 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800273 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800274 logging.info('Try restore the OS image...')
275 self.faft_client.run_shell_command('chromeos-install --yes')
276 self.sync_and_warm_reboot()
277 self.wait_for_client_offline()
278 try:
279 self.wait_for_client(install_deps=True)
280 logging.info('Successfully restore OS image.')
281 return
282 except AssertionError:
283 logging.info('Restoring OS image doesn\'t help.')
284
285
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800286 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800287 """Ensure client in recovery boot; reboot into it if necessary.
288
289 Raises:
290 error.TestError: if failed to boot the USB image.
291 """
292 # DUT works fine and is already in recovery boot, done.
293 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800294 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800295 return
296
297 logging.info('Try boot into USB image...')
298 self.servo.enable_usb_hub(host=True)
299 self.enable_rec_mode_and_reboot()
300 self.wait_fw_screen_and_plug_usb()
301 try:
302 self.wait_for_client(install_deps=True)
303 except AssertionError:
304 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800305
306
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800307 def _restore_routine_from_timeout(self, next_step=None):
308 """A routine to try to restore the system from a timeout error.
309
310 This method is called when FAFT failed to connect DUT after reboot.
311
312 Args:
313 next_step: Optional, a FAFT_STEP dict of the next step, which is used
314 for diagnostic.
315
316 Raises:
317 error.TestFail: This exception is already raised, with a decription
318 why it failed.
319 """
320 next_checker_matched = False
321 if next_step is not None:
322 next_test = {}
323 next_test.update(self._faft_template)
324 next_test.update(next_step)
325
326 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
327 # identify if it is a network flaky.
328
329 recovery_reason = self._retrieve_recovery_reason_from_trap()
330 if next_step is not None and recovery_reason:
331 if self._call_action(next_test['state_checker']):
332 # Repluging the USB can pass the state_checker of the next step,
333 # meaning that the firmware failed to boot into USB directly.
334 next_checker_matched = True
335
336 # Reset client to a workable state.
337 self._reset_client()
338
339 # Raise the proper TestFail exception.
340 if next_checker_matched:
341 raise error.TestFail('Firmware failed to auto-boot USB in the '
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800342 'recovery boot (reason: %d)' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800343 elif recovery_reason:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800344 raise error.TestFail('Trapped in the recovery screen (reason: %d) '
345 'and timed out' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800346 else:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800347 raise error.TestFail('Timed out waiting for DUT reboot')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800348
349
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800350 def assert_test_image_in_path(self, image_path, install_shim=False):
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800351 """Assert the image of image_path be a Chrome OS test image.
352
353 Args:
354 image_path: A path on the host to the test image.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800355 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800356
357 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800358 error.TestError: if the image is not a test (install shim) image.
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800359 """
360 try:
Tom Wai-Hong Tam5929b1e2012-11-07 09:40:42 +0800361 build_ver, build_hash = lab_test.VerifyImageAndGetId(
362 os.environ['CROS_WORKON_SRCROOT'],
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800363 image_path,
364 install_shim=install_shim)
Vic Yang772df8a2012-10-31 10:10:49 +0800365 logging.info('Build of image: %s %s', build_ver, build_hash)
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800366 except ChromeOSTestError:
367 raise error.TestError(
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800368 'An USB disk containning a %s image should be plugged '
369 'in the servo board.' %
370 ('install shim' if install_shim else 'test'))
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800371
372
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800373 def assert_test_image_in_usb_disk(self, usb_dev=None, install_shim=False):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800374 """Assert an USB disk plugged-in on servo and a test image inside.
375
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800376 Args:
377 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
378 If None, it is detected automatically.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800379 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800380
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800381 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800382 error.TestError: if USB disk not detected or not a test (install shim)
383 image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800384 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800385 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800386 return
387
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800388 # TODO(waihong@chromium.org): We skip the check when servod runs in
389 # a different host since no easy way to access the servo host so far.
390 # Should find a way to work-around it.
391 if not self.servo.is_localhost():
392 logging.info('Skip checking Chrome OS test image in USB as servod '
393 'runs in a different host.')
394 return
395
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800396 if usb_dev:
397 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
398 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700399 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800400 usb_dev = self.servo.probe_host_usb_dev()
401 if not usb_dev:
402 raise error.TestError(
403 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800404 self.assert_test_image_in_path(usb_dev, install_shim=install_shim)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800405 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800406
407
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800408 def setup_usbkey(self, usbkey, host=None, install_shim=False):
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800409 """Setup the USB disk for the test.
410
411 It checks the setup of USB disk and a valid ChromeOS test image inside.
412 It also muxes the USB disk to either the host or DUT by request.
413
414 Args:
415 usbkey: True if the USB disk is required for the test, False if not
416 required.
417 host: Optional, True to mux the USB disk to host, False to mux it
418 to DUT, default to do nothing.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800419 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800420 """
421 if usbkey:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800422 self.assert_test_image_in_usb_disk(install_shim=install_shim)
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800423 elif host is None:
424 # USB disk is not required for the test. Better to mux it to host.
425 host = True
426
427 if host is True:
428 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
429 elif host is False:
430 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
431
432
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800433 def get_server_address(self):
434 """Get the server address seen from the client.
435
436 Returns:
437 A string of the server address.
438 """
439 r = self.faft_client.run_shell_command_get_output("echo $SSH_CLIENT")
440 return r[0].split()[0]
441
442
Simran Basi741b5d42012-05-18 11:27:15 -0700443 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800444 """Install the test image specied by the path onto the USB and DUT disk.
445
446 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500447 recovery mode. Then runs 'chromeos-install' (and possible
448 chromeos-firmwareupdate') to install it to DUT disk.
449
450 Sample command line:
451
452 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
453 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
454 server/site_tests/firmware_XXXX/control
455
456 This test requires an automated recovery to occur while simulating
457 inserting and removing the usb key from the servo. To allow this the
458 following hardware setup is required:
459 1. servo2 board connected via servoflex.
460 2. USB key inserted in the servo2.
461 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
462 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800463
464 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800465 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800466 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800467
468 Raises:
469 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800470 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800471 if not image_path:
472 return
473
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800474 if self.check_setup_done('reimage'):
475 return
476
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800477 if image_path.startswith(self._HTTP_PREFIX):
478 # TODO(waihong@chromium.org): Add the check of the URL to ensure
479 # it is a test image.
480 devserver = None
481 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800482 elif self.servo.is_localhost():
483 self.assert_test_image_in_path(image_path)
484 # If servod is localhost, i.e. both servod and FAFT see the same
485 # file system, do nothing.
486 devserver = None
487 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800488 else:
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800489 self.assert_test_image_in_path(image_path)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800490 image_dir, image_base = os.path.split(image_path)
491 logging.info('Starting devserver to serve the image...')
492 # The following stdout and stderr arguments should not be None,
493 # even we don't use them. Otherwise, the socket of devserve is
494 # created as fd 1 (as no stdout) but it still thinks stdout is fd
495 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800496 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800497 '--archive_dir=%s' % image_dir,
498 '--port=%s' % self._DEVSERVER_PORT],
499 stdout=subprocess.PIPE,
500 stderr=subprocess.PIPE)
501 image_url = '%s%s:%s/static/archive/%s' % (
502 self._HTTP_PREFIX,
503 self.get_server_address(),
504 self._DEVSERVER_PORT,
505 image_base)
506
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800507 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800508 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800509 # devserver is a service running forever. If it is terminated,
510 # some error does happen.
511 if devserver.poll():
512 raise error.TestError('Starting devserver failed, '
513 'returning %d.' % devserver.returncode)
514
Vic Yang772df8a2012-10-31 10:10:49 +0800515 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800516 self.servo.image_to_servo_usb(image_url)
517
518 if devserver and devserver.poll() is None:
519 logging.info('Shutting down devserver...')
520 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500521
522 # DUT is powered off while imaging servo USB.
523 # Now turn it on.
524 self.servo.power_short_press()
525 self.wait_for_client()
526 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
527
528 install_cmd = 'chromeos-install --yes'
529 if firmware_update:
530 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800531 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500532
533 self.register_faft_sequence((
534 { # Step 1, request 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': ('developer', 'normal'),
537 }),
538 'userspace_action': self.faft_client.request_recovery_boot,
539 'firmware_action': self.wait_fw_screen_and_plug_usb,
540 'install_deps_after_boot': True,
541 },
542 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800543 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500544 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800545 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500546 }),
547 'userspace_action': (self.faft_client.run_shell_command,
548 install_cmd),
549 'reboot_action': self.cold_reboot,
550 'install_deps_after_boot': True,
551 },
552 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800553 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500554 'mainfw_type': ('developer', 'normal')
555 }),
556 },
557 ))
558 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800559
560 if firmware_update:
561 self.clear_saved_firmware()
562
Mike Truty49153d82012-08-21 22:27:30 -0500563 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800564 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800565 # Mark usb_check done so it won't check a test image in USB anymore.
566 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800567 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800568
569
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800570 def clear_set_gbb_flags(self, clear_mask, set_mask):
571 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800572
573 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800574 clear_mask: A mask of flags to be cleared.
575 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800576 """
577 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800578 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
579
580 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800581 logging.info('Change the GBB flags from 0x%x to 0x%x.',
582 gbb_flags, new_flags)
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800583 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800584 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800585 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800586 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800587 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800588 self.run_faft_step({
589 'firmware_action': self.wait_fw_screen_and_ctrl_d,
590 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800591
592
Vic Yang772df8a2012-10-31 10:10:49 +0800593 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800594 """Check if current platform has required EC capabilities.
595
596 Args:
597 required_cap: A list containing required EC capabilities. Pass in
598 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800599 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800600
601 Returns:
602 True if requirements are met. Otherwise, False.
603 """
604 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800605 if not suppress_warning:
606 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800607 return False
608
Vic Yang772df8a2012-10-31 10:10:49 +0800609 if not required_cap:
610 return True
611
Vic Yang4d72cb62012-07-24 11:51:09 +0800612 for cap in required_cap:
613 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800614 if not suppress_warning:
615 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800616 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800617 return False
618
619 return True
620
621
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800622 def check_root_part_on_non_recovery(self, part):
623 """Check the partition number of root device and on normal/dev boot.
624
625 Returns:
626 True if the root device matched and on normal/dev boot;
627 otherwise, False.
628 """
Vic Yangf93f7022012-10-31 09:40:36 +0800629 return self.checkers.root_part_checker(part) and \
630 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800631 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800632 })
633
634
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800635 def _join_part(self, dev, part):
636 """Return a concatenated string of device and partition number.
637
638 Args:
639 dev: A string of device, e.g.'/dev/sda'.
640 part: A string of partition number, e.g.'3'.
641
642 Returns:
643 A concatenated string of device and partition number, e.g.'/dev/sda3'.
644
645 >>> seq = FAFTSequence()
646 >>> seq._join_part('/dev/sda', '3')
647 '/dev/sda3'
648 >>> seq._join_part('/dev/mmcblk0', '2')
649 '/dev/mmcblk0p2'
650 """
651 if 'mmcblk' in dev:
652 return dev + 'p' + part
653 else:
654 return dev + part
655
656
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800657 def copy_kernel_and_rootfs(self, from_part, to_part):
658 """Copy kernel and rootfs from from_part to to_part.
659
660 Args:
661 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800662 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800663 """
664 root_dev = self.faft_client.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800665 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800666 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800667 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800668 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
669 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800670 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800671 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800672 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800673 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
674 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800675
676
677 def ensure_kernel_boot(self, part):
678 """Ensure the request kernel boot.
679
680 If not, it duplicates the current kernel to the requested kernel
681 and sets the requested higher priority to ensure it boot.
682
683 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800684 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800685 """
Vic Yangf93f7022012-10-31 09:40:36 +0800686 if not self.checkers.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800687 if self.faft_client.diff_kernel_a_b():
688 self.copy_kernel_and_rootfs(
689 from_part=self.OTHER_KERNEL_MAP[part],
690 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800691 self.run_faft_step({
692 'userspace_action': (self.reset_and_prioritize_kernel, part),
693 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800694
695
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800696 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800697 """Set hardware write protect pin.
698
699 Args:
700 enable: True if asserting write protect pin. Otherwise, False.
701 """
702 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
703 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800704 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800705
706
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800707 def set_ec_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800708 """Set EC write protect status and reboot to take effect.
709
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800710 The write protect state is only activated if both hardware write
711 protect pin is asserted and software write protect flag is set.
Vic Yang416f2032012-08-28 10:18:03 +0800712 This method asserts/deasserts hardware write protect pin first, and
713 set corresponding EC software write protect flag.
714
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800715 If the device uses non-Chrome EC, set the software write protect via
716 flashrom.
717
718 If the device uses Chrome EC, a reboot is required for write protect
719 to take effect. Since the software write protect flag cannot be unset
720 if hardware write protect pin is asserted, we need to deasserted the
721 pin first if we are deactivating write protect. Similarly, a reboot
722 is required before we can modify the software flag.
723
Vic Yang416f2032012-08-28 10:18:03 +0800724 Args:
725 enable: True if activating EC write protect. Otherwise, False.
726 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800727 self.set_hardware_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800728 if self.client_attr.chrome_ec:
729 self.set_chrome_ec_write_protect_and_reboot(enable)
730 else:
731 self.faft_client.set_EC_write_protect(enable)
732 self.sync_and_warm_reboot()
733
734
735 def set_chrome_ec_write_protect_and_reboot(self, enable):
736 """Set Chrome EC write protect status and reboot to take effect.
737
738 Args:
739 enable: True if activating EC write protect. Otherwise, False.
740 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800741 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800742 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800743 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800744 self.sync_and_ec_reboot()
745 else:
746 # Reboot after deasserting hardware write protect pin to deactivate
747 # write protect. And then remove software write protect flag.
748 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800749 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800750
751
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800752 def setup_ec_write_protect(self, ec_wp):
753 """Setup for EC write-protection.
754
755 It makes sure the EC in the requested write-protection state. If not, it
756 flips the state. Flipping the write-protection requires DUT reboot.
757
758 Args:
759 ec_wp: True to request EC write-protected; False to request EC not
760 write-protected; None to do nothing.
761 """
762 if ec_wp is None:
763 self._old_ec_wp = None
764 return
765 self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
766 if ec_wp != self._old_ec_wp:
767 logging.info('The test required EC is %swrite-protected. Reboot '
768 'and flip the state.', '' if ec_wp else 'not ')
769 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800770 'reboot_action': (self.set_ec_write_protect_and_reboot, ec_wp)
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800771 })
772
773
774 def restore_ec_write_protect(self):
775 """Restore the original EC write-protection."""
776 if self._old_ec_wp is None:
777 return
778 if not self.checkers.crossystem_checker(
779 {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
780 logging.info('Restore the original EC write protection and reboot.')
781 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800782 'reboot_action': (self.set_ec_write_protect_and_reboot,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800783 self._old_ec_wp)
784 })
785
786
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800787 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800788 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800789 if not self.client_attr.has_keyboard:
790 logging.info('Running usbkm232-ctrld...')
791 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800792 else:
793 self.servo.ctrl_d()
794
795
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800796 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800797 """Send Ctrl-U key to DUT.
798
799 Raises:
800 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
801 on a no-build-in-keyboard device.
802 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800803 if not self.client_attr.has_keyboard:
804 logging.info('Running usbkm232-ctrlu...')
805 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800806 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
807 self.ec.key_down('<ctrl_l>')
808 self.ec.key_down('u')
809 self.ec.key_up('u')
810 self.ec.key_up('<ctrl_l>')
811 elif self.client_attr.has_keyboard:
812 raise error.TestError(
813 "Can't send Ctrl-U to DUT without using Chrome EC.")
814 else:
815 raise error.TestError(
816 "Should specify the ctrl_u_cmd argument.")
817
818
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800819 def press_enter(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800820 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800821 if not self.client_attr.has_keyboard:
822 logging.info('Running usbkm232-enter...')
823 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800824 else:
825 self.servo.enter_key()
826
827
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800828 def wait_fw_screen_and_ctrl_d(self):
829 """Wait for firmware warning screen and press Ctrl-D."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800830 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800831 self.press_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800832
833
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800834 def wait_fw_screen_and_ctrl_u(self):
835 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800836 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800837 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800838
839
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800840 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
841 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800842 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800843 self.press_enter()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800844
845 # For Alex/ZGB, there is a dev warning screen in text mode.
846 # Skip it by pressing Ctrl-D.
847 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800848 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800849 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800850
851
Mike Truty49153d82012-08-21 22:27:30 -0500852 def wait_fw_screen_and_unplug_usb(self):
853 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800854 time.sleep(self.delay.load_usb)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800855 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800856 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500857
858
859 def wait_fw_screen_and_plug_usb(self):
860 """Wait for firmware warning screen and then unplug and plug the USB."""
861 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800862 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
863
864
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800865 def wait_fw_screen_and_press_power(self):
866 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800867 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800868 # While the firmware screen, the power button probing loop sleeps
869 # 0.25 second on every scan. Use the normal delay (1.2 second) for
870 # power press.
871 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800872
873
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800874 def wait_longer_fw_screen_and_press_power(self):
875 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800876 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800877 self.wait_fw_screen_and_press_power()
878
879
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800880 def wait_fw_screen_and_close_lid(self):
881 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800882 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800883 self.servo.lid_close()
884
885
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800886 def wait_longer_fw_screen_and_close_lid(self):
887 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800888 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800889 self.wait_fw_screen_and_close_lid()
890
891
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800892 def setup_gbb_flags(self):
893 """Setup the GBB flags for FAFT test."""
894 if self.check_setup_done('gbb_flags'):
895 return
896
897 logging.info('Set proper GBB flags for test.')
898 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
899 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
900 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
901 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800902 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
903 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800904 self.mark_setup_done('gbb_flags')
905
906
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800907 def setup_tried_fwb(self, tried_fwb):
908 """Setup for fw B tried state.
909
910 It makes sure the system in the requested fw B tried state. If not, it
911 tries to do so.
912
913 Args:
914 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
915 """
916 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800917 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800918 logging.info(
919 'Firmware is not booted with tried_fwb. Reboot into it.')
920 self.run_faft_step({
921 'userspace_action': self.faft_client.set_try_fw_b,
922 })
923 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800924 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800925 logging.info(
926 'Firmware is booted with tried_fwb. Reboot to clear.')
927 self.run_faft_step({})
928
929
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800930 def enable_rec_mode_and_reboot(self):
931 """Switch to rec mode and reboot.
932
933 This method emulates the behavior of the old physical recovery switch,
934 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
935 recovery mode, i.e. just press Power + Esc + Refresh.
936 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800937 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800938 # Reset twice to emulate a long recovery-key-combo hold.
939 cold_reset_num = 2 if self.client_attr.long_rec_combo else 1
940 for _ in range(cold_reset_num):
941 # Cold reset to clear EC_IN_RW signal
942 self.servo.set('cold_reset', 'on')
943 time.sleep(self.delay.hold_cold_reset)
944 self.servo.set('cold_reset', 'off')
945 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800946 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800947 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800948 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800949 self.servo.power_short_press()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800950 elif self.client_attr.broken_rec_mode:
951 if self._host.has_power():
952 self._host.power_cycle()
953 else:
954 logging.info('You have %d seconds to power cycle this device.',
955 self.delay.user_power_cycle)
956 time.sleep(self.delay.user_power_cycle)
957 logging.info('Booting to recovery mode.')
958 self.servo.custom_recovery_mode()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800959 else:
960 self.servo.enable_recovery_mode()
961 self.cold_reboot()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800962 time.sleep(self.delay.ec_reboot_cmd)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800963 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800964
965
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800966 def enable_dev_mode_and_reboot(self):
967 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800968 if self.client_attr.keyboard_dev:
969 self.enable_keyboard_dev_mode()
970 else:
971 self.servo.enable_development_mode()
972 self.faft_client.run_shell_command(
973 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800974
975
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800976 def enable_normal_mode_and_reboot(self):
977 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800978 if self.client_attr.keyboard_dev:
979 self.disable_keyboard_dev_mode()
980 else:
981 self.servo.disable_development_mode()
982 self.faft_client.run_shell_command(
983 'chromeos-firmwareupdate --mode tonormal && reboot')
984
985
986 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
987 """Wait for firmware screen and then switch into or out of dev mode.
988
989 Args:
990 dev: True if switching into dev mode. Otherwise, False.
991 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800992 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +0800993 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800994 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +0800995 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800996 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +0800997 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800998 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +0800999
1000
1001 def enable_keyboard_dev_mode(self):
1002 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +08001003 # Plug out USB disk for preventing recovery boot without warning
1004 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +08001005 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +08001006 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001007 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001008 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +08001009
1010
1011 def disable_keyboard_dev_mode(self):
1012 logging.info("Disabling keyboard controlled developer mode")
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -08001013 if (not self.client_attr.chrome_ec and
1014 not self.client_attr.broken_rec_mode):
Vic Yang611dd852012-08-02 15:36:31 +08001015 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001016 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001017 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001018 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001019
1020
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001021 def setup_dev_mode(self, dev_mode):
1022 """Setup for development mode.
1023
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001024 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001025 tries to do so.
1026
1027 Args:
1028 dev_mode: True if requested in dev mode; False if normal mode.
1029 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001030 # Change the default firmware_action for dev mode passing the fw screen.
1031 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001032 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
1033 else None),
1034 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001035 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +08001036 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001037 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001038 logging.info('Dev switch is not on. Now switch it on.')
1039 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001040 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001041 'mainfw_type': 'developer'}):
1042 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001043 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001044 'userspace_action': None if self.client_attr.keyboard_dev
1045 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001046 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001047 'reboot_action': self.enable_keyboard_dev_mode if
1048 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001049 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001050 else:
Vic Yange7553162012-06-20 16:20:47 +08001051 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001052 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001053 logging.info('Dev switch is not off. Now switch it off.')
1054 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001055 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001056 'mainfw_type': 'normal'}):
1057 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001058 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001059 'userspace_action': None if self.client_attr.keyboard_dev
1060 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001061 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001062 'reboot_action': self.disable_keyboard_dev_mode if
1063 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001064 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001065
1066
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001067 def setup_kernel(self, part):
1068 """Setup for kernel test.
1069
1070 It makes sure both kernel A and B bootable and the current boot is
1071 the requested kernel part.
1072
1073 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001074 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001075 """
1076 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001077 if self.faft_client.diff_kernel_a_b():
1078 self.copy_kernel_and_rootfs(from_part=part,
1079 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001080 self.reset_and_prioritize_kernel(part)
1081
1082
1083 def reset_and_prioritize_kernel(self, part):
1084 """Make the requested partition highest priority.
1085
1086 This function also reset kerenl A and B to bootable.
1087
1088 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001089 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001090 """
1091 root_dev = self.faft_client.get_root_dev()
1092 # Reset kernel A and B to bootable.
1093 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1094 (self.KERNEL_MAP['a'], root_dev))
1095 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1096 (self.KERNEL_MAP['b'], root_dev))
1097 # Set kernel part highest priority.
1098 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1099 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001100 # Safer to sync and wait until the cgpt status written to the disk.
1101 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001102 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001103
1104
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001105 def warm_reboot(self):
1106 """Request a warm reboot.
1107
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001108 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001109 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001110 # Use cold reset if the warm reset is broken.
1111 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001112 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1113 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001114 else:
1115 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001116
1117
1118 def cold_reboot(self):
1119 """Request a cold reboot.
1120
1121 A wrapper for underlying servo cold reset.
1122 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001123 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001124 self.servo.set('pwr_button', 'press')
1125 self.servo.set('cold_reset', 'on')
1126 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001127 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001128 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001129 else:
1130 self.servo.cold_reset()
1131
1132
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001133 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001134 """Request the client sync and do a warm reboot.
1135
1136 This is the default reboot action on FAFT.
1137 """
1138 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001139 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001140 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001141
1142
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001143 def sync_and_cold_reboot(self):
1144 """Request the client sync and do a cold reboot.
1145
1146 This reboot action is used to reset EC for recovery mode.
1147 """
1148 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001149 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001150 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001151
1152
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001153 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001154 """Request the client sync and do a EC triggered reboot.
1155
1156 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001157 flags: Optional, a space-separated string of flags passed to EC
1158 reboot command, including:
1159 default: EC soft reboot;
1160 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001161 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001162 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001163 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001164 self.ec.reboot(flags)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001165 time.sleep(self.delay.ec_reboot_cmd)
Vic Yangf86728a2012-07-30 10:44:07 +08001166 self.check_lid_and_power_on()
1167
1168
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001169 def reboot_with_factory_install_shim(self):
1170 """Request reboot with factory install shim to reset TPM.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001171
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001172 Factory install shim requires dev mode enabled. So this method switches
1173 firmware to dev mode first and reboot. The client uses factory install
1174 shim to reset TPM values.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001175 """
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001176 # Unplug USB first to avoid the complicated USB autoboot cases.
1177 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yangf93f7022012-10-31 09:40:36 +08001178 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001179 if not is_dev:
1180 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001181 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001182 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001183 self.wait_fw_screen_and_plug_usb()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001184 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001185 self.warm_reboot()
1186
1187
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001188 def full_power_off_and_on(self):
1189 """Shutdown the device by pressing power button and power on again."""
1190 # Press power button to trigger Chrome OS normal shutdown process.
1191 self.servo.power_normal_press()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001192 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001193 # Short press power button to boot DUT again.
1194 self.servo.power_short_press()
1195
1196
Vic Yangf86728a2012-07-30 10:44:07 +08001197 def check_lid_and_power_on(self):
1198 """
1199 On devices with EC software sync, system powers on after EC reboots if
1200 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1201 This method checks lid switch state and presses power button if
1202 necessary.
1203 """
1204 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001205 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001206 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001207
1208
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001209 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1210 """Modify the kernel header magic in USB stick.
1211
1212 The kernel header magic is the first 8-byte of kernel partition.
1213 We modify it to make it fail on kernel verification check.
1214
1215 Args:
1216 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1217 from_magic: A string of magic which we change it from.
1218 to_magic: A string of magic which we change it to.
1219
1220 Raises:
1221 error.TestError: if failed to change magic.
1222 """
1223 assert len(from_magic) == 8
1224 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001225 # USB image only contains one kernel.
1226 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001227 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1228 current_magic = utils.system_output(read_cmd)
1229 if current_magic == to_magic:
Vic Yang772df8a2012-10-31 10:10:49 +08001230 logging.info("The kernel magic is already %s.", current_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001231 return
1232 if current_magic != from_magic:
1233 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1234
Vic Yang772df8a2012-10-31 10:10:49 +08001235 logging.info('Modify the kernel magic in USB, from %s to %s.',
1236 from_magic, to_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001237 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1238 " 2>/dev/null" % (to_magic, kernel_part))
1239 utils.system(write_cmd)
1240
1241 if utils.system_output(read_cmd) != to_magic:
1242 raise error.TestError("Failed to write new magic.")
1243
1244
1245 def corrupt_usb_kernel(self, usb_dev):
1246 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1247
1248 Args:
1249 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1250 """
1251 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1252 self.CORRUPTED_MAGIC)
1253
1254
1255 def restore_usb_kernel(self, usb_dev):
1256 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1257
1258 Args:
1259 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1260 """
1261 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1262 self.CHROMEOS_MAGIC)
1263
1264
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001265 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001266 """Call the action function with/without arguments.
1267
1268 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001269 action_tuple: A function, or a tuple (function, args, error_msg),
1270 in which, args and error_msg are optional. args is
1271 either a value or a tuple if multiple arguments.
Vic Yang52116d42012-11-05 16:22:34 +08001272 This can also be a list containing multiple function
1273 or tuple. In this case, these actions are called in
1274 sequence.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001275 check_status: Check the return value of action function. If not
1276 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001277
1278 Returns:
1279 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001280
1281 Raises:
1282 error.TestError: An error when the action function is not callable.
1283 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001284 """
Vic Yang52116d42012-11-05 16:22:34 +08001285 if isinstance(action_tuple, list):
1286 return all([self._call_action(action, check_status=check_status)
1287 for action in action_tuple])
1288
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001289 action = action_tuple
1290 args = ()
1291 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001292 if isinstance(action_tuple, tuple):
1293 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001294 if len(action_tuple) >= 2:
1295 args = action_tuple[1]
1296 if not isinstance(args, tuple):
1297 args = (args,)
1298 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001299 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001300
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001301 if action is None:
1302 return
1303
1304 if not callable(action):
1305 raise error.TestError('action is not callable!')
1306
1307 info_msg = 'calling %s' % str(action)
1308 if args:
1309 info_msg += ' with args %s' % str(args)
1310 logging.info(info_msg)
1311 ret = action(*args)
1312
1313 if check_status and not ret:
1314 raise error.TestFail('%s: %s returning %s' %
1315 (error_msg, info_msg, str(ret)))
1316 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001317
1318
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001319 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1320 post_power_action=None):
1321 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1322
1323 Args:
1324 shutdown_action: a function which makes DUT shutdown, like pressing
1325 power key.
1326 pre_power_action: a function which is called before next power on.
1327 post_power_action: a function which is called after next power on.
1328
1329 Raises:
1330 error.TestFail: if the shutdown_action() failed to turn DUT off.
1331 """
1332 self._call_action(shutdown_action)
1333 logging.info('Wait to ensure DUT shut down...')
1334 try:
1335 self.wait_for_client()
1336 raise error.TestFail(
1337 'Should shut the device down after calling %s.' %
1338 str(shutdown_action))
1339 except AssertionError:
1340 logging.info(
1341 'DUT is surely shutdown. We are going to power it on again...')
1342
1343 if pre_power_action:
1344 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001345 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001346 if post_power_action:
1347 self._call_action(post_power_action)
1348
1349
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001350 def register_faft_template(self, template):
1351 """Register FAFT template, the default FAFT_STEP of each step.
1352
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001353 Any missing field falls back to the original faft_template.
1354
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001355 Args:
1356 template: A FAFT_STEP dict.
1357 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001358 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001359
1360
1361 def register_faft_sequence(self, sequence):
1362 """Register FAFT sequence.
1363
1364 Args:
1365 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1366 """
1367 self._faft_sequence = sequence
1368
1369
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001370 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001371 """Run a single FAFT step.
1372
1373 Any missing field falls back to faft_template. An empty step means
1374 running the default faft_template.
1375
1376 Args:
1377 step: A FAFT_STEP dict.
1378 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001379 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1380 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001381
1382 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001383 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001384 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001385 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001386 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1387 'firmware_action', 'install_deps_after_boot')
1388
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001389 test = {}
1390 test.update(self._faft_template)
1391 test.update(step)
1392
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001393 for key in test:
1394 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001395 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001396
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001397 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001398 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001399
1400 self._call_action(test['userspace_action'])
1401
1402 # Don't run reboot_action and firmware_action if no_reboot is True.
1403 if not no_reboot:
1404 self._call_action(test['reboot_action'])
1405 self.wait_for_client_offline()
1406 self._call_action(test['firmware_action'])
1407
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001408 try:
1409 if 'install_deps_after_boot' in test:
1410 self.wait_for_client(
1411 install_deps=test['install_deps_after_boot'])
1412 else:
1413 self.wait_for_client()
1414 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001415 logging.info('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001416 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001417
1418
1419 def run_faft_sequence(self):
1420 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001421 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001422 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001423 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001424 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001425 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001426 if index == len(sequence) - 1:
1427 self.run_faft_step(step, no_reboot=True)
1428 else:
1429 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001430
1431
ctchang38ae4922012-09-03 17:01:16 +08001432 def get_current_firmware_sha(self):
1433 """Get current firmware sha of body and vblock.
1434
1435 Returns:
1436 Current firmware sha follows the order (
1437 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1438 """
1439 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1440 self.faft_client.get_firmware_sha('a'),
1441 self.faft_client.get_firmware_sig_sha('b'),
1442 self.faft_client.get_firmware_sha('b'))
1443 return current_firmware_sha
1444
1445
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001446 def is_firmware_changed(self):
1447 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001448
1449 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001450 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001451 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001452 # Device may not be rebooted after test.
1453 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001454
1455 current_sha = self.get_current_firmware_sha()
1456
1457 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001458 return False
ctchang38ae4922012-09-03 17:01:16 +08001459 else:
ctchang38ae4922012-09-03 17:01:16 +08001460 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1461 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1462 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1463 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001464 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001465 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1466 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1467 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1468 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001469 return True
ctchang38ae4922012-09-03 17:01:16 +08001470
1471
1472 def backup_firmware(self, suffix='.original'):
1473 """Backup firmware to file, and then send it to host.
1474
1475 Args:
1476 suffix: a string appended to backup file name
1477 """
1478 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001479 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1480 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1481 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001482
1483 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001484 logging.info('Backup firmware stored in %s with suffix %s',
1485 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001486
1487
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001488 def is_firmware_saved(self):
1489 """Check if a firmware saved (called backup_firmware before).
1490
1491 Returns:
1492 True if the firmware is backuped; otherwise False.
1493 """
1494 return self._backup_firmware_sha != ()
1495
1496
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001497 def clear_saved_firmware(self):
1498 """Clear the firmware saved by the method backup_firmware."""
1499 self._backup_firmware_sha = ()
1500
1501
ctchang38ae4922012-09-03 17:01:16 +08001502 def restore_firmware(self, suffix='.original'):
1503 """Restore firmware from host in resultsdir.
1504
1505 Args:
1506 suffix: a string appended to backup file name
1507 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001508 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001509 return
1510
1511 # Backup current corrupted firmware.
1512 self.backup_firmware(suffix='.corrupt')
1513
1514 # Restore firmware.
1515 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001516 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1517 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001518
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001519 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001520 self.sync_and_warm_reboot()
1521 self.wait_for_client_offline()
1522 self.wait_for_client()
1523
ctchang38ae4922012-09-03 17:01:16 +08001524 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001525
1526
1527 def setup_firmwareupdate_shellball(self, shellball=None):
1528 """Deside a shellball to use in firmware update test.
1529
1530 Check if there is a given shellball, and it is a shell script. Then,
1531 send it to the remote host. Otherwise, use
1532 /usr/sbin/chromeos-firmwareupdate.
1533
1534 Args:
1535 shellball: path of a shellball or default to None.
1536
1537 Returns:
1538 Path of shellball in remote host.
1539 If use default shellball, reutrn None.
1540 """
1541 updater_path = None
1542 if shellball:
1543 # Determine the firmware file is a shellball or a raw binary.
1544 is_shellball = (utils.system_output("file %s" % shellball).find(
1545 "shell script") != -1)
1546 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001547 logging.info('Device will update firmware with shellball %s',
1548 shellball)
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001549 temp_dir = self.faft_client.create_temp_dir('shellball_')
1550 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1551 self._client.send_file(shellball, temp_shellball)
1552 updater_path = temp_shellball
1553 else:
1554 raise error.TestFail(
1555 'The given shellball is not a shell script.')
1556 return updater_path