blob: ef71c54db0a2af0bef0727eec702ba6b91fde374 [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
Tom Wai-Hong Tamc5c14ef2012-11-20 16:33:37 +0800179 self._host = None
180 if (self.client_attr.broken_rec_mode and
181 self.servo.get_target_hostname()):
182 self._host = hosts.create_host(self.servo.get_target_hostname())
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800183
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800184
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800185 def setup(self, ec_wp=None):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800186 """Autotest setup function."""
187 super(FAFTSequence, self).setup()
188 if not self._remote_infos['faft']['used']:
189 raise error.TestError('The use_faft flag should be enabled.')
190 self.register_faft_template({
191 'state_checker': (None),
192 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800193 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800194 'firmware_action': (None)
195 })
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800196 self.install_test_image(self._install_image_path, self._firmware_update)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800197 self.setup_gbb_flags()
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800198 self.setup_ec_write_protect(ec_wp)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800199
200
201 def cleanup(self):
202 """Autotest cleanup function."""
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800203 self.restore_ec_write_protect()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800204 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800205 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800206 super(FAFTSequence, self).cleanup()
207
208
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800209 def invalidate_firmware_setup(self):
210 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800211
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800212 This method is called when the firmware is re-flashed. It resets all
213 firmware related setup states so that the next test setup properly
214 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800215 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800216 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800217
218
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800219 def _retrieve_recovery_reason_from_trap(self):
220 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800221
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800222 Returns:
223 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800224 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800225 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800226 logging.info('Try to retrieve recovery reason...')
227 if self.servo.get('usb_mux_sel1') == 'dut_sees_usbkey':
228 self.wait_fw_screen_and_plug_usb()
229 else:
230 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
231
232 try:
233 self.wait_for_client(install_deps=True)
234 lines = self.faft_client.run_shell_command_get_output(
235 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800236 recovery_reason = int(lines[0])
237 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800238 except AssertionError:
239 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800240 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800241
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800242
243 def _reset_client(self):
244 """Reset client to a workable state.
245
246 This method is called when the client is not responsive. It may be
247 caused by the following cases:
248 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
249 - corrupted firmware;
250 - corrutped OS image.
251 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800252 # DUT may halt on a firmware screen. Try cold reboot.
253 logging.info('Try cold reboot...')
254 self.cold_reboot()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800255 self.wait_for_client_offline()
256 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800257 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800258 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800259 return
260 except AssertionError:
261 pass
262
263 # DUT may be broken by a corrupted firmware. Restore firmware.
264 # We assume the recovery boot still works fine. Since the recovery
265 # code is in RO region and all FAFT tests don't change the RO region
266 # except GBB.
267 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800268 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800269 logging.info('Try restore the original firmware...')
270 if self.is_firmware_changed():
271 try:
272 self.restore_firmware()
273 return
274 except AssertionError:
275 logging.info('Restoring firmware doesn\'t help.')
276
277 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800278 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800279 logging.info('Try restore the OS image...')
280 self.faft_client.run_shell_command('chromeos-install --yes')
281 self.sync_and_warm_reboot()
282 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800283 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800284 try:
285 self.wait_for_client(install_deps=True)
286 logging.info('Successfully restore OS image.')
287 return
288 except AssertionError:
289 logging.info('Restoring OS image doesn\'t help.')
290
291
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800292 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800293 """Ensure client in recovery boot; reboot into it if necessary.
294
295 Raises:
296 error.TestError: if failed to boot the USB image.
297 """
298 # DUT works fine and is already in recovery boot, done.
299 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800300 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800301 return
302
303 logging.info('Try boot into USB image...')
304 self.servo.enable_usb_hub(host=True)
305 self.enable_rec_mode_and_reboot()
306 self.wait_fw_screen_and_plug_usb()
307 try:
308 self.wait_for_client(install_deps=True)
309 except AssertionError:
310 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800311
312
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800313 def _restore_routine_from_timeout(self, next_step=None):
314 """A routine to try to restore the system from a timeout error.
315
316 This method is called when FAFT failed to connect DUT after reboot.
317
318 Args:
319 next_step: Optional, a FAFT_STEP dict of the next step, which is used
320 for diagnostic.
321
322 Raises:
323 error.TestFail: This exception is already raised, with a decription
324 why it failed.
325 """
326 next_checker_matched = False
327 if next_step is not None:
328 next_test = {}
329 next_test.update(self._faft_template)
330 next_test.update(next_step)
331
332 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
333 # identify if it is a network flaky.
334
335 recovery_reason = self._retrieve_recovery_reason_from_trap()
336 if next_step is not None and recovery_reason:
337 if self._call_action(next_test['state_checker']):
338 # Repluging the USB can pass the state_checker of the next step,
339 # meaning that the firmware failed to boot into USB directly.
340 next_checker_matched = True
341
342 # Reset client to a workable state.
343 self._reset_client()
344
345 # Raise the proper TestFail exception.
346 if next_checker_matched:
347 raise error.TestFail('Firmware failed to auto-boot USB in the '
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800348 'recovery boot (reason: %d)' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800349 elif recovery_reason:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800350 raise error.TestFail('Trapped in the recovery screen (reason: %d) '
351 'and timed out' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800352 else:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800353 raise error.TestFail('Timed out waiting for DUT reboot')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800354
355
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800356 def assert_test_image_in_path(self, image_path, install_shim=False):
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800357 """Assert the image of image_path be a Chrome OS test image.
358
359 Args:
360 image_path: A path on the host to the test image.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800361 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800362
363 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800364 error.TestError: if the image is not a test (install shim) image.
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800365 """
366 try:
Tom Wai-Hong Tam5929b1e2012-11-07 09:40:42 +0800367 build_ver, build_hash = lab_test.VerifyImageAndGetId(
368 os.environ['CROS_WORKON_SRCROOT'],
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800369 image_path,
370 install_shim=install_shim)
Vic Yang772df8a2012-10-31 10:10:49 +0800371 logging.info('Build of image: %s %s', build_ver, build_hash)
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800372 except ChromeOSTestError:
373 raise error.TestError(
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800374 'An USB disk containning a %s image should be plugged '
375 'in the servo board.' %
376 ('install shim' if install_shim else 'test'))
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800377
378
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800379 def assert_test_image_in_usb_disk(self, usb_dev=None, install_shim=False):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800380 """Assert an USB disk plugged-in on servo and a test image inside.
381
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800382 Args:
383 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
384 If None, it is detected automatically.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800385 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800386
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800387 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800388 error.TestError: if USB disk not detected or not a test (install shim)
389 image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800390 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800391 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800392 return
393
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800394 # TODO(waihong@chromium.org): We skip the check when servod runs in
395 # a different host since no easy way to access the servo host so far.
396 # Should find a way to work-around it.
397 if not self.servo.is_localhost():
398 logging.info('Skip checking Chrome OS test image in USB as servod '
399 'runs in a different host.')
400 return
401
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800402 if usb_dev:
403 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
404 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700405 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800406 usb_dev = self.servo.probe_host_usb_dev()
407 if not usb_dev:
408 raise error.TestError(
409 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800410 self.assert_test_image_in_path(usb_dev, install_shim=install_shim)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800411 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800412
413
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800414 def setup_usbkey(self, usbkey, host=None, install_shim=False):
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800415 """Setup the USB disk for the test.
416
417 It checks the setup of USB disk and a valid ChromeOS test image inside.
418 It also muxes the USB disk to either the host or DUT by request.
419
420 Args:
421 usbkey: True if the USB disk is required for the test, False if not
422 required.
423 host: Optional, True to mux the USB disk to host, False to mux it
424 to DUT, default to do nothing.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800425 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800426 """
427 if usbkey:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800428 self.assert_test_image_in_usb_disk(install_shim=install_shim)
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800429 elif host is None:
430 # USB disk is not required for the test. Better to mux it to host.
431 host = True
432
433 if host is True:
434 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
435 elif host is False:
436 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
437
438
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800439 def get_server_address(self):
440 """Get the server address seen from the client.
441
442 Returns:
443 A string of the server address.
444 """
445 r = self.faft_client.run_shell_command_get_output("echo $SSH_CLIENT")
446 return r[0].split()[0]
447
448
Simran Basi741b5d42012-05-18 11:27:15 -0700449 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800450 """Install the test image specied by the path onto the USB and DUT disk.
451
452 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500453 recovery mode. Then runs 'chromeos-install' (and possible
454 chromeos-firmwareupdate') to install it to DUT disk.
455
456 Sample command line:
457
458 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
459 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
460 server/site_tests/firmware_XXXX/control
461
462 This test requires an automated recovery to occur while simulating
463 inserting and removing the usb key from the servo. To allow this the
464 following hardware setup is required:
465 1. servo2 board connected via servoflex.
466 2. USB key inserted in the servo2.
467 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
468 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800469
470 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800471 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800472 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800473
474 Raises:
475 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800476 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800477 if not image_path:
478 return
479
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800480 if self.check_setup_done('reimage'):
481 return
482
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800483 if image_path.startswith(self._HTTP_PREFIX):
484 # TODO(waihong@chromium.org): Add the check of the URL to ensure
485 # it is a test image.
486 devserver = None
487 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800488 elif self.servo.is_localhost():
489 self.assert_test_image_in_path(image_path)
490 # If servod is localhost, i.e. both servod and FAFT see the same
491 # file system, do nothing.
492 devserver = None
493 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800494 else:
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800495 self.assert_test_image_in_path(image_path)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800496 image_dir, image_base = os.path.split(image_path)
497 logging.info('Starting devserver to serve the image...')
498 # The following stdout and stderr arguments should not be None,
499 # even we don't use them. Otherwise, the socket of devserve is
500 # created as fd 1 (as no stdout) but it still thinks stdout is fd
501 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800502 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800503 '--archive_dir=%s' % image_dir,
504 '--port=%s' % self._DEVSERVER_PORT],
505 stdout=subprocess.PIPE,
506 stderr=subprocess.PIPE)
507 image_url = '%s%s:%s/static/archive/%s' % (
508 self._HTTP_PREFIX,
509 self.get_server_address(),
510 self._DEVSERVER_PORT,
511 image_base)
512
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800513 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800514 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800515 # devserver is a service running forever. If it is terminated,
516 # some error does happen.
517 if devserver.poll():
518 raise error.TestError('Starting devserver failed, '
519 'returning %d.' % devserver.returncode)
520
Vic Yang772df8a2012-10-31 10:10:49 +0800521 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800522 self.servo.image_to_servo_usb(image_url)
523
524 if devserver and devserver.poll() is None:
525 logging.info('Shutting down devserver...')
526 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500527
528 # DUT is powered off while imaging servo USB.
529 # Now turn it on.
530 self.servo.power_short_press()
531 self.wait_for_client()
532 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
533
534 install_cmd = 'chromeos-install --yes'
535 if firmware_update:
536 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800537 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500538
539 self.register_faft_sequence((
540 { # Step 1, request recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800541 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500542 'mainfw_type': ('developer', 'normal'),
543 }),
544 'userspace_action': self.faft_client.request_recovery_boot,
545 'firmware_action': self.wait_fw_screen_and_plug_usb,
546 'install_deps_after_boot': True,
547 },
548 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800549 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500550 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800551 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500552 }),
553 'userspace_action': (self.faft_client.run_shell_command,
554 install_cmd),
555 'reboot_action': self.cold_reboot,
556 'install_deps_after_boot': True,
557 },
558 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800559 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500560 'mainfw_type': ('developer', 'normal')
561 }),
562 },
563 ))
564 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800565
566 if firmware_update:
567 self.clear_saved_firmware()
568
Mike Truty49153d82012-08-21 22:27:30 -0500569 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800570 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800571 # Mark usb_check done so it won't check a test image in USB anymore.
572 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800573 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800574
575
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800576 def clear_set_gbb_flags(self, clear_mask, set_mask):
577 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800578
579 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800580 clear_mask: A mask of flags to be cleared.
581 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800582 """
583 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800584 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
585
586 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800587 logging.info('Change the GBB flags from 0x%x to 0x%x.',
588 gbb_flags, new_flags)
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800589 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800590 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800591 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800592 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800593 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800594 self.run_faft_step({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800595 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800596 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800597
598
Vic Yang772df8a2012-10-31 10:10:49 +0800599 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800600 """Check if current platform has required EC capabilities.
601
602 Args:
603 required_cap: A list containing required EC capabilities. Pass in
604 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800605 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800606
607 Returns:
608 True if requirements are met. Otherwise, False.
609 """
610 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800611 if not suppress_warning:
612 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800613 return False
614
Vic Yang772df8a2012-10-31 10:10:49 +0800615 if not required_cap:
616 return True
617
Vic Yang4d72cb62012-07-24 11:51:09 +0800618 for cap in required_cap:
619 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800620 if not suppress_warning:
621 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800622 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800623 return False
624
625 return True
626
627
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800628 def check_root_part_on_non_recovery(self, part):
629 """Check the partition number of root device and on normal/dev boot.
630
631 Returns:
632 True if the root device matched and on normal/dev boot;
633 otherwise, False.
634 """
Vic Yangf93f7022012-10-31 09:40:36 +0800635 return self.checkers.root_part_checker(part) and \
636 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800637 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800638 })
639
640
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800641 def _join_part(self, dev, part):
642 """Return a concatenated string of device and partition number.
643
644 Args:
645 dev: A string of device, e.g.'/dev/sda'.
646 part: A string of partition number, e.g.'3'.
647
648 Returns:
649 A concatenated string of device and partition number, e.g.'/dev/sda3'.
650
651 >>> seq = FAFTSequence()
652 >>> seq._join_part('/dev/sda', '3')
653 '/dev/sda3'
654 >>> seq._join_part('/dev/mmcblk0', '2')
655 '/dev/mmcblk0p2'
656 """
657 if 'mmcblk' in dev:
658 return dev + 'p' + part
659 else:
660 return dev + part
661
662
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800663 def copy_kernel_and_rootfs(self, from_part, to_part):
664 """Copy kernel and rootfs from from_part to to_part.
665
666 Args:
667 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800668 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800669 """
670 root_dev = self.faft_client.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800671 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800672 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800673 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800674 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
675 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800676 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800677 from_part, to_part)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800678 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800679 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
680 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800681
682
683 def ensure_kernel_boot(self, part):
684 """Ensure the request kernel boot.
685
686 If not, it duplicates the current kernel to the requested kernel
687 and sets the requested higher priority to ensure it boot.
688
689 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800690 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800691 """
Vic Yangf93f7022012-10-31 09:40:36 +0800692 if not self.checkers.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800693 if self.faft_client.diff_kernel_a_b():
694 self.copy_kernel_and_rootfs(
695 from_part=self.OTHER_KERNEL_MAP[part],
696 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800697 self.run_faft_step({
698 'userspace_action': (self.reset_and_prioritize_kernel, part),
699 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800700
701
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800702 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800703 """Set hardware write protect pin.
704
705 Args:
706 enable: True if asserting write protect pin. Otherwise, False.
707 """
708 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
709 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800710 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800711
712
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800713 def set_ec_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800714 """Set EC write protect status and reboot to take effect.
715
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800716 The write protect state is only activated if both hardware write
717 protect pin is asserted and software write protect flag is set.
Vic Yang416f2032012-08-28 10:18:03 +0800718 This method asserts/deasserts hardware write protect pin first, and
719 set corresponding EC software write protect flag.
720
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800721 If the device uses non-Chrome EC, set the software write protect via
722 flashrom.
723
724 If the device uses Chrome EC, a reboot is required for write protect
725 to take effect. Since the software write protect flag cannot be unset
726 if hardware write protect pin is asserted, we need to deasserted the
727 pin first if we are deactivating write protect. Similarly, a reboot
728 is required before we can modify the software flag.
729
Vic Yang416f2032012-08-28 10:18:03 +0800730 Args:
731 enable: True if activating EC write protect. Otherwise, False.
732 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800733 self.set_hardware_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800734 if self.client_attr.chrome_ec:
735 self.set_chrome_ec_write_protect_and_reboot(enable)
736 else:
737 self.faft_client.set_EC_write_protect(enable)
738 self.sync_and_warm_reboot()
739
740
741 def set_chrome_ec_write_protect_and_reboot(self, enable):
742 """Set Chrome EC write protect status and reboot to take effect.
743
744 Args:
745 enable: True if activating EC write protect. Otherwise, False.
746 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800747 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800748 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800749 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800750 self.sync_and_ec_reboot()
751 else:
752 # Reboot after deasserting hardware write protect pin to deactivate
753 # write protect. And then remove software write protect flag.
754 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800755 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800756
757
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800758 def setup_ec_write_protect(self, ec_wp):
759 """Setup for EC write-protection.
760
761 It makes sure the EC in the requested write-protection state. If not, it
762 flips the state. Flipping the write-protection requires DUT reboot.
763
764 Args:
765 ec_wp: True to request EC write-protected; False to request EC not
766 write-protected; None to do nothing.
767 """
768 if ec_wp is None:
769 self._old_ec_wp = None
770 return
771 self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
772 if ec_wp != self._old_ec_wp:
773 logging.info('The test required EC is %swrite-protected. Reboot '
774 'and flip the state.', '' if ec_wp else 'not ')
775 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800776 'reboot_action': (self.set_ec_write_protect_and_reboot, ec_wp)
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800777 })
778
779
780 def restore_ec_write_protect(self):
781 """Restore the original EC write-protection."""
782 if self._old_ec_wp is None:
783 return
784 if not self.checkers.crossystem_checker(
785 {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
786 logging.info('Restore the original EC write protection and reboot.')
787 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800788 'reboot_action': (self.set_ec_write_protect_and_reboot,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800789 self._old_ec_wp)
790 })
791
792
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800793 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800794 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800795 if not self.client_attr.has_keyboard:
796 logging.info('Running usbkm232-ctrld...')
797 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800798 else:
799 self.servo.ctrl_d()
800
801
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800802 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800803 """Send Ctrl-U key to DUT.
804
805 Raises:
806 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
807 on a no-build-in-keyboard device.
808 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800809 if not self.client_attr.has_keyboard:
810 logging.info('Running usbkm232-ctrlu...')
811 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800812 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
813 self.ec.key_down('<ctrl_l>')
814 self.ec.key_down('u')
815 self.ec.key_up('u')
816 self.ec.key_up('<ctrl_l>')
817 elif self.client_attr.has_keyboard:
818 raise error.TestError(
819 "Can't send Ctrl-U to DUT without using Chrome EC.")
820 else:
821 raise error.TestError(
822 "Should specify the ctrl_u_cmd argument.")
823
824
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800825 def press_enter(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800826 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800827 if not self.client_attr.has_keyboard:
828 logging.info('Running usbkm232-enter...')
829 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800830 else:
831 self.servo.enter_key()
832
833
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800834 def wait_dev_screen_and_ctrl_d(self):
835 """Wait for firmware warning screen and press Ctrl-D."""
836 time.sleep(self.delay.dev_screen)
837 self.press_ctrl_d()
838
839
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800840 def wait_fw_screen_and_ctrl_d(self):
841 """Wait for firmware warning screen and press Ctrl-D."""
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_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800844
845
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800846 def wait_fw_screen_and_ctrl_u(self):
847 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800848 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800849 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800850
851
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800852 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
853 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800854 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800855 self.press_enter()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800856
857 # For Alex/ZGB, there is a dev warning screen in text mode.
858 # Skip it by pressing Ctrl-D.
859 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800860 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800861 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800862
863
Mike Truty49153d82012-08-21 22:27:30 -0500864 def wait_fw_screen_and_unplug_usb(self):
865 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800866 time.sleep(self.delay.load_usb)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800867 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800868 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500869
870
871 def wait_fw_screen_and_plug_usb(self):
872 """Wait for firmware warning screen and then unplug and plug the USB."""
873 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800874 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
875
876
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800877 def wait_fw_screen_and_press_power(self):
878 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800879 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800880 # While the firmware screen, the power button probing loop sleeps
881 # 0.25 second on every scan. Use the normal delay (1.2 second) for
882 # power press.
883 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800884
885
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800886 def wait_longer_fw_screen_and_press_power(self):
887 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800888 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800889 self.wait_fw_screen_and_press_power()
890
891
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800892 def wait_fw_screen_and_close_lid(self):
893 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800894 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800895 self.servo.lid_close()
896
897
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800898 def wait_longer_fw_screen_and_close_lid(self):
899 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800900 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800901 self.wait_fw_screen_and_close_lid()
902
903
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800904 def setup_gbb_flags(self):
905 """Setup the GBB flags for FAFT test."""
906 if self.check_setup_done('gbb_flags'):
907 return
908
909 logging.info('Set proper GBB flags for test.')
910 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
911 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
912 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
913 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800914 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
915 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800916 self.mark_setup_done('gbb_flags')
917
918
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800919 def setup_tried_fwb(self, tried_fwb):
920 """Setup for fw B tried state.
921
922 It makes sure the system in the requested fw B tried state. If not, it
923 tries to do so.
924
925 Args:
926 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
927 """
928 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800929 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800930 logging.info(
931 'Firmware is not booted with tried_fwb. Reboot into it.')
932 self.run_faft_step({
933 'userspace_action': self.faft_client.set_try_fw_b,
934 })
935 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800936 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800937 logging.info(
938 'Firmware is booted with tried_fwb. Reboot to clear.')
939 self.run_faft_step({})
940
941
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800942 def enable_rec_mode_and_reboot(self):
943 """Switch to rec mode and reboot.
944
945 This method emulates the behavior of the old physical recovery switch,
946 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
947 recovery mode, i.e. just press Power + Esc + Refresh.
948 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800949 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800950 # Reset twice to emulate a long recovery-key-combo hold.
951 cold_reset_num = 2 if self.client_attr.long_rec_combo else 1
952 for _ in range(cold_reset_num):
953 # Cold reset to clear EC_IN_RW signal
954 self.servo.set('cold_reset', 'on')
955 time.sleep(self.delay.hold_cold_reset)
956 self.servo.set('cold_reset', 'off')
957 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800958 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800959 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800960 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800961 self.servo.power_short_press()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800962 elif self.client_attr.broken_rec_mode:
Tom Wai-Hong Tamc5c14ef2012-11-20 16:33:37 +0800963 if self._host and self._host.has_power():
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800964 self._host.power_cycle()
965 else:
966 logging.info('You have %d seconds to power cycle this device.',
967 self.delay.user_power_cycle)
968 time.sleep(self.delay.user_power_cycle)
969 logging.info('Booting to recovery mode.')
970 self.servo.custom_recovery_mode()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800971 else:
972 self.servo.enable_recovery_mode()
973 self.cold_reboot()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800974 time.sleep(self.delay.ec_reboot_cmd)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800975 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800976
977
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800978 def enable_dev_mode_and_reboot(self):
979 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800980 if self.client_attr.keyboard_dev:
981 self.enable_keyboard_dev_mode()
982 else:
983 self.servo.enable_development_mode()
984 self.faft_client.run_shell_command(
985 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800986
987
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800988 def enable_normal_mode_and_reboot(self):
989 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800990 if self.client_attr.keyboard_dev:
991 self.disable_keyboard_dev_mode()
992 else:
993 self.servo.disable_development_mode()
994 self.faft_client.run_shell_command(
995 'chromeos-firmwareupdate --mode tonormal && reboot')
996
997
998 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
999 """Wait for firmware screen and then switch into or out of dev mode.
1000
1001 Args:
1002 dev: True if switching into dev mode. Otherwise, False.
1003 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001004 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +08001005 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001006 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +08001007 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001008 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +08001009 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001010 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +08001011
1012
1013 def enable_keyboard_dev_mode(self):
1014 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +08001015 # Plug out USB disk for preventing recovery boot without warning
1016 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +08001017 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +08001018 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001019 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001020 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +08001021
1022
1023 def disable_keyboard_dev_mode(self):
1024 logging.info("Disabling keyboard controlled developer mode")
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -08001025 if (not self.client_attr.chrome_ec and
1026 not self.client_attr.broken_rec_mode):
Vic Yang611dd852012-08-02 15:36:31 +08001027 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001028 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001029 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001030 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001031
1032
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001033 def setup_dev_mode(self, dev_mode):
1034 """Setup for development mode.
1035
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001036 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001037 tries to do so.
1038
1039 Args:
1040 dev_mode: True if requested in dev mode; False if normal mode.
1041 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001042 # Change the default firmware_action for dev mode passing the fw screen.
1043 self.register_faft_template({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +08001044 'firmware_action': (self.wait_dev_screen_and_ctrl_d if dev_mode
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001045 else None),
1046 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001047 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +08001048 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001049 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001050 logging.info('Dev switch is not on. Now switch it on.')
1051 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001052 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001053 'mainfw_type': 'developer'}):
1054 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001055 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001056 'userspace_action': None if self.client_attr.keyboard_dev
1057 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001058 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001059 'reboot_action': self.enable_keyboard_dev_mode if
1060 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001061 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001062 else:
Vic Yange7553162012-06-20 16:20:47 +08001063 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001064 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001065 logging.info('Dev switch is not off. Now switch it off.')
1066 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001067 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001068 'mainfw_type': 'normal'}):
1069 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001070 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001071 'userspace_action': None if self.client_attr.keyboard_dev
1072 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001073 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001074 'reboot_action': self.disable_keyboard_dev_mode if
1075 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001076 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001077
1078
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001079 def setup_kernel(self, part):
1080 """Setup for kernel test.
1081
1082 It makes sure both kernel A and B bootable and the current boot is
1083 the requested kernel part.
1084
1085 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001086 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001087 """
1088 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001089 if self.faft_client.diff_kernel_a_b():
1090 self.copy_kernel_and_rootfs(from_part=part,
1091 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001092 self.reset_and_prioritize_kernel(part)
1093
1094
1095 def reset_and_prioritize_kernel(self, part):
1096 """Make the requested partition highest priority.
1097
1098 This function also reset kerenl A and B to bootable.
1099
1100 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001101 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001102 """
1103 root_dev = self.faft_client.get_root_dev()
1104 # Reset kernel A and B to bootable.
1105 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1106 (self.KERNEL_MAP['a'], root_dev))
1107 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1108 (self.KERNEL_MAP['b'], root_dev))
1109 # Set kernel part highest priority.
1110 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1111 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001112 # Safer to sync and wait until the cgpt status written to the disk.
1113 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001114 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001115
1116
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001117 def warm_reboot(self):
1118 """Request a warm reboot.
1119
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001120 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001121 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001122 # Use cold reset if the warm reset is broken.
1123 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001124 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1125 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001126 else:
1127 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001128
1129
1130 def cold_reboot(self):
1131 """Request a cold reboot.
1132
1133 A wrapper for underlying servo cold reset.
1134 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001135 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001136 self.servo.set('pwr_button', 'press')
1137 self.servo.set('cold_reset', 'on')
1138 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001139 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001140 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001141 else:
1142 self.servo.cold_reset()
1143
1144
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001145 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001146 """Request the client sync and do a warm reboot.
1147
1148 This is the default reboot action on FAFT.
1149 """
1150 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001151 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001152 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001153
1154
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001155 def sync_and_cold_reboot(self):
1156 """Request the client sync and do a cold reboot.
1157
1158 This reboot action is used to reset EC for recovery mode.
1159 """
1160 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001161 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001162 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001163
1164
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001165 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001166 """Request the client sync and do a EC triggered reboot.
1167
1168 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001169 flags: Optional, a space-separated string of flags passed to EC
1170 reboot command, including:
1171 default: EC soft reboot;
1172 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001173 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001174 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001175 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001176 self.ec.reboot(flags)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001177 time.sleep(self.delay.ec_reboot_cmd)
Vic Yangf86728a2012-07-30 10:44:07 +08001178 self.check_lid_and_power_on()
1179
1180
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001181 def reboot_with_factory_install_shim(self):
1182 """Request reboot with factory install shim to reset TPM.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001183
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001184 Factory install shim requires dev mode enabled. So this method switches
1185 firmware to dev mode first and reboot. The client uses factory install
1186 shim to reset TPM values.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001187 """
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001188 # Unplug USB first to avoid the complicated USB autoboot cases.
1189 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yangf93f7022012-10-31 09:40:36 +08001190 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001191 if not is_dev:
1192 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001193 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001194 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001195 self.wait_fw_screen_and_plug_usb()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001196 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001197 self.warm_reboot()
1198
1199
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001200 def full_power_off_and_on(self):
1201 """Shutdown the device by pressing power button and power on again."""
1202 # Press power button to trigger Chrome OS normal shutdown process.
1203 self.servo.power_normal_press()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001204 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001205 # Short press power button to boot DUT again.
1206 self.servo.power_short_press()
1207
1208
Vic Yangf86728a2012-07-30 10:44:07 +08001209 def check_lid_and_power_on(self):
1210 """
1211 On devices with EC software sync, system powers on after EC reboots if
1212 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1213 This method checks lid switch state and presses power button if
1214 necessary.
1215 """
1216 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001217 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001218 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001219
1220
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001221 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1222 """Modify the kernel header magic in USB stick.
1223
1224 The kernel header magic is the first 8-byte of kernel partition.
1225 We modify it to make it fail on kernel verification check.
1226
1227 Args:
1228 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1229 from_magic: A string of magic which we change it from.
1230 to_magic: A string of magic which we change it to.
1231
1232 Raises:
1233 error.TestError: if failed to change magic.
1234 """
1235 assert len(from_magic) == 8
1236 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001237 # USB image only contains one kernel.
1238 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001239 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1240 current_magic = utils.system_output(read_cmd)
1241 if current_magic == to_magic:
Vic Yang772df8a2012-10-31 10:10:49 +08001242 logging.info("The kernel magic is already %s.", current_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001243 return
1244 if current_magic != from_magic:
1245 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1246
Vic Yang772df8a2012-10-31 10:10:49 +08001247 logging.info('Modify the kernel magic in USB, from %s to %s.',
1248 from_magic, to_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001249 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1250 " 2>/dev/null" % (to_magic, kernel_part))
1251 utils.system(write_cmd)
1252
1253 if utils.system_output(read_cmd) != to_magic:
1254 raise error.TestError("Failed to write new magic.")
1255
1256
1257 def corrupt_usb_kernel(self, usb_dev):
1258 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1259
1260 Args:
1261 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1262 """
1263 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1264 self.CORRUPTED_MAGIC)
1265
1266
1267 def restore_usb_kernel(self, usb_dev):
1268 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1269
1270 Args:
1271 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1272 """
1273 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1274 self.CHROMEOS_MAGIC)
1275
1276
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001277 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001278 """Call the action function with/without arguments.
1279
1280 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001281 action_tuple: A function, or a tuple (function, args, error_msg),
1282 in which, args and error_msg are optional. args is
1283 either a value or a tuple if multiple arguments.
Vic Yang52116d42012-11-05 16:22:34 +08001284 This can also be a list containing multiple function
1285 or tuple. In this case, these actions are called in
1286 sequence.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001287 check_status: Check the return value of action function. If not
1288 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001289
1290 Returns:
1291 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001292
1293 Raises:
1294 error.TestError: An error when the action function is not callable.
1295 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001296 """
Vic Yang52116d42012-11-05 16:22:34 +08001297 if isinstance(action_tuple, list):
1298 return all([self._call_action(action, check_status=check_status)
1299 for action in action_tuple])
1300
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001301 action = action_tuple
1302 args = ()
1303 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001304 if isinstance(action_tuple, tuple):
1305 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001306 if len(action_tuple) >= 2:
1307 args = action_tuple[1]
1308 if not isinstance(args, tuple):
1309 args = (args,)
1310 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001311 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001312
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001313 if action is None:
1314 return
1315
1316 if not callable(action):
1317 raise error.TestError('action is not callable!')
1318
1319 info_msg = 'calling %s' % str(action)
1320 if args:
1321 info_msg += ' with args %s' % str(args)
1322 logging.info(info_msg)
1323 ret = action(*args)
1324
1325 if check_status and not ret:
1326 raise error.TestFail('%s: %s returning %s' %
1327 (error_msg, info_msg, str(ret)))
1328 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001329
1330
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001331 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1332 post_power_action=None):
1333 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1334
1335 Args:
1336 shutdown_action: a function which makes DUT shutdown, like pressing
1337 power key.
1338 pre_power_action: a function which is called before next power on.
1339 post_power_action: a function which is called after next power on.
1340
1341 Raises:
1342 error.TestFail: if the shutdown_action() failed to turn DUT off.
1343 """
1344 self._call_action(shutdown_action)
1345 logging.info('Wait to ensure DUT shut down...')
1346 try:
1347 self.wait_for_client()
1348 raise error.TestFail(
1349 'Should shut the device down after calling %s.' %
1350 str(shutdown_action))
1351 except AssertionError:
1352 logging.info(
1353 'DUT is surely shutdown. We are going to power it on again...')
1354
1355 if pre_power_action:
1356 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001357 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001358 if post_power_action:
1359 self._call_action(post_power_action)
1360
1361
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001362 def register_faft_template(self, template):
1363 """Register FAFT template, the default FAFT_STEP of each step.
1364
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001365 Any missing field falls back to the original faft_template.
1366
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001367 Args:
1368 template: A FAFT_STEP dict.
1369 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001370 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001371
1372
1373 def register_faft_sequence(self, sequence):
1374 """Register FAFT sequence.
1375
1376 Args:
1377 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1378 """
1379 self._faft_sequence = sequence
1380
1381
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001382 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001383 """Run a single FAFT step.
1384
1385 Any missing field falls back to faft_template. An empty step means
1386 running the default faft_template.
1387
1388 Args:
1389 step: A FAFT_STEP dict.
1390 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001391 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1392 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001393
1394 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001395 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001396 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001397 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001398 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1399 'firmware_action', 'install_deps_after_boot')
1400
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001401 test = {}
1402 test.update(self._faft_template)
1403 test.update(step)
1404
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001405 for key in test:
1406 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001407 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001408
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001409 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001410 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001411
1412 self._call_action(test['userspace_action'])
1413
1414 # Don't run reboot_action and firmware_action if no_reboot is True.
1415 if not no_reboot:
1416 self._call_action(test['reboot_action'])
1417 self.wait_for_client_offline()
1418 self._call_action(test['firmware_action'])
1419
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001420 try:
1421 if 'install_deps_after_boot' in test:
1422 self.wait_for_client(
1423 install_deps=test['install_deps_after_boot'])
1424 else:
1425 self.wait_for_client()
1426 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001427 logging.info('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001428 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001429
1430
1431 def run_faft_sequence(self):
1432 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001433 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001434 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001435 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001436 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001437 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001438 if index == len(sequence) - 1:
1439 self.run_faft_step(step, no_reboot=True)
1440 else:
1441 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001442
1443
ctchang38ae4922012-09-03 17:01:16 +08001444 def get_current_firmware_sha(self):
1445 """Get current firmware sha of body and vblock.
1446
1447 Returns:
1448 Current firmware sha follows the order (
1449 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1450 """
1451 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1452 self.faft_client.get_firmware_sha('a'),
1453 self.faft_client.get_firmware_sig_sha('b'),
1454 self.faft_client.get_firmware_sha('b'))
1455 return current_firmware_sha
1456
1457
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001458 def is_firmware_changed(self):
1459 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001460
1461 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001462 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001463 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001464 # Device may not be rebooted after test.
1465 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001466
1467 current_sha = self.get_current_firmware_sha()
1468
1469 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001470 return False
ctchang38ae4922012-09-03 17:01:16 +08001471 else:
ctchang38ae4922012-09-03 17:01:16 +08001472 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1473 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1474 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1475 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001476 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001477 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1478 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1479 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1480 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001481 return True
ctchang38ae4922012-09-03 17:01:16 +08001482
1483
1484 def backup_firmware(self, suffix='.original'):
1485 """Backup firmware to file, and then send it to host.
1486
1487 Args:
1488 suffix: a string appended to backup file name
1489 """
1490 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001491 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1492 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1493 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001494
1495 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001496 logging.info('Backup firmware stored in %s with suffix %s',
1497 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001498
1499
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001500 def is_firmware_saved(self):
1501 """Check if a firmware saved (called backup_firmware before).
1502
1503 Returns:
1504 True if the firmware is backuped; otherwise False.
1505 """
1506 return self._backup_firmware_sha != ()
1507
1508
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001509 def clear_saved_firmware(self):
1510 """Clear the firmware saved by the method backup_firmware."""
1511 self._backup_firmware_sha = ()
1512
1513
ctchang38ae4922012-09-03 17:01:16 +08001514 def restore_firmware(self, suffix='.original'):
1515 """Restore firmware from host in resultsdir.
1516
1517 Args:
1518 suffix: a string appended to backup file name
1519 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001520 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001521 return
1522
1523 # Backup current corrupted firmware.
1524 self.backup_firmware(suffix='.corrupt')
1525
1526 # Restore firmware.
1527 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001528 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1529 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001530
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001531 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001532 self.sync_and_warm_reboot()
1533 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +08001534 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001535 self.wait_for_client()
1536
ctchang38ae4922012-09-03 17:01:16 +08001537 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001538
1539
1540 def setup_firmwareupdate_shellball(self, shellball=None):
1541 """Deside a shellball to use in firmware update test.
1542
1543 Check if there is a given shellball, and it is a shell script. Then,
1544 send it to the remote host. Otherwise, use
1545 /usr/sbin/chromeos-firmwareupdate.
1546
1547 Args:
1548 shellball: path of a shellball or default to None.
1549
1550 Returns:
1551 Path of shellball in remote host.
1552 If use default shellball, reutrn None.
1553 """
1554 updater_path = None
1555 if shellball:
1556 # Determine the firmware file is a shellball or a raw binary.
1557 is_shellball = (utils.system_output("file %s" % shellball).find(
1558 "shell script") != -1)
1559 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001560 logging.info('Device will update firmware with shellball %s',
1561 shellball)
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001562 temp_dir = self.faft_client.create_temp_dir('shellball_')
1563 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1564 self._client.send_file(shellball, temp_shellball)
1565 updater_path = temp_shellball
1566 else:
1567 raise error.TestFail(
1568 'The given shellball is not a shell script.')
1569 return updater_path