blob: 9cb95592da5ad60e4e09d362641b5da3bf1ba80e [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 Tam40fd9472012-01-09 17:11:02 +08009import sys
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +080010import tempfile
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 Tam6019a1a2012-10-12 14:03:34 +080016from autotest_lib.server.cros.chrome_ec import ChromeEC
Vic Yangebd6de62012-06-26 14:25:57 +080017from autotest_lib.server.cros.faft_client_attribute import FAFTClientAttribute
Tom Wai-Hong Tam22b77302011-11-03 13:03:48 +080018from autotest_lib.server.cros.servo_test import ServoTest
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080019from autotest_lib.site_utils import lab_test
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080020
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080021dirname = os.path.dirname(sys.modules[__name__].__file__)
22autotest_dir = os.path.abspath(os.path.join(dirname, "..", ".."))
23cros_dir = os.path.join(autotest_dir, "..", "..", "..", "..")
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080024
25class 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 Tamadbec3e2012-10-15 14:20:15 +080071 _customized_key_commands: The dict of the customized key commands,
72 including Ctrl-D, Ctrl-U, Enter, Space, and recovery reboot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +080073 _install_image_path: The path of Chrome OS test image to be installed.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +080074 _firmware_update: Boolean. True if firmware update needed after
75 installing the image.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +080076 """
77 version = 1
78
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +080079
80 # Mapping of partition number of kernel and rootfs.
81 KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
82 ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
83 OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
84 OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
85
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080086 # Delay between power-on and firmware screen.
Tom Wai-Hong Tam66af37b2012-08-01 10:48:42 +080087 FIRMWARE_SCREEN_DELAY = 10
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080088 # Delay between passing firmware screen and text mode warning screen.
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +080089 TEXT_SCREEN_DELAY = 20
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +080090 # Delay for waiting beep done.
91 BEEP_DELAY = 1
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080092 # Delay of loading the USB kernel.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080093 USB_LOAD_DELAY = 10
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080094 # Delay between USB plug-out and plug-in.
Tom Wai-Hong Tam9ca742a2011-12-05 15:48:57 +080095 USB_PLUG_DELAY = 10
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080096 # Delay after running the 'sync' command.
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +080097 SYNC_DELAY = 5
Vic Yang59cac9c2012-05-21 15:28:42 +080098 # Delay for waiting client to return before EC reboot
99 EC_REBOOT_DELAY = 1
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +0800100 # Delay for waiting client to full power off
101 FULL_POWER_OFF_DELAY = 30
Vic Yang59cac9c2012-05-21 15:28:42 +0800102 # Delay between EC reboot and pressing power button
103 POWER_BTN_DELAY = 0.5
Vic Yangf86728a2012-07-30 10:44:07 +0800104 # Delay of EC software sync hash calculating time
105 SOFTWARE_SYNC_DELAY = 6
Vic Yanga7250662012-08-31 04:00:08 +0800106 # Delay between EC boot and ChromeEC console functional
107 EC_BOOT_DELAY = 0.5
108 # Duration of holding cold_reset to reset device
109 COLD_RESET_DELAY = 0.1
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800110
Tom Wai-Hong Tam51ef2e12012-07-27 15:04:12 +0800111 # The developer screen timeouts fit our spec.
112 DEV_SCREEN_TIMEOUT = 30
113
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800114 CHROMEOS_MAGIC = "CHROMEOS"
115 CORRUPTED_MAGIC = "CORRUPTD"
116
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800117 _faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800118 _faft_sequence = ()
119
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800120 _customized_key_commands = {
121 'ctrl_d': None,
122 'ctrl_u': None,
123 'enter': None,
124 'rec_reboot': None,
125 'space': None,
126 }
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800127 _install_image_path = None
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800128 _firmware_update = False
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800129
ctchang38ae4922012-09-03 17:01:16 +0800130 _backup_firmware_sha = ()
131
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800132
133 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
134 # Parse arguments from command line
135 args = {}
136 for arg in cmdline_args:
137 match = re.search("^(\w+)=(.+)", arg)
138 if match:
139 args[match.group(1)] = match.group(2)
140
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800141 # Keep the arguments which will be used later.
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800142 for key in self._customized_key_commands:
143 key_cmd = key + '_cmd'
144 if key_cmd in args:
145 self._customized_key_commands[key] = args[key_cmd]
146 logging.info('Customized %s key command: %s' %
147 (key, args[key_cmd]))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800148 if 'image' in args:
149 self._install_image_path = args['image']
150 logging.info('Install Chrome OS test image path: %s' %
151 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800152 if 'firmware_update' in args and args['firmware_update'].lower() \
153 not in ('0', 'false', 'no'):
154 if self._install_image_path:
155 self._firmware_update = True
156 logging.info('Also update firmware after installing.')
157 else:
158 logging.warning('Firmware update will not not performed '
159 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800160
161 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
162 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800163 if use_faft:
164 self.client_attr = FAFTClientAttribute(
165 self.faft_client.get_platform_name())
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800166
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800167 if self.client_attr.chrome_ec:
168 self.ec = ChromeEC(self.servo)
169
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700170 # Setting up key matrix mapping
171 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
172
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800173
174 def setup(self):
175 """Autotest setup function."""
176 super(FAFTSequence, self).setup()
177 if not self._remote_infos['faft']['used']:
178 raise error.TestError('The use_faft flag should be enabled.')
179 self.register_faft_template({
180 'state_checker': (None),
181 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800182 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800183 'firmware_action': (None)
184 })
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800185 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
186 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
Tom Wai-Hong Tam1e7f1ed2012-10-18 17:03:13 +0800187 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
188 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800189 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800190 if self._install_image_path:
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800191 self.install_test_image(self._install_image_path,
192 self._firmware_update)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800193
194
195 def cleanup(self):
196 """Autotest cleanup function."""
197 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
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800202 def reset_client(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800203 """Reset client, if necessary.
204
205 This method is called when the client is not responsive. It may be
206 caused by the following cases:
207 - network flaky (can be recovered by replugging the Ethernet);
208 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
209 - corrupted firmware;
210 - corrutped OS image.
211 """
212 # DUT works fine, done.
213 if self._ping_test(self._client.ip, timeout=5):
214 return
215
216 # TODO(waihong@chromium.org): Implement replugging the Ethernet in the
217 # first reset item.
218
219 # DUT may halt on a firmware screen. Try cold reboot.
220 logging.info('Try cold reboot...')
221 self.cold_reboot()
222 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800223 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800224 return
225 except AssertionError:
226 pass
227
228 # DUT may be broken by a corrupted firmware. Restore firmware.
229 # We assume the recovery boot still works fine. Since the recovery
230 # code is in RO region and all FAFT tests don't change the RO region
231 # except GBB.
232 if self.is_firmware_saved():
233 self.ensure_client_in_recovery()
234 logging.info('Try restore the original firmware...')
235 if self.is_firmware_changed():
236 try:
237 self.restore_firmware()
238 return
239 except AssertionError:
240 logging.info('Restoring firmware doesn\'t help.')
241
242 # DUT may be broken by a corrupted OS image. Restore OS image.
243 self.ensure_client_in_recovery()
244 logging.info('Try restore the OS image...')
245 self.faft_client.run_shell_command('chromeos-install --yes')
246 self.sync_and_warm_reboot()
247 self.wait_for_client_offline()
248 try:
249 self.wait_for_client(install_deps=True)
250 logging.info('Successfully restore OS image.')
251 return
252 except AssertionError:
253 logging.info('Restoring OS image doesn\'t help.')
254
255
256 def ensure_client_in_recovery(self):
257 """Ensure client in recovery boot; reboot into it if necessary.
258
259 Raises:
260 error.TestError: if failed to boot the USB image.
261 """
262 # DUT works fine and is already in recovery boot, done.
263 if self._ping_test(self._client.ip, timeout=5):
264 if self.crossystem_checker({'mainfw_type': 'recovery'}):
265 return
266
267 logging.info('Try boot into USB image...')
268 self.servo.enable_usb_hub(host=True)
269 self.enable_rec_mode_and_reboot()
270 self.wait_fw_screen_and_plug_usb()
271 try:
272 self.wait_for_client(install_deps=True)
273 except AssertionError:
274 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800275
276
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800277 def assert_test_image_in_usb_disk(self, usb_dev=None):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800278 """Assert an USB disk plugged-in on servo and a test image inside.
279
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800280 Args:
281 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
282 If None, it is detected automatically.
283
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800284 Raises:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800285 error.TestError: if USB disk not detected or not a test image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800286 """
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800287 if usb_dev:
288 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
289 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700290 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800291 usb_dev = self.servo.probe_host_usb_dev()
292 if not usb_dev:
293 raise error.TestError(
294 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800295
296 tmp_dir = tempfile.mkdtemp()
Tom Wai-Hong Tamb0e80852011-12-07 16:15:06 +0800297 utils.system('sudo mount -r -t ext2 %s3 %s' % (usb_dev, tmp_dir))
Tom Wai-Hong Tame77459e2011-11-03 17:19:46 +0800298 code = utils.system(
299 'grep -qE "(Test Build|testimage-channel)" %s/etc/lsb-release' %
300 tmp_dir, ignore_status=True)
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800301 utils.system('sudo umount %s' % tmp_dir)
302 os.removedirs(tmp_dir)
303 if code != 0:
304 raise error.TestError(
305 'The image in the USB disk should be a test image.')
306
307
Simran Basi741b5d42012-05-18 11:27:15 -0700308 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800309 """Install the test image specied by the path onto the USB and DUT disk.
310
311 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500312 recovery mode. Then runs 'chromeos-install' (and possible
313 chromeos-firmwareupdate') to install it to DUT disk.
314
315 Sample command line:
316
317 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
318 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
319 server/site_tests/firmware_XXXX/control
320
321 This test requires an automated recovery to occur while simulating
322 inserting and removing the usb key from the servo. To allow this the
323 following hardware setup is required:
324 1. servo2 board connected via servoflex.
325 2. USB key inserted in the servo2.
326 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
327 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800328
329 Args:
330 image_path: Path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800331 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800332 """
333 build_ver, build_hash = lab_test.VerifyImageAndGetId(cros_dir,
334 image_path)
335 logging.info('Processing build: %s %s' % (build_ver, build_hash))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800336
Mike Truty49153d82012-08-21 22:27:30 -0500337 # Reuse the servo method that uses the servo USB key to install
338 # the test image.
339 self.servo.image_to_servo_usb(image_path)
340
341 # DUT is powered off while imaging servo USB.
342 # Now turn it on.
343 self.servo.power_short_press()
344 self.wait_for_client()
345 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
346
347 install_cmd = 'chromeos-install --yes'
348 if firmware_update:
349 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
350
351 self.register_faft_sequence((
352 { # Step 1, request recovery boot
353 'state_checker': (self.crossystem_checker, {
354 'mainfw_type': ('developer', 'normal'),
355 }),
356 'userspace_action': self.faft_client.request_recovery_boot,
357 'firmware_action': self.wait_fw_screen_and_plug_usb,
358 'install_deps_after_boot': True,
359 },
360 { # Step 2, expected recovery boot
361 'state_checker': (self.crossystem_checker, {
362 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800363 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500364 }),
365 'userspace_action': (self.faft_client.run_shell_command,
366 install_cmd),
367 'reboot_action': self.cold_reboot,
368 'install_deps_after_boot': True,
369 },
370 { # Step 3, expected normal or developer boot (not recovery)
371 'state_checker': (self.crossystem_checker, {
372 'mainfw_type': ('developer', 'normal')
373 }),
374 },
375 ))
376 self.run_faft_sequence()
377 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800378 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800379
380
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800381 def clear_set_gbb_flags(self, clear_mask, set_mask):
382 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800383
384 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800385 clear_mask: A mask of flags to be cleared.
386 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800387 """
388 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800389 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
390
391 if (gbb_flags != new_flags):
392 logging.info('Change the GBB flags from 0x%x to 0x%x.' %
393 (gbb_flags, new_flags))
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800394 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800395 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800396 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800397 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800398 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800399 self.run_faft_step({
400 'firmware_action': self.wait_fw_screen_and_ctrl_d,
401 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800402
403
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800404 def check_ec_capability(self, required_cap=[], suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800405 """Check if current platform has required EC capabilities.
406
407 Args:
408 required_cap: A list containing required EC capabilities. Pass in
409 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800410 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800411
412 Returns:
413 True if requirements are met. Otherwise, False.
414 """
415 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800416 if not suppress_warning:
417 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800418 return False
419
420 for cap in required_cap:
421 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800422 if not suppress_warning:
423 logging.warn('Requires EC capability "%s" to run this '
424 'test.' % cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800425 return False
426
427 return True
428
429
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800430 def _parse_crossystem_output(self, lines):
431 """Parse the crossystem output into a dict.
432
433 Args:
434 lines: The list of crossystem output strings.
435
436 Returns:
437 A dict which contains the crossystem keys/values.
438
439 Raises:
440 error.TestError: If wrong format in crossystem output.
441
442 >>> seq = FAFTSequence()
443 >>> seq._parse_crossystem_output([ \
444 "arch = x86 # Platform architecture", \
445 "cros_debug = 1 # OS should allow debug", \
446 ])
447 {'cros_debug': '1', 'arch': 'x86'}
448 >>> seq._parse_crossystem_output([ \
449 "arch=x86", \
450 ])
451 Traceback (most recent call last):
452 ...
453 TestError: Failed to parse crossystem output: arch=x86
454 >>> seq._parse_crossystem_output([ \
455 "arch = x86 # Platform architecture", \
456 "arch = arm # Platform architecture", \
457 ])
458 Traceback (most recent call last):
459 ...
460 TestError: Duplicated crossystem key: arch
461 """
462 pattern = "^([^ =]*) *= *(.*[^ ]) *# [^#]*$"
463 parsed_list = {}
464 for line in lines:
465 matched = re.match(pattern, line.strip())
466 if not matched:
467 raise error.TestError("Failed to parse crossystem output: %s"
468 % line)
469 (name, value) = (matched.group(1), matched.group(2))
470 if name in parsed_list:
471 raise error.TestError("Duplicated crossystem key: %s" % name)
472 parsed_list[name] = value
473 return parsed_list
474
475
476 def crossystem_checker(self, expected_dict):
477 """Check the crossystem values matched.
478
479 Given an expect_dict which describes the expected crossystem values,
480 this function check the current crossystem values are matched or not.
481
482 Args:
483 expected_dict: A dict which contains the expected values.
484
485 Returns:
486 True if the crossystem value matched; otherwise, False.
487 """
488 lines = self.faft_client.run_shell_command_get_output('crossystem')
489 got_dict = self._parse_crossystem_output(lines)
490 for key in expected_dict:
491 if key not in got_dict:
492 logging.info('Expected key "%s" not in crossystem result' % key)
493 return False
494 if isinstance(expected_dict[key], str):
495 if got_dict[key] != expected_dict[key]:
496 logging.info("Expected '%s' value '%s' but got '%s'" %
497 (key, expected_dict[key], got_dict[key]))
498 return False
499 elif isinstance(expected_dict[key], tuple):
500 # Expected value is a tuple of possible actual values.
501 if got_dict[key] not in expected_dict[key]:
502 logging.info("Expected '%s' values %s but got '%s'" %
503 (key, str(expected_dict[key]), got_dict[key]))
504 return False
505 else:
506 logging.info("The expected_dict is neither a str nor a dict.")
507 return False
508 return True
509
510
Tom Wai-Hong Tam39b93b92012-09-04 16:56:05 +0800511 def vdat_flags_checker(self, mask, value):
512 """Check the flags from VbSharedData matched.
513
514 This function checks the masked flags from VbSharedData using crossystem
515 are matched the given value.
516
517 Args:
518 mask: A bitmask of flags to be matched.
519 value: An expected value.
520
521 Returns:
522 True if the flags matched; otherwise, False.
523 """
524 lines = self.faft_client.run_shell_command_get_output(
525 'crossystem vdat_flags')
526 vdat_flags = int(lines[0], 16)
527 if vdat_flags & mask != value:
528 logging.info("Expected vdat_flags 0x%x mask 0x%x but got 0x%x" %
529 (value, mask, vdat_flags))
530 return False
531 return True
532
533
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800534 def ro_normal_checker(self, expected_fw=None, twostop=False):
535 """Check the current boot uses RO boot.
536
537 Args:
538 expected_fw: A string of expected firmware, 'A', 'B', or
539 None if don't care.
540 twostop: True to expect a TwoStop boot; False to expect a RO boot.
541
542 Returns:
543 True if the currect boot firmware matched and used RO boot;
544 otherwise, False.
545 """
546 crossystem_dict = {'tried_fwb': '0'}
547 if expected_fw:
548 crossystem_dict['mainfw_act'] = expected_fw.upper()
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800549 if self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800550 crossystem_dict['ecfw_act'] = ('RW' if twostop else 'RO')
551
552 return (self.vdat_flags_checker(
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800553 vboot.VDAT_FLAG_LF_USE_RO_NORMAL,
554 0 if twostop else vboot.VDAT_FLAG_LF_USE_RO_NORMAL) and
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800555 self.crossystem_checker(crossystem_dict))
556
557
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800558 def dev_boot_usb_checker(self, dev_boot_usb=True):
559 """Check the current boot is from a developer USB (Ctrl-U trigger).
560
561 Args:
562 dev_boot_usb: True to expect an USB boot;
563 False to expect an internal device boot.
564
565 Returns:
566 True if the currect boot device matched; otherwise, False.
567 """
568 return (self.crossystem_checker({'mainfw_type': 'developer'})
569 and self.faft_client.is_removable_device_boot() == dev_boot_usb)
570
571
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800572 def root_part_checker(self, expected_part):
573 """Check the partition number of the root device matched.
574
575 Args:
576 expected_part: A string containing the number of the expected root
577 partition.
578
579 Returns:
580 True if the currect root partition number matched; otherwise, False.
581 """
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +0800582 part = self.faft_client.get_root_part()[-1]
583 if self.ROOTFS_MAP[expected_part] != part:
584 logging.info("Expected root part %s but got %s" %
585 (self.ROOTFS_MAP[expected_part], part))
586 return False
587 return True
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800588
589
Vic Yang59cac9c2012-05-21 15:28:42 +0800590 def ec_act_copy_checker(self, expected_copy):
591 """Check the EC running firmware copy matches.
592
593 Args:
594 expected_copy: A string containing 'RO', 'A', or 'B' indicating
595 the expected copy of EC running firmware.
596
597 Returns:
598 True if the current EC running copy matches; otherwise, False.
599 """
600 lines = self.faft_client.run_shell_command_get_output('ectool version')
601 pattern = re.compile("Firmware copy: (.*)")
602 for line in lines:
603 matched = pattern.match(line)
604 if matched and matched.group(1) == expected_copy:
605 return True
606 return False
607
608
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800609 def check_root_part_on_non_recovery(self, part):
610 """Check the partition number of root device and on normal/dev boot.
611
612 Returns:
613 True if the root device matched and on normal/dev boot;
614 otherwise, False.
615 """
616 return self.root_part_checker(part) and \
617 self.crossystem_checker({
618 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800619 })
620
621
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800622 def _join_part(self, dev, part):
623 """Return a concatenated string of device and partition number.
624
625 Args:
626 dev: A string of device, e.g.'/dev/sda'.
627 part: A string of partition number, e.g.'3'.
628
629 Returns:
630 A concatenated string of device and partition number, e.g.'/dev/sda3'.
631
632 >>> seq = FAFTSequence()
633 >>> seq._join_part('/dev/sda', '3')
634 '/dev/sda3'
635 >>> seq._join_part('/dev/mmcblk0', '2')
636 '/dev/mmcblk0p2'
637 """
638 if 'mmcblk' in dev:
639 return dev + 'p' + part
640 else:
641 return dev + part
642
643
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800644 def copy_kernel_and_rootfs(self, from_part, to_part):
645 """Copy kernel and rootfs from from_part to to_part.
646
647 Args:
648 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800649 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800650 """
651 root_dev = self.faft_client.get_root_dev()
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800652 logging.info('Copying kernel from %s to %s. Please wait...' %
653 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800654 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800655 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
656 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
657 logging.info('Copying rootfs from %s to %s. Please wait...' %
658 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800659 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800660 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
661 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800662
663
664 def ensure_kernel_boot(self, part):
665 """Ensure the request kernel boot.
666
667 If not, it duplicates the current kernel to the requested kernel
668 and sets the requested higher priority to ensure it boot.
669
670 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800671 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800672 """
673 if not self.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800674 if self.faft_client.diff_kernel_a_b():
675 self.copy_kernel_and_rootfs(
676 from_part=self.OTHER_KERNEL_MAP[part],
677 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800678 self.run_faft_step({
679 'userspace_action': (self.reset_and_prioritize_kernel, part),
680 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800681
682
Vic Yang416f2032012-08-28 10:18:03 +0800683 def set_hardware_write_protect(self, enabled):
Vic Yang2cabf812012-08-28 02:39:04 +0800684 """Set hardware write protect pin.
685
686 Args:
687 enable: True if asserting write protect pin. Otherwise, False.
688 """
689 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
690 self.servo.set('fw_wp_en', 'on')
Vic Yang416f2032012-08-28 10:18:03 +0800691 self.servo.set('fw_wp', 'on' if enabled else 'off')
692
693
694 def set_EC_write_protect_and_reboot(self, enabled):
695 """Set EC write protect status and reboot to take effect.
696
697 EC write protect is only activated if both hardware write protect pin
698 is asserted and software write protect flag is set. Also, a reboot is
699 required for write protect to take effect.
700
701 Since the software write protect flag cannot be unset if hardware write
702 protect pin is asserted, we need to deasserted the pin first if we are
703 deactivating write protect. Similarly, a reboot is required before we
704 can modify the software flag.
705
706 This method asserts/deasserts hardware write protect pin first, and
707 set corresponding EC software write protect flag.
708
709 Args:
710 enable: True if activating EC write protect. Otherwise, False.
711 """
712 self.set_hardware_write_protect(enabled)
713 if enabled:
714 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800715 self.ec.send_command("flashwp enable")
Vic Yang416f2032012-08-28 10:18:03 +0800716 self.sync_and_ec_reboot()
717 else:
718 # Reboot after deasserting hardware write protect pin to deactivate
719 # write protect. And then remove software write protect flag.
720 self.sync_and_ec_reboot()
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800721 self.ec.send_command("flashwp disable")
Vic Yang2cabf812012-08-28 02:39:04 +0800722
723
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800724 def send_ctrl_d_to_dut(self):
725 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800726 if self._customized_key_commands['ctrl_d']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800727 logging.info('running the customized Ctrl-D key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800728 os.system(self._customized_key_commands['ctrl_d'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800729 else:
730 self.servo.ctrl_d()
731
732
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800733 def send_ctrl_u_to_dut(self):
734 """Send Ctrl-U key to DUT.
735
736 Raises:
737 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
738 on a no-build-in-keyboard device.
739 """
740 if self._customized_key_commands['ctrl_u']:
741 logging.info('running the customized Ctrl-U key command')
742 os.system(self._customized_key_commands['ctrl_u'])
743 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
744 self.ec.key_down('<ctrl_l>')
745 self.ec.key_down('u')
746 self.ec.key_up('u')
747 self.ec.key_up('<ctrl_l>')
748 elif self.client_attr.has_keyboard:
749 raise error.TestError(
750 "Can't send Ctrl-U to DUT without using Chrome EC.")
751 else:
752 raise error.TestError(
753 "Should specify the ctrl_u_cmd argument.")
754
755
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800756 def send_enter_to_dut(self):
757 """Send Enter key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800758 if self._customized_key_commands['enter']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800759 logging.info('running the customized Enter key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800760 os.system(self._customized_key_commands['enter'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800761 else:
762 self.servo.enter_key()
763
764
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800765 def send_space_to_dut(self):
766 """Send Space key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800767 if self._customized_key_commands['space']:
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800768 logging.info('running the customized Space key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800769 os.system(self._customized_key_commands['space'])
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800770 else:
771 # Send the alternative key combinaton of space key to servo.
772 self.servo.ctrl_refresh_key()
773
774
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800775 def wait_fw_screen_and_ctrl_d(self):
776 """Wait for firmware warning screen and press Ctrl-D."""
777 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800778 self.send_ctrl_d_to_dut()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800779
780
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800781 def wait_fw_screen_and_ctrl_u(self):
782 """Wait for firmware warning screen and press Ctrl-U."""
783 time.sleep(self.FIRMWARE_SCREEN_DELAY)
784 self.send_ctrl_u_to_dut()
785
786
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800787 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
788 """Wait for firmware warning screen and trigger recovery boot."""
789 time.sleep(self.FIRMWARE_SCREEN_DELAY)
790 self.send_enter_to_dut()
791
792 # For Alex/ZGB, there is a dev warning screen in text mode.
793 # Skip it by pressing Ctrl-D.
794 if need_dev_transition:
795 time.sleep(self.TEXT_SCREEN_DELAY)
796 self.send_ctrl_d_to_dut()
797
798
Mike Truty49153d82012-08-21 22:27:30 -0500799 def wait_fw_screen_and_unplug_usb(self):
800 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +0800801 time.sleep(self.USB_LOAD_DELAY)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800802 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
803 time.sleep(self.USB_PLUG_DELAY)
Mike Truty49153d82012-08-21 22:27:30 -0500804
805
806 def wait_fw_screen_and_plug_usb(self):
807 """Wait for firmware warning screen and then unplug and plug the USB."""
808 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800809 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
810
811
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800812 def wait_fw_screen_and_press_power(self):
813 """Wait for firmware warning screen and press power button."""
814 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800815 # While the firmware screen, the power button probing loop sleeps
816 # 0.25 second on every scan. Use the normal delay (1.2 second) for
817 # power press.
818 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800819
820
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800821 def wait_longer_fw_screen_and_press_power(self):
822 """Wait for firmware screen without timeout and press power button."""
823 time.sleep(self.DEV_SCREEN_TIMEOUT)
824 self.wait_fw_screen_and_press_power()
825
826
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800827 def wait_fw_screen_and_close_lid(self):
828 """Wait for firmware warning screen and close lid."""
829 time.sleep(self.FIRMWARE_SCREEN_DELAY)
830 self.servo.lid_close()
831
832
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800833 def wait_longer_fw_screen_and_close_lid(self):
834 """Wait for firmware screen without timeout and close lid."""
835 time.sleep(self.FIRMWARE_SCREEN_DELAY)
836 self.wait_fw_screen_and_close_lid()
837
838
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800839 def setup_tried_fwb(self, tried_fwb):
840 """Setup for fw B tried state.
841
842 It makes sure the system in the requested fw B tried state. If not, it
843 tries to do so.
844
845 Args:
846 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
847 """
848 if tried_fwb:
849 if not self.crossystem_checker({'tried_fwb': '1'}):
850 logging.info(
851 'Firmware is not booted with tried_fwb. Reboot into it.')
852 self.run_faft_step({
853 'userspace_action': self.faft_client.set_try_fw_b,
854 })
855 else:
856 if not self.crossystem_checker({'tried_fwb': '0'}):
857 logging.info(
858 'Firmware is booted with tried_fwb. Reboot to clear.')
859 self.run_faft_step({})
860
861
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800862 def enable_rec_mode_and_reboot(self):
863 """Switch to rec mode and reboot.
864
865 This method emulates the behavior of the old physical recovery switch,
866 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
867 recovery mode, i.e. just press Power + Esc + Refresh.
868 """
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800869 if self._customized_key_commands['rec_reboot']:
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800870 logging.info('running the customized rec reboot command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800871 os.system(self._customized_key_commands['rec_reboot'])
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800872 elif self.client_attr.chrome_ec:
Vic Yang81273092012-08-21 15:57:09 +0800873 # Cold reset to clear EC_IN_RW signal
Vic Yanga7250662012-08-31 04:00:08 +0800874 self.servo.set('cold_reset', 'on')
875 time.sleep(self.COLD_RESET_DELAY)
876 self.servo.set('cold_reset', 'off')
877 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800878 self.ec.send_command("reboot ap-off")
Vic Yang611dd852012-08-02 15:36:31 +0800879 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800880 self.ec.send_command("hostevent set 0x4000")
Vic Yang611dd852012-08-02 15:36:31 +0800881 self.servo.power_short_press()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800882 else:
883 self.servo.enable_recovery_mode()
884 self.cold_reboot()
885 time.sleep(self.EC_REBOOT_DELAY)
886 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800887
888
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800889 def enable_dev_mode_and_reboot(self):
890 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800891 if self.client_attr.keyboard_dev:
892 self.enable_keyboard_dev_mode()
893 else:
894 self.servo.enable_development_mode()
895 self.faft_client.run_shell_command(
896 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800897
898
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800899 def enable_normal_mode_and_reboot(self):
900 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800901 if self.client_attr.keyboard_dev:
902 self.disable_keyboard_dev_mode()
903 else:
904 self.servo.disable_development_mode()
905 self.faft_client.run_shell_command(
906 'chromeos-firmwareupdate --mode tonormal && reboot')
907
908
909 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
910 """Wait for firmware screen and then switch into or out of dev mode.
911
912 Args:
913 dev: True if switching into dev mode. Otherwise, False.
914 """
915 time.sleep(self.FIRMWARE_SCREEN_DELAY)
916 if dev:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800917 self.send_ctrl_d_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800918 else:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800919 self.send_enter_to_dut()
Tom Wai-Hong Tam1408f172012-07-31 15:06:21 +0800920 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800921 self.send_enter_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800922
923
924 def enable_keyboard_dev_mode(self):
925 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +0800926 # Plug out USB disk for preventing recovery boot without warning
927 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +0800928 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800929 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800930 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800931 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +0800932
933
934 def disable_keyboard_dev_mode(self):
935 logging.info("Disabling keyboard controlled developer mode")
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800936 if not self.client_attr.chrome_ec:
Vic Yang611dd852012-08-02 15:36:31 +0800937 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +0800938 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800939 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800940 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800941
942
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800943 def setup_dev_mode(self, dev_mode):
944 """Setup for development mode.
945
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800946 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800947 tries to do so.
948
949 Args:
950 dev_mode: True if requested in dev mode; False if normal mode.
951 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800952 # Change the default firmware_action for dev mode passing the fw screen.
953 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800954 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
955 else None),
956 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800957 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +0800958 if (not self.client_attr.keyboard_dev and
959 not self.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800960 logging.info('Dev switch is not on. Now switch it on.')
961 self.servo.enable_development_mode()
962 if not self.crossystem_checker({'devsw_boot': '1',
963 'mainfw_type': 'developer'}):
964 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800965 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800966 'userspace_action': None if self.client_attr.keyboard_dev
967 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800968 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800969 'reboot_action': self.enable_keyboard_dev_mode if
970 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800971 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800972 else:
Vic Yange7553162012-06-20 16:20:47 +0800973 if (not self.client_attr.keyboard_dev and
974 not self.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800975 logging.info('Dev switch is not off. Now switch it off.')
976 self.servo.disable_development_mode()
977 if not self.crossystem_checker({'devsw_boot': '0',
978 'mainfw_type': 'normal'}):
979 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800980 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800981 'userspace_action': None if self.client_attr.keyboard_dev
982 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800983 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800984 'reboot_action': self.disable_keyboard_dev_mode if
985 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800986 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800987
988
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800989 def setup_kernel(self, part):
990 """Setup for kernel test.
991
992 It makes sure both kernel A and B bootable and the current boot is
993 the requested kernel part.
994
995 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800996 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800997 """
998 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800999 if self.faft_client.diff_kernel_a_b():
1000 self.copy_kernel_and_rootfs(from_part=part,
1001 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001002 self.reset_and_prioritize_kernel(part)
1003
1004
1005 def reset_and_prioritize_kernel(self, part):
1006 """Make the requested partition highest priority.
1007
1008 This function also reset kerenl A and B to bootable.
1009
1010 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001011 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001012 """
1013 root_dev = self.faft_client.get_root_dev()
1014 # Reset kernel A and B to bootable.
1015 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1016 (self.KERNEL_MAP['a'], root_dev))
1017 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1018 (self.KERNEL_MAP['b'], root_dev))
1019 # Set kernel part highest priority.
1020 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1021 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001022 # Safer to sync and wait until the cgpt status written to the disk.
1023 self.faft_client.run_shell_command('sync')
1024 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001025
1026
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001027 def warm_reboot(self):
1028 """Request a warm reboot.
1029
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001030 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001031 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001032 # Use cold reset if the warm reset is broken.
1033 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001034 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1035 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001036 else:
1037 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001038
1039
1040 def cold_reboot(self):
1041 """Request a cold reboot.
1042
1043 A wrapper for underlying servo cold reset.
1044 """
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001045 if self.client_attr.platform == 'Parrot':
1046 self.servo.set('pwr_button', 'press')
1047 self.servo.set('cold_reset', 'on')
1048 self.servo.set('cold_reset', 'off')
1049 time.sleep(self.POWER_BTN_DELAY)
1050 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +08001051 elif self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001052 # We don't use servo.cold_reset() here because software sync is
1053 # not yet finished, and device may or may not come up after cold
1054 # reset. Pressing power button before firmware comes up solves this.
1055 #
1056 # The correct behavior should be (not work now):
1057 # - If rebooting EC with rec mode on, power on AP and it boots
1058 # into recovery mode.
1059 # - If rebooting EC with rec mode off, power on AP for software
1060 # sync. Then AP checks if lid open or not. If lid open, continue;
1061 # otherwise, shut AP down and need servo for a power button
1062 # press.
1063 self.servo.set('cold_reset', 'on')
1064 self.servo.set('cold_reset', 'off')
1065 time.sleep(self.POWER_BTN_DELAY)
1066 self.servo.power_short_press()
1067 else:
1068 self.servo.cold_reset()
1069
1070
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001071 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001072 """Request the client sync and do a warm reboot.
1073
1074 This is the default reboot action on FAFT.
1075 """
1076 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001077 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001078 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001079
1080
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001081 def sync_and_cold_reboot(self):
1082 """Request the client sync and do a cold reboot.
1083
1084 This reboot action is used to reset EC for recovery mode.
1085 """
1086 self.faft_client.run_shell_command('sync')
1087 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001088 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001089
1090
Vic Yangaeb10392012-08-28 09:25:09 +08001091 def sync_and_ec_reboot(self, args=''):
1092 """Request the client sync and do a EC triggered reboot.
1093
1094 Args:
1095 args: Arguments passed to "ectool reboot_ec". Including:
1096 RO: jump to EC RO firmware.
1097 RW: jump to EC RW firmware.
1098 cold: Cold/hard reboot.
1099 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001100 self.faft_client.run_shell_command('sync')
1101 time.sleep(self.SYNC_DELAY)
Vic Yangaeb10392012-08-28 09:25:09 +08001102 # Since EC reboot happens immediately, delay before actual reboot to
1103 # allow FAFT client returning.
1104 self.faft_client.run_shell_command('(sleep %d; ectool reboot_ec %s)&' %
1105 (self.EC_REBOOT_DELAY, args))
Vic Yangf86728a2012-07-30 10:44:07 +08001106 time.sleep(self.EC_REBOOT_DELAY)
1107 self.check_lid_and_power_on()
1108
1109
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001110 def full_power_off_and_on(self):
1111 """Shutdown the device by pressing power button and power on again."""
1112 # Press power button to trigger Chrome OS normal shutdown process.
1113 self.servo.power_normal_press()
1114 time.sleep(self.FULL_POWER_OFF_DELAY)
1115 # Short press power button to boot DUT again.
1116 self.servo.power_short_press()
1117
1118
Vic Yangf86728a2012-07-30 10:44:07 +08001119 def check_lid_and_power_on(self):
1120 """
1121 On devices with EC software sync, system powers on after EC reboots if
1122 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1123 This method checks lid switch state and presses power button if
1124 necessary.
1125 """
1126 if self.servo.get("lid_open") == "no":
1127 time.sleep(self.SOFTWARE_SYNC_DELAY)
1128 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001129
1130
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001131 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1132 """Modify the kernel header magic in USB stick.
1133
1134 The kernel header magic is the first 8-byte of kernel partition.
1135 We modify it to make it fail on kernel verification check.
1136
1137 Args:
1138 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1139 from_magic: A string of magic which we change it from.
1140 to_magic: A string of magic which we change it to.
1141
1142 Raises:
1143 error.TestError: if failed to change magic.
1144 """
1145 assert len(from_magic) == 8
1146 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001147 # USB image only contains one kernel.
1148 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001149 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1150 current_magic = utils.system_output(read_cmd)
1151 if current_magic == to_magic:
1152 logging.info("The kernel magic is already %s." % current_magic)
1153 return
1154 if current_magic != from_magic:
1155 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1156
1157 logging.info('Modify the kernel magic in USB, from %s to %s.' %
1158 (from_magic, to_magic))
1159 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1160 " 2>/dev/null" % (to_magic, kernel_part))
1161 utils.system(write_cmd)
1162
1163 if utils.system_output(read_cmd) != to_magic:
1164 raise error.TestError("Failed to write new magic.")
1165
1166
1167 def corrupt_usb_kernel(self, usb_dev):
1168 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1169
1170 Args:
1171 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1172 """
1173 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1174 self.CORRUPTED_MAGIC)
1175
1176
1177 def restore_usb_kernel(self, usb_dev):
1178 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1179
1180 Args:
1181 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1182 """
1183 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1184 self.CHROMEOS_MAGIC)
1185
1186
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001187 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001188 """Call the action function with/without arguments.
1189
1190 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001191 action_tuple: A function, or a tuple (function, args, error_msg),
1192 in which, args and error_msg are optional. args is
1193 either a value or a tuple if multiple arguments.
1194 check_status: Check the return value of action function. If not
1195 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001196
1197 Returns:
1198 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001199
1200 Raises:
1201 error.TestError: An error when the action function is not callable.
1202 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001203 """
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001204 action = action_tuple
1205 args = ()
1206 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001207 if isinstance(action_tuple, tuple):
1208 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001209 if len(action_tuple) >= 2:
1210 args = action_tuple[1]
1211 if not isinstance(args, tuple):
1212 args = (args,)
1213 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001214 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001215
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001216 if action is None:
1217 return
1218
1219 if not callable(action):
1220 raise error.TestError('action is not callable!')
1221
1222 info_msg = 'calling %s' % str(action)
1223 if args:
1224 info_msg += ' with args %s' % str(args)
1225 logging.info(info_msg)
1226 ret = action(*args)
1227
1228 if check_status and not ret:
1229 raise error.TestFail('%s: %s returning %s' %
1230 (error_msg, info_msg, str(ret)))
1231 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001232
1233
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001234 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1235 post_power_action=None):
1236 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1237
1238 Args:
1239 shutdown_action: a function which makes DUT shutdown, like pressing
1240 power key.
1241 pre_power_action: a function which is called before next power on.
1242 post_power_action: a function which is called after next power on.
1243
1244 Raises:
1245 error.TestFail: if the shutdown_action() failed to turn DUT off.
1246 """
1247 self._call_action(shutdown_action)
1248 logging.info('Wait to ensure DUT shut down...')
1249 try:
1250 self.wait_for_client()
1251 raise error.TestFail(
1252 'Should shut the device down after calling %s.' %
1253 str(shutdown_action))
1254 except AssertionError:
1255 logging.info(
1256 'DUT is surely shutdown. We are going to power it on again...')
1257
1258 if pre_power_action:
1259 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001260 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001261 if post_power_action:
1262 self._call_action(post_power_action)
1263
1264
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001265 def register_faft_template(self, template):
1266 """Register FAFT template, the default FAFT_STEP of each step.
1267
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001268 Any missing field falls back to the original faft_template.
1269
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001270 Args:
1271 template: A FAFT_STEP dict.
1272 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001273 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001274
1275
1276 def register_faft_sequence(self, sequence):
1277 """Register FAFT sequence.
1278
1279 Args:
1280 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1281 """
1282 self._faft_sequence = sequence
1283
1284
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001285 def run_faft_step(self, step, no_reboot=False):
1286 """Run a single FAFT step.
1287
1288 Any missing field falls back to faft_template. An empty step means
1289 running the default faft_template.
1290
1291 Args:
1292 step: A FAFT_STEP dict.
1293 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001294
1295 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001296 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001297 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001298 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1299 'firmware_action', 'install_deps_after_boot')
1300
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001301 test = {}
1302 test.update(self._faft_template)
1303 test.update(step)
1304
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001305 for key in test:
1306 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001307 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001308
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001309 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001310 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001311
1312 self._call_action(test['userspace_action'])
1313
1314 # Don't run reboot_action and firmware_action if no_reboot is True.
1315 if not no_reboot:
1316 self._call_action(test['reboot_action'])
1317 self.wait_for_client_offline()
1318 self._call_action(test['firmware_action'])
1319
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001320 try:
1321 if 'install_deps_after_boot' in test:
1322 self.wait_for_client(
1323 install_deps=test['install_deps_after_boot'])
1324 else:
1325 self.wait_for_client()
1326 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001327 logging.info('wait_for_client() timed out.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001328 self.reset_client()
1329 raise
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001330
1331
1332 def run_faft_sequence(self):
1333 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001334 sequence = self._faft_sequence
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001335 index = 1
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001336 for step in sequence:
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001337 logging.info('======== Running FAFT sequence step %d ========' %
1338 index)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001339 # Don't reboot in the last step.
1340 self.run_faft_step(step, no_reboot=(step is sequence[-1]))
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001341 index += 1
ctchang38ae4922012-09-03 17:01:16 +08001342
1343
ctchang38ae4922012-09-03 17:01:16 +08001344 def get_current_firmware_sha(self):
1345 """Get current firmware sha of body and vblock.
1346
1347 Returns:
1348 Current firmware sha follows the order (
1349 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1350 """
1351 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1352 self.faft_client.get_firmware_sha('a'),
1353 self.faft_client.get_firmware_sig_sha('b'),
1354 self.faft_client.get_firmware_sha('b'))
1355 return current_firmware_sha
1356
1357
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001358 def is_firmware_changed(self):
1359 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001360
1361 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001362 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001363 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001364 # Device may not be rebooted after test.
1365 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001366
1367 current_sha = self.get_current_firmware_sha()
1368
1369 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001370 return False
ctchang38ae4922012-09-03 17:01:16 +08001371 else:
ctchang38ae4922012-09-03 17:01:16 +08001372 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1373 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1374 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1375 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001376 logging.info("Firmware changed:")
1377 logging.info('VBOOTA is changed: %s' % corrupt_VBOOTA)
1378 logging.info('VBOOTB is changed: %s' % corrupt_VBOOTB)
1379 logging.info('FVMAIN is changed: %s' % corrupt_FVMAIN)
1380 logging.info('FVMAINB is changed: %s' % corrupt_FVMAINB)
1381 return True
ctchang38ae4922012-09-03 17:01:16 +08001382
1383
1384 def backup_firmware(self, suffix='.original'):
1385 """Backup firmware to file, and then send it to host.
1386
1387 Args:
1388 suffix: a string appended to backup file name
1389 """
1390 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001391 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1392 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1393 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001394
1395 self._backup_firmware_sha = self.get_current_firmware_sha()
1396 logging.info('Backup firmware stored in %s with suffix %s' % (
1397 self.resultsdir, suffix))
1398
1399
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001400 def is_firmware_saved(self):
1401 """Check if a firmware saved (called backup_firmware before).
1402
1403 Returns:
1404 True if the firmware is backuped; otherwise False.
1405 """
1406 return self._backup_firmware_sha != ()
1407
1408
ctchang38ae4922012-09-03 17:01:16 +08001409 def restore_firmware(self, suffix='.original'):
1410 """Restore firmware from host in resultsdir.
1411
1412 Args:
1413 suffix: a string appended to backup file name
1414 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001415 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001416 return
1417
1418 # Backup current corrupted firmware.
1419 self.backup_firmware(suffix='.corrupt')
1420
1421 # Restore firmware.
1422 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001423 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1424 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001425
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001426 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001427 self.sync_and_warm_reboot()
1428 self.wait_for_client_offline()
1429 self.wait_for_client()
1430
ctchang38ae4922012-09-03 17:01:16 +08001431 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001432
1433
1434 def setup_firmwareupdate_shellball(self, shellball=None):
1435 """Deside a shellball to use in firmware update test.
1436
1437 Check if there is a given shellball, and it is a shell script. Then,
1438 send it to the remote host. Otherwise, use
1439 /usr/sbin/chromeos-firmwareupdate.
1440
1441 Args:
1442 shellball: path of a shellball or default to None.
1443
1444 Returns:
1445 Path of shellball in remote host.
1446 If use default shellball, reutrn None.
1447 """
1448 updater_path = None
1449 if shellball:
1450 # Determine the firmware file is a shellball or a raw binary.
1451 is_shellball = (utils.system_output("file %s" % shellball).find(
1452 "shell script") != -1)
1453 if is_shellball:
1454 logging.info('Device will update firmware with shellball %s'
1455 % shellball)
1456 temp_dir = self.faft_client.create_temp_dir('shellball_')
1457 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1458 self._client.send_file(shellball, temp_shellball)
1459 updater_path = temp_shellball
1460 else:
1461 raise error.TestFail(
1462 'The given shellball is not a shell script.')
1463 return updater_path