blob: ec7e36c8b6b2f4e5b7717a8e45e871a38521d25d [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 |
187 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB,
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800188 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800189 if self._install_image_path:
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800190 self.install_test_image(self._install_image_path,
191 self._firmware_update)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800192
193
194 def cleanup(self):
195 """Autotest cleanup function."""
196 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800197 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800198 super(FAFTSequence, self).cleanup()
199
200
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800201 def reset_client(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800202 """Reset client, if necessary.
203
204 This method is called when the client is not responsive. It may be
205 caused by the following cases:
206 - network flaky (can be recovered by replugging the Ethernet);
207 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
208 - corrupted firmware;
209 - corrutped OS image.
210 """
211 # DUT works fine, done.
212 if self._ping_test(self._client.ip, timeout=5):
213 return
214
215 # TODO(waihong@chromium.org): Implement replugging the Ethernet in the
216 # first reset item.
217
218 # DUT may halt on a firmware screen. Try cold reboot.
219 logging.info('Try cold reboot...')
220 self.cold_reboot()
221 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800222 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800223 return
224 except AssertionError:
225 pass
226
227 # DUT may be broken by a corrupted firmware. Restore firmware.
228 # We assume the recovery boot still works fine. Since the recovery
229 # code is in RO region and all FAFT tests don't change the RO region
230 # except GBB.
231 if self.is_firmware_saved():
232 self.ensure_client_in_recovery()
233 logging.info('Try restore the original firmware...')
234 if self.is_firmware_changed():
235 try:
236 self.restore_firmware()
237 return
238 except AssertionError:
239 logging.info('Restoring firmware doesn\'t help.')
240
241 # DUT may be broken by a corrupted OS image. Restore OS image.
242 self.ensure_client_in_recovery()
243 logging.info('Try restore the OS image...')
244 self.faft_client.run_shell_command('chromeos-install --yes')
245 self.sync_and_warm_reboot()
246 self.wait_for_client_offline()
247 try:
248 self.wait_for_client(install_deps=True)
249 logging.info('Successfully restore OS image.')
250 return
251 except AssertionError:
252 logging.info('Restoring OS image doesn\'t help.')
253
254
255 def ensure_client_in_recovery(self):
256 """Ensure client in recovery boot; reboot into it if necessary.
257
258 Raises:
259 error.TestError: if failed to boot the USB image.
260 """
261 # DUT works fine and is already in recovery boot, done.
262 if self._ping_test(self._client.ip, timeout=5):
263 if self.crossystem_checker({'mainfw_type': 'recovery'}):
264 return
265
266 logging.info('Try boot into USB image...')
267 self.servo.enable_usb_hub(host=True)
268 self.enable_rec_mode_and_reboot()
269 self.wait_fw_screen_and_plug_usb()
270 try:
271 self.wait_for_client(install_deps=True)
272 except AssertionError:
273 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800274
275
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800276 def assert_test_image_in_usb_disk(self, usb_dev=None):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800277 """Assert an USB disk plugged-in on servo and a test image inside.
278
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800279 Args:
280 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
281 If None, it is detected automatically.
282
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800283 Raises:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800284 error.TestError: if USB disk not detected or not a test image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800285 """
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800286 if usb_dev:
287 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
288 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700289 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800290 usb_dev = self.servo.probe_host_usb_dev()
291 if not usb_dev:
292 raise error.TestError(
293 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800294
295 tmp_dir = tempfile.mkdtemp()
Tom Wai-Hong Tamb0e80852011-12-07 16:15:06 +0800296 utils.system('sudo mount -r -t ext2 %s3 %s' % (usb_dev, tmp_dir))
Tom Wai-Hong Tame77459e2011-11-03 17:19:46 +0800297 code = utils.system(
298 'grep -qE "(Test Build|testimage-channel)" %s/etc/lsb-release' %
299 tmp_dir, ignore_status=True)
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800300 utils.system('sudo umount %s' % tmp_dir)
301 os.removedirs(tmp_dir)
302 if code != 0:
303 raise error.TestError(
304 'The image in the USB disk should be a test image.')
305
306
Simran Basi741b5d42012-05-18 11:27:15 -0700307 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800308 """Install the test image specied by the path onto the USB and DUT disk.
309
310 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500311 recovery mode. Then runs 'chromeos-install' (and possible
312 chromeos-firmwareupdate') to install it to DUT disk.
313
314 Sample command line:
315
316 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
317 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
318 server/site_tests/firmware_XXXX/control
319
320 This test requires an automated recovery to occur while simulating
321 inserting and removing the usb key from the servo. To allow this the
322 following hardware setup is required:
323 1. servo2 board connected via servoflex.
324 2. USB key inserted in the servo2.
325 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
326 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800327
328 Args:
329 image_path: Path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800330 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800331 """
332 build_ver, build_hash = lab_test.VerifyImageAndGetId(cros_dir,
333 image_path)
334 logging.info('Processing build: %s %s' % (build_ver, build_hash))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800335
Mike Truty49153d82012-08-21 22:27:30 -0500336 # Reuse the servo method that uses the servo USB key to install
337 # the test image.
338 self.servo.image_to_servo_usb(image_path)
339
340 # DUT is powered off while imaging servo USB.
341 # Now turn it on.
342 self.servo.power_short_press()
343 self.wait_for_client()
344 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
345
346 install_cmd = 'chromeos-install --yes'
347 if firmware_update:
348 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
349
350 self.register_faft_sequence((
351 { # Step 1, request recovery boot
352 'state_checker': (self.crossystem_checker, {
353 'mainfw_type': ('developer', 'normal'),
354 }),
355 'userspace_action': self.faft_client.request_recovery_boot,
356 'firmware_action': self.wait_fw_screen_and_plug_usb,
357 'install_deps_after_boot': True,
358 },
359 { # Step 2, expected recovery boot
360 'state_checker': (self.crossystem_checker, {
361 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800362 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500363 }),
364 'userspace_action': (self.faft_client.run_shell_command,
365 install_cmd),
366 'reboot_action': self.cold_reboot,
367 'install_deps_after_boot': True,
368 },
369 { # Step 3, expected normal or developer boot (not recovery)
370 'state_checker': (self.crossystem_checker, {
371 'mainfw_type': ('developer', 'normal')
372 }),
373 },
374 ))
375 self.run_faft_sequence()
376 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800377 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800378
379
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800380 def clear_set_gbb_flags(self, clear_mask, set_mask):
381 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800382
383 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800384 clear_mask: A mask of flags to be cleared.
385 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800386 """
387 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800388 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
389
390 if (gbb_flags != new_flags):
391 logging.info('Change the GBB flags from 0x%x to 0x%x.' %
392 (gbb_flags, new_flags))
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800393 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800394 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800395 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800396 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800397 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800398 self.run_faft_step({
399 'firmware_action': self.wait_fw_screen_and_ctrl_d,
400 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800401
402
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800403 def check_ec_capability(self, required_cap=[], suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800404 """Check if current platform has required EC capabilities.
405
406 Args:
407 required_cap: A list containing required EC capabilities. Pass in
408 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800409 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800410
411 Returns:
412 True if requirements are met. Otherwise, False.
413 """
414 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800415 if not suppress_warning:
416 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800417 return False
418
419 for cap in required_cap:
420 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800421 if not suppress_warning:
422 logging.warn('Requires EC capability "%s" to run this '
423 'test.' % cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800424 return False
425
426 return True
427
428
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800429 def _parse_crossystem_output(self, lines):
430 """Parse the crossystem output into a dict.
431
432 Args:
433 lines: The list of crossystem output strings.
434
435 Returns:
436 A dict which contains the crossystem keys/values.
437
438 Raises:
439 error.TestError: If wrong format in crossystem output.
440
441 >>> seq = FAFTSequence()
442 >>> seq._parse_crossystem_output([ \
443 "arch = x86 # Platform architecture", \
444 "cros_debug = 1 # OS should allow debug", \
445 ])
446 {'cros_debug': '1', 'arch': 'x86'}
447 >>> seq._parse_crossystem_output([ \
448 "arch=x86", \
449 ])
450 Traceback (most recent call last):
451 ...
452 TestError: Failed to parse crossystem output: arch=x86
453 >>> seq._parse_crossystem_output([ \
454 "arch = x86 # Platform architecture", \
455 "arch = arm # Platform architecture", \
456 ])
457 Traceback (most recent call last):
458 ...
459 TestError: Duplicated crossystem key: arch
460 """
461 pattern = "^([^ =]*) *= *(.*[^ ]) *# [^#]*$"
462 parsed_list = {}
463 for line in lines:
464 matched = re.match(pattern, line.strip())
465 if not matched:
466 raise error.TestError("Failed to parse crossystem output: %s"
467 % line)
468 (name, value) = (matched.group(1), matched.group(2))
469 if name in parsed_list:
470 raise error.TestError("Duplicated crossystem key: %s" % name)
471 parsed_list[name] = value
472 return parsed_list
473
474
475 def crossystem_checker(self, expected_dict):
476 """Check the crossystem values matched.
477
478 Given an expect_dict which describes the expected crossystem values,
479 this function check the current crossystem values are matched or not.
480
481 Args:
482 expected_dict: A dict which contains the expected values.
483
484 Returns:
485 True if the crossystem value matched; otherwise, False.
486 """
487 lines = self.faft_client.run_shell_command_get_output('crossystem')
488 got_dict = self._parse_crossystem_output(lines)
489 for key in expected_dict:
490 if key not in got_dict:
491 logging.info('Expected key "%s" not in crossystem result' % key)
492 return False
493 if isinstance(expected_dict[key], str):
494 if got_dict[key] != expected_dict[key]:
495 logging.info("Expected '%s' value '%s' but got '%s'" %
496 (key, expected_dict[key], got_dict[key]))
497 return False
498 elif isinstance(expected_dict[key], tuple):
499 # Expected value is a tuple of possible actual values.
500 if got_dict[key] not in expected_dict[key]:
501 logging.info("Expected '%s' values %s but got '%s'" %
502 (key, str(expected_dict[key]), got_dict[key]))
503 return False
504 else:
505 logging.info("The expected_dict is neither a str nor a dict.")
506 return False
507 return True
508
509
Tom Wai-Hong Tam39b93b92012-09-04 16:56:05 +0800510 def vdat_flags_checker(self, mask, value):
511 """Check the flags from VbSharedData matched.
512
513 This function checks the masked flags from VbSharedData using crossystem
514 are matched the given value.
515
516 Args:
517 mask: A bitmask of flags to be matched.
518 value: An expected value.
519
520 Returns:
521 True if the flags matched; otherwise, False.
522 """
523 lines = self.faft_client.run_shell_command_get_output(
524 'crossystem vdat_flags')
525 vdat_flags = int(lines[0], 16)
526 if vdat_flags & mask != value:
527 logging.info("Expected vdat_flags 0x%x mask 0x%x but got 0x%x" %
528 (value, mask, vdat_flags))
529 return False
530 return True
531
532
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800533 def ro_normal_checker(self, expected_fw=None, twostop=False):
534 """Check the current boot uses RO boot.
535
536 Args:
537 expected_fw: A string of expected firmware, 'A', 'B', or
538 None if don't care.
539 twostop: True to expect a TwoStop boot; False to expect a RO boot.
540
541 Returns:
542 True if the currect boot firmware matched and used RO boot;
543 otherwise, False.
544 """
545 crossystem_dict = {'tried_fwb': '0'}
546 if expected_fw:
547 crossystem_dict['mainfw_act'] = expected_fw.upper()
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800548 if self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800549 crossystem_dict['ecfw_act'] = ('RW' if twostop else 'RO')
550
551 return (self.vdat_flags_checker(
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800552 vboot.VDAT_FLAG_LF_USE_RO_NORMAL,
553 0 if twostop else vboot.VDAT_FLAG_LF_USE_RO_NORMAL) and
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800554 self.crossystem_checker(crossystem_dict))
555
556
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800557 def dev_boot_usb_checker(self, dev_boot_usb=True):
558 """Check the current boot is from a developer USB (Ctrl-U trigger).
559
560 Args:
561 dev_boot_usb: True to expect an USB boot;
562 False to expect an internal device boot.
563
564 Returns:
565 True if the currect boot device matched; otherwise, False.
566 """
567 return (self.crossystem_checker({'mainfw_type': 'developer'})
568 and self.faft_client.is_removable_device_boot() == dev_boot_usb)
569
570
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800571 def root_part_checker(self, expected_part):
572 """Check the partition number of the root device matched.
573
574 Args:
575 expected_part: A string containing the number of the expected root
576 partition.
577
578 Returns:
579 True if the currect root partition number matched; otherwise, False.
580 """
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +0800581 part = self.faft_client.get_root_part()[-1]
582 if self.ROOTFS_MAP[expected_part] != part:
583 logging.info("Expected root part %s but got %s" %
584 (self.ROOTFS_MAP[expected_part], part))
585 return False
586 return True
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800587
588
Vic Yang59cac9c2012-05-21 15:28:42 +0800589 def ec_act_copy_checker(self, expected_copy):
590 """Check the EC running firmware copy matches.
591
592 Args:
593 expected_copy: A string containing 'RO', 'A', or 'B' indicating
594 the expected copy of EC running firmware.
595
596 Returns:
597 True if the current EC running copy matches; otherwise, False.
598 """
599 lines = self.faft_client.run_shell_command_get_output('ectool version')
600 pattern = re.compile("Firmware copy: (.*)")
601 for line in lines:
602 matched = pattern.match(line)
603 if matched and matched.group(1) == expected_copy:
604 return True
605 return False
606
607
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800608 def check_root_part_on_non_recovery(self, part):
609 """Check the partition number of root device and on normal/dev boot.
610
611 Returns:
612 True if the root device matched and on normal/dev boot;
613 otherwise, False.
614 """
615 return self.root_part_checker(part) and \
616 self.crossystem_checker({
617 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800618 })
619
620
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800621 def _join_part(self, dev, part):
622 """Return a concatenated string of device and partition number.
623
624 Args:
625 dev: A string of device, e.g.'/dev/sda'.
626 part: A string of partition number, e.g.'3'.
627
628 Returns:
629 A concatenated string of device and partition number, e.g.'/dev/sda3'.
630
631 >>> seq = FAFTSequence()
632 >>> seq._join_part('/dev/sda', '3')
633 '/dev/sda3'
634 >>> seq._join_part('/dev/mmcblk0', '2')
635 '/dev/mmcblk0p2'
636 """
637 if 'mmcblk' in dev:
638 return dev + 'p' + part
639 else:
640 return dev + part
641
642
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800643 def copy_kernel_and_rootfs(self, from_part, to_part):
644 """Copy kernel and rootfs from from_part to to_part.
645
646 Args:
647 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800648 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800649 """
650 root_dev = self.faft_client.get_root_dev()
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800651 logging.info('Copying kernel from %s to %s. Please wait...' %
652 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800653 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800654 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
655 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
656 logging.info('Copying rootfs from %s to %s. Please wait...' %
657 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800658 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800659 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
660 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800661
662
663 def ensure_kernel_boot(self, part):
664 """Ensure the request kernel boot.
665
666 If not, it duplicates the current kernel to the requested kernel
667 and sets the requested higher priority to ensure it boot.
668
669 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800670 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800671 """
672 if not self.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800673 if self.faft_client.diff_kernel_a_b():
674 self.copy_kernel_and_rootfs(
675 from_part=self.OTHER_KERNEL_MAP[part],
676 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800677 self.run_faft_step({
678 'userspace_action': (self.reset_and_prioritize_kernel, part),
679 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800680
681
Vic Yang416f2032012-08-28 10:18:03 +0800682 def set_hardware_write_protect(self, enabled):
Vic Yang2cabf812012-08-28 02:39:04 +0800683 """Set hardware write protect pin.
684
685 Args:
686 enable: True if asserting write protect pin. Otherwise, False.
687 """
688 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
689 self.servo.set('fw_wp_en', 'on')
Vic Yang416f2032012-08-28 10:18:03 +0800690 self.servo.set('fw_wp', 'on' if enabled else 'off')
691
692
693 def set_EC_write_protect_and_reboot(self, enabled):
694 """Set EC write protect status and reboot to take effect.
695
696 EC write protect is only activated if both hardware write protect pin
697 is asserted and software write protect flag is set. Also, a reboot is
698 required for write protect to take effect.
699
700 Since the software write protect flag cannot be unset if hardware write
701 protect pin is asserted, we need to deasserted the pin first if we are
702 deactivating write protect. Similarly, a reboot is required before we
703 can modify the software flag.
704
705 This method asserts/deasserts hardware write protect pin first, and
706 set corresponding EC software write protect flag.
707
708 Args:
709 enable: True if activating EC write protect. Otherwise, False.
710 """
711 self.set_hardware_write_protect(enabled)
712 if enabled:
713 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800714 self.ec.send_command("flashwp enable")
Vic Yang416f2032012-08-28 10:18:03 +0800715 self.sync_and_ec_reboot()
716 else:
717 # Reboot after deasserting hardware write protect pin to deactivate
718 # write protect. And then remove software write protect flag.
719 self.sync_and_ec_reboot()
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800720 self.ec.send_command("flashwp disable")
Vic Yang2cabf812012-08-28 02:39:04 +0800721
722
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800723 def send_ctrl_d_to_dut(self):
724 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800725 if self._customized_key_commands['ctrl_d']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800726 logging.info('running the customized Ctrl-D key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800727 os.system(self._customized_key_commands['ctrl_d'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800728 else:
729 self.servo.ctrl_d()
730
731
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800732 def send_ctrl_u_to_dut(self):
733 """Send Ctrl-U key to DUT.
734
735 Raises:
736 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
737 on a no-build-in-keyboard device.
738 """
739 if self._customized_key_commands['ctrl_u']:
740 logging.info('running the customized Ctrl-U key command')
741 os.system(self._customized_key_commands['ctrl_u'])
742 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
743 self.ec.key_down('<ctrl_l>')
744 self.ec.key_down('u')
745 self.ec.key_up('u')
746 self.ec.key_up('<ctrl_l>')
747 elif self.client_attr.has_keyboard:
748 raise error.TestError(
749 "Can't send Ctrl-U to DUT without using Chrome EC.")
750 else:
751 raise error.TestError(
752 "Should specify the ctrl_u_cmd argument.")
753
754
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800755 def send_enter_to_dut(self):
756 """Send Enter key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800757 if self._customized_key_commands['enter']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800758 logging.info('running the customized Enter key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800759 os.system(self._customized_key_commands['enter'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800760 else:
761 self.servo.enter_key()
762
763
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800764 def send_space_to_dut(self):
765 """Send Space key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800766 if self._customized_key_commands['space']:
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800767 logging.info('running the customized Space key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800768 os.system(self._customized_key_commands['space'])
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800769 else:
770 # Send the alternative key combinaton of space key to servo.
771 self.servo.ctrl_refresh_key()
772
773
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800774 def wait_fw_screen_and_ctrl_d(self):
775 """Wait for firmware warning screen and press Ctrl-D."""
776 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800777 self.send_ctrl_d_to_dut()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800778
779
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800780 def wait_fw_screen_and_ctrl_u(self):
781 """Wait for firmware warning screen and press Ctrl-U."""
782 time.sleep(self.FIRMWARE_SCREEN_DELAY)
783 self.send_ctrl_u_to_dut()
784
785
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800786 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
787 """Wait for firmware warning screen and trigger recovery boot."""
788 time.sleep(self.FIRMWARE_SCREEN_DELAY)
789 self.send_enter_to_dut()
790
791 # For Alex/ZGB, there is a dev warning screen in text mode.
792 # Skip it by pressing Ctrl-D.
793 if need_dev_transition:
794 time.sleep(self.TEXT_SCREEN_DELAY)
795 self.send_ctrl_d_to_dut()
796
797
Mike Truty49153d82012-08-21 22:27:30 -0500798 def wait_fw_screen_and_unplug_usb(self):
799 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +0800800 time.sleep(self.USB_LOAD_DELAY)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800801 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
802 time.sleep(self.USB_PLUG_DELAY)
Mike Truty49153d82012-08-21 22:27:30 -0500803
804
805 def wait_fw_screen_and_plug_usb(self):
806 """Wait for firmware warning screen and then unplug and plug the USB."""
807 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800808 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
809
810
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800811 def wait_fw_screen_and_press_power(self):
812 """Wait for firmware warning screen and press power button."""
813 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800814 # While the firmware screen, the power button probing loop sleeps
815 # 0.25 second on every scan. Use the normal delay (1.2 second) for
816 # power press.
817 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800818
819
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800820 def wait_longer_fw_screen_and_press_power(self):
821 """Wait for firmware screen without timeout and press power button."""
822 time.sleep(self.DEV_SCREEN_TIMEOUT)
823 self.wait_fw_screen_and_press_power()
824
825
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800826 def wait_fw_screen_and_close_lid(self):
827 """Wait for firmware warning screen and close lid."""
828 time.sleep(self.FIRMWARE_SCREEN_DELAY)
829 self.servo.lid_close()
830
831
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800832 def wait_longer_fw_screen_and_close_lid(self):
833 """Wait for firmware screen without timeout and close lid."""
834 time.sleep(self.FIRMWARE_SCREEN_DELAY)
835 self.wait_fw_screen_and_close_lid()
836
837
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800838 def setup_tried_fwb(self, tried_fwb):
839 """Setup for fw B tried state.
840
841 It makes sure the system in the requested fw B tried state. If not, it
842 tries to do so.
843
844 Args:
845 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
846 """
847 if tried_fwb:
848 if not self.crossystem_checker({'tried_fwb': '1'}):
849 logging.info(
850 'Firmware is not booted with tried_fwb. Reboot into it.')
851 self.run_faft_step({
852 'userspace_action': self.faft_client.set_try_fw_b,
853 })
854 else:
855 if not self.crossystem_checker({'tried_fwb': '0'}):
856 logging.info(
857 'Firmware is booted with tried_fwb. Reboot to clear.')
858 self.run_faft_step({})
859
860
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800861 def enable_rec_mode_and_reboot(self):
862 """Switch to rec mode and reboot.
863
864 This method emulates the behavior of the old physical recovery switch,
865 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
866 recovery mode, i.e. just press Power + Esc + Refresh.
867 """
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800868 if self._customized_key_commands['rec_reboot']:
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800869 logging.info('running the customized rec reboot command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800870 os.system(self._customized_key_commands['rec_reboot'])
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800871 elif self.client_attr.chrome_ec:
Vic Yang81273092012-08-21 15:57:09 +0800872 # Cold reset to clear EC_IN_RW signal
Vic Yanga7250662012-08-31 04:00:08 +0800873 self.servo.set('cold_reset', 'on')
874 time.sleep(self.COLD_RESET_DELAY)
875 self.servo.set('cold_reset', 'off')
876 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800877 self.ec.send_command("reboot ap-off")
Vic Yang611dd852012-08-02 15:36:31 +0800878 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800879 self.ec.send_command("hostevent set 0x4000")
Vic Yang611dd852012-08-02 15:36:31 +0800880 self.servo.power_short_press()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800881 else:
882 self.servo.enable_recovery_mode()
883 self.cold_reboot()
884 time.sleep(self.EC_REBOOT_DELAY)
885 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800886
887
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800888 def enable_dev_mode_and_reboot(self):
889 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800890 if self.client_attr.keyboard_dev:
891 self.enable_keyboard_dev_mode()
892 else:
893 self.servo.enable_development_mode()
894 self.faft_client.run_shell_command(
895 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800896
897
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800898 def enable_normal_mode_and_reboot(self):
899 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800900 if self.client_attr.keyboard_dev:
901 self.disable_keyboard_dev_mode()
902 else:
903 self.servo.disable_development_mode()
904 self.faft_client.run_shell_command(
905 'chromeos-firmwareupdate --mode tonormal && reboot')
906
907
908 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
909 """Wait for firmware screen and then switch into or out of dev mode.
910
911 Args:
912 dev: True if switching into dev mode. Otherwise, False.
913 """
914 time.sleep(self.FIRMWARE_SCREEN_DELAY)
915 if dev:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800916 self.send_ctrl_d_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800917 else:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800918 self.send_enter_to_dut()
Tom Wai-Hong Tam1408f172012-07-31 15:06:21 +0800919 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800920 self.send_enter_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800921
922
923 def enable_keyboard_dev_mode(self):
924 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +0800925 # Plug out USB disk for preventing recovery boot without warning
926 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +0800927 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800928 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800929 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800930 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +0800931
932
933 def disable_keyboard_dev_mode(self):
934 logging.info("Disabling keyboard controlled developer mode")
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800935 if not self.client_attr.chrome_ec:
Vic Yang611dd852012-08-02 15:36:31 +0800936 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +0800937 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800938 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800939 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800940
941
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800942 def setup_dev_mode(self, dev_mode):
943 """Setup for development mode.
944
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800945 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800946 tries to do so.
947
948 Args:
949 dev_mode: True if requested in dev mode; False if normal mode.
950 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800951 # Change the default firmware_action for dev mode passing the fw screen.
952 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800953 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
954 else None),
955 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800956 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +0800957 if (not self.client_attr.keyboard_dev and
958 not self.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800959 logging.info('Dev switch is not on. Now switch it on.')
960 self.servo.enable_development_mode()
961 if not self.crossystem_checker({'devsw_boot': '1',
962 'mainfw_type': 'developer'}):
963 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800964 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800965 'userspace_action': None if self.client_attr.keyboard_dev
966 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800967 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800968 'reboot_action': self.enable_keyboard_dev_mode if
969 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800970 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800971 else:
Vic Yange7553162012-06-20 16:20:47 +0800972 if (not self.client_attr.keyboard_dev and
973 not self.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800974 logging.info('Dev switch is not off. Now switch it off.')
975 self.servo.disable_development_mode()
976 if not self.crossystem_checker({'devsw_boot': '0',
977 'mainfw_type': 'normal'}):
978 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800979 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800980 'userspace_action': None if self.client_attr.keyboard_dev
981 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800982 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800983 'reboot_action': self.disable_keyboard_dev_mode if
984 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800985 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800986
987
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800988 def setup_kernel(self, part):
989 """Setup for kernel test.
990
991 It makes sure both kernel A and B bootable and the current boot is
992 the requested kernel part.
993
994 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800995 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800996 """
997 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800998 if self.faft_client.diff_kernel_a_b():
999 self.copy_kernel_and_rootfs(from_part=part,
1000 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001001 self.reset_and_prioritize_kernel(part)
1002
1003
1004 def reset_and_prioritize_kernel(self, part):
1005 """Make the requested partition highest priority.
1006
1007 This function also reset kerenl A and B to bootable.
1008
1009 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001010 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001011 """
1012 root_dev = self.faft_client.get_root_dev()
1013 # Reset kernel A and B to bootable.
1014 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1015 (self.KERNEL_MAP['a'], root_dev))
1016 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1017 (self.KERNEL_MAP['b'], root_dev))
1018 # Set kernel part highest priority.
1019 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1020 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001021 # Safer to sync and wait until the cgpt status written to the disk.
1022 self.faft_client.run_shell_command('sync')
1023 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001024
1025
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001026 def warm_reboot(self):
1027 """Request a warm reboot.
1028
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001029 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001030 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001031 # Use cold reset if the warm reset is broken.
1032 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001033 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1034 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001035 else:
1036 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001037
1038
1039 def cold_reboot(self):
1040 """Request a cold reboot.
1041
1042 A wrapper for underlying servo cold reset.
1043 """
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001044 if self.client_attr.platform == 'Parrot':
1045 self.servo.set('pwr_button', 'press')
1046 self.servo.set('cold_reset', 'on')
1047 self.servo.set('cold_reset', 'off')
1048 time.sleep(self.POWER_BTN_DELAY)
1049 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +08001050 elif self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001051 # We don't use servo.cold_reset() here because software sync is
1052 # not yet finished, and device may or may not come up after cold
1053 # reset. Pressing power button before firmware comes up solves this.
1054 #
1055 # The correct behavior should be (not work now):
1056 # - If rebooting EC with rec mode on, power on AP and it boots
1057 # into recovery mode.
1058 # - If rebooting EC with rec mode off, power on AP for software
1059 # sync. Then AP checks if lid open or not. If lid open, continue;
1060 # otherwise, shut AP down and need servo for a power button
1061 # press.
1062 self.servo.set('cold_reset', 'on')
1063 self.servo.set('cold_reset', 'off')
1064 time.sleep(self.POWER_BTN_DELAY)
1065 self.servo.power_short_press()
1066 else:
1067 self.servo.cold_reset()
1068
1069
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001070 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001071 """Request the client sync and do a warm reboot.
1072
1073 This is the default reboot action on FAFT.
1074 """
1075 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001076 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001077 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001078
1079
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001080 def sync_and_cold_reboot(self):
1081 """Request the client sync and do a cold reboot.
1082
1083 This reboot action is used to reset EC for recovery mode.
1084 """
1085 self.faft_client.run_shell_command('sync')
1086 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001087 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001088
1089
Vic Yangaeb10392012-08-28 09:25:09 +08001090 def sync_and_ec_reboot(self, args=''):
1091 """Request the client sync and do a EC triggered reboot.
1092
1093 Args:
1094 args: Arguments passed to "ectool reboot_ec". Including:
1095 RO: jump to EC RO firmware.
1096 RW: jump to EC RW firmware.
1097 cold: Cold/hard reboot.
1098 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001099 self.faft_client.run_shell_command('sync')
1100 time.sleep(self.SYNC_DELAY)
Vic Yangaeb10392012-08-28 09:25:09 +08001101 # Since EC reboot happens immediately, delay before actual reboot to
1102 # allow FAFT client returning.
1103 self.faft_client.run_shell_command('(sleep %d; ectool reboot_ec %s)&' %
1104 (self.EC_REBOOT_DELAY, args))
Vic Yangf86728a2012-07-30 10:44:07 +08001105 time.sleep(self.EC_REBOOT_DELAY)
1106 self.check_lid_and_power_on()
1107
1108
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001109 def full_power_off_and_on(self):
1110 """Shutdown the device by pressing power button and power on again."""
1111 # Press power button to trigger Chrome OS normal shutdown process.
1112 self.servo.power_normal_press()
1113 time.sleep(self.FULL_POWER_OFF_DELAY)
1114 # Short press power button to boot DUT again.
1115 self.servo.power_short_press()
1116
1117
Vic Yangf86728a2012-07-30 10:44:07 +08001118 def check_lid_and_power_on(self):
1119 """
1120 On devices with EC software sync, system powers on after EC reboots if
1121 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1122 This method checks lid switch state and presses power button if
1123 necessary.
1124 """
1125 if self.servo.get("lid_open") == "no":
1126 time.sleep(self.SOFTWARE_SYNC_DELAY)
1127 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001128
1129
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001130 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1131 """Modify the kernel header magic in USB stick.
1132
1133 The kernel header magic is the first 8-byte of kernel partition.
1134 We modify it to make it fail on kernel verification check.
1135
1136 Args:
1137 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1138 from_magic: A string of magic which we change it from.
1139 to_magic: A string of magic which we change it to.
1140
1141 Raises:
1142 error.TestError: if failed to change magic.
1143 """
1144 assert len(from_magic) == 8
1145 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001146 # USB image only contains one kernel.
1147 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001148 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1149 current_magic = utils.system_output(read_cmd)
1150 if current_magic == to_magic:
1151 logging.info("The kernel magic is already %s." % current_magic)
1152 return
1153 if current_magic != from_magic:
1154 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1155
1156 logging.info('Modify the kernel magic in USB, from %s to %s.' %
1157 (from_magic, to_magic))
1158 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1159 " 2>/dev/null" % (to_magic, kernel_part))
1160 utils.system(write_cmd)
1161
1162 if utils.system_output(read_cmd) != to_magic:
1163 raise error.TestError("Failed to write new magic.")
1164
1165
1166 def corrupt_usb_kernel(self, usb_dev):
1167 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1168
1169 Args:
1170 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1171 """
1172 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1173 self.CORRUPTED_MAGIC)
1174
1175
1176 def restore_usb_kernel(self, usb_dev):
1177 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1178
1179 Args:
1180 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1181 """
1182 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1183 self.CHROMEOS_MAGIC)
1184
1185
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001186 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001187 """Call the action function with/without arguments.
1188
1189 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001190 action_tuple: A function, or a tuple (function, args, error_msg),
1191 in which, args and error_msg are optional. args is
1192 either a value or a tuple if multiple arguments.
1193 check_status: Check the return value of action function. If not
1194 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001195
1196 Returns:
1197 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001198
1199 Raises:
1200 error.TestError: An error when the action function is not callable.
1201 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001202 """
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001203 action = action_tuple
1204 args = ()
1205 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001206 if isinstance(action_tuple, tuple):
1207 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001208 if len(action_tuple) >= 2:
1209 args = action_tuple[1]
1210 if not isinstance(args, tuple):
1211 args = (args,)
1212 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001213 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001214
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001215 if action is None:
1216 return
1217
1218 if not callable(action):
1219 raise error.TestError('action is not callable!')
1220
1221 info_msg = 'calling %s' % str(action)
1222 if args:
1223 info_msg += ' with args %s' % str(args)
1224 logging.info(info_msg)
1225 ret = action(*args)
1226
1227 if check_status and not ret:
1228 raise error.TestFail('%s: %s returning %s' %
1229 (error_msg, info_msg, str(ret)))
1230 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001231
1232
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001233 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1234 post_power_action=None):
1235 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1236
1237 Args:
1238 shutdown_action: a function which makes DUT shutdown, like pressing
1239 power key.
1240 pre_power_action: a function which is called before next power on.
1241 post_power_action: a function which is called after next power on.
1242
1243 Raises:
1244 error.TestFail: if the shutdown_action() failed to turn DUT off.
1245 """
1246 self._call_action(shutdown_action)
1247 logging.info('Wait to ensure DUT shut down...')
1248 try:
1249 self.wait_for_client()
1250 raise error.TestFail(
1251 'Should shut the device down after calling %s.' %
1252 str(shutdown_action))
1253 except AssertionError:
1254 logging.info(
1255 'DUT is surely shutdown. We are going to power it on again...')
1256
1257 if pre_power_action:
1258 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001259 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001260 if post_power_action:
1261 self._call_action(post_power_action)
1262
1263
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001264 def register_faft_template(self, template):
1265 """Register FAFT template, the default FAFT_STEP of each step.
1266
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001267 Any missing field falls back to the original faft_template.
1268
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001269 Args:
1270 template: A FAFT_STEP dict.
1271 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001272 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001273
1274
1275 def register_faft_sequence(self, sequence):
1276 """Register FAFT sequence.
1277
1278 Args:
1279 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1280 """
1281 self._faft_sequence = sequence
1282
1283
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001284 def run_faft_step(self, step, no_reboot=False):
1285 """Run a single FAFT step.
1286
1287 Any missing field falls back to faft_template. An empty step means
1288 running the default faft_template.
1289
1290 Args:
1291 step: A FAFT_STEP dict.
1292 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001293
1294 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001295 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001296 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001297 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1298 'firmware_action', 'install_deps_after_boot')
1299
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001300 test = {}
1301 test.update(self._faft_template)
1302 test.update(step)
1303
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001304 for key in test:
1305 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001306 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001307
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001308 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001309 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001310
1311 self._call_action(test['userspace_action'])
1312
1313 # Don't run reboot_action and firmware_action if no_reboot is True.
1314 if not no_reboot:
1315 self._call_action(test['reboot_action'])
1316 self.wait_for_client_offline()
1317 self._call_action(test['firmware_action'])
1318
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001319 try:
1320 if 'install_deps_after_boot' in test:
1321 self.wait_for_client(
1322 install_deps=test['install_deps_after_boot'])
1323 else:
1324 self.wait_for_client()
1325 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001326 logging.info('wait_for_client() timed out.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001327 self.reset_client()
1328 raise
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001329
1330
1331 def run_faft_sequence(self):
1332 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001333 sequence = self._faft_sequence
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001334 index = 1
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001335 for step in sequence:
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001336 logging.info('======== Running FAFT sequence step %d ========' %
1337 index)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001338 # Don't reboot in the last step.
1339 self.run_faft_step(step, no_reboot=(step is sequence[-1]))
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001340 index += 1
ctchang38ae4922012-09-03 17:01:16 +08001341
1342
ctchang38ae4922012-09-03 17:01:16 +08001343 def get_current_firmware_sha(self):
1344 """Get current firmware sha of body and vblock.
1345
1346 Returns:
1347 Current firmware sha follows the order (
1348 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1349 """
1350 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1351 self.faft_client.get_firmware_sha('a'),
1352 self.faft_client.get_firmware_sig_sha('b'),
1353 self.faft_client.get_firmware_sha('b'))
1354 return current_firmware_sha
1355
1356
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001357 def is_firmware_changed(self):
1358 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001359
1360 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001361 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001362 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001363 # Device may not be rebooted after test.
1364 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001365
1366 current_sha = self.get_current_firmware_sha()
1367
1368 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001369 return False
ctchang38ae4922012-09-03 17:01:16 +08001370 else:
ctchang38ae4922012-09-03 17:01:16 +08001371 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1372 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1373 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1374 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001375 logging.info("Firmware changed:")
1376 logging.info('VBOOTA is changed: %s' % corrupt_VBOOTA)
1377 logging.info('VBOOTB is changed: %s' % corrupt_VBOOTB)
1378 logging.info('FVMAIN is changed: %s' % corrupt_FVMAIN)
1379 logging.info('FVMAINB is changed: %s' % corrupt_FVMAINB)
1380 return True
ctchang38ae4922012-09-03 17:01:16 +08001381
1382
1383 def backup_firmware(self, suffix='.original'):
1384 """Backup firmware to file, and then send it to host.
1385
1386 Args:
1387 suffix: a string appended to backup file name
1388 """
1389 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001390 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1391 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1392 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001393
1394 self._backup_firmware_sha = self.get_current_firmware_sha()
1395 logging.info('Backup firmware stored in %s with suffix %s' % (
1396 self.resultsdir, suffix))
1397
1398
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001399 def is_firmware_saved(self):
1400 """Check if a firmware saved (called backup_firmware before).
1401
1402 Returns:
1403 True if the firmware is backuped; otherwise False.
1404 """
1405 return self._backup_firmware_sha != ()
1406
1407
ctchang38ae4922012-09-03 17:01:16 +08001408 def restore_firmware(self, suffix='.original'):
1409 """Restore firmware from host in resultsdir.
1410
1411 Args:
1412 suffix: a string appended to backup file name
1413 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001414 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001415 return
1416
1417 # Backup current corrupted firmware.
1418 self.backup_firmware(suffix='.corrupt')
1419
1420 # Restore firmware.
1421 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001422 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1423 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001424
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001425 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001426 self.sync_and_warm_reboot()
1427 self.wait_for_client_offline()
1428 self.wait_for_client()
1429
ctchang38ae4922012-09-03 17:01:16 +08001430 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001431
1432
1433 def setup_firmwareupdate_shellball(self, shellball=None):
1434 """Deside a shellball to use in firmware update test.
1435
1436 Check if there is a given shellball, and it is a shell script. Then,
1437 send it to the remote host. Otherwise, use
1438 /usr/sbin/chromeos-firmwareupdate.
1439
1440 Args:
1441 shellball: path of a shellball or default to None.
1442
1443 Returns:
1444 Path of shellball in remote host.
1445 If use default shellball, reutrn None.
1446 """
1447 updater_path = None
1448 if shellball:
1449 # Determine the firmware file is a shellball or a raw binary.
1450 is_shellball = (utils.system_output("file %s" % shellball).find(
1451 "shell script") != -1)
1452 if is_shellball:
1453 logging.info('Device will update firmware with shellball %s'
1454 % shellball)
1455 temp_dir = self.faft_client.create_temp_dir('shellball_')
1456 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1457 self._client.send_file(shellball, temp_shellball)
1458 updater_path = temp_shellball
1459 else:
1460 raise error.TestFail(
1461 'The given shellball is not a shell script.')
1462 return updater_path