blob: c28f0371a21c0eff8301423a597336f46bc8cc36 [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 Tama70f0fe2011-09-02 18:28:47 +080010import time
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080011
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +080012from autotest_lib.client.bin import utils
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080013from autotest_lib.client.common_lib import error
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +080014from autotest_lib.server.cros import vboot_constants as vboot
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +080015from autotest_lib.server.cros import chrome_ec
Vic Yangf93f7022012-10-31 09:40:36 +080016from autotest_lib.server.cros.faft_checkers import FAFTCheckers
Vic Yangebd6de62012-06-26 14:25:57 +080017from autotest_lib.server.cros.faft_client_attribute import FAFTClientAttribute
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +080018from autotest_lib.server.cros.faft_delay_constants import FAFTDelayConstants
Tom Wai-Hong Tam22b77302011-11-03 13:03:48 +080019from autotest_lib.server.cros.servo_test import ServoTest
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -080020from autotest_lib.server import hosts
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080021
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080022class FAFTSequence(ServoTest):
23 """
24 The base class of Fully Automated Firmware Test Sequence.
25
26 Many firmware tests require several reboot cycles and verify the resulted
27 system states. To do that, an Autotest test case should detailly handle
28 every action on each step. It makes the test case hard to read and many
29 duplicated code. The base class FAFTSequence is to solve this problem.
30
31 The actions of one reboot cycle is defined in a dict, namely FAFT_STEP.
32 There are four functions in the FAFT_STEP dict:
33 state_checker: a function to check the current is valid or not,
34 returning True if valid, otherwise, False to break the whole
35 test sequence.
36 userspace_action: a function to describe the action ran in userspace.
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +080037 reboot_action: a function to do reboot, default: sync_and_warm_reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080038 firmware_action: a function to describe the action ran after reboot.
39
Tom Wai-Hong Tam7c17ff22011-10-26 09:44:09 +080040 And configurations:
41 install_deps_after_boot: if True, install the Autotest dependency after
42 boot; otherwise, do nothing. It is for the cases of recovery mode
43 test. The test boots a USB/SD image instead of an internal image.
44 The previous installed Autotest dependency on the internal image
45 is lost. So need to install it again.
46
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080047 The default FAFT_STEP checks nothing in state_checker and does nothing in
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +080048 userspace_action and firmware_action. Its reboot_action is a hardware
49 reboot. You can change the default FAFT_STEP by calling
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080050 self.register_faft_template(FAFT_STEP).
51
52 A FAFT test case consists of several FAFT_STEP's, namely FAFT_SEQUENCE.
53 FAFT_SEQUENCE is an array of FAFT_STEP's. Any missing fields on FAFT_STEP
54 fall back to default.
55
56 In the run_once(), it should register and run FAFT_SEQUENCE like:
57 def run_once(self):
58 self.register_faft_sequence(FAFT_SEQUENCE)
59 self.run_faft_sequnce()
60
61 Note that in the last step, we only run state_checker. The
62 userspace_action, reboot_action, and firmware_action are not executed.
63
64 Attributes:
65 _faft_template: The default FAFT_STEP of each step. The actions would
66 be over-written if the registered FAFT_SEQUENCE is valid.
67 _faft_sequence: The registered FAFT_SEQUENCE.
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080068 _install_image_path: The URL or the path on the host to the Chrome OS
69 test image to be installed.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080070 _firmware_update: Boolean. True if firmware update needed after
71 installing the image.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080072 """
73 version = 1
74
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +080075 # Mapping of partition number of kernel and rootfs.
76 KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
77 ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
78 OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
79 OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
80
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +080081 CHROMEOS_MAGIC = "CHROMEOS"
82 CORRUPTED_MAGIC = "CORRUPTD"
83
Vadim Bendebury89ec24e2012-12-17 12:54:18 -080084 _ROOTFS_PARTITION_NUMBER = 3
85
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +080086 _HTTP_PREFIX = 'http://'
87 _DEVSERVER_PORT = '8090'
88
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +080089 _faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080090 _faft_sequence = ()
91
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080092 _install_image_path = None
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080093 _firmware_update = False
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +080094
ctchang38ae4922012-09-03 17:01:16 +080095 _backup_firmware_sha = ()
96
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +080097 # Class level variable, keep track the states of one time setup.
98 # This variable is preserved across tests which inherit this class.
99 _global_setup_done = {
100 'gbb_flags': False,
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800101 'reimage': False,
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800102 'usb_check': False,
103 }
Vic Yang54f70572012-10-19 17:05:26 +0800104
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800105 @classmethod
106 def check_setup_done(cls, label):
107 """Check if the given setup is done.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800108
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800109 Args:
110 label: The label of the setup.
111 """
112 return cls._global_setup_done[label]
113
114
115 @classmethod
116 def mark_setup_done(cls, label):
117 """Mark the given setup done.
118
119 Args:
120 label: The label of the setup.
121 """
122 cls._global_setup_done[label] = True
123
124
125 @classmethod
126 def unmark_setup_done(cls, label):
127 """Mark the given setup not done.
128
129 Args:
130 label: The label of the setup.
131 """
132 cls._global_setup_done[label] = False
Vic Yang54f70572012-10-19 17:05:26 +0800133
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800134
135 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
136 # Parse arguments from command line
137 args = {}
138 for arg in cmdline_args:
139 match = re.search("^(\w+)=(.+)", arg)
140 if match:
141 args[match.group(1)] = match.group(2)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800142 if 'image' in args:
143 self._install_image_path = args['image']
Vic Yang772df8a2012-10-31 10:10:49 +0800144 logging.info('Install Chrome OS test image path: %s',
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800145 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800146 if 'firmware_update' in args and args['firmware_update'].lower() \
147 not in ('0', 'false', 'no'):
148 if self._install_image_path:
149 self._firmware_update = True
150 logging.info('Also update firmware after installing.')
151 else:
152 logging.warning('Firmware update will not not performed '
153 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800154
155 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
156 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800157 if use_faft:
158 self.client_attr = FAFTClientAttribute(
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800159 self.faft_client.system.get_platform_name())
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800160 self.delay = FAFTDelayConstants(
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800161 self.faft_client.system.get_platform_name())
Vic Yangf93f7022012-10-31 09:40:36 +0800162 self.checkers = FAFTCheckers(self, self.faft_client)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800163
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800164 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800165 self.ec = chrome_ec.ChromeEC(self.servo)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800166
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800167 if not self.client_attr.has_keyboard:
168 # The environment variable USBKM232_UART_DEVICE should point
169 # to the USB-KM232 UART device.
170 if ('USBKM232_UART_DEVICE' not in os.environ or
171 not os.path.exists(os.environ['USBKM232_UART_DEVICE'])):
172 raise error.TestError('Must set a valid environment '
173 'variable USBKM232_UART_DEVICE.')
174
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700175 # Setting up key matrix mapping
176 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
177
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800178
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800179 def setup(self, ec_wp=None):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800180 """Autotest setup function."""
181 super(FAFTSequence, self).setup()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800182 self.register_faft_template({
183 'state_checker': (None),
184 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800185 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800186 'firmware_action': (None)
187 })
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800188 self.install_test_image(self._install_image_path, self._firmware_update)
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800189 self.record_system_info()
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800190 self.setup_gbb_flags()
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800191 self.setup_ec_write_protect(ec_wp)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800192
193
194 def cleanup(self):
195 """Autotest cleanup function."""
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800196 self.restore_ec_write_protect()
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800197 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800198 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800199 super(FAFTSequence, self).cleanup()
200
201
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800202 def record_system_info(self):
203 """Record some critical system info to the attr keyval.
204
205 This info is used by generate_test_report and local_dash later.
206 """
207 self.write_attr_keyval({
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800208 'fw_version': self.faft_client.ec.get_version(),
209 'hwid': self.faft_client.system.get_crossystem_value('hwid'),
210 'fwid': self.faft_client.system.get_crossystem_value('fwid'),
Tom Wai-Hong Tamb92669c2012-11-29 13:57:11 +0800211 })
212
213
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800214 def invalidate_firmware_setup(self):
215 """Invalidate all firmware related setup state.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800216
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800217 This method is called when the firmware is re-flashed. It resets all
218 firmware related setup states so that the next test setup properly
219 again.
Vic Yangdbaba8f2012-10-17 16:05:35 +0800220 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800221 self.unmark_setup_done('gbb_flags')
Vic Yangdbaba8f2012-10-17 16:05:35 +0800222
223
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800224 def _retrieve_recovery_reason_from_trap(self):
225 """Try to retrieve the recovery reason from a trapped recovery screen.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800226
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800227 Returns:
228 The recovery_reason, 0 if any error.
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800229 """
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800230 recovery_reason = 0
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800231 logging.info('Try to retrieve recovery reason...')
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800232 if self.servo.get_usbkey_direction() == 'dut':
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800233 self.wait_fw_screen_and_plug_usb()
234 else:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800235 self.servo.switch_usbkey('dut')
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800236
237 try:
238 self.wait_for_client(install_deps=True)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800239 lines = self.faft_client.system.run_shell_command_get_output(
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800240 'crossystem recovery_reason')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800241 recovery_reason = int(lines[0])
242 logging.info('Got the recovery reason %d.', recovery_reason)
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800243 except AssertionError:
244 logging.info('Failed to get the recovery reason.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800245 return recovery_reason
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +0800246
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800247
248 def _reset_client(self):
249 """Reset client to a workable state.
250
251 This method is called when the client is not responsive. It may be
252 caused by the following cases:
253 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
254 - corrupted firmware;
255 - corrutped OS image.
256 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800257 # DUT may halt on a firmware screen. Try cold reboot.
258 logging.info('Try cold reboot...')
259 self.cold_reboot()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800260 self.wait_for_client_offline()
261 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800262 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800263 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800264 return
265 except AssertionError:
266 pass
267
268 # DUT may be broken by a corrupted firmware. Restore firmware.
269 # We assume the recovery boot still works fine. Since the recovery
270 # code is in RO region and all FAFT tests don't change the RO region
271 # except GBB.
272 if self.is_firmware_saved():
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800273 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800274 logging.info('Try restore the original firmware...')
275 if self.is_firmware_changed():
276 try:
277 self.restore_firmware()
278 return
279 except AssertionError:
280 logging.info('Restoring firmware doesn\'t help.')
281
282 # DUT may be broken by a corrupted OS image. Restore OS image.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800283 self._ensure_client_in_recovery()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800284 logging.info('Try restore the OS image...')
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800285 self.faft_client.system.run_shell_command('chromeos-install --yes')
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800286 self.sync_and_warm_reboot()
287 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +0800288 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800289 try:
290 self.wait_for_client(install_deps=True)
291 logging.info('Successfully restore OS image.')
292 return
293 except AssertionError:
294 logging.info('Restoring OS image doesn\'t help.')
295
296
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800297 def _ensure_client_in_recovery(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800298 """Ensure client in recovery boot; reboot into it if necessary.
299
300 Raises:
301 error.TestError: if failed to boot the USB image.
302 """
303 # DUT works fine and is already in recovery boot, done.
304 if self._ping_test(self._client.ip, timeout=5):
Vic Yangf93f7022012-10-31 09:40:36 +0800305 if self.checkers.crossystem_checker({'mainfw_type': 'recovery'}):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800306 return
307
308 logging.info('Try boot into USB image...')
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800309 self.servo.switch_usbkey('host')
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800310 self.enable_rec_mode_and_reboot()
311 self.wait_fw_screen_and_plug_usb()
312 try:
313 self.wait_for_client(install_deps=True)
314 except AssertionError:
315 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800316
317
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800318 def _restore_routine_from_timeout(self, next_step=None):
319 """A routine to try to restore the system from a timeout error.
320
321 This method is called when FAFT failed to connect DUT after reboot.
322
323 Args:
324 next_step: Optional, a FAFT_STEP dict of the next step, which is used
325 for diagnostic.
326
327 Raises:
328 error.TestFail: This exception is already raised, with a decription
329 why it failed.
330 """
331 next_checker_matched = False
332 if next_step is not None:
333 next_test = {}
334 next_test.update(self._faft_template)
335 next_test.update(next_step)
336
337 # TODO(waihong@chromium.org): Implement replugging the Ethernet to
338 # identify if it is a network flaky.
339
340 recovery_reason = self._retrieve_recovery_reason_from_trap()
341 if next_step is not None and recovery_reason:
342 if self._call_action(next_test['state_checker']):
343 # Repluging the USB can pass the state_checker of the next step,
344 # meaning that the firmware failed to boot into USB directly.
345 next_checker_matched = True
346
347 # Reset client to a workable state.
348 self._reset_client()
349
350 # Raise the proper TestFail exception.
351 if next_checker_matched:
352 raise error.TestFail('Firmware failed to auto-boot USB in the '
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800353 'recovery boot (reason: %d)' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800354 elif recovery_reason:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800355 raise error.TestFail('Trapped in the recovery screen (reason: %d) '
356 'and timed out' % recovery_reason)
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800357 else:
Tom Wai-Hong Tam66648432012-11-07 10:06:00 +0800358 raise error.TestFail('Timed out waiting for DUT reboot')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +0800359
360
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800361 def assert_test_image_in_usb_disk(self, usb_dev=None, install_shim=False):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800362 """Assert an USB disk plugged-in on servo and a test image inside.
363
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800364 Args:
365 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
366 If None, it is detected automatically.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800367 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800368
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800369 Raises:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800370 error.TestError: if USB disk not detected or not a test (install shim)
371 image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800372 """
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800373 if self.check_setup_done('usb_check'):
Vic Yang54f70572012-10-19 17:05:26 +0800374 return
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800375 if usb_dev:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800376 assert self.servo.get_usbkey_direction() == 'host'
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800377 else:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800378 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800379 usb_dev = self.servo.probe_host_usb_dev()
380 if not usb_dev:
381 raise error.TestError(
382 'An USB disk should be plugged in the servo board.')
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800383
384 rootfs = '%s%s' % (usb_dev, self._ROOTFS_PARTITION_NUMBER)
385 logging.info('usb dev is %s', usb_dev)
386 tmpd = self.servo.system_output('mktemp -d -t usbcheck.XXXX')
387 self.servo.system('mount -o ro %s %s' % (rootfs, tmpd))
388
389 if install_shim:
390 dir_list = self.servo.system_output('ls -a %s' %
391 os.path.join(tmpd, 'root'))
392 check_passed = '.factory_installer' in dir_list
393 else:
394 check_passed = self.servo.system_output(
395 'grep -i "CHROMEOS_RELEASE_DESCRIPTION=.*test" %s' %
396 os.path.join(tmpd, 'etc/lsb-release'),
397 ignore_status=True)
398 for cmd in ('umount %s' % rootfs, 'sync', 'rm -rf %s' % tmpd):
399 self.servo.system(cmd)
400
401 if not check_passed:
402 raise error.TestError(
403 'No Chrome OS %s found on the USB flash plugged into servo' %
404 'install shim' if install_shim else 'test')
405
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800406 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800407
408
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800409 def setup_usbkey(self, usbkey, host=None, install_shim=False):
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800410 """Setup the USB disk for the test.
411
412 It checks the setup of USB disk and a valid ChromeOS test image inside.
413 It also muxes the USB disk to either the host or DUT by request.
414
415 Args:
416 usbkey: True if the USB disk is required for the test, False if not
417 required.
418 host: Optional, True to mux the USB disk to host, False to mux it
419 to DUT, default to do nothing.
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800420 install_shim: True to verify an install shim instead of a test image.
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800421 """
422 if usbkey:
Tom Wai-Hong Tama6b382c2012-11-14 09:31:02 +0800423 self.assert_test_image_in_usb_disk(install_shim=install_shim)
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800424 elif host is None:
425 # USB disk is not required for the test. Better to mux it to host.
426 host = True
427
428 if host is True:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800429 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800430 elif host is False:
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800431 self.servo.switch_usbkey('dut')
Tom Wai-Hong Tam893bcc02012-11-02 16:13:34 +0800432
433
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800434 def get_server_address(self):
435 """Get the server address seen from the client.
436
437 Returns:
438 A string of the server address.
439 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800440 r = self.faft_client.system.run_shell_command_get_output(
441 "echo $SSH_CLIENT")
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800442 return r[0].split()[0]
443
444
Simran Basi741b5d42012-05-18 11:27:15 -0700445 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800446 """Install the test image specied by the path onto the USB and DUT disk.
447
448 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500449 recovery mode. Then runs 'chromeos-install' (and possible
450 chromeos-firmwareupdate') to install it to DUT disk.
451
452 Sample command line:
453
454 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
455 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
456 server/site_tests/firmware_XXXX/control
457
458 This test requires an automated recovery to occur while simulating
459 inserting and removing the usb key from the servo. To allow this the
460 following hardware setup is required:
461 1. servo2 board connected via servoflex.
462 2. USB key inserted in the servo2.
463 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
464 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800465
466 Args:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800467 image_path: An URL or a path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800468 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800469
470 Raises:
471 error.TestError: If devserver failed to start.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800472 """
Tom Wai-Hong Tam19ad9682012-10-24 09:33:42 +0800473 if not image_path:
474 return
475
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800476 if self.check_setup_done('reimage'):
477 return
478
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800479 if image_path.startswith(self._HTTP_PREFIX):
480 # TODO(waihong@chromium.org): Add the check of the URL to ensure
481 # it is a test image.
482 devserver = None
483 image_url = image_path
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800484 elif self.servo.is_localhost():
Tom Wai-Hong Tam42f136d2012-10-26 11:11:23 +0800485 # If servod is localhost, i.e. both servod and FAFT see the same
486 # file system, do nothing.
487 devserver = None
488 image_url = image_path
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800489 else:
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800490 image_dir, image_base = os.path.split(image_path)
491 logging.info('Starting devserver to serve the image...')
492 # The following stdout and stderr arguments should not be None,
493 # even we don't use them. Otherwise, the socket of devserve is
494 # created as fd 1 (as no stdout) but it still thinks stdout is fd
495 # 1 and dump the log to the socket. Wrong HTTP protocol happens.
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800496 devserver = subprocess.Popen(['/usr/lib/devserver/devserver.py',
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800497 '--archive_dir=%s' % image_dir,
498 '--port=%s' % self._DEVSERVER_PORT],
499 stdout=subprocess.PIPE,
500 stderr=subprocess.PIPE)
501 image_url = '%s%s:%s/static/archive/%s' % (
502 self._HTTP_PREFIX,
503 self.get_server_address(),
504 self._DEVSERVER_PORT,
505 image_base)
506
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800507 # Wait devserver startup completely
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800508 time.sleep(self.delay.devserver)
Tom Wai-Hong Tam71818d82012-10-24 14:57:43 +0800509 # devserver is a service running forever. If it is terminated,
510 # some error does happen.
511 if devserver.poll():
512 raise error.TestError('Starting devserver failed, '
513 'returning %d.' % devserver.returncode)
514
Vic Yang772df8a2012-10-31 10:10:49 +0800515 logging.info('Ask Servo to install the image from %s', image_url)
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800516 self.servo.image_to_servo_usb(image_url)
517
Vadim Bendebury89ec24e2012-12-17 12:54:18 -0800518 self.assert_test_image_in_usb_disk()
519
Tom Wai-Hong Tame796de42012-10-16 19:42:20 +0800520 if devserver and devserver.poll() is None:
521 logging.info('Shutting down devserver...')
522 devserver.terminate()
Mike Truty49153d82012-08-21 22:27:30 -0500523
524 # DUT is powered off while imaging servo USB.
525 # Now turn it on.
526 self.servo.power_short_press()
527 self.wait_for_client()
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800528 self.servo.switch_usbkey('dut')
Mike Truty49153d82012-08-21 22:27:30 -0500529
530 install_cmd = 'chromeos-install --yes'
531 if firmware_update:
532 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800533 self.backup_firmware()
Mike Truty49153d82012-08-21 22:27:30 -0500534
535 self.register_faft_sequence((
536 { # Step 1, request recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800537 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500538 'mainfw_type': ('developer', 'normal'),
539 }),
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800540 'userspace_action': (
541 self.faft_client.system.request_recovery_boot),
Mike Truty49153d82012-08-21 22:27:30 -0500542 'firmware_action': self.wait_fw_screen_and_plug_usb,
543 'install_deps_after_boot': True,
544 },
545 { # Step 2, expected recovery boot
Vic Yangf93f7022012-10-31 09:40:36 +0800546 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500547 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800548 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500549 }),
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800550 'userspace_action': (self.faft_client.system.run_shell_command,
Mike Truty49153d82012-08-21 22:27:30 -0500551 install_cmd),
552 'reboot_action': self.cold_reboot,
553 'install_deps_after_boot': True,
554 },
555 { # Step 3, expected normal or developer boot (not recovery)
Vic Yangf93f7022012-10-31 09:40:36 +0800556 'state_checker': (self.checkers.crossystem_checker, {
Mike Truty49153d82012-08-21 22:27:30 -0500557 'mainfw_type': ('developer', 'normal')
558 }),
559 },
560 ))
561 self.run_faft_sequence()
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +0800562
563 if firmware_update:
564 self.clear_saved_firmware()
565
Mike Truty49153d82012-08-21 22:27:30 -0500566 # 'Unplug' any USB keys in the servo from the dut.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800567 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam6668b762012-10-23 11:45:36 +0800568 # Mark usb_check done so it won't check a test image in USB anymore.
569 self.mark_setup_done('usb_check')
Tom Wai-Hong Tam73229372012-10-23 11:58:16 +0800570 self.mark_setup_done('reimage')
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800571
572
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800573 def clear_set_gbb_flags(self, clear_mask, set_mask):
574 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800575
576 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800577 clear_mask: A mask of flags to be cleared.
578 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800579 """
Tom Wai-Hong Tamc1a569f2012-12-04 15:07:25 +0800580 gbb_flags = self.faft_client.bios.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800581 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
582
583 if (gbb_flags != new_flags):
Vic Yang772df8a2012-10-31 10:10:49 +0800584 logging.info('Change the GBB flags from 0x%x to 0x%x.',
585 gbb_flags, new_flags)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800586 self.faft_client.system.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800587 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800588 self.faft_client.bios.reload()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800589 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800590 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800591 self.run_faft_step({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800592 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800593 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800594
595
Vic Yang772df8a2012-10-31 10:10:49 +0800596 def check_ec_capability(self, required_cap=None, suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800597 """Check if current platform has required EC capabilities.
598
599 Args:
600 required_cap: A list containing required EC capabilities. Pass in
601 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800602 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800603
604 Returns:
605 True if requirements are met. Otherwise, False.
606 """
607 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800608 if not suppress_warning:
609 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800610 return False
611
Vic Yang772df8a2012-10-31 10:10:49 +0800612 if not required_cap:
613 return True
614
Vic Yang4d72cb62012-07-24 11:51:09 +0800615 for cap in required_cap:
616 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800617 if not suppress_warning:
618 logging.warn('Requires EC capability "%s" to run this '
Vic Yang772df8a2012-10-31 10:10:49 +0800619 'test.', cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800620 return False
621
622 return True
623
624
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800625 def check_root_part_on_non_recovery(self, part):
626 """Check the partition number of root device and on normal/dev boot.
627
628 Returns:
629 True if the root device matched and on normal/dev boot;
630 otherwise, False.
631 """
Vic Yangf93f7022012-10-31 09:40:36 +0800632 return self.checkers.root_part_checker(part) and \
633 self.checkers.crossystem_checker({
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800634 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800635 })
636
637
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800638 def _join_part(self, dev, part):
639 """Return a concatenated string of device and partition number.
640
641 Args:
642 dev: A string of device, e.g.'/dev/sda'.
643 part: A string of partition number, e.g.'3'.
644
645 Returns:
646 A concatenated string of device and partition number, e.g.'/dev/sda3'.
647
648 >>> seq = FAFTSequence()
649 >>> seq._join_part('/dev/sda', '3')
650 '/dev/sda3'
651 >>> seq._join_part('/dev/mmcblk0', '2')
652 '/dev/mmcblk0p2'
653 """
654 if 'mmcblk' in dev:
655 return dev + 'p' + part
656 else:
657 return dev + part
658
659
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800660 def copy_kernel_and_rootfs(self, from_part, to_part):
661 """Copy kernel and rootfs from from_part to to_part.
662
663 Args:
664 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800665 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800666 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800667 root_dev = self.faft_client.system.get_root_dev()
Vic Yang772df8a2012-10-31 10:10:49 +0800668 logging.info('Copying kernel from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800669 from_part, to_part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800670 self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800671 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
672 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
Vic Yang772df8a2012-10-31 10:10:49 +0800673 logging.info('Copying rootfs from %s to %s. Please wait...',
Vic Yang55f31252012-11-01 17:07:54 +0800674 from_part, to_part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800675 self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800676 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
677 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800678
679
680 def ensure_kernel_boot(self, part):
681 """Ensure the request kernel boot.
682
683 If not, it duplicates the current kernel to the requested kernel
684 and sets the requested higher priority to ensure it boot.
685
686 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800687 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800688 """
Vic Yangf93f7022012-10-31 09:40:36 +0800689 if not self.checkers.root_part_checker(part):
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800690 if self.faft_client.kernel.diff_a_b():
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800691 self.copy_kernel_and_rootfs(
692 from_part=self.OTHER_KERNEL_MAP[part],
693 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800694 self.run_faft_step({
695 'userspace_action': (self.reset_and_prioritize_kernel, part),
696 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800697
698
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800699 def set_hardware_write_protect(self, enable):
Vic Yang2cabf812012-08-28 02:39:04 +0800700 """Set hardware write protect pin.
701
702 Args:
703 enable: True if asserting write protect pin. Otherwise, False.
704 """
705 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
706 self.servo.set('fw_wp_en', 'on')
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800707 self.servo.set('fw_wp', 'on' if enable else 'off')
Vic Yang416f2032012-08-28 10:18:03 +0800708
709
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800710 def set_ec_write_protect_and_reboot(self, enable):
Vic Yang416f2032012-08-28 10:18:03 +0800711 """Set EC write protect status and reboot to take effect.
712
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800713 The write protect state is only activated if both hardware write
714 protect pin is asserted and software write protect flag is set.
Vic Yang416f2032012-08-28 10:18:03 +0800715 This method asserts/deasserts hardware write protect pin first, and
716 set corresponding EC software write protect flag.
717
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800718 If the device uses non-Chrome EC, set the software write protect via
719 flashrom.
720
721 If the device uses Chrome EC, a reboot is required for write protect
722 to take effect. Since the software write protect flag cannot be unset
723 if hardware write protect pin is asserted, we need to deasserted the
724 pin first if we are deactivating write protect. Similarly, a reboot
725 is required before we can modify the software flag.
726
Vic Yang416f2032012-08-28 10:18:03 +0800727 Args:
728 enable: True if activating EC write protect. Otherwise, False.
729 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800730 self.set_hardware_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800731 if self.client_attr.chrome_ec:
732 self.set_chrome_ec_write_protect_and_reboot(enable)
733 else:
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800734 self.faft_client.ec.set_write_protect(enable)
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800735 self.sync_and_warm_reboot()
736
737
738 def set_chrome_ec_write_protect_and_reboot(self, enable):
739 """Set Chrome EC write protect status and reboot to take effect.
740
741 Args:
742 enable: True if activating EC write protect. Otherwise, False.
743 """
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800744 if enable:
Vic Yang416f2032012-08-28 10:18:03 +0800745 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800746 self.ec.set_flash_write_protect(enable)
Vic Yang416f2032012-08-28 10:18:03 +0800747 self.sync_and_ec_reboot()
748 else:
749 # Reboot after deasserting hardware write protect pin to deactivate
750 # write protect. And then remove software write protect flag.
751 self.sync_and_ec_reboot()
Tom Wai-Hong Tam05574ee2012-10-30 11:34:21 +0800752 self.ec.set_flash_write_protect(enable)
Vic Yang2cabf812012-08-28 02:39:04 +0800753
754
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800755 def setup_ec_write_protect(self, ec_wp):
756 """Setup for EC write-protection.
757
758 It makes sure the EC in the requested write-protection state. If not, it
759 flips the state. Flipping the write-protection requires DUT reboot.
760
761 Args:
762 ec_wp: True to request EC write-protected; False to request EC not
763 write-protected; None to do nothing.
764 """
765 if ec_wp is None:
766 self._old_ec_wp = None
767 return
768 self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
769 if ec_wp != self._old_ec_wp:
770 logging.info('The test required EC is %swrite-protected. Reboot '
771 'and flip the state.', '' if ec_wp else 'not ')
772 self.run_faft_step({
Tom Wai-Hong Tamdd830982013-01-16 10:31:05 +0800773 'reboot_action': (self.set_ec_write_protect_and_reboot, ec_wp),
774 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800775 })
776
777
778 def restore_ec_write_protect(self):
779 """Restore the original EC write-protection."""
780 if self._old_ec_wp is None:
781 return
782 if not self.checkers.crossystem_checker(
783 {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
784 logging.info('Restore the original EC write protection and reboot.')
785 self.run_faft_step({
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800786 'reboot_action': (self.set_ec_write_protect_and_reboot,
Tom Wai-Hong Tamdd830982013-01-16 10:31:05 +0800787 self._old_ec_wp),
788 'firmware_action': self.wait_dev_screen_and_ctrl_d,
Tom Wai-Hong Tam700c9fd2012-11-15 18:18:30 +0800789 })
790
791
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800792 def press_ctrl_d(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800793 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800794 if not self.client_attr.has_keyboard:
795 logging.info('Running usbkm232-ctrld...')
796 os.system('usbkm232-ctrld')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800797 else:
798 self.servo.ctrl_d()
799
800
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800801 def press_ctrl_u(self):
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800802 """Send Ctrl-U key to DUT.
803
804 Raises:
805 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
806 on a no-build-in-keyboard device.
807 """
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800808 if not self.client_attr.has_keyboard:
809 logging.info('Running usbkm232-ctrlu...')
810 os.system('usbkm232-ctrlu')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800811 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
812 self.ec.key_down('<ctrl_l>')
813 self.ec.key_down('u')
814 self.ec.key_up('u')
815 self.ec.key_up('<ctrl_l>')
816 elif self.client_attr.has_keyboard:
817 raise error.TestError(
818 "Can't send Ctrl-U to DUT without using Chrome EC.")
819 else:
820 raise error.TestError(
821 "Should specify the ctrl_u_cmd argument.")
822
823
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800824 def press_enter(self):
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800825 """Send Enter key to DUT."""
Tom Wai-Hong Tam9c15b4b2012-10-29 17:59:26 +0800826 if not self.client_attr.has_keyboard:
827 logging.info('Running usbkm232-enter...')
828 os.system('usbkm232-enter')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800829 else:
830 self.servo.enter_key()
831
832
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +0800833 def wait_dev_screen_and_ctrl_d(self):
834 """Wait for firmware warning screen and press Ctrl-D."""
835 time.sleep(self.delay.dev_screen)
836 self.press_ctrl_d()
837
838
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800839 def wait_fw_screen_and_ctrl_d(self):
840 """Wait for firmware warning screen and press Ctrl-D."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800841 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800842 self.press_ctrl_d()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800843
844
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800845 def wait_fw_screen_and_ctrl_u(self):
846 """Wait for firmware warning screen and press Ctrl-U."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800847 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800848 self.press_ctrl_u()
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800849
850
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800851 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
852 """Wait for firmware warning screen and trigger recovery boot."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800853 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800854 self.press_enter()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800855
856 # For Alex/ZGB, there is a dev warning screen in text mode.
857 # Skip it by pressing Ctrl-D.
858 if need_dev_transition:
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800859 time.sleep(self.delay.legacy_text_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +0800860 self.press_ctrl_d()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800861
862
Mike Truty49153d82012-08-21 22:27:30 -0500863 def wait_fw_screen_and_unplug_usb(self):
864 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800865 time.sleep(self.delay.load_usb)
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800866 self.servo.switch_usbkey('host')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800867 time.sleep(self.delay.between_usb_plug)
Mike Truty49153d82012-08-21 22:27:30 -0500868
869
870 def wait_fw_screen_and_plug_usb(self):
871 """Wait for firmware warning screen and then unplug and plug the USB."""
872 self.wait_fw_screen_and_unplug_usb()
Vadim Bendeburye7bd9362012-12-19 14:35:20 -0800873 self.servo.switch_usbkey('dut')
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800874
875
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800876 def wait_fw_screen_and_press_power(self):
877 """Wait for firmware warning screen and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800878 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800879 # While the firmware screen, the power button probing loop sleeps
880 # 0.25 second on every scan. Use the normal delay (1.2 second) for
881 # power press.
882 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800883
884
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800885 def wait_longer_fw_screen_and_press_power(self):
886 """Wait for firmware screen without timeout and press power button."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800887 time.sleep(self.delay.dev_screen_timeout)
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800888 self.wait_fw_screen_and_press_power()
889
890
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800891 def wait_fw_screen_and_close_lid(self):
892 """Wait for firmware warning screen and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800893 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800894 self.servo.lid_close()
895
896
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800897 def wait_longer_fw_screen_and_close_lid(self):
898 """Wait for firmware screen without timeout and close lid."""
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800899 time.sleep(self.delay.firmware_screen)
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800900 self.wait_fw_screen_and_close_lid()
901
902
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800903 def setup_gbb_flags(self):
904 """Setup the GBB flags for FAFT test."""
Tom Wai-Hong Tamee835002013-02-05 11:50:15 +0800905 if self.client_attr.gbb_version < 1.1:
906 logging.info('Skip modifying GBB on versions older than 1.1.')
907 return
908
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800909 if self.check_setup_done('gbb_flags'):
910 return
911
912 logging.info('Set proper GBB flags for test.')
913 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
914 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
915 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
916 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800917 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
918 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
Tom Wai-Hong Tam01d5e572012-10-23 10:07:11 +0800919 self.mark_setup_done('gbb_flags')
920
921
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800922 def setup_tried_fwb(self, tried_fwb):
923 """Setup for fw B tried state.
924
925 It makes sure the system in the requested fw B tried state. If not, it
926 tries to do so.
927
928 Args:
929 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
930 """
931 if tried_fwb:
Vic Yangf93f7022012-10-31 09:40:36 +0800932 if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800933 logging.info(
934 'Firmware is not booted with tried_fwb. Reboot into it.')
935 self.run_faft_step({
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800936 'userspace_action': self.faft_client.system.set_try_fw_b,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800937 })
938 else:
Vic Yangf93f7022012-10-31 09:40:36 +0800939 if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800940 logging.info(
941 'Firmware is booted with tried_fwb. Reboot to clear.')
942 self.run_faft_step({})
943
944
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800945 def enable_rec_mode_and_reboot(self):
946 """Switch to rec mode and reboot.
947
948 This method emulates the behavior of the old physical recovery switch,
949 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
950 recovery mode, i.e. just press Power + Esc + Refresh.
951 """
Tom Wai-Hong Tam80419a82012-10-30 09:10:00 +0800952 if self.client_attr.chrome_ec:
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800953 # Reset twice to emulate a long recovery-key-combo hold.
954 cold_reset_num = 2 if self.client_attr.long_rec_combo else 1
Tom Wai-Hong Tam4c9684a2012-12-11 10:48:05 +0800955 for i in range(cold_reset_num):
956 if i:
957 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam41128082012-11-16 12:02:45 +0800958 # Cold reset to clear EC_IN_RW signal
959 self.servo.set('cold_reset', 'on')
960 time.sleep(self.delay.hold_cold_reset)
961 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +0800962 self.ec.reboot("ap-off")
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +0800963 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tam665281c2012-10-30 11:55:10 +0800964 self.ec.set_hostevent(chrome_ec.HOSTEVENT_KEYBOARD_RECOVERY)
Vic Yang611dd852012-08-02 15:36:31 +0800965 self.servo.power_short_press()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800966 elif self.client_attr.broken_rec_mode:
J. Richard Barnetted5f807a2013-02-11 16:51:00 -0800967 if self._client.has_power():
968 self._client.power_cycle()
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -0800969 else:
970 logging.info('You have %d seconds to power cycle this device.',
971 self.delay.user_power_cycle)
972 time.sleep(self.delay.user_power_cycle)
973 logging.info('Booting to recovery mode.')
974 self.servo.custom_recovery_mode()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800975 else:
976 self.servo.enable_recovery_mode()
977 self.cold_reboot()
Tom Wai-Hong Tamad4aaae2012-12-12 11:02:06 +0800978 time.sleep(self.delay.ec_boot_to_console)
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800979 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800980
981
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800982 def enable_dev_mode_and_reboot(self):
983 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800984 if self.client_attr.keyboard_dev:
985 self.enable_keyboard_dev_mode()
986 else:
987 self.servo.enable_development_mode()
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800988 self.faft_client.system.run_shell_command(
Vic Yange7553162012-06-20 16:20:47 +0800989 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800990
991
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800992 def enable_normal_mode_and_reboot(self):
993 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800994 if self.client_attr.keyboard_dev:
995 self.disable_keyboard_dev_mode()
996 else:
997 self.servo.disable_development_mode()
Chun-ting Changd43aa9b2012-11-16 10:12:05 +0800998 self.faft_client.system.run_shell_command(
Vic Yange7553162012-06-20 16:20:47 +0800999 'chromeos-firmwareupdate --mode tonormal && reboot')
1000
1001
1002 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
1003 """Wait for firmware screen and then switch into or out of dev mode.
1004
1005 Args:
1006 dev: True if switching into dev mode. Otherwise, False.
1007 """
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001008 time.sleep(self.delay.firmware_screen)
Vic Yange7553162012-06-20 16:20:47 +08001009 if dev:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001010 self.press_ctrl_d()
Vic Yange7553162012-06-20 16:20:47 +08001011 else:
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001012 self.press_enter()
Vic Yang0dc84b82012-10-31 12:29:39 +08001013 time.sleep(self.delay.confirm_screen)
Tom Wai-Hong Tam91612bc2012-10-29 16:04:21 +08001014 self.press_enter()
Vic Yange7553162012-06-20 16:20:47 +08001015
1016
1017 def enable_keyboard_dev_mode(self):
1018 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +08001019 # Plug out USB disk for preventing recovery boot without warning
Vadim Bendeburye7bd9362012-12-19 14:35:20 -08001020 self.servo.switch_usbkey('host')
Vic Yange7553162012-06-20 16:20:47 +08001021 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +08001022 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001023 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001024 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +08001025
Gediminas Ramanauskas9da80f22012-11-14 12:59:43 -08001026 # TODO (crosbug.com/p/16231) remove this conditional completely if/when
1027 # issue is resolved.
1028 if self.client_attr.platform == 'Parrot':
1029 self.wait_for_client_offline()
1030 self.cold_reboot()
1031
Vic Yange7553162012-06-20 16:20:47 +08001032
1033 def disable_keyboard_dev_mode(self):
1034 logging.info("Disabling keyboard controlled developer mode")
Gediminas Ramanauskasba352ad2012-11-09 09:43:32 -08001035 if (not self.client_attr.chrome_ec and
1036 not self.client_attr.broken_rec_mode):
Vic Yang611dd852012-08-02 15:36:31 +08001037 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001038 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +08001039 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +08001040 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001041
1042
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001043 def setup_dev_mode(self, dev_mode):
1044 """Setup for development mode.
1045
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001046 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001047 tries to do so.
1048
1049 Args:
1050 dev_mode: True if requested in dev mode; False if normal mode.
1051 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001052 # Change the default firmware_action for dev mode passing the fw screen.
1053 self.register_faft_template({
Tom Wai-Hong Tam56977782012-11-23 16:13:28 +08001054 'firmware_action': (self.wait_dev_screen_and_ctrl_d if dev_mode
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001055 else None),
1056 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001057 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +08001058 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001059 not self.checkers.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001060 logging.info('Dev switch is not on. Now switch it on.')
1061 self.servo.enable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001062 if not self.checkers.crossystem_checker({'devsw_boot': '1',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001063 'mainfw_type': 'developer'}):
1064 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001065 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001066 'userspace_action': None if self.client_attr.keyboard_dev
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001067 else (self.faft_client.system.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001068 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001069 'reboot_action': self.enable_keyboard_dev_mode if
1070 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001071 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001072 else:
Vic Yange7553162012-06-20 16:20:47 +08001073 if (not self.client_attr.keyboard_dev and
Vic Yangf93f7022012-10-31 09:40:36 +08001074 not self.checkers.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001075 logging.info('Dev switch is not off. Now switch it off.')
1076 self.servo.disable_development_mode()
Vic Yangf93f7022012-10-31 09:40:36 +08001077 if not self.checkers.crossystem_checker({'devsw_boot': '0',
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001078 'mainfw_type': 'normal'}):
1079 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001080 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +08001081 'userspace_action': None if self.client_attr.keyboard_dev
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001082 else (self.faft_client.system.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +08001083 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001084 'reboot_action': self.disable_keyboard_dev_mode if
1085 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001086 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001087
1088
Tom Wai-Hong Tam4c153fa2013-01-22 13:56:06 +08001089 def setup_rw_boot(self, section='a'):
1090 """Make sure firmware is in RW-boot mode.
1091
1092 If the given firmware section is in RO-boot mode, turn off the RO-boot
1093 flag and reboot DUT into RW-boot mode.
1094
1095 Args:
1096 section: A firmware section, either 'a' or 'b'.
1097 """
1098 flags = self.faft_client.bios.get_preamble_flags(section)
1099 if flags & vboot.PREAMBLE_USE_RO_NORMAL:
1100 flags = flags ^ vboot.PREAMBLE_USE_RO_NORMAL
1101 self.run_faft_step({
1102 'userspace_action': (self.faft_client.bios.set_preamble_flags,
1103 (section, flags))
1104 })
1105
1106
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001107 def setup_kernel(self, part):
1108 """Setup for kernel test.
1109
1110 It makes sure both kernel A and B bootable and the current boot is
1111 the requested kernel part.
1112
1113 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001114 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001115 """
1116 self.ensure_kernel_boot(part)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001117 if self.faft_client.kernel.diff_a_b():
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001118 self.copy_kernel_and_rootfs(from_part=part,
1119 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001120 self.reset_and_prioritize_kernel(part)
1121
1122
1123 def reset_and_prioritize_kernel(self, part):
1124 """Make the requested partition highest priority.
1125
1126 This function also reset kerenl A and B to bootable.
1127
1128 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001129 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001130 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001131 root_dev = self.faft_client.system.get_root_dev()
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001132 # Reset kernel A and B to bootable.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001133 self.faft_client.system.run_shell_command(
1134 'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['a'], root_dev))
1135 self.faft_client.system.run_shell_command(
1136 'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['b'], root_dev))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001137 # Set kernel part highest priority.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001138 self.faft_client.system.run_shell_command('cgpt prioritize -i%s %s' %
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001139 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001140 # Safer to sync and wait until the cgpt status written to the disk.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001141 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001142 time.sleep(self.delay.sync)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001143
1144
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001145 def warm_reboot(self):
1146 """Request a warm reboot.
1147
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001148 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001149 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001150 # Use cold reset if the warm reset is broken.
1151 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001152 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1153 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001154 else:
1155 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001156
1157
1158 def cold_reboot(self):
1159 """Request a cold reboot.
1160
1161 A wrapper for underlying servo cold reset.
1162 """
Gediminas Ramanauskasc6025692012-10-23 14:33:40 -07001163 if self.client_attr.broken_warm_reset:
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001164 self.servo.set('pwr_button', 'press')
1165 self.servo.set('cold_reset', 'on')
1166 self.servo.set('cold_reset', 'off')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001167 time.sleep(self.delay.ec_boot_to_pwr_button)
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001168 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001169 else:
1170 self.servo.cold_reset()
1171
1172
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001173 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001174 """Request the client sync and do a warm reboot.
1175
1176 This is the default reboot action on FAFT.
1177 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001178 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001179 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001180 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001181
1182
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001183 def sync_and_cold_reboot(self):
1184 """Request the client sync and do a cold reboot.
1185
1186 This reboot action is used to reset EC for recovery mode.
1187 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001188 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001189 time.sleep(self.delay.sync)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001190 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001191
1192
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001193 def sync_and_ec_reboot(self, flags=''):
Vic Yangaeb10392012-08-28 09:25:09 +08001194 """Request the client sync and do a EC triggered reboot.
1195
1196 Args:
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001197 flags: Optional, a space-separated string of flags passed to EC
1198 reboot command, including:
1199 default: EC soft reboot;
1200 'hard': EC cold/hard reboot.
Vic Yangaeb10392012-08-28 09:25:09 +08001201 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001202 self.faft_client.system.run_shell_command('sync')
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001203 time.sleep(self.delay.sync)
Tom Wai-Hong Tambb92e6c2012-10-30 11:06:09 +08001204 self.ec.reboot(flags)
Tom Wai-Hong Tamad4aaae2012-12-12 11:02:06 +08001205 time.sleep(self.delay.ec_boot_to_console)
Vic Yangf86728a2012-07-30 10:44:07 +08001206 self.check_lid_and_power_on()
1207
1208
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001209 def reboot_with_factory_install_shim(self):
1210 """Request reboot with factory install shim to reset TPM.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001211
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001212 Factory install shim requires dev mode enabled. So this method switches
1213 firmware to dev mode first and reboot. The client uses factory install
1214 shim to reset TPM values.
Chun-ting Changa4f65532012-10-17 16:57:28 +08001215 """
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001216 # Unplug USB first to avoid the complicated USB autoboot cases.
Vadim Bendeburye7bd9362012-12-19 14:35:20 -08001217 self.servo.switch_usbkey('host')
Vic Yangf93f7022012-10-31 09:40:36 +08001218 is_dev = self.checkers.crossystem_checker({'devsw_boot': '1'})
Chun-ting Changa4f65532012-10-17 16:57:28 +08001219 if not is_dev:
1220 self.enable_dev_mode_and_reboot()
Vic Yangf1fdf712012-10-31 12:09:22 +08001221 time.sleep(self.delay.sync)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001222 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam3d00ab72012-11-14 10:39:22 +08001223 self.wait_fw_screen_and_plug_usb()
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001224 time.sleep(self.delay.install_shim_done)
Chun-ting Changa4f65532012-10-17 16:57:28 +08001225 self.warm_reboot()
1226
1227
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001228 def full_power_off_and_on(self):
1229 """Shutdown the device by pressing power button and power on again."""
1230 # Press power button to trigger Chrome OS normal shutdown process.
Tom Wai-Hong Tambe464992012-12-12 10:54:07 +08001231 # We use a customized delay since the normal-press 1.2s is not enough.
1232 self.servo.power_key(self.delay.hold_pwr_button)
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001233 time.sleep(self.delay.shutdown)
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001234 # Short press power button to boot DUT again.
1235 self.servo.power_short_press()
1236
1237
Vic Yangf86728a2012-07-30 10:44:07 +08001238 def check_lid_and_power_on(self):
1239 """
1240 On devices with EC software sync, system powers on after EC reboots if
1241 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1242 This method checks lid switch state and presses power button if
1243 necessary.
1244 """
1245 if self.servo.get("lid_open") == "no":
Tom Wai-Hong Tam41738762012-10-29 14:32:39 +08001246 time.sleep(self.delay.software_sync)
Vic Yangf86728a2012-07-30 10:44:07 +08001247 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001248
1249
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001250 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1251 """Modify the kernel header magic in USB stick.
1252
1253 The kernel header magic is the first 8-byte of kernel partition.
1254 We modify it to make it fail on kernel verification check.
1255
1256 Args:
1257 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1258 from_magic: A string of magic which we change it from.
1259 to_magic: A string of magic which we change it to.
1260
1261 Raises:
1262 error.TestError: if failed to change magic.
1263 """
Vadim Bendeburyb0b0b832013-02-04 22:08:40 -08001264 assert len(from_magic) == 8
1265 assert len(to_magic) == 8
1266 # USB image only contains one kernel.
1267 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
1268 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1269 current_magic = self.servo.system_output(read_cmd)
1270 if current_magic == to_magic:
1271 logging.info("The kernel magic is already %s.", current_magic)
1272 return
1273 if current_magic != from_magic:
1274 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1275
1276 logging.info('Modify the kernel magic in USB, from %s to %s.',
1277 from_magic, to_magic)
1278 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1279 " 2>/dev/null" % (to_magic, kernel_part))
1280 self.servo.system(write_cmd)
1281
1282 if self.servo.system_output(read_cmd) != to_magic:
1283 raise error.TestError("Failed to write new magic.")
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001284
1285
1286 def corrupt_usb_kernel(self, usb_dev):
1287 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1288
1289 Args:
1290 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1291 """
1292 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1293 self.CORRUPTED_MAGIC)
1294
1295
1296 def restore_usb_kernel(self, usb_dev):
1297 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1298
1299 Args:
1300 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1301 """
1302 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1303 self.CHROMEOS_MAGIC)
1304
1305
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001306 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001307 """Call the action function with/without arguments.
1308
1309 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001310 action_tuple: A function, or a tuple (function, args, error_msg),
1311 in which, args and error_msg are optional. args is
1312 either a value or a tuple if multiple arguments.
Vic Yang52116d42012-11-05 16:22:34 +08001313 This can also be a list containing multiple function
1314 or tuple. In this case, these actions are called in
1315 sequence.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001316 check_status: Check the return value of action function. If not
1317 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001318
1319 Returns:
1320 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001321
1322 Raises:
1323 error.TestError: An error when the action function is not callable.
1324 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001325 """
Vic Yang52116d42012-11-05 16:22:34 +08001326 if isinstance(action_tuple, list):
1327 return all([self._call_action(action, check_status=check_status)
1328 for action in action_tuple])
1329
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001330 action = action_tuple
1331 args = ()
1332 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001333 if isinstance(action_tuple, tuple):
1334 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001335 if len(action_tuple) >= 2:
1336 args = action_tuple[1]
1337 if not isinstance(args, tuple):
1338 args = (args,)
1339 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001340 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001341
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001342 if action is None:
1343 return
1344
1345 if not callable(action):
1346 raise error.TestError('action is not callable!')
1347
1348 info_msg = 'calling %s' % str(action)
1349 if args:
1350 info_msg += ' with args %s' % str(args)
1351 logging.info(info_msg)
1352 ret = action(*args)
1353
1354 if check_status and not ret:
1355 raise error.TestFail('%s: %s returning %s' %
1356 (error_msg, info_msg, str(ret)))
1357 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001358
1359
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001360 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
Tom Wai-Hong Tam8da40de2012-12-12 12:15:54 +08001361 post_power_action=None, shutdown_timeout=None):
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001362 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1363
1364 Args:
1365 shutdown_action: a function which makes DUT shutdown, like pressing
1366 power key.
1367 pre_power_action: a function which is called before next power on.
1368 post_power_action: a function which is called after next power on.
Tom Wai-Hong Tam8da40de2012-12-12 12:15:54 +08001369 shutdown_timeout: a timeout to confirm DUT shutdown.
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001370
1371 Raises:
1372 error.TestFail: if the shutdown_action() failed to turn DUT off.
1373 """
1374 self._call_action(shutdown_action)
1375 logging.info('Wait to ensure DUT shut down...')
1376 try:
Tom Wai-Hong Tam8da40de2012-12-12 12:15:54 +08001377 if shutdown_timeout is None:
1378 shutdown_timeout = self.delay.shutdown_timeout
1379 self.wait_for_client(timeout=shutdown_timeout)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001380 raise error.TestFail(
1381 'Should shut the device down after calling %s.' %
1382 str(shutdown_action))
1383 except AssertionError:
1384 logging.info(
1385 'DUT is surely shutdown. We are going to power it on again...')
1386
1387 if pre_power_action:
1388 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001389 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001390 if post_power_action:
1391 self._call_action(post_power_action)
1392
1393
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001394 def register_faft_template(self, template):
1395 """Register FAFT template, the default FAFT_STEP of each step.
1396
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001397 Any missing field falls back to the original faft_template.
1398
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001399 Args:
1400 template: A FAFT_STEP dict.
1401 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001402 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001403
1404
1405 def register_faft_sequence(self, sequence):
1406 """Register FAFT sequence.
1407
1408 Args:
1409 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1410 """
1411 self._faft_sequence = sequence
1412
1413
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001414 def run_faft_step(self, step, no_reboot=False, next_step=None):
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001415 """Run a single FAFT step.
1416
1417 Any missing field falls back to faft_template. An empty step means
1418 running the default faft_template.
1419
1420 Args:
1421 step: A FAFT_STEP dict.
1422 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001423 next_step: Optional, a FAFT_STEP dict of the next step, which is used
1424 for diagnostic.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001425
1426 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001427 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tam4bb85e22012-10-25 14:35:24 +08001428 error.TestFail: Test failed in waiting DUT reboot.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001429 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001430 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1431 'firmware_action', 'install_deps_after_boot')
1432
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001433 test = {}
1434 test.update(self._faft_template)
1435 test.update(step)
1436
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001437 for key in test:
1438 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001439 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001440
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001441 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001442 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001443
1444 self._call_action(test['userspace_action'])
1445
1446 # Don't run reboot_action and firmware_action if no_reboot is True.
1447 if not no_reboot:
1448 self._call_action(test['reboot_action'])
1449 self.wait_for_client_offline()
1450 self._call_action(test['firmware_action'])
1451
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001452 try:
1453 if 'install_deps_after_boot' in test:
1454 self.wait_for_client(
1455 install_deps=test['install_deps_after_boot'])
1456 else:
1457 self.wait_for_client()
1458 except AssertionError:
Yusuf Mohsinally928f8c72012-12-11 15:27:02 -08001459 logging.error('wait_for_client() timed out.')
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001460 self._restore_routine_from_timeout(next_step)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001461
1462
1463 def run_faft_sequence(self):
1464 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001465 sequence = self._faft_sequence
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001466 for index, step in enumerate(sequence):
Vic Yang772df8a2012-10-31 10:10:49 +08001467 logging.info('======== Running FAFT sequence step %d ========',
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001468 index + 1)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001469 # Don't reboot in the last step.
Tom Wai-Hong Tamc285f4c2012-10-30 15:44:39 +08001470 if index == len(sequence) - 1:
1471 self.run_faft_step(step, no_reboot=True)
1472 else:
1473 self.run_faft_step(step, next_step=sequence[index + 1])
ctchang38ae4922012-09-03 17:01:16 +08001474
1475
ctchang38ae4922012-09-03 17:01:16 +08001476 def get_current_firmware_sha(self):
1477 """Get current firmware sha of body and vblock.
1478
1479 Returns:
1480 Current firmware sha follows the order (
1481 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1482 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001483 current_firmware_sha = (self.faft_client.bios.get_sig_sha('a'),
1484 self.faft_client.bios.get_body_sha('a'),
1485 self.faft_client.bios.get_sig_sha('b'),
1486 self.faft_client.bios.get_body_sha('b'))
ctchang38ae4922012-09-03 17:01:16 +08001487 return current_firmware_sha
1488
1489
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001490 def is_firmware_changed(self):
1491 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001492
1493 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001494 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001495 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001496 # Device may not be rebooted after test.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001497 self.faft_client.bios.reload()
ctchang38ae4922012-09-03 17:01:16 +08001498
1499 current_sha = self.get_current_firmware_sha()
1500
1501 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001502 return False
ctchang38ae4922012-09-03 17:01:16 +08001503 else:
ctchang38ae4922012-09-03 17:01:16 +08001504 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1505 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1506 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1507 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001508 logging.info("Firmware changed:")
Vic Yang772df8a2012-10-31 10:10:49 +08001509 logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1510 logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1511 logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1512 logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001513 return True
ctchang38ae4922012-09-03 17:01:16 +08001514
1515
1516 def backup_firmware(self, suffix='.original'):
1517 """Backup firmware to file, and then send it to host.
1518
1519 Args:
1520 suffix: a string appended to backup file name
1521 """
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001522 remote_temp_dir = self.faft_client.system.create_temp_dir()
1523 self.faft_client.bios.dump_whole(os.path.join(remote_temp_dir, 'bios'))
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001524 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1525 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001526
1527 self._backup_firmware_sha = self.get_current_firmware_sha()
Vic Yang772df8a2012-10-31 10:10:49 +08001528 logging.info('Backup firmware stored in %s with suffix %s',
1529 self.resultsdir, suffix)
ctchang38ae4922012-09-03 17:01:16 +08001530
1531
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001532 def is_firmware_saved(self):
1533 """Check if a firmware saved (called backup_firmware before).
1534
1535 Returns:
1536 True if the firmware is backuped; otherwise False.
1537 """
1538 return self._backup_firmware_sha != ()
1539
1540
Tom Wai-Hong Tam1dd11592012-10-26 15:01:45 +08001541 def clear_saved_firmware(self):
1542 """Clear the firmware saved by the method backup_firmware."""
1543 self._backup_firmware_sha = ()
1544
1545
ctchang38ae4922012-09-03 17:01:16 +08001546 def restore_firmware(self, suffix='.original'):
1547 """Restore firmware from host in resultsdir.
1548
1549 Args:
1550 suffix: a string appended to backup file name
1551 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001552 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001553 return
1554
1555 # Backup current corrupted firmware.
1556 self.backup_firmware(suffix='.corrupt')
1557
1558 # Restore firmware.
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001559 remote_temp_dir = self.faft_client.system.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001560 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1561 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001562
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001563 self.faft_client.bios.write_whole(
1564 os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001565 self.sync_and_warm_reboot()
1566 self.wait_for_client_offline()
Tom Wai-Hong Tame2f9cf92012-11-26 10:04:11 +08001567 self.wait_dev_screen_and_ctrl_d()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001568 self.wait_for_client()
1569
ctchang38ae4922012-09-03 17:01:16 +08001570 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001571
1572
1573 def setup_firmwareupdate_shellball(self, shellball=None):
1574 """Deside a shellball to use in firmware update test.
1575
1576 Check if there is a given shellball, and it is a shell script. Then,
1577 send it to the remote host. Otherwise, use
1578 /usr/sbin/chromeos-firmwareupdate.
1579
1580 Args:
1581 shellball: path of a shellball or default to None.
1582
1583 Returns:
1584 Path of shellball in remote host.
1585 If use default shellball, reutrn None.
1586 """
1587 updater_path = None
1588 if shellball:
1589 # Determine the firmware file is a shellball or a raw binary.
1590 is_shellball = (utils.system_output("file %s" % shellball).find(
1591 "shell script") != -1)
1592 if is_shellball:
Vic Yang772df8a2012-10-31 10:10:49 +08001593 logging.info('Device will update firmware with shellball %s',
1594 shellball)
Chun-ting Changd43aa9b2012-11-16 10:12:05 +08001595 temp_dir = self.faft_client.system.create_temp_dir(
1596 'shellball_')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001597 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1598 self._client.send_file(shellball, temp_shellball)
1599 updater_path = temp_shellball
1600 else:
1601 raise error.TestFail(
1602 'The given shellball is not a shell script.')
1603 return updater_path