blob: e225d51e91b368e86e3979a8c29c6fb3467f4086 [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 Tama79574c2012-02-07 09:29:03 +080090 # Delay of loading the USB kernel.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080091 USB_LOAD_DELAY = 10
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080092 # Delay between USB plug-out and plug-in.
Tom Wai-Hong Tam9ca742a2011-12-05 15:48:57 +080093 USB_PLUG_DELAY = 10
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +080094 # Delay after running the 'sync' command.
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +080095 SYNC_DELAY = 5
Vic Yang59cac9c2012-05-21 15:28:42 +080096 # Delay for waiting client to return before EC reboot
97 EC_REBOOT_DELAY = 1
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +080098 # Delay for waiting client to full power off
99 FULL_POWER_OFF_DELAY = 30
Vic Yang59cac9c2012-05-21 15:28:42 +0800100 # Delay between EC reboot and pressing power button
101 POWER_BTN_DELAY = 0.5
Vic Yangf86728a2012-07-30 10:44:07 +0800102 # Delay of EC software sync hash calculating time
103 SOFTWARE_SYNC_DELAY = 6
Vic Yanga7250662012-08-31 04:00:08 +0800104 # Delay between EC boot and ChromeEC console functional
105 EC_BOOT_DELAY = 0.5
106 # Duration of holding cold_reset to reset device
107 COLD_RESET_DELAY = 0.1
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800108
Tom Wai-Hong Tam51ef2e12012-07-27 15:04:12 +0800109 # The developer screen timeouts fit our spec.
110 DEV_SCREEN_TIMEOUT = 30
111
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800112 CHROMEOS_MAGIC = "CHROMEOS"
113 CORRUPTED_MAGIC = "CORRUPTD"
114
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800115 _faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800116 _faft_sequence = ()
117
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800118 _customized_key_commands = {
119 'ctrl_d': None,
120 'ctrl_u': None,
121 'enter': None,
122 'rec_reboot': None,
123 'space': None,
124 }
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800125 _install_image_path = None
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800126 _firmware_update = False
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800127
ctchang38ae4922012-09-03 17:01:16 +0800128 _backup_firmware_sha = ()
129
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800130
131 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
132 # Parse arguments from command line
133 args = {}
134 for arg in cmdline_args:
135 match = re.search("^(\w+)=(.+)", arg)
136 if match:
137 args[match.group(1)] = match.group(2)
138
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800139 # Keep the arguments which will be used later.
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800140 for key in self._customized_key_commands:
141 key_cmd = key + '_cmd'
142 if key_cmd in args:
143 self._customized_key_commands[key] = args[key_cmd]
144 logging.info('Customized %s key command: %s' %
145 (key, args[key_cmd]))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800146 if 'image' in args:
147 self._install_image_path = args['image']
148 logging.info('Install Chrome OS test image path: %s' %
149 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800150 if 'firmware_update' in args and args['firmware_update'].lower() \
151 not in ('0', 'false', 'no'):
152 if self._install_image_path:
153 self._firmware_update = True
154 logging.info('Also update firmware after installing.')
155 else:
156 logging.warning('Firmware update will not not performed '
157 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800158
159 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
160 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800161 if use_faft:
162 self.client_attr = FAFTClientAttribute(
163 self.faft_client.get_platform_name())
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800164
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800165 if self.client_attr.chrome_ec:
166 self.ec = ChromeEC(self.servo)
167
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700168 # Setting up key matrix mapping
169 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
170
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800171
172 def setup(self):
173 """Autotest setup function."""
174 super(FAFTSequence, self).setup()
175 if not self._remote_infos['faft']['used']:
176 raise error.TestError('The use_faft flag should be enabled.')
177 self.register_faft_template({
178 'state_checker': (None),
179 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800180 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800181 'firmware_action': (None)
182 })
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800183 self.clear_set_gbb_flags(vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
184 vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY,
185 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800186 if self._install_image_path:
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800187 self.install_test_image(self._install_image_path,
188 self._firmware_update)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800189
190
191 def cleanup(self):
192 """Autotest cleanup function."""
193 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800194 self._faft_template = {}
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800195 super(FAFTSequence, self).cleanup()
196
197
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800198 def reset_client(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800199 """Reset client, if necessary.
200
201 This method is called when the client is not responsive. It may be
202 caused by the following cases:
203 - network flaky (can be recovered by replugging the Ethernet);
204 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
205 - corrupted firmware;
206 - corrutped OS image.
207 """
208 # DUT works fine, done.
209 if self._ping_test(self._client.ip, timeout=5):
210 return
211
212 # TODO(waihong@chromium.org): Implement replugging the Ethernet in the
213 # first reset item.
214
215 # DUT may halt on a firmware screen. Try cold reboot.
216 logging.info('Try cold reboot...')
217 self.cold_reboot()
218 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800219 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800220 return
221 except AssertionError:
222 pass
223
224 # DUT may be broken by a corrupted firmware. Restore firmware.
225 # We assume the recovery boot still works fine. Since the recovery
226 # code is in RO region and all FAFT tests don't change the RO region
227 # except GBB.
228 if self.is_firmware_saved():
229 self.ensure_client_in_recovery()
230 logging.info('Try restore the original firmware...')
231 if self.is_firmware_changed():
232 try:
233 self.restore_firmware()
234 return
235 except AssertionError:
236 logging.info('Restoring firmware doesn\'t help.')
237
238 # DUT may be broken by a corrupted OS image. Restore OS image.
239 self.ensure_client_in_recovery()
240 logging.info('Try restore the OS image...')
241 self.faft_client.run_shell_command('chromeos-install --yes')
242 self.sync_and_warm_reboot()
243 self.wait_for_client_offline()
244 try:
245 self.wait_for_client(install_deps=True)
246 logging.info('Successfully restore OS image.')
247 return
248 except AssertionError:
249 logging.info('Restoring OS image doesn\'t help.')
250
251
252 def ensure_client_in_recovery(self):
253 """Ensure client in recovery boot; reboot into it if necessary.
254
255 Raises:
256 error.TestError: if failed to boot the USB image.
257 """
258 # DUT works fine and is already in recovery boot, done.
259 if self._ping_test(self._client.ip, timeout=5):
260 if self.crossystem_checker({'mainfw_type': 'recovery'}):
261 return
262
263 logging.info('Try boot into USB image...')
264 self.servo.enable_usb_hub(host=True)
265 self.enable_rec_mode_and_reboot()
266 self.wait_fw_screen_and_plug_usb()
267 try:
268 self.wait_for_client(install_deps=True)
269 except AssertionError:
270 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800271
272
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800273 def assert_test_image_in_usb_disk(self, usb_dev=None):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800274 """Assert an USB disk plugged-in on servo and a test image inside.
275
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800276 Args:
277 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
278 If None, it is detected automatically.
279
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800280 Raises:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800281 error.TestError: if USB disk not detected or not a test image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800282 """
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800283 if usb_dev:
284 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
285 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700286 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800287 usb_dev = self.servo.probe_host_usb_dev()
288 if not usb_dev:
289 raise error.TestError(
290 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800291
292 tmp_dir = tempfile.mkdtemp()
Tom Wai-Hong Tamb0e80852011-12-07 16:15:06 +0800293 utils.system('sudo mount -r -t ext2 %s3 %s' % (usb_dev, tmp_dir))
Tom Wai-Hong Tame77459e2011-11-03 17:19:46 +0800294 code = utils.system(
295 'grep -qE "(Test Build|testimage-channel)" %s/etc/lsb-release' %
296 tmp_dir, ignore_status=True)
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800297 utils.system('sudo umount %s' % tmp_dir)
298 os.removedirs(tmp_dir)
299 if code != 0:
300 raise error.TestError(
301 'The image in the USB disk should be a test image.')
302
303
Simran Basi741b5d42012-05-18 11:27:15 -0700304 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800305 """Install the test image specied by the path onto the USB and DUT disk.
306
307 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500308 recovery mode. Then runs 'chromeos-install' (and possible
309 chromeos-firmwareupdate') to install it to DUT disk.
310
311 Sample command line:
312
313 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
314 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
315 server/site_tests/firmware_XXXX/control
316
317 This test requires an automated recovery to occur while simulating
318 inserting and removing the usb key from the servo. To allow this the
319 following hardware setup is required:
320 1. servo2 board connected via servoflex.
321 2. USB key inserted in the servo2.
322 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
323 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800324
325 Args:
326 image_path: Path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800327 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800328 """
329 build_ver, build_hash = lab_test.VerifyImageAndGetId(cros_dir,
330 image_path)
331 logging.info('Processing build: %s %s' % (build_ver, build_hash))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800332
Mike Truty49153d82012-08-21 22:27:30 -0500333 # Reuse the servo method that uses the servo USB key to install
334 # the test image.
335 self.servo.image_to_servo_usb(image_path)
336
337 # DUT is powered off while imaging servo USB.
338 # Now turn it on.
339 self.servo.power_short_press()
340 self.wait_for_client()
341 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
342
343 install_cmd = 'chromeos-install --yes'
344 if firmware_update:
345 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
346
347 self.register_faft_sequence((
348 { # Step 1, request recovery boot
349 'state_checker': (self.crossystem_checker, {
350 'mainfw_type': ('developer', 'normal'),
351 }),
352 'userspace_action': self.faft_client.request_recovery_boot,
353 'firmware_action': self.wait_fw_screen_and_plug_usb,
354 'install_deps_after_boot': True,
355 },
356 { # Step 2, expected recovery boot
357 'state_checker': (self.crossystem_checker, {
358 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800359 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500360 }),
361 'userspace_action': (self.faft_client.run_shell_command,
362 install_cmd),
363 'reboot_action': self.cold_reboot,
364 'install_deps_after_boot': True,
365 },
366 { # Step 3, expected normal or developer boot (not recovery)
367 'state_checker': (self.crossystem_checker, {
368 'mainfw_type': ('developer', 'normal')
369 }),
370 },
371 ))
372 self.run_faft_sequence()
373 # 'Unplug' any USB keys in the servo from the dut.
374 self.servo.disable_usb_hub()
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800375
376
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800377 def clear_set_gbb_flags(self, clear_mask, set_mask):
378 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800379
380 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800381 clear_mask: A mask of flags to be cleared.
382 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800383 """
384 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800385 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
386
387 if (gbb_flags != new_flags):
388 logging.info('Change the GBB flags from 0x%x to 0x%x.' %
389 (gbb_flags, new_flags))
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800390 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800391 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800392 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800393 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800394 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800395 self.run_faft_step({
396 'firmware_action': self.wait_fw_screen_and_ctrl_d,
397 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800398
399
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800400 def check_ec_capability(self, required_cap=[], suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800401 """Check if current platform has required EC capabilities.
402
403 Args:
404 required_cap: A list containing required EC capabilities. Pass in
405 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800406 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800407
408 Returns:
409 True if requirements are met. Otherwise, False.
410 """
411 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800412 if not suppress_warning:
413 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800414 return False
415
416 for cap in required_cap:
417 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800418 if not suppress_warning:
419 logging.warn('Requires EC capability "%s" to run this '
420 'test.' % cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800421 return False
422
423 return True
424
425
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800426 def _parse_crossystem_output(self, lines):
427 """Parse the crossystem output into a dict.
428
429 Args:
430 lines: The list of crossystem output strings.
431
432 Returns:
433 A dict which contains the crossystem keys/values.
434
435 Raises:
436 error.TestError: If wrong format in crossystem output.
437
438 >>> seq = FAFTSequence()
439 >>> seq._parse_crossystem_output([ \
440 "arch = x86 # Platform architecture", \
441 "cros_debug = 1 # OS should allow debug", \
442 ])
443 {'cros_debug': '1', 'arch': 'x86'}
444 >>> seq._parse_crossystem_output([ \
445 "arch=x86", \
446 ])
447 Traceback (most recent call last):
448 ...
449 TestError: Failed to parse crossystem output: arch=x86
450 >>> seq._parse_crossystem_output([ \
451 "arch = x86 # Platform architecture", \
452 "arch = arm # Platform architecture", \
453 ])
454 Traceback (most recent call last):
455 ...
456 TestError: Duplicated crossystem key: arch
457 """
458 pattern = "^([^ =]*) *= *(.*[^ ]) *# [^#]*$"
459 parsed_list = {}
460 for line in lines:
461 matched = re.match(pattern, line.strip())
462 if not matched:
463 raise error.TestError("Failed to parse crossystem output: %s"
464 % line)
465 (name, value) = (matched.group(1), matched.group(2))
466 if name in parsed_list:
467 raise error.TestError("Duplicated crossystem key: %s" % name)
468 parsed_list[name] = value
469 return parsed_list
470
471
472 def crossystem_checker(self, expected_dict):
473 """Check the crossystem values matched.
474
475 Given an expect_dict which describes the expected crossystem values,
476 this function check the current crossystem values are matched or not.
477
478 Args:
479 expected_dict: A dict which contains the expected values.
480
481 Returns:
482 True if the crossystem value matched; otherwise, False.
483 """
484 lines = self.faft_client.run_shell_command_get_output('crossystem')
485 got_dict = self._parse_crossystem_output(lines)
486 for key in expected_dict:
487 if key not in got_dict:
488 logging.info('Expected key "%s" not in crossystem result' % key)
489 return False
490 if isinstance(expected_dict[key], str):
491 if got_dict[key] != expected_dict[key]:
492 logging.info("Expected '%s' value '%s' but got '%s'" %
493 (key, expected_dict[key], got_dict[key]))
494 return False
495 elif isinstance(expected_dict[key], tuple):
496 # Expected value is a tuple of possible actual values.
497 if got_dict[key] not in expected_dict[key]:
498 logging.info("Expected '%s' values %s but got '%s'" %
499 (key, str(expected_dict[key]), got_dict[key]))
500 return False
501 else:
502 logging.info("The expected_dict is neither a str nor a dict.")
503 return False
504 return True
505
506
Tom Wai-Hong Tam39b93b92012-09-04 16:56:05 +0800507 def vdat_flags_checker(self, mask, value):
508 """Check the flags from VbSharedData matched.
509
510 This function checks the masked flags from VbSharedData using crossystem
511 are matched the given value.
512
513 Args:
514 mask: A bitmask of flags to be matched.
515 value: An expected value.
516
517 Returns:
518 True if the flags matched; otherwise, False.
519 """
520 lines = self.faft_client.run_shell_command_get_output(
521 'crossystem vdat_flags')
522 vdat_flags = int(lines[0], 16)
523 if vdat_flags & mask != value:
524 logging.info("Expected vdat_flags 0x%x mask 0x%x but got 0x%x" %
525 (value, mask, vdat_flags))
526 return False
527 return True
528
529
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800530 def ro_normal_checker(self, expected_fw=None, twostop=False):
531 """Check the current boot uses RO boot.
532
533 Args:
534 expected_fw: A string of expected firmware, 'A', 'B', or
535 None if don't care.
536 twostop: True to expect a TwoStop boot; False to expect a RO boot.
537
538 Returns:
539 True if the currect boot firmware matched and used RO boot;
540 otherwise, False.
541 """
542 crossystem_dict = {'tried_fwb': '0'}
543 if expected_fw:
544 crossystem_dict['mainfw_act'] = expected_fw.upper()
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800545 if self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800546 crossystem_dict['ecfw_act'] = ('RW' if twostop else 'RO')
547
548 return (self.vdat_flags_checker(
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800549 vboot.VDAT_FLAG_LF_USE_RO_NORMAL,
550 0 if twostop else vboot.VDAT_FLAG_LF_USE_RO_NORMAL) and
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800551 self.crossystem_checker(crossystem_dict))
552
553
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800554 def root_part_checker(self, expected_part):
555 """Check the partition number of the root device matched.
556
557 Args:
558 expected_part: A string containing the number of the expected root
559 partition.
560
561 Returns:
562 True if the currect root partition number matched; otherwise, False.
563 """
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +0800564 part = self.faft_client.get_root_part()[-1]
565 if self.ROOTFS_MAP[expected_part] != part:
566 logging.info("Expected root part %s but got %s" %
567 (self.ROOTFS_MAP[expected_part], part))
568 return False
569 return True
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800570
571
Vic Yang59cac9c2012-05-21 15:28:42 +0800572 def ec_act_copy_checker(self, expected_copy):
573 """Check the EC running firmware copy matches.
574
575 Args:
576 expected_copy: A string containing 'RO', 'A', or 'B' indicating
577 the expected copy of EC running firmware.
578
579 Returns:
580 True if the current EC running copy matches; otherwise, False.
581 """
582 lines = self.faft_client.run_shell_command_get_output('ectool version')
583 pattern = re.compile("Firmware copy: (.*)")
584 for line in lines:
585 matched = pattern.match(line)
586 if matched and matched.group(1) == expected_copy:
587 return True
588 return False
589
590
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800591 def check_root_part_on_non_recovery(self, part):
592 """Check the partition number of root device and on normal/dev boot.
593
594 Returns:
595 True if the root device matched and on normal/dev boot;
596 otherwise, False.
597 """
598 return self.root_part_checker(part) and \
599 self.crossystem_checker({
600 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800601 })
602
603
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800604 def _join_part(self, dev, part):
605 """Return a concatenated string of device and partition number.
606
607 Args:
608 dev: A string of device, e.g.'/dev/sda'.
609 part: A string of partition number, e.g.'3'.
610
611 Returns:
612 A concatenated string of device and partition number, e.g.'/dev/sda3'.
613
614 >>> seq = FAFTSequence()
615 >>> seq._join_part('/dev/sda', '3')
616 '/dev/sda3'
617 >>> seq._join_part('/dev/mmcblk0', '2')
618 '/dev/mmcblk0p2'
619 """
620 if 'mmcblk' in dev:
621 return dev + 'p' + part
622 else:
623 return dev + part
624
625
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800626 def copy_kernel_and_rootfs(self, from_part, to_part):
627 """Copy kernel and rootfs from from_part to to_part.
628
629 Args:
630 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800631 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800632 """
633 root_dev = self.faft_client.get_root_dev()
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800634 logging.info('Copying kernel from %s to %s. Please wait...' %
635 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800636 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800637 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
638 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
639 logging.info('Copying rootfs from %s to %s. Please wait...' %
640 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800641 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800642 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
643 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800644
645
646 def ensure_kernel_boot(self, part):
647 """Ensure the request kernel boot.
648
649 If not, it duplicates the current kernel to the requested kernel
650 and sets the requested higher priority to ensure it boot.
651
652 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800653 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800654 """
655 if not self.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800656 if self.faft_client.diff_kernel_a_b():
657 self.copy_kernel_and_rootfs(
658 from_part=self.OTHER_KERNEL_MAP[part],
659 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800660 self.run_faft_step({
661 'userspace_action': (self.reset_and_prioritize_kernel, part),
662 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800663
664
Vic Yang416f2032012-08-28 10:18:03 +0800665 def set_hardware_write_protect(self, enabled):
Vic Yang2cabf812012-08-28 02:39:04 +0800666 """Set hardware write protect pin.
667
668 Args:
669 enable: True if asserting write protect pin. Otherwise, False.
670 """
671 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
672 self.servo.set('fw_wp_en', 'on')
Vic Yang416f2032012-08-28 10:18:03 +0800673 self.servo.set('fw_wp', 'on' if enabled else 'off')
674
675
676 def set_EC_write_protect_and_reboot(self, enabled):
677 """Set EC write protect status and reboot to take effect.
678
679 EC write protect is only activated if both hardware write protect pin
680 is asserted and software write protect flag is set. Also, a reboot is
681 required for write protect to take effect.
682
683 Since the software write protect flag cannot be unset if hardware write
684 protect pin is asserted, we need to deasserted the pin first if we are
685 deactivating write protect. Similarly, a reboot is required before we
686 can modify the software flag.
687
688 This method asserts/deasserts hardware write protect pin first, and
689 set corresponding EC software write protect flag.
690
691 Args:
692 enable: True if activating EC write protect. Otherwise, False.
693 """
694 self.set_hardware_write_protect(enabled)
695 if enabled:
696 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800697 self.ec.send_command("flashwp enable")
Vic Yang416f2032012-08-28 10:18:03 +0800698 self.sync_and_ec_reboot()
699 else:
700 # Reboot after deasserting hardware write protect pin to deactivate
701 # write protect. And then remove software write protect flag.
702 self.sync_and_ec_reboot()
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800703 self.ec.send_command("flashwp disable")
Vic Yang2cabf812012-08-28 02:39:04 +0800704
705
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800706 def send_ctrl_d_to_dut(self):
707 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800708 if self._customized_key_commands['ctrl_d']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800709 logging.info('running the customized Ctrl-D key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800710 os.system(self._customized_key_commands['ctrl_d'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800711 else:
712 self.servo.ctrl_d()
713
714
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800715 def send_ctrl_u_to_dut(self):
716 """Send Ctrl-U key to DUT.
717
718 Raises:
719 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
720 on a no-build-in-keyboard device.
721 """
722 if self._customized_key_commands['ctrl_u']:
723 logging.info('running the customized Ctrl-U key command')
724 os.system(self._customized_key_commands['ctrl_u'])
725 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
726 self.ec.key_down('<ctrl_l>')
727 self.ec.key_down('u')
728 self.ec.key_up('u')
729 self.ec.key_up('<ctrl_l>')
730 elif self.client_attr.has_keyboard:
731 raise error.TestError(
732 "Can't send Ctrl-U to DUT without using Chrome EC.")
733 else:
734 raise error.TestError(
735 "Should specify the ctrl_u_cmd argument.")
736
737
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800738 def send_enter_to_dut(self):
739 """Send Enter key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800740 if self._customized_key_commands['enter']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800741 logging.info('running the customized Enter key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800742 os.system(self._customized_key_commands['enter'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800743 else:
744 self.servo.enter_key()
745
746
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800747 def send_space_to_dut(self):
748 """Send Space key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800749 if self._customized_key_commands['space']:
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800750 logging.info('running the customized Space key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800751 os.system(self._customized_key_commands['space'])
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800752 else:
753 # Send the alternative key combinaton of space key to servo.
754 self.servo.ctrl_refresh_key()
755
756
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800757 def wait_fw_screen_and_ctrl_d(self):
758 """Wait for firmware warning screen and press Ctrl-D."""
759 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800760 self.send_ctrl_d_to_dut()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800761
762
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800763 def wait_fw_screen_and_ctrl_u(self):
764 """Wait for firmware warning screen and press Ctrl-U."""
765 time.sleep(self.FIRMWARE_SCREEN_DELAY)
766 self.send_ctrl_u_to_dut()
767
768
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800769 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
770 """Wait for firmware warning screen and trigger recovery boot."""
771 time.sleep(self.FIRMWARE_SCREEN_DELAY)
772 self.send_enter_to_dut()
773
774 # For Alex/ZGB, there is a dev warning screen in text mode.
775 # Skip it by pressing Ctrl-D.
776 if need_dev_transition:
777 time.sleep(self.TEXT_SCREEN_DELAY)
778 self.send_ctrl_d_to_dut()
779
780
Mike Truty49153d82012-08-21 22:27:30 -0500781 def wait_fw_screen_and_unplug_usb(self):
782 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +0800783 time.sleep(self.USB_LOAD_DELAY)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800784 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
785 time.sleep(self.USB_PLUG_DELAY)
Mike Truty49153d82012-08-21 22:27:30 -0500786
787
788 def wait_fw_screen_and_plug_usb(self):
789 """Wait for firmware warning screen and then unplug and plug the USB."""
790 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800791 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
792
793
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800794 def wait_fw_screen_and_press_power(self):
795 """Wait for firmware warning screen and press power button."""
796 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800797 # While the firmware screen, the power button probing loop sleeps
798 # 0.25 second on every scan. Use the normal delay (1.2 second) for
799 # power press.
800 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800801
802
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800803 def wait_longer_fw_screen_and_press_power(self):
804 """Wait for firmware screen without timeout and press power button."""
805 time.sleep(self.DEV_SCREEN_TIMEOUT)
806 self.wait_fw_screen_and_press_power()
807
808
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800809 def wait_fw_screen_and_close_lid(self):
810 """Wait for firmware warning screen and close lid."""
811 time.sleep(self.FIRMWARE_SCREEN_DELAY)
812 self.servo.lid_close()
813
814
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800815 def wait_longer_fw_screen_and_close_lid(self):
816 """Wait for firmware screen without timeout and close lid."""
817 time.sleep(self.FIRMWARE_SCREEN_DELAY)
818 self.wait_fw_screen_and_close_lid()
819
820
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800821 def setup_tried_fwb(self, tried_fwb):
822 """Setup for fw B tried state.
823
824 It makes sure the system in the requested fw B tried state. If not, it
825 tries to do so.
826
827 Args:
828 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
829 """
830 if tried_fwb:
831 if not self.crossystem_checker({'tried_fwb': '1'}):
832 logging.info(
833 'Firmware is not booted with tried_fwb. Reboot into it.')
834 self.run_faft_step({
835 'userspace_action': self.faft_client.set_try_fw_b,
836 })
837 else:
838 if not self.crossystem_checker({'tried_fwb': '0'}):
839 logging.info(
840 'Firmware is booted with tried_fwb. Reboot to clear.')
841 self.run_faft_step({})
842
843
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800844 def enable_rec_mode_and_reboot(self):
845 """Switch to rec mode and reboot.
846
847 This method emulates the behavior of the old physical recovery switch,
848 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
849 recovery mode, i.e. just press Power + Esc + Refresh.
850 """
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800851 if self._customized_key_commands['rec_reboot']:
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800852 logging.info('running the customized rec reboot command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800853 os.system(self._customized_key_commands['rec_reboot'])
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800854 elif self.client_attr.chrome_ec:
Vic Yang81273092012-08-21 15:57:09 +0800855 # Cold reset to clear EC_IN_RW signal
Vic Yanga7250662012-08-31 04:00:08 +0800856 self.servo.set('cold_reset', 'on')
857 time.sleep(self.COLD_RESET_DELAY)
858 self.servo.set('cold_reset', 'off')
859 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800860 self.ec.send_command("reboot ap-off")
Vic Yang611dd852012-08-02 15:36:31 +0800861 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800862 self.ec.send_command("hostevent set 0x4000")
Vic Yang611dd852012-08-02 15:36:31 +0800863 self.servo.power_short_press()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800864 else:
865 self.servo.enable_recovery_mode()
866 self.cold_reboot()
867 time.sleep(self.EC_REBOOT_DELAY)
868 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800869
870
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800871 def enable_dev_mode_and_reboot(self):
872 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800873 if self.client_attr.keyboard_dev:
874 self.enable_keyboard_dev_mode()
875 else:
876 self.servo.enable_development_mode()
877 self.faft_client.run_shell_command(
878 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800879
880
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800881 def enable_normal_mode_and_reboot(self):
882 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800883 if self.client_attr.keyboard_dev:
884 self.disable_keyboard_dev_mode()
885 else:
886 self.servo.disable_development_mode()
887 self.faft_client.run_shell_command(
888 'chromeos-firmwareupdate --mode tonormal && reboot')
889
890
891 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
892 """Wait for firmware screen and then switch into or out of dev mode.
893
894 Args:
895 dev: True if switching into dev mode. Otherwise, False.
896 """
897 time.sleep(self.FIRMWARE_SCREEN_DELAY)
898 if dev:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800899 self.send_ctrl_d_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800900 else:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800901 self.send_enter_to_dut()
Tom Wai-Hong Tam1408f172012-07-31 15:06:21 +0800902 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800903 self.send_enter_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800904
905
906 def enable_keyboard_dev_mode(self):
907 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +0800908 # Plug out USB disk for preventing recovery boot without warning
909 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +0800910 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800911 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800912 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800913 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +0800914
915
916 def disable_keyboard_dev_mode(self):
917 logging.info("Disabling keyboard controlled developer mode")
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800918 if not self.client_attr.chrome_ec:
Vic Yang611dd852012-08-02 15:36:31 +0800919 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +0800920 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800921 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800922 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800923
924
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800925 def setup_dev_mode(self, dev_mode):
926 """Setup for development mode.
927
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800928 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800929 tries to do so.
930
931 Args:
932 dev_mode: True if requested in dev mode; False if normal mode.
933 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800934 # Change the default firmware_action for dev mode passing the fw screen.
935 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800936 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
937 else None),
938 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800939 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +0800940 if (not self.client_attr.keyboard_dev and
941 not self.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800942 logging.info('Dev switch is not on. Now switch it on.')
943 self.servo.enable_development_mode()
944 if not self.crossystem_checker({'devsw_boot': '1',
945 'mainfw_type': 'developer'}):
946 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800947 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800948 'userspace_action': None if self.client_attr.keyboard_dev
949 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800950 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800951 'reboot_action': self.enable_keyboard_dev_mode if
952 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800953 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800954 else:
Vic Yange7553162012-06-20 16:20:47 +0800955 if (not self.client_attr.keyboard_dev and
956 not self.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800957 logging.info('Dev switch is not off. Now switch it off.')
958 self.servo.disable_development_mode()
959 if not self.crossystem_checker({'devsw_boot': '0',
960 'mainfw_type': 'normal'}):
961 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800962 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800963 'userspace_action': None if self.client_attr.keyboard_dev
964 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800965 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800966 'reboot_action': self.disable_keyboard_dev_mode if
967 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800968 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800969
970
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800971 def setup_kernel(self, part):
972 """Setup for kernel test.
973
974 It makes sure both kernel A and B bootable and the current boot is
975 the requested kernel part.
976
977 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800978 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800979 """
980 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800981 if self.faft_client.diff_kernel_a_b():
982 self.copy_kernel_and_rootfs(from_part=part,
983 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800984 self.reset_and_prioritize_kernel(part)
985
986
987 def reset_and_prioritize_kernel(self, part):
988 """Make the requested partition highest priority.
989
990 This function also reset kerenl A and B to bootable.
991
992 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800993 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800994 """
995 root_dev = self.faft_client.get_root_dev()
996 # Reset kernel A and B to bootable.
997 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
998 (self.KERNEL_MAP['a'], root_dev))
999 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1000 (self.KERNEL_MAP['b'], root_dev))
1001 # Set kernel part highest priority.
1002 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1003 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001004 # Safer to sync and wait until the cgpt status written to the disk.
1005 self.faft_client.run_shell_command('sync')
1006 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001007
1008
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001009 def warm_reboot(self):
1010 """Request a warm reboot.
1011
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001012 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001013 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001014 # Use cold reset if the warm reset is broken.
1015 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001016 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1017 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001018 else:
1019 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001020
1021
1022 def cold_reboot(self):
1023 """Request a cold reboot.
1024
1025 A wrapper for underlying servo cold reset.
1026 """
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001027 if self.client_attr.platform == 'Parrot':
1028 self.servo.set('pwr_button', 'press')
1029 self.servo.set('cold_reset', 'on')
1030 self.servo.set('cold_reset', 'off')
1031 time.sleep(self.POWER_BTN_DELAY)
1032 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +08001033 elif self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001034 # We don't use servo.cold_reset() here because software sync is
1035 # not yet finished, and device may or may not come up after cold
1036 # reset. Pressing power button before firmware comes up solves this.
1037 #
1038 # The correct behavior should be (not work now):
1039 # - If rebooting EC with rec mode on, power on AP and it boots
1040 # into recovery mode.
1041 # - If rebooting EC with rec mode off, power on AP for software
1042 # sync. Then AP checks if lid open or not. If lid open, continue;
1043 # otherwise, shut AP down and need servo for a power button
1044 # press.
1045 self.servo.set('cold_reset', 'on')
1046 self.servo.set('cold_reset', 'off')
1047 time.sleep(self.POWER_BTN_DELAY)
1048 self.servo.power_short_press()
1049 else:
1050 self.servo.cold_reset()
1051
1052
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001053 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001054 """Request the client sync and do a warm reboot.
1055
1056 This is the default reboot action on FAFT.
1057 """
1058 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001059 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001060 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001061
1062
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001063 def sync_and_cold_reboot(self):
1064 """Request the client sync and do a cold reboot.
1065
1066 This reboot action is used to reset EC for recovery mode.
1067 """
1068 self.faft_client.run_shell_command('sync')
1069 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001070 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001071
1072
Vic Yangaeb10392012-08-28 09:25:09 +08001073 def sync_and_ec_reboot(self, args=''):
1074 """Request the client sync and do a EC triggered reboot.
1075
1076 Args:
1077 args: Arguments passed to "ectool reboot_ec". Including:
1078 RO: jump to EC RO firmware.
1079 RW: jump to EC RW firmware.
1080 cold: Cold/hard reboot.
1081 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001082 self.faft_client.run_shell_command('sync')
1083 time.sleep(self.SYNC_DELAY)
Vic Yangaeb10392012-08-28 09:25:09 +08001084 # Since EC reboot happens immediately, delay before actual reboot to
1085 # allow FAFT client returning.
1086 self.faft_client.run_shell_command('(sleep %d; ectool reboot_ec %s)&' %
1087 (self.EC_REBOOT_DELAY, args))
Vic Yangf86728a2012-07-30 10:44:07 +08001088 time.sleep(self.EC_REBOOT_DELAY)
1089 self.check_lid_and_power_on()
1090
1091
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001092 def full_power_off_and_on(self):
1093 """Shutdown the device by pressing power button and power on again."""
1094 # Press power button to trigger Chrome OS normal shutdown process.
1095 self.servo.power_normal_press()
1096 time.sleep(self.FULL_POWER_OFF_DELAY)
1097 # Short press power button to boot DUT again.
1098 self.servo.power_short_press()
1099
1100
Vic Yangf86728a2012-07-30 10:44:07 +08001101 def check_lid_and_power_on(self):
1102 """
1103 On devices with EC software sync, system powers on after EC reboots if
1104 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1105 This method checks lid switch state and presses power button if
1106 necessary.
1107 """
1108 if self.servo.get("lid_open") == "no":
1109 time.sleep(self.SOFTWARE_SYNC_DELAY)
1110 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001111
1112
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001113 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1114 """Modify the kernel header magic in USB stick.
1115
1116 The kernel header magic is the first 8-byte of kernel partition.
1117 We modify it to make it fail on kernel verification check.
1118
1119 Args:
1120 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1121 from_magic: A string of magic which we change it from.
1122 to_magic: A string of magic which we change it to.
1123
1124 Raises:
1125 error.TestError: if failed to change magic.
1126 """
1127 assert len(from_magic) == 8
1128 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001129 # USB image only contains one kernel.
1130 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001131 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1132 current_magic = utils.system_output(read_cmd)
1133 if current_magic == to_magic:
1134 logging.info("The kernel magic is already %s." % current_magic)
1135 return
1136 if current_magic != from_magic:
1137 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1138
1139 logging.info('Modify the kernel magic in USB, from %s to %s.' %
1140 (from_magic, to_magic))
1141 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1142 " 2>/dev/null" % (to_magic, kernel_part))
1143 utils.system(write_cmd)
1144
1145 if utils.system_output(read_cmd) != to_magic:
1146 raise error.TestError("Failed to write new magic.")
1147
1148
1149 def corrupt_usb_kernel(self, usb_dev):
1150 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1151
1152 Args:
1153 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1154 """
1155 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1156 self.CORRUPTED_MAGIC)
1157
1158
1159 def restore_usb_kernel(self, usb_dev):
1160 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1161
1162 Args:
1163 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1164 """
1165 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1166 self.CHROMEOS_MAGIC)
1167
1168
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001169 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001170 """Call the action function with/without arguments.
1171
1172 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001173 action_tuple: A function, or a tuple (function, args, error_msg),
1174 in which, args and error_msg are optional. args is
1175 either a value or a tuple if multiple arguments.
1176 check_status: Check the return value of action function. If not
1177 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001178
1179 Returns:
1180 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001181
1182 Raises:
1183 error.TestError: An error when the action function is not callable.
1184 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001185 """
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001186 action = action_tuple
1187 args = ()
1188 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001189 if isinstance(action_tuple, tuple):
1190 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001191 if len(action_tuple) >= 2:
1192 args = action_tuple[1]
1193 if not isinstance(args, tuple):
1194 args = (args,)
1195 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001196 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001197
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001198 if action is None:
1199 return
1200
1201 if not callable(action):
1202 raise error.TestError('action is not callable!')
1203
1204 info_msg = 'calling %s' % str(action)
1205 if args:
1206 info_msg += ' with args %s' % str(args)
1207 logging.info(info_msg)
1208 ret = action(*args)
1209
1210 if check_status and not ret:
1211 raise error.TestFail('%s: %s returning %s' %
1212 (error_msg, info_msg, str(ret)))
1213 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001214
1215
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001216 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1217 post_power_action=None):
1218 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1219
1220 Args:
1221 shutdown_action: a function which makes DUT shutdown, like pressing
1222 power key.
1223 pre_power_action: a function which is called before next power on.
1224 post_power_action: a function which is called after next power on.
1225
1226 Raises:
1227 error.TestFail: if the shutdown_action() failed to turn DUT off.
1228 """
1229 self._call_action(shutdown_action)
1230 logging.info('Wait to ensure DUT shut down...')
1231 try:
1232 self.wait_for_client()
1233 raise error.TestFail(
1234 'Should shut the device down after calling %s.' %
1235 str(shutdown_action))
1236 except AssertionError:
1237 logging.info(
1238 'DUT is surely shutdown. We are going to power it on again...')
1239
1240 if pre_power_action:
1241 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001242 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001243 if post_power_action:
1244 self._call_action(post_power_action)
1245
1246
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001247 def register_faft_template(self, template):
1248 """Register FAFT template, the default FAFT_STEP of each step.
1249
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001250 Any missing field falls back to the original faft_template.
1251
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001252 Args:
1253 template: A FAFT_STEP dict.
1254 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001255 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001256
1257
1258 def register_faft_sequence(self, sequence):
1259 """Register FAFT sequence.
1260
1261 Args:
1262 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1263 """
1264 self._faft_sequence = sequence
1265
1266
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001267 def run_faft_step(self, step, no_reboot=False):
1268 """Run a single FAFT step.
1269
1270 Any missing field falls back to faft_template. An empty step means
1271 running the default faft_template.
1272
1273 Args:
1274 step: A FAFT_STEP dict.
1275 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001276
1277 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001278 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001279 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001280 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1281 'firmware_action', 'install_deps_after_boot')
1282
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001283 test = {}
1284 test.update(self._faft_template)
1285 test.update(step)
1286
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001287 for key in test:
1288 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001289 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001290
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001291 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001292 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001293
1294 self._call_action(test['userspace_action'])
1295
1296 # Don't run reboot_action and firmware_action if no_reboot is True.
1297 if not no_reboot:
1298 self._call_action(test['reboot_action'])
1299 self.wait_for_client_offline()
1300 self._call_action(test['firmware_action'])
1301
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001302 try:
1303 if 'install_deps_after_boot' in test:
1304 self.wait_for_client(
1305 install_deps=test['install_deps_after_boot'])
1306 else:
1307 self.wait_for_client()
1308 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001309 logging.info('wait_for_client() timed out.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001310 self.reset_client()
1311 raise
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001312
1313
1314 def run_faft_sequence(self):
1315 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001316 sequence = self._faft_sequence
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001317 index = 1
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001318 for step in sequence:
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001319 logging.info('======== Running FAFT sequence step %d ========' %
1320 index)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001321 # Don't reboot in the last step.
1322 self.run_faft_step(step, no_reboot=(step is sequence[-1]))
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001323 index += 1
ctchang38ae4922012-09-03 17:01:16 +08001324
1325
ctchang38ae4922012-09-03 17:01:16 +08001326 def get_current_firmware_sha(self):
1327 """Get current firmware sha of body and vblock.
1328
1329 Returns:
1330 Current firmware sha follows the order (
1331 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1332 """
1333 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1334 self.faft_client.get_firmware_sha('a'),
1335 self.faft_client.get_firmware_sig_sha('b'),
1336 self.faft_client.get_firmware_sha('b'))
1337 return current_firmware_sha
1338
1339
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001340 def is_firmware_changed(self):
1341 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001342
1343 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001344 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001345 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001346 # Device may not be rebooted after test.
1347 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001348
1349 current_sha = self.get_current_firmware_sha()
1350
1351 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001352 return False
ctchang38ae4922012-09-03 17:01:16 +08001353 else:
ctchang38ae4922012-09-03 17:01:16 +08001354 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1355 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1356 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1357 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001358 logging.info("Firmware changed:")
1359 logging.info('VBOOTA is changed: %s' % corrupt_VBOOTA)
1360 logging.info('VBOOTB is changed: %s' % corrupt_VBOOTB)
1361 logging.info('FVMAIN is changed: %s' % corrupt_FVMAIN)
1362 logging.info('FVMAINB is changed: %s' % corrupt_FVMAINB)
1363 return True
ctchang38ae4922012-09-03 17:01:16 +08001364
1365
1366 def backup_firmware(self, suffix='.original'):
1367 """Backup firmware to file, and then send it to host.
1368
1369 Args:
1370 suffix: a string appended to backup file name
1371 """
1372 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001373 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1374 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1375 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001376
1377 self._backup_firmware_sha = self.get_current_firmware_sha()
1378 logging.info('Backup firmware stored in %s with suffix %s' % (
1379 self.resultsdir, suffix))
1380
1381
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001382 def is_firmware_saved(self):
1383 """Check if a firmware saved (called backup_firmware before).
1384
1385 Returns:
1386 True if the firmware is backuped; otherwise False.
1387 """
1388 return self._backup_firmware_sha != ()
1389
1390
ctchang38ae4922012-09-03 17:01:16 +08001391 def restore_firmware(self, suffix='.original'):
1392 """Restore firmware from host in resultsdir.
1393
1394 Args:
1395 suffix: a string appended to backup file name
1396 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001397 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001398 return
1399
1400 # Backup current corrupted firmware.
1401 self.backup_firmware(suffix='.corrupt')
1402
1403 # Restore firmware.
1404 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001405 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1406 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001407
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001408 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001409 self.sync_and_warm_reboot()
1410 self.wait_for_client_offline()
1411 self.wait_for_client()
1412
ctchang38ae4922012-09-03 17:01:16 +08001413 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001414
1415
1416 def setup_firmwareupdate_shellball(self, shellball=None):
1417 """Deside a shellball to use in firmware update test.
1418
1419 Check if there is a given shellball, and it is a shell script. Then,
1420 send it to the remote host. Otherwise, use
1421 /usr/sbin/chromeos-firmwareupdate.
1422
1423 Args:
1424 shellball: path of a shellball or default to None.
1425
1426 Returns:
1427 Path of shellball in remote host.
1428 If use default shellball, reutrn None.
1429 """
1430 updater_path = None
1431 if shellball:
1432 # Determine the firmware file is a shellball or a raw binary.
1433 is_shellball = (utils.system_output("file %s" % shellball).find(
1434 "shell script") != -1)
1435 if is_shellball:
1436 logging.info('Device will update firmware with shellball %s'
1437 % shellball)
1438 temp_dir = self.faft_client.create_temp_dir('shellball_')
1439 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1440 self._client.send_file(shellball, temp_shellball)
1441 updater_path = temp_shellball
1442 else:
1443 raise error.TestFail(
1444 'The given shellball is not a shell script.')
1445 return updater_path