blob: 62b737e580e3cfe83ea1776f5f6a6738586c4545 [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(
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800160 self.faft_client.system.get_platform_name())
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800161 self.delay = FAFTDelayConstants(
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800162 self.faft_client.system.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 Tamb92669c2012-11-29 13:57:11 +0800197 self.record_system_info()
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800198 self.setup_gbb_flags()
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800199 self.setup_ec_write_protect(ec_wp)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800200
201
202 def cleanup(self):
203 """Autotest cleanup function."""
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800204 self.restore_ec_write_protect()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800205 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800206 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800207 super(FAFTSequence, self).cleanup()
208
209
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800210 def record_system_info(self):
211 """Record some critical system info to the attr keyval.
212
213 This info is used by generate_test_report and local_dash later.
214 """
215 self.write_attr_keyval({
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800216 'fw_version': self.faft_client.ec.get_version(),
217 'hwid': self.faft_client.system.get_crossystem_value('hwid'),
218 'fwid': self.faft_client.system.get_crossystem_value('fwid'),
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800219 })
220
221
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800222 def invalidate_firmware_setup(self):
223 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800224
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800225 This method is called when the firmware is re-flashed. It resets all
226 firmware related setup states so that the next test setup properly
227 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800228 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800229 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800230
231
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800232 def _retrieve_recovery_reason_from_trap(self):
233 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800234
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800235 Returns:
236 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800237 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800238 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800239 logging.info('Try to retrieve recovery reason...')
240 if self.servo.get('usb_mux_sel1') == 'dut_sees_usbkey':
241 self.wait_fw_screen_and_plug_usb()
242 else:
243 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
244
245 try:
246 self.wait_for_client(install_deps=True)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800247 lines = self.faft_client.system.run_shell_command_get_output(
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800248 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800249 recovery_reason = int(lines[0])
250 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800251 except AssertionError:
252 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800253 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800254
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800255
256 def _reset_client(self):
257 """Reset client to a workable state.
258
259 This method is called when the client is not responsive. It may be
260 caused by the following cases:
261 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
262 - corrupted firmware;
263 - corrutped OS image.
264 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800265 # DUT may halt on a firmware screen. Try cold reboot.
266 logging.info('Try cold reboot...')
267 self.cold_reboot()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800268 self.wait_for_client_offline()
269 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800270 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800271 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800272 return
273 except AssertionError:
274 pass
275
276 # DUT may be broken by a corrupted firmware. Restore firmware.
277 # We assume the recovery boot still works fine. Since the recovery
278 # code is in RO region and all FAFT tests don't change the RO region
279 # except GBB.
280 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800281 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800282 logging.info('Try restore the original firmware...')
283 if self.is_firmware_changed():
284 try:
285 self.restore_firmware()
286 return
287 except AssertionError:
288 logging.info('Restoring firmware doesn\'t help.')
289
290 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800291 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800292 logging.info('Try restore the OS image...')
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800293 self.faft_client.system.run_shell_command('chromeos-install --yes')
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800294 self.sync_and_warm_reboot()
295 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800296 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800297 try:
298 self.wait_for_client(install_deps=True)
299 logging.info('Successfully restore OS image.')
300 return
301 except AssertionError:
302 logging.info('Restoring OS image doesn\'t help.')
303
304
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800305 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800306 """Ensure client in recovery boot; reboot into it if necessary.
307
308 Raises:
309 error.TestError: if failed to boot the USB image.
310 """
311 # DUT works fine and is already in recovery boot, done.
312 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800313 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800314 return
315
316 logging.info('Try boot into USB image...')
317 self.servo.enable_usb_hub(host=True)
318 self.enable_rec_mode_and_reboot()
319 self.wait_fw_screen_and_plug_usb()
320 try:
321 self.wait_for_client(install_deps=True)
322 except AssertionError:
323 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800324
325
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800326 def _restore_routine_from_timeout(self, next_step=None):
327 """A routine to try to restore the system from a timeout error.
328
329 This method is called when FAFT failed to connect DUT after reboot.
330
331 Args:
332 next_step: Optional, a FAFT_STEP dict of the next step, which is used
333 for diagnostic.
334
335 Raises:
336 error.TestFail: This exception is already raised, with a decription
337 why it failed.
338 """
339 next_checker_matched = False
340 if next_step is not None:
341 next_test = {}
342 next_test.update(self._faft_template)
343 next_test.update(next_step)
344
345 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
346 # identify if it is a network flaky.
347
348 recovery_reason = self._retrieve_recovery_reason_from_trap()
349 if next_step is not None and recovery_reason:
350 if self._call_action(next_test['state_checker']):
351 # Repluging the USB can pass the state_checker of the next step,
352 # meaning that the firmware failed to boot into USB directly.
353 next_checker_matched = True
354
355 # Reset client to a workable state.
356 self._reset_client()
357
358 # Raise the proper TestFail exception.
359 if next_checker_matched:
360 raise error.TestFail('Firmware failed to auto-boot USB in the '
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800361 'recovery boot (reason: %d)' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800362 elif recovery_reason:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800363 raise error.TestFail('Trapped in the recovery screen (reason: %d) '
364 'and timed out' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800365 else:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800366 raise error.TestFail('Timed out waiting for DUT reboot')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800367
368
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800369 def assert_test_image_in_path(self, image_path, install_shim=False):
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800370 """Assert the image of image_path be a Chrome OS test image.
371
372 Args:
373 image_path: A path on the host to the test image.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800374 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800375
376 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800377 error.TestError: if the image is not a test (install shim) image.
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800378 """
379 try:
Tom Wai-Hong Tam5929b1e2012-11-07 09:40:42 +0800380 build_ver, build_hash = lab_test.VerifyImageAndGetId(
381 os.environ['CROS_WORKON_SRCROOT'],
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800382 image_path,
383 install_shim=install_shim)
Vic Yang772df8a2012-10-31 10:10:49 +0800384 logging.info('Build of image: %s %s', build_ver, build_hash)
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800385 except ChromeOSTestError:
386 raise error.TestError(
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800387 'An USB disk containning a %s image should be plugged '
388 'in the servo board.' %
389 ('install shim' if install_shim else 'test'))
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800390
391
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800392 def assert_test_image_in_usb_disk(self, usb_dev=None, install_shim=False):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800393 """Assert an USB disk plugged-in on servo and a test image inside.
394
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800395 Args:
396 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
397 If None, it is detected automatically.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800398 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800399
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800400 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800401 error.TestError: if USB disk not detected or not a test (install shim)
402 image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800403 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800404 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800405 return
406
Tom Wai-Hong Tam1c86c7a2012-10-22 10:08:24 +0800407 # TODO(waihong@chromium.org): We skip the check when servod runs in
408 # a different host since no easy way to access the servo host so far.
409 # Should find a way to work-around it.
410 if not self.servo.is_localhost():
411 logging.info('Skip checking Chrome OS test image in USB as servod '
412 'runs in a different host.')
413 return
414
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800415 if usb_dev:
416 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
417 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700418 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800419 usb_dev = self.servo.probe_host_usb_dev()
420 if not usb_dev:
421 raise error.TestError(
422 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800423 self.assert_test_image_in_path(usb_dev, install_shim=install_shim)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800424 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800425
426
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800427 def setup_usbkey(self, usbkey, host=None, install_shim=False):
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800428 """Setup the USB disk for the test.
429
430 It checks the setup of USB disk and a valid ChromeOS test image inside.
431 It also muxes the USB disk to either the host or DUT by request.
432
433 Args:
434 usbkey: True if the USB disk is required for the test, False if not
435 required.
436 host: Optional, True to mux the USB disk to host, False to mux it
437 to DUT, default to do nothing.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800438 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800439 """
440 if usbkey:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800441 self.assert_test_image_in_usb_disk(install_shim=install_shim)
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800442 elif host is None:
443 # USB disk is not required for the test. Better to mux it to host.
444 host = True
445
446 if host is True:
447 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
448 elif host is False:
449 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
450
451
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800452 def get_server_address(self):
453 """Get the server address seen from the client.
454
455 Returns:
456 A string of the server address.
457 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800458 r = self.faft_client.system.run_shell_command_get_output(
459 "echo $SSH_CLIENT")
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800460 return r[0].split()[0]
461
462
Simran Basi741b5d42012-05-18 11:27:15 -0700463 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800464 """Install the test image specied by the path onto the USB and DUT disk.
465
466 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500467 recovery mode. Then runs 'chromeos-install' (and possible
468 chromeos-firmwareupdate') to install it to DUT disk.
469
470 Sample command line:
471
472 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
473 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
474 server/site_tests/firmware_XXXX/control
475
476 This test requires an automated recovery to occur while simulating
477 inserting and removing the usb key from the servo. To allow this the
478 following hardware setup is required:
479 1. servo2 board connected via servoflex.
480 2. USB key inserted in the servo2.
481 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
482 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800483
484 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800485 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800486 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800487
488 Raises:
489 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800490 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800491 if not image_path:
492 return
493
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800494 if self.check_setup_done('reimage'):
495 return
496
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800497 if image_path.startswith(self._HTTP_PREFIX):
498 # TODO(waihong@chromium.org): Add the check of the URL to ensure
499 # it is a test image.
500 devserver = None
501 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800502 elif self.servo.is_localhost():
503 self.assert_test_image_in_path(image_path)
504 # If servod is localhost, i.e. both servod and FAFT see the same
505 # file system, do nothing.
506 devserver = None
507 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800508 else:
Tom Wai-Hong Tam08885ae2012-10-19 17:16:45 +0800509 self.assert_test_image_in_path(image_path)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800510 image_dir, image_base = os.path.split(image_path)
511 logging.info('Starting devserver to serve the image...')
512 # The following stdout and stderr arguments should not be None,
513 # even we don't use them. Otherwise, the socket of devserve is
514 # created as fd 1 (as no stdout) but it still thinks stdout is fd
515 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800516 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800517 '--archive_dir=%s' % image_dir,
518 '--port=%s' % self._DEVSERVER_PORT],
519 stdout=subprocess.PIPE,
520 stderr=subprocess.PIPE)
521 image_url = '%s%s:%s/static/archive/%s' % (
522 self._HTTP_PREFIX,
523 self.get_server_address(),
524 self._DEVSERVER_PORT,
525 image_base)
526
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800527 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800528 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800529 # devserver is a service running forever. If it is terminated,
530 # some error does happen.
531 if devserver.poll():
532 raise error.TestError('Starting devserver failed, '
533 'returning %d.' % devserver.returncode)
534
Vic Yang772df8a2012-10-31 10:10:49 +0800535 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800536 self.servo.image_to_servo_usb(image_url)
537
538 if devserver and devserver.poll() is None:
539 logging.info('Shutting down devserver...')
540 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500541
542 # DUT is powered off while imaging servo USB.
543 # Now turn it on.
544 self.servo.power_short_press()
545 self.wait_for_client()
546 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
547
548 install_cmd = 'chromeos-install --yes'
549 if firmware_update:
550 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800551 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500552
553 self.register_faft_sequence((
554 { # Step 1, request recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800555 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500556 'mainfw_type': ('developer', 'normal'),
557 }),
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800558 'userspace_action': (
559 self.faft_client.system.request_recovery_boot),
Mike Truty49153d82012-08-21 22:27:30 -0500560 'firmware_action': self.wait_fw_screen_and_plug_usb,
561 'install_deps_after_boot': True,
562 },
563 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800564 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500565 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800566 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500567 }),
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800568 'userspace_action': (self.faft_client.system.run_shell_command,
Mike Truty49153d82012-08-21 22:27:30 -0500569 install_cmd),
570 'reboot_action': self.cold_reboot,
571 'install_deps_after_boot': True,
572 },
573 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800574 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500575 'mainfw_type': ('developer', 'normal')
576 }),
577 },
578 ))
579 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800580
581 if firmware_update:
582 self.clear_saved_firmware()
583
Mike Truty49153d82012-08-21 22:27:30 -0500584 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800585 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800586 # Mark usb_check done so it won't check a test image in USB anymore.
587 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800588 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800589
590
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800591 def clear_set_gbb_flags(self, clear_mask, set_mask):
592 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800593
594 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800595 clear_mask: A mask of flags to be cleared.
596 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800597 """
Tom Wai-Hong Tamc1a569f2012-12-04 15:07:25 +0800598 gbb_flags = self.faft_client.bios.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800599 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
600
601 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800602 logging.info('Change the GBB flags from 0x%x to 0x%x.',
603 gbb_flags, new_flags)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800604 self.faft_client.system.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800605 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800606 self.faft_client.bios.reload()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800607 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800608 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800609 self.run_faft_step({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800610 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800611 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800612
613
Vic Yang772df8a2012-10-31 10:10:49 +0800614 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800615 """Check if current platform has required EC capabilities.
616
617 Args:
618 required_cap: A list containing required EC capabilities. Pass in
619 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800620 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800621
622 Returns:
623 True if requirements are met. Otherwise, False.
624 """
625 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800626 if not suppress_warning:
627 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800628 return False
629
Vic Yang772df8a2012-10-31 10:10:49 +0800630 if not required_cap:
631 return True
632
Vic Yang4d72cb62012-07-24 11:51:09 +0800633 for cap in required_cap:
634 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800635 if not suppress_warning:
636 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800637 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800638 return False
639
640 return True
641
642
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800643 def check_root_part_on_non_recovery(self, part):
644 """Check the partition number of root device and on normal/dev boot.
645
646 Returns:
647 True if the root device matched and on normal/dev boot;
648 otherwise, False.
649 """
Vic Yangf93f7022012-10-31 09:40:36 +0800650 return self.checkers.root_part_checker(part) and \
651 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800652 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800653 })
654
655
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800656 def _join_part(self, dev, part):
657 """Return a concatenated string of device and partition number.
658
659 Args:
660 dev: A string of device, e.g.'/dev/sda'.
661 part: A string of partition number, e.g.'3'.
662
663 Returns:
664 A concatenated string of device and partition number, e.g.'/dev/sda3'.
665
666 >>> seq = FAFTSequence()
667 >>> seq._join_part('/dev/sda', '3')
668 '/dev/sda3'
669 >>> seq._join_part('/dev/mmcblk0', '2')
670 '/dev/mmcblk0p2'
671 """
672 if 'mmcblk' in dev:
673 return dev + 'p' + part
674 else:
675 return dev + part
676
677
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800678 def copy_kernel_and_rootfs(self, from_part, to_part):
679 """Copy kernel and rootfs from from_part to to_part.
680
681 Args:
682 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800683 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800684 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800685 root_dev = self.faft_client.system.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800686 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800687 from_part, to_part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800688 self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800689 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
690 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800691 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800692 from_part, to_part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800693 self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800694 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
695 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800696
697
698 def ensure_kernel_boot(self, part):
699 """Ensure the request kernel boot.
700
701 If not, it duplicates the current kernel to the requested kernel
702 and sets the requested higher priority to ensure it boot.
703
704 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800705 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800706 """
Vic Yangf93f7022012-10-31 09:40:36 +0800707 if not self.checkers.root_part_checker(part):
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800708 if self.faft_client.kernel.diff_a_b():
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800709 self.copy_kernel_and_rootfs(
710 from_part=self.OTHER_KERNEL_MAP[part],
711 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800712 self.run_faft_step({
713 'userspace_action': (self.reset_and_prioritize_kernel, part),
714 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800715
716
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800717 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800718 """Set hardware write protect pin.
719
720 Args:
721 enable: True if asserting write protect pin. Otherwise, False.
722 """
723 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
724 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800725 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800726
727
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800728 def set_ec_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800729 """Set EC write protect status and reboot to take effect.
730
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800731 The write protect state is only activated if both hardware write
732 protect pin is asserted and software write protect flag is set.
Vic Yang416f2032012-08-28 10:18:03 +0800733 This method asserts/deasserts hardware write protect pin first, and
734 set corresponding EC software write protect flag.
735
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800736 If the device uses non-Chrome EC, set the software write protect via
737 flashrom.
738
739 If the device uses Chrome EC, a reboot is required for write protect
740 to take effect. Since the software write protect flag cannot be unset
741 if hardware write protect pin is asserted, we need to deasserted the
742 pin first if we are deactivating write protect. Similarly, a reboot
743 is required before we can modify the software flag.
744
Vic Yang416f2032012-08-28 10:18:03 +0800745 Args:
746 enable: True if activating EC write protect. Otherwise, False.
747 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800748 self.set_hardware_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800749 if self.client_attr.chrome_ec:
750 self.set_chrome_ec_write_protect_and_reboot(enable)
751 else:
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800752 self.faft_client.ec.set_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800753 self.sync_and_warm_reboot()
754
755
756 def set_chrome_ec_write_protect_and_reboot(self, enable):
757 """Set Chrome EC write protect status and reboot to take effect.
758
759 Args:
760 enable: True if activating EC write protect. Otherwise, False.
761 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800762 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800763 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800764 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800765 self.sync_and_ec_reboot()
766 else:
767 # Reboot after deasserting hardware write protect pin to deactivate
768 # write protect. And then remove software write protect flag.
769 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800770 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800771
772
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800773 def setup_ec_write_protect(self, ec_wp):
774 """Setup for EC write-protection.
775
776 It makes sure the EC in the requested write-protection state. If not, it
777 flips the state. Flipping the write-protection requires DUT reboot.
778
779 Args:
780 ec_wp: True to request EC write-protected; False to request EC not
781 write-protected; None to do nothing.
782 """
783 if ec_wp is None:
784 self._old_ec_wp = None
785 return
786 self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
787 if ec_wp != self._old_ec_wp:
788 logging.info('The test required EC is %swrite-protected. Reboot '
789 'and flip the state.', '' if ec_wp else 'not ')
790 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800791 'reboot_action': (self.set_ec_write_protect_and_reboot, ec_wp)
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800792 })
793
794
795 def restore_ec_write_protect(self):
796 """Restore the original EC write-protection."""
797 if self._old_ec_wp is None:
798 return
799 if not self.checkers.crossystem_checker(
800 {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
801 logging.info('Restore the original EC write protection and reboot.')
802 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800803 'reboot_action': (self.set_ec_write_protect_and_reboot,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800804 self._old_ec_wp)
805 })
806
807
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800808 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800809 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800810 if not self.client_attr.has_keyboard:
811 logging.info('Running usbkm232-ctrld...')
812 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800813 else:
814 self.servo.ctrl_d()
815
816
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800817 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800818 """Send Ctrl-U key to DUT.
819
820 Raises:
821 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
822 on a no-build-in-keyboard device.
823 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800824 if not self.client_attr.has_keyboard:
825 logging.info('Running usbkm232-ctrlu...')
826 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800827 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
828 self.ec.key_down('<ctrl_l>')
829 self.ec.key_down('u')
830 self.ec.key_up('u')
831 self.ec.key_up('<ctrl_l>')
832 elif self.client_attr.has_keyboard:
833 raise error.TestError(
834 "Can't send Ctrl-U to DUT without using Chrome EC.")
835 else:
836 raise error.TestError(
837 "Should specify the ctrl_u_cmd argument.")
838
839
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800840 def press_enter(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800841 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800842 if not self.client_attr.has_keyboard:
843 logging.info('Running usbkm232-enter...')
844 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800845 else:
846 self.servo.enter_key()
847
848
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800849 def wait_dev_screen_and_ctrl_d(self):
850 """Wait for firmware warning screen and press Ctrl-D."""
851 time.sleep(self.delay.dev_screen)
852 self.press_ctrl_d()
853
854
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800855 def wait_fw_screen_and_ctrl_d(self):
856 """Wait for firmware warning screen and press Ctrl-D."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800857 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800858 self.press_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800859
860
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800861 def wait_fw_screen_and_ctrl_u(self):
862 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800863 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800864 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800865
866
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800867 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
868 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800869 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800870 self.press_enter()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800871
872 # For Alex/ZGB, there is a dev warning screen in text mode.
873 # Skip it by pressing Ctrl-D.
874 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800875 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800876 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800877
878
Mike Truty49153d82012-08-21 22:27:30 -0500879 def wait_fw_screen_and_unplug_usb(self):
880 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800881 time.sleep(self.delay.load_usb)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800882 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800883 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500884
885
886 def wait_fw_screen_and_plug_usb(self):
887 """Wait for firmware warning screen and then unplug and plug the USB."""
888 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800889 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
890
891
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800892 def wait_fw_screen_and_press_power(self):
893 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800894 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800895 # While the firmware screen, the power button probing loop sleeps
896 # 0.25 second on every scan. Use the normal delay (1.2 second) for
897 # power press.
898 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800899
900
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800901 def wait_longer_fw_screen_and_press_power(self):
902 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800903 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800904 self.wait_fw_screen_and_press_power()
905
906
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800907 def wait_fw_screen_and_close_lid(self):
908 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800909 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800910 self.servo.lid_close()
911
912
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800913 def wait_longer_fw_screen_and_close_lid(self):
914 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800915 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800916 self.wait_fw_screen_and_close_lid()
917
918
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800919 def setup_gbb_flags(self):
920 """Setup the GBB flags for FAFT test."""
921 if self.check_setup_done('gbb_flags'):
922 return
923
924 logging.info('Set proper GBB flags for test.')
925 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
926 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
927 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
928 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800929 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
930 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800931 self.mark_setup_done('gbb_flags')
932
933
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800934 def setup_tried_fwb(self, tried_fwb):
935 """Setup for fw B tried state.
936
937 It makes sure the system in the requested fw B tried state. If not, it
938 tries to do so.
939
940 Args:
941 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
942 """
943 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800944 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800945 logging.info(
946 'Firmware is not booted with tried_fwb. Reboot into it.')
947 self.run_faft_step({
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800948 'userspace_action': self.faft_client.system.set_try_fw_b,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800949 })
950 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800951 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800952 logging.info(
953 'Firmware is booted with tried_fwb. Reboot to clear.')
954 self.run_faft_step({})
955
956
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800957 def enable_rec_mode_and_reboot(self):
958 """Switch to rec mode and reboot.
959
960 This method emulates the behavior of the old physical recovery switch,
961 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
962 recovery mode, i.e. just press Power + Esc + Refresh.
963 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800964 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800965 # Reset twice to emulate a long recovery-key-combo hold.
966 cold_reset_num = 2 if self.client_attr.long_rec_combo else 1
Tom Wai-Hong Tam4c9684a2012-12-11 10:48:05 +0800967 for i in range(cold_reset_num):
968 if i:
969 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800970 # Cold reset to clear EC_IN_RW signal
971 self.servo.set('cold_reset', 'on')
972 time.sleep(self.delay.hold_cold_reset)
973 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800974 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800975 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800976 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800977 self.servo.power_short_press()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800978 elif self.client_attr.broken_rec_mode:
Tom Wai-Hong Tamc5c14ef2012-11-20 16:33:37 +0800979 if self._host and self._host.has_power():
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800980 self._host.power_cycle()
981 else:
982 logging.info('You have %d seconds to power cycle this device.',
983 self.delay.user_power_cycle)
984 time.sleep(self.delay.user_power_cycle)
985 logging.info('Booting to recovery mode.')
986 self.servo.custom_recovery_mode()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800987 else:
988 self.servo.enable_recovery_mode()
989 self.cold_reboot()
Tom Wai-Hong Tamad4aaae2012-12-12 11:02:06 +0800990 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800991 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800992
993
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800994 def enable_dev_mode_and_reboot(self):
995 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800996 if self.client_attr.keyboard_dev:
997 self.enable_keyboard_dev_mode()
998 else:
999 self.servo.enable_development_mode()
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001000 self.faft_client.system.run_shell_command(
Vic Yange7553162012-06-20 16:20:47 +08001001 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001002
1003
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +08001004 def enable_normal_mode_and_reboot(self):
1005 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +08001006 if self.client_attr.keyboard_dev:
1007 self.disable_keyboard_dev_mode()
1008 else:
1009 self.servo.disable_development_mode()
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001010 self.faft_client.system.run_shell_command(
Vic Yange7553162012-06-20 16:20:47 +08001011 'chromeos-firmwareupdate --mode tonormal && reboot')
1012
1013
1014 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
1015 """Wait for firmware screen and then switch into or out of dev mode.
1016
1017 Args:
1018 dev: True if switching into dev mode. Otherwise, False.
1019 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001020 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +08001021 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001022 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +08001023 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001024 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +08001025 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001026 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +08001027
1028
1029 def enable_keyboard_dev_mode(self):
1030 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +08001031 # Plug out USB disk for preventing recovery boot without warning
1032 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +08001033 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +08001034 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001035 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001036 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +08001037
1038
1039 def disable_keyboard_dev_mode(self):
1040 logging.info("Disabling keyboard controlled developer mode")
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -08001041 if (not self.client_attr.chrome_ec and
1042 not self.client_attr.broken_rec_mode):
Vic Yang611dd852012-08-02 15:36:31 +08001043 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001044 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001045 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001046 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001047
1048
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001049 def setup_dev_mode(self, dev_mode):
1050 """Setup for development mode.
1051
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001052 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001053 tries to do so.
1054
1055 Args:
1056 dev_mode: True if requested in dev mode; False if normal mode.
1057 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001058 # Change the default firmware_action for dev mode passing the fw screen.
1059 self.register_faft_template({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +08001060 'firmware_action': (self.wait_dev_screen_and_ctrl_d if dev_mode
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001061 else None),
1062 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001063 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +08001064 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001065 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001066 logging.info('Dev switch is not on. Now switch it on.')
1067 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001068 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001069 'mainfw_type': 'developer'}):
1070 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001071 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001072 'userspace_action': None if self.client_attr.keyboard_dev
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001073 else (self.faft_client.system.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001074 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001075 'reboot_action': self.enable_keyboard_dev_mode if
1076 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001077 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001078 else:
Vic Yange7553162012-06-20 16:20:47 +08001079 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001080 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001081 logging.info('Dev switch is not off. Now switch it off.')
1082 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001083 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001084 'mainfw_type': 'normal'}):
1085 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001086 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001087 'userspace_action': None if self.client_attr.keyboard_dev
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001088 else (self.faft_client.system.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001089 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001090 'reboot_action': self.disable_keyboard_dev_mode if
1091 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001092 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001093
1094
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001095 def setup_kernel(self, part):
1096 """Setup for kernel test.
1097
1098 It makes sure both kernel A and B bootable and the current boot is
1099 the requested kernel part.
1100
1101 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001102 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001103 """
1104 self.ensure_kernel_boot(part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001105 if self.faft_client.kernel.diff_a_b():
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001106 self.copy_kernel_and_rootfs(from_part=part,
1107 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001108 self.reset_and_prioritize_kernel(part)
1109
1110
1111 def reset_and_prioritize_kernel(self, part):
1112 """Make the requested partition highest priority.
1113
1114 This function also reset kerenl A and B to bootable.
1115
1116 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001117 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001118 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001119 root_dev = self.faft_client.system.get_root_dev()
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001120 # Reset kernel A and B to bootable.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001121 self.faft_client.system.run_shell_command(
1122 'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['a'], root_dev))
1123 self.faft_client.system.run_shell_command(
1124 'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['b'], root_dev))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001125 # Set kernel part highest priority.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001126 self.faft_client.system.run_shell_command('cgpt prioritize -i%s %s' %
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001127 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001128 # Safer to sync and wait until the cgpt status written to the disk.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001129 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001130 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001131
1132
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001133 def warm_reboot(self):
1134 """Request a warm reboot.
1135
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001136 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001137 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001138 # Use cold reset if the warm reset is broken.
1139 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001140 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1141 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001142 else:
1143 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001144
1145
1146 def cold_reboot(self):
1147 """Request a cold reboot.
1148
1149 A wrapper for underlying servo cold reset.
1150 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001151 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001152 self.servo.set('pwr_button', 'press')
1153 self.servo.set('cold_reset', 'on')
1154 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001155 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001156 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001157 else:
1158 self.servo.cold_reset()
1159
1160
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001161 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001162 """Request the client sync and do a warm reboot.
1163
1164 This is the default reboot action on FAFT.
1165 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001166 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001167 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001168 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001169
1170
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001171 def sync_and_cold_reboot(self):
1172 """Request the client sync and do a cold reboot.
1173
1174 This reboot action is used to reset EC for recovery mode.
1175 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001176 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001177 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001178 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001179
1180
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001181 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001182 """Request the client sync and do a EC triggered reboot.
1183
1184 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001185 flags: Optional, a space-separated string of flags passed to EC
1186 reboot command, including:
1187 default: EC soft reboot;
1188 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001189 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001190 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001191 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001192 self.ec.reboot(flags)
Tom Wai-Hong Tamad4aaae2012-12-12 11:02:06 +08001193 time.sleep(self.delay.ec_boot_to_console)
Vic Yangf86728a2012-07-30 10:44:07 +08001194 self.check_lid_and_power_on()
1195
1196
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001197 def reboot_with_factory_install_shim(self):
1198 """Request reboot with factory install shim to reset TPM.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001199
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001200 Factory install shim requires dev mode enabled. So this method switches
1201 firmware to dev mode first and reboot. The client uses factory install
1202 shim to reset TPM values.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001203 """
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001204 # Unplug USB first to avoid the complicated USB autoboot cases.
1205 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yangf93f7022012-10-31 09:40:36 +08001206 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001207 if not is_dev:
1208 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001209 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001210 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001211 self.wait_fw_screen_and_plug_usb()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001212 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001213 self.warm_reboot()
1214
1215
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001216 def full_power_off_and_on(self):
1217 """Shutdown the device by pressing power button and power on again."""
1218 # Press power button to trigger Chrome OS normal shutdown process.
Tom Wai-Hong Tambe464992012-12-12 10:54:07 +08001219 # We use a customized delay since the normal-press 1.2s is not enough.
1220 self.servo.power_key(self.delay.hold_pwr_button)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001221 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001222 # Short press power button to boot DUT again.
1223 self.servo.power_short_press()
1224
1225
Vic Yangf86728a2012-07-30 10:44:07 +08001226 def check_lid_and_power_on(self):
1227 """
1228 On devices with EC software sync, system powers on after EC reboots if
1229 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1230 This method checks lid switch state and presses power button if
1231 necessary.
1232 """
1233 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001234 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001235 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001236
1237
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001238 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1239 """Modify the kernel header magic in USB stick.
1240
1241 The kernel header magic is the first 8-byte of kernel partition.
1242 We modify it to make it fail on kernel verification check.
1243
1244 Args:
1245 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1246 from_magic: A string of magic which we change it from.
1247 to_magic: A string of magic which we change it to.
1248
1249 Raises:
1250 error.TestError: if failed to change magic.
1251 """
1252 assert len(from_magic) == 8
1253 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001254 # USB image only contains one kernel.
1255 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001256 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1257 current_magic = utils.system_output(read_cmd)
1258 if current_magic == to_magic:
Vic Yang772df8a2012-10-31 10:10:49 +08001259 logging.info("The kernel magic is already %s.", current_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001260 return
1261 if current_magic != from_magic:
1262 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1263
Vic Yang772df8a2012-10-31 10:10:49 +08001264 logging.info('Modify the kernel magic in USB, from %s to %s.',
1265 from_magic, to_magic)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001266 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1267 " 2>/dev/null" % (to_magic, kernel_part))
1268 utils.system(write_cmd)
1269
1270 if utils.system_output(read_cmd) != to_magic:
1271 raise error.TestError("Failed to write new magic.")
1272
1273
1274 def corrupt_usb_kernel(self, usb_dev):
1275 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1276
1277 Args:
1278 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1279 """
1280 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1281 self.CORRUPTED_MAGIC)
1282
1283
1284 def restore_usb_kernel(self, usb_dev):
1285 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1286
1287 Args:
1288 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1289 """
1290 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1291 self.CHROMEOS_MAGIC)
1292
1293
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001294 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001295 """Call the action function with/without arguments.
1296
1297 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001298 action_tuple: A function, or a tuple (function, args, error_msg),
1299 in which, args and error_msg are optional. args is
1300 either a value or a tuple if multiple arguments.
Vic Yang52116d42012-11-05 16:22:34 +08001301 This can also be a list containing multiple function
1302 or tuple. In this case, these actions are called in
1303 sequence.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001304 check_status: Check the return value of action function. If not
1305 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001306
1307 Returns:
1308 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001309
1310 Raises:
1311 error.TestError: An error when the action function is not callable.
1312 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001313 """
Vic Yang52116d42012-11-05 16:22:34 +08001314 if isinstance(action_tuple, list):
1315 return all([self._call_action(action, check_status=check_status)
1316 for action in action_tuple])
1317
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001318 action = action_tuple
1319 args = ()
1320 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001321 if isinstance(action_tuple, tuple):
1322 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001323 if len(action_tuple) >= 2:
1324 args = action_tuple[1]
1325 if not isinstance(args, tuple):
1326 args = (args,)
1327 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001328 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001329
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001330 if action is None:
1331 return
1332
1333 if not callable(action):
1334 raise error.TestError('action is not callable!')
1335
1336 info_msg = 'calling %s' % str(action)
1337 if args:
1338 info_msg += ' with args %s' % str(args)
1339 logging.info(info_msg)
1340 ret = action(*args)
1341
1342 if check_status and not ret:
1343 raise error.TestFail('%s: %s returning %s' %
1344 (error_msg, info_msg, str(ret)))
1345 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001346
1347
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001348 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1349 post_power_action=None):
1350 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1351
1352 Args:
1353 shutdown_action: a function which makes DUT shutdown, like pressing
1354 power key.
1355 pre_power_action: a function which is called before next power on.
1356 post_power_action: a function which is called after next power on.
1357
1358 Raises:
1359 error.TestFail: if the shutdown_action() failed to turn DUT off.
1360 """
1361 self._call_action(shutdown_action)
1362 logging.info('Wait to ensure DUT shut down...')
1363 try:
1364 self.wait_for_client()
1365 raise error.TestFail(
1366 'Should shut the device down after calling %s.' %
1367 str(shutdown_action))
1368 except AssertionError:
1369 logging.info(
1370 'DUT is surely shutdown. We are going to power it on again...')
1371
1372 if pre_power_action:
1373 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001374 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001375 if post_power_action:
1376 self._call_action(post_power_action)
1377
1378
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001379 def register_faft_template(self, template):
1380 """Register FAFT template, the default FAFT_STEP of each step.
1381
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001382 Any missing field falls back to the original faft_template.
1383
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001384 Args:
1385 template: A FAFT_STEP dict.
1386 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001387 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001388
1389
1390 def register_faft_sequence(self, sequence):
1391 """Register FAFT sequence.
1392
1393 Args:
1394 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1395 """
1396 self._faft_sequence = sequence
1397
1398
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001399 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001400 """Run a single FAFT step.
1401
1402 Any missing field falls back to faft_template. An empty step means
1403 running the default faft_template.
1404
1405 Args:
1406 step: A FAFT_STEP dict.
1407 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001408 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1409 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001410
1411 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001412 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001413 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001414 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001415 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1416 'firmware_action', 'install_deps_after_boot')
1417
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001418 test = {}
1419 test.update(self._faft_template)
1420 test.update(step)
1421
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001422 for key in test:
1423 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001424 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001425
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001426 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001427 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001428
1429 self._call_action(test['userspace_action'])
1430
1431 # Don't run reboot_action and firmware_action if no_reboot is True.
1432 if not no_reboot:
1433 self._call_action(test['reboot_action'])
1434 self.wait_for_client_offline()
1435 self._call_action(test['firmware_action'])
1436
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001437 try:
1438 if 'install_deps_after_boot' in test:
1439 self.wait_for_client(
1440 install_deps=test['install_deps_after_boot'])
1441 else:
1442 self.wait_for_client()
1443 except AssertionError:
Yusuf Mohsinally928f8c72012-12-11 15:27:02 -08001444 logging.error('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001445 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001446
1447
1448 def run_faft_sequence(self):
1449 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001450 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001451 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001452 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001453 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001454 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001455 if index == len(sequence) - 1:
1456 self.run_faft_step(step, no_reboot=True)
1457 else:
1458 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001459
1460
ctchang38ae4922012-09-03 17:01:16 +08001461 def get_current_firmware_sha(self):
1462 """Get current firmware sha of body and vblock.
1463
1464 Returns:
1465 Current firmware sha follows the order (
1466 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1467 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001468 current_firmware_sha = (self.faft_client.bios.get_sig_sha('a'),
1469 self.faft_client.bios.get_body_sha('a'),
1470 self.faft_client.bios.get_sig_sha('b'),
1471 self.faft_client.bios.get_body_sha('b'))
ctchang38ae4922012-09-03 17:01:16 +08001472 return current_firmware_sha
1473
1474
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001475 def is_firmware_changed(self):
1476 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001477
1478 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001479 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001480 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001481 # Device may not be rebooted after test.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001482 self.faft_client.bios.reload()
ctchang38ae4922012-09-03 17:01:16 +08001483
1484 current_sha = self.get_current_firmware_sha()
1485
1486 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001487 return False
ctchang38ae4922012-09-03 17:01:16 +08001488 else:
ctchang38ae4922012-09-03 17:01:16 +08001489 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1490 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1491 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1492 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001493 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001494 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1495 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1496 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1497 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001498 return True
ctchang38ae4922012-09-03 17:01:16 +08001499
1500
1501 def backup_firmware(self, suffix='.original'):
1502 """Backup firmware to file, and then send it to host.
1503
1504 Args:
1505 suffix: a string appended to backup file name
1506 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001507 remote_temp_dir = self.faft_client.system.create_temp_dir()
1508 self.faft_client.bios.dump_whole(os.path.join(remote_temp_dir, 'bios'))
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001509 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1510 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001511
1512 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001513 logging.info('Backup firmware stored in %s with suffix %s',
1514 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001515
1516
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001517 def is_firmware_saved(self):
1518 """Check if a firmware saved (called backup_firmware before).
1519
1520 Returns:
1521 True if the firmware is backuped; otherwise False.
1522 """
1523 return self._backup_firmware_sha != ()
1524
1525
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001526 def clear_saved_firmware(self):
1527 """Clear the firmware saved by the method backup_firmware."""
1528 self._backup_firmware_sha = ()
1529
1530
ctchang38ae4922012-09-03 17:01:16 +08001531 def restore_firmware(self, suffix='.original'):
1532 """Restore firmware from host in resultsdir.
1533
1534 Args:
1535 suffix: a string appended to backup file name
1536 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001537 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001538 return
1539
1540 # Backup current corrupted firmware.
1541 self.backup_firmware(suffix='.corrupt')
1542
1543 # Restore firmware.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001544 remote_temp_dir = self.faft_client.system.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001545 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1546 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001547
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001548 self.faft_client.bios.write_whole(
1549 os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001550 self.sync_and_warm_reboot()
1551 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +08001552 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001553 self.wait_for_client()
1554
ctchang38ae4922012-09-03 17:01:16 +08001555 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001556
1557
1558 def setup_firmwareupdate_shellball(self, shellball=None):
1559 """Deside a shellball to use in firmware update test.
1560
1561 Check if there is a given shellball, and it is a shell script. Then,
1562 send it to the remote host. Otherwise, use
1563 /usr/sbin/chromeos-firmwareupdate.
1564
1565 Args:
1566 shellball: path of a shellball or default to None.
1567
1568 Returns:
1569 Path of shellball in remote host.
1570 If use default shellball, reutrn None.
1571 """
1572 updater_path = None
1573 if shellball:
1574 # Determine the firmware file is a shellball or a raw binary.
1575 is_shellball = (utils.system_output("file %s" % shellball).find(
1576 "shell script") != -1)
1577 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001578 logging.info('Device will update firmware with shellball %s',
1579 shellball)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001580 temp_dir = self.faft_client.system.create_temp_dir(
1581 'shellball_')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001582 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1583 self._client.send_file(shellball, temp_shellball)
1584 updater_path = temp_shellball
1585 else:
1586 raise error.TestFail(
1587 'The given shellball is not a shell script.')
1588 return updater_path