blob: 06f2586f5e22ea57584d8401c2c8a94e22ae6e53 [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
Vic Yangdbaba8f2012-10-17 16:05:35 +0800132 # True if this is the first test in the same run
133 _first_test = True
134 _setup_invalidated = False
135
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800136
137 def initialize(self, host, cmdline_args, use_pyauto=False, use_faft=False):
138 # Parse arguments from command line
139 args = {}
140 for arg in cmdline_args:
141 match = re.search("^(\w+)=(.+)", arg)
142 if match:
143 args[match.group(1)] = match.group(2)
144
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800145 # Keep the arguments which will be used later.
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800146 for key in self._customized_key_commands:
147 key_cmd = key + '_cmd'
148 if key_cmd in args:
149 self._customized_key_commands[key] = args[key_cmd]
150 logging.info('Customized %s key command: %s' %
151 (key, args[key_cmd]))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800152 if 'image' in args:
153 self._install_image_path = args['image']
154 logging.info('Install Chrome OS test image path: %s' %
155 self._install_image_path)
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800156 if 'firmware_update' in args and args['firmware_update'].lower() \
157 not in ('0', 'false', 'no'):
158 if self._install_image_path:
159 self._firmware_update = True
160 logging.info('Also update firmware after installing.')
161 else:
162 logging.warning('Firmware update will not not performed '
163 'since no image is specified.')
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800164
165 super(FAFTSequence, self).initialize(host, cmdline_args, use_pyauto,
166 use_faft)
Vic Yangebd6de62012-06-26 14:25:57 +0800167 if use_faft:
168 self.client_attr = FAFTClientAttribute(
169 self.faft_client.get_platform_name())
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800170
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800171 if self.client_attr.chrome_ec:
172 self.ec = ChromeEC(self.servo)
173
Gediminas Ramanauskas3297d4f2012-09-10 15:30:10 -0700174 # Setting up key matrix mapping
175 self.servo.set_key_matrix(self.client_attr.key_matrix_layout)
176
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800177
178 def setup(self):
179 """Autotest setup function."""
180 super(FAFTSequence, self).setup()
181 if not self._remote_infos['faft']['used']:
182 raise error.TestError('The use_faft flag should be enabled.')
183 self.register_faft_template({
184 'state_checker': (None),
185 'userspace_action': (None),
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +0800186 'reboot_action': (self.sync_and_warm_reboot),
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800187 'firmware_action': (None)
188 })
Vic Yangdbaba8f2012-10-17 16:05:35 +0800189 if FAFTSequence._first_test:
190 logging.info('Running first test. Set proper GBB flags.')
191 self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
192 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
193 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
194 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
195 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800196 if self._install_image_path:
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800197 self.install_test_image(self._install_image_path,
198 self._firmware_update)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800199
200
201 def cleanup(self):
202 """Autotest cleanup function."""
203 self._faft_sequence = ()
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +0800204 self._faft_template = {}
Vic Yangdbaba8f2012-10-17 16:05:35 +0800205 FAFTSequence._first_test = self._setup_invalidated
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800206 super(FAFTSequence, self).cleanup()
207
208
Vic Yangdbaba8f2012-10-17 16:05:35 +0800209 def invalidate_setup(self):
210 """Invalidate current setup flag.
211
212 This reset the first test flag so that the next test setup
213 properly again.
214 """
215 self._setup_invalidated = True
216
217
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800218 def reset_client(self):
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800219 """Reset client, if necessary.
220
221 This method is called when the client is not responsive. It may be
222 caused by the following cases:
223 - network flaky (can be recovered by replugging the Ethernet);
224 - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
225 - corrupted firmware;
226 - corrutped OS image.
227 """
228 # DUT works fine, done.
229 if self._ping_test(self._client.ip, timeout=5):
230 return
231
232 # TODO(waihong@chromium.org): Implement replugging the Ethernet in the
233 # first reset item.
234
235 # DUT may halt on a firmware screen. Try cold reboot.
236 logging.info('Try cold reboot...')
237 self.cold_reboot()
238 try:
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800239 self.wait_for_client()
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +0800240 return
241 except AssertionError:
242 pass
243
244 # DUT may be broken by a corrupted firmware. Restore firmware.
245 # We assume the recovery boot still works fine. Since the recovery
246 # code is in RO region and all FAFT tests don't change the RO region
247 # except GBB.
248 if self.is_firmware_saved():
249 self.ensure_client_in_recovery()
250 logging.info('Try restore the original firmware...')
251 if self.is_firmware_changed():
252 try:
253 self.restore_firmware()
254 return
255 except AssertionError:
256 logging.info('Restoring firmware doesn\'t help.')
257
258 # DUT may be broken by a corrupted OS image. Restore OS image.
259 self.ensure_client_in_recovery()
260 logging.info('Try restore the OS image...')
261 self.faft_client.run_shell_command('chromeos-install --yes')
262 self.sync_and_warm_reboot()
263 self.wait_for_client_offline()
264 try:
265 self.wait_for_client(install_deps=True)
266 logging.info('Successfully restore OS image.')
267 return
268 except AssertionError:
269 logging.info('Restoring OS image doesn\'t help.')
270
271
272 def ensure_client_in_recovery(self):
273 """Ensure client in recovery boot; reboot into it if necessary.
274
275 Raises:
276 error.TestError: if failed to boot the USB image.
277 """
278 # DUT works fine and is already in recovery boot, done.
279 if self._ping_test(self._client.ip, timeout=5):
280 if self.crossystem_checker({'mainfw_type': 'recovery'}):
281 return
282
283 logging.info('Try boot into USB image...')
284 self.servo.enable_usb_hub(host=True)
285 self.enable_rec_mode_and_reboot()
286 self.wait_fw_screen_and_plug_usb()
287 try:
288 self.wait_for_client(install_deps=True)
289 except AssertionError:
290 raise error.TestError('Failed to boot the USB image.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +0800291
292
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800293 def assert_test_image_in_usb_disk(self, usb_dev=None):
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800294 """Assert an USB disk plugged-in on servo and a test image inside.
295
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800296 Args:
297 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
298 If None, it is detected automatically.
299
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800300 Raises:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800301 error.TestError: if USB disk not detected or not a test image.
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800302 """
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800303 if usb_dev:
304 assert self.servo.get('usb_mux_sel1') == 'servo_sees_usbkey'
305 else:
Vadim Bendeburycacf29f2012-07-30 17:49:11 -0700306 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam91f49822011-12-28 15:44:15 +0800307 usb_dev = self.servo.probe_host_usb_dev()
308 if not usb_dev:
309 raise error.TestError(
310 'An USB disk should be plugged in the servo board.')
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800311
312 tmp_dir = tempfile.mkdtemp()
Tom Wai-Hong Tamb0e80852011-12-07 16:15:06 +0800313 utils.system('sudo mount -r -t ext2 %s3 %s' % (usb_dev, tmp_dir))
Tom Wai-Hong Tame77459e2011-11-03 17:19:46 +0800314 code = utils.system(
315 'grep -qE "(Test Build|testimage-channel)" %s/etc/lsb-release' %
316 tmp_dir, ignore_status=True)
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800317 utils.system('sudo umount %s' % tmp_dir)
318 os.removedirs(tmp_dir)
319 if code != 0:
320 raise error.TestError(
321 'The image in the USB disk should be a test image.')
322
323
Simran Basi741b5d42012-05-18 11:27:15 -0700324 def install_test_image(self, image_path=None, firmware_update=False):
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800325 """Install the test image specied by the path onto the USB and DUT disk.
326
327 The method first copies the image to USB disk and reboots into it via
Mike Truty49153d82012-08-21 22:27:30 -0500328 recovery mode. Then runs 'chromeos-install' (and possible
329 chromeos-firmwareupdate') to install it to DUT disk.
330
331 Sample command line:
332
333 run_remote_tests.sh --servo --board=daisy --remote=w.x.y.z \
334 --args="image=/tmp/chromiumos_test_image.bin firmware_update=True" \
335 server/site_tests/firmware_XXXX/control
336
337 This test requires an automated recovery to occur while simulating
338 inserting and removing the usb key from the servo. To allow this the
339 following hardware setup is required:
340 1. servo2 board connected via servoflex.
341 2. USB key inserted in the servo2.
342 3. servo2 connected to the dut via dut_hub_in in the usb 2.0 slot.
343 4. network connected via usb dongle in the dut in usb 3.0 slot.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800344
345 Args:
346 image_path: Path on the host to the test image.
Tom Wai-Hong Tam1a3ff742012-01-11 16:36:46 +0800347 firmware_update: Also update the firmware after installing.
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800348 """
349 build_ver, build_hash = lab_test.VerifyImageAndGetId(cros_dir,
350 image_path)
351 logging.info('Processing build: %s %s' % (build_ver, build_hash))
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800352
Mike Truty49153d82012-08-21 22:27:30 -0500353 # Reuse the servo method that uses the servo USB key to install
354 # the test image.
355 self.servo.image_to_servo_usb(image_path)
356
357 # DUT is powered off while imaging servo USB.
358 # Now turn it on.
359 self.servo.power_short_press()
360 self.wait_for_client()
361 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
362
363 install_cmd = 'chromeos-install --yes'
364 if firmware_update:
365 install_cmd += ' && chromeos-firmwareupdate --mode recovery'
366
367 self.register_faft_sequence((
368 { # Step 1, request recovery boot
369 'state_checker': (self.crossystem_checker, {
370 'mainfw_type': ('developer', 'normal'),
371 }),
372 'userspace_action': self.faft_client.request_recovery_boot,
373 'firmware_action': self.wait_fw_screen_and_plug_usb,
374 'install_deps_after_boot': True,
375 },
376 { # Step 2, expected recovery boot
377 'state_checker': (self.crossystem_checker, {
378 'mainfw_type': 'recovery',
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800379 'recovery_reason' : vboot.RECOVERY_REASON['US_TEST'],
Mike Truty49153d82012-08-21 22:27:30 -0500380 }),
381 'userspace_action': (self.faft_client.run_shell_command,
382 install_cmd),
383 'reboot_action': self.cold_reboot,
384 'install_deps_after_boot': True,
385 },
386 { # Step 3, expected normal or developer boot (not recovery)
387 'state_checker': (self.crossystem_checker, {
388 'mainfw_type': ('developer', 'normal')
389 }),
390 },
391 ))
392 self.run_faft_sequence()
393 # 'Unplug' any USB keys in the servo from the dut.
Tom Wai-Hong Tam953c7742012-10-16 21:09:31 +0800394 self.servo.enable_usb_hub(host=True)
Tom Wai-Hong Tam40fd9472012-01-09 17:11:02 +0800395
396
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800397 def clear_set_gbb_flags(self, clear_mask, set_mask):
398 """Clear and set the GBB flags in the current flashrom.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800399
400 Args:
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800401 clear_mask: A mask of flags to be cleared.
402 set_mask: A mask of flags to be set.
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800403 """
404 gbb_flags = self.faft_client.get_gbb_flags()
Tom Wai-Hong Tamfa3142e2012-08-16 11:53:58 +0800405 new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
406
407 if (gbb_flags != new_flags):
408 logging.info('Change the GBB flags from 0x%x to 0x%x.' %
409 (gbb_flags, new_flags))
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800410 self.faft_client.run_shell_command(
Tom Wai-Hong Tamfda76e22012-08-08 17:19:10 +0800411 '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800412 self.faft_client.reload_firmware()
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800413 # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800414 if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
Tom Wai-Hong Tama2481922012-08-08 17:24:42 +0800415 self.run_faft_step({
416 'firmware_action': self.wait_fw_screen_and_ctrl_d,
417 })
Tom Wai-Hong Tam15ce5812012-07-26 14:14:18 +0800418
419
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800420 def check_ec_capability(self, required_cap=[], suppress_warning=False):
Vic Yang4d72cb62012-07-24 11:51:09 +0800421 """Check if current platform has required EC capabilities.
422
423 Args:
424 required_cap: A list containing required EC capabilities. Pass in
425 None to only check for presence of Chrome EC.
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800426 suppress_warning: True to suppress any warning messages.
Vic Yang4d72cb62012-07-24 11:51:09 +0800427
428 Returns:
429 True if requirements are met. Otherwise, False.
430 """
431 if not self.client_attr.chrome_ec:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800432 if not suppress_warning:
433 logging.warn('Requires Chrome EC to run this test.')
Vic Yang4d72cb62012-07-24 11:51:09 +0800434 return False
435
436 for cap in required_cap:
437 if cap not in self.client_attr.ec_capability:
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800438 if not suppress_warning:
439 logging.warn('Requires EC capability "%s" to run this '
440 'test.' % cap)
Vic Yang4d72cb62012-07-24 11:51:09 +0800441 return False
442
443 return True
444
445
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +0800446 def _parse_crossystem_output(self, lines):
447 """Parse the crossystem output into a dict.
448
449 Args:
450 lines: The list of crossystem output strings.
451
452 Returns:
453 A dict which contains the crossystem keys/values.
454
455 Raises:
456 error.TestError: If wrong format in crossystem output.
457
458 >>> seq = FAFTSequence()
459 >>> seq._parse_crossystem_output([ \
460 "arch = x86 # Platform architecture", \
461 "cros_debug = 1 # OS should allow debug", \
462 ])
463 {'cros_debug': '1', 'arch': 'x86'}
464 >>> seq._parse_crossystem_output([ \
465 "arch=x86", \
466 ])
467 Traceback (most recent call last):
468 ...
469 TestError: Failed to parse crossystem output: arch=x86
470 >>> seq._parse_crossystem_output([ \
471 "arch = x86 # Platform architecture", \
472 "arch = arm # Platform architecture", \
473 ])
474 Traceback (most recent call last):
475 ...
476 TestError: Duplicated crossystem key: arch
477 """
478 pattern = "^([^ =]*) *= *(.*[^ ]) *# [^#]*$"
479 parsed_list = {}
480 for line in lines:
481 matched = re.match(pattern, line.strip())
482 if not matched:
483 raise error.TestError("Failed to parse crossystem output: %s"
484 % line)
485 (name, value) = (matched.group(1), matched.group(2))
486 if name in parsed_list:
487 raise error.TestError("Duplicated crossystem key: %s" % name)
488 parsed_list[name] = value
489 return parsed_list
490
491
492 def crossystem_checker(self, expected_dict):
493 """Check the crossystem values matched.
494
495 Given an expect_dict which describes the expected crossystem values,
496 this function check the current crossystem values are matched or not.
497
498 Args:
499 expected_dict: A dict which contains the expected values.
500
501 Returns:
502 True if the crossystem value matched; otherwise, False.
503 """
504 lines = self.faft_client.run_shell_command_get_output('crossystem')
505 got_dict = self._parse_crossystem_output(lines)
506 for key in expected_dict:
507 if key not in got_dict:
508 logging.info('Expected key "%s" not in crossystem result' % key)
509 return False
510 if isinstance(expected_dict[key], str):
511 if got_dict[key] != expected_dict[key]:
512 logging.info("Expected '%s' value '%s' but got '%s'" %
513 (key, expected_dict[key], got_dict[key]))
514 return False
515 elif isinstance(expected_dict[key], tuple):
516 # Expected value is a tuple of possible actual values.
517 if got_dict[key] not in expected_dict[key]:
518 logging.info("Expected '%s' values %s but got '%s'" %
519 (key, str(expected_dict[key]), got_dict[key]))
520 return False
521 else:
522 logging.info("The expected_dict is neither a str nor a dict.")
523 return False
524 return True
525
526
Tom Wai-Hong Tam39b93b92012-09-04 16:56:05 +0800527 def vdat_flags_checker(self, mask, value):
528 """Check the flags from VbSharedData matched.
529
530 This function checks the masked flags from VbSharedData using crossystem
531 are matched the given value.
532
533 Args:
534 mask: A bitmask of flags to be matched.
535 value: An expected value.
536
537 Returns:
538 True if the flags matched; otherwise, False.
539 """
540 lines = self.faft_client.run_shell_command_get_output(
541 'crossystem vdat_flags')
542 vdat_flags = int(lines[0], 16)
543 if vdat_flags & mask != value:
544 logging.info("Expected vdat_flags 0x%x mask 0x%x but got 0x%x" %
545 (value, mask, vdat_flags))
546 return False
547 return True
548
549
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800550 def ro_normal_checker(self, expected_fw=None, twostop=False):
551 """Check the current boot uses RO boot.
552
553 Args:
554 expected_fw: A string of expected firmware, 'A', 'B', or
555 None if don't care.
556 twostop: True to expect a TwoStop boot; False to expect a RO boot.
557
558 Returns:
559 True if the currect boot firmware matched and used RO boot;
560 otherwise, False.
561 """
562 crossystem_dict = {'tried_fwb': '0'}
563 if expected_fw:
564 crossystem_dict['mainfw_act'] = expected_fw.upper()
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +0800565 if self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800566 crossystem_dict['ecfw_act'] = ('RW' if twostop else 'RO')
567
568 return (self.vdat_flags_checker(
Tom Wai-Hong Tam6ec46e32012-10-05 16:39:21 +0800569 vboot.VDAT_FLAG_LF_USE_RO_NORMAL,
570 0 if twostop else vboot.VDAT_FLAG_LF_USE_RO_NORMAL) and
Tom Wai-Hong Tam3e82e362012-09-05 10:17:55 +0800571 self.crossystem_checker(crossystem_dict))
572
573
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800574 def dev_boot_usb_checker(self, dev_boot_usb=True):
575 """Check the current boot is from a developer USB (Ctrl-U trigger).
576
577 Args:
578 dev_boot_usb: True to expect an USB boot;
579 False to expect an internal device boot.
580
581 Returns:
582 True if the currect boot device matched; otherwise, False.
583 """
584 return (self.crossystem_checker({'mainfw_type': 'developer'})
585 and self.faft_client.is_removable_device_boot() == dev_boot_usb)
586
587
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800588 def root_part_checker(self, expected_part):
589 """Check the partition number of the root device matched.
590
591 Args:
592 expected_part: A string containing the number of the expected root
593 partition.
594
595 Returns:
596 True if the currect root partition number matched; otherwise, False.
597 """
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +0800598 part = self.faft_client.get_root_part()[-1]
599 if self.ROOTFS_MAP[expected_part] != part:
600 logging.info("Expected root part %s but got %s" %
601 (self.ROOTFS_MAP[expected_part], part))
602 return False
603 return True
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800604
605
Vic Yang59cac9c2012-05-21 15:28:42 +0800606 def ec_act_copy_checker(self, expected_copy):
607 """Check the EC running firmware copy matches.
608
609 Args:
610 expected_copy: A string containing 'RO', 'A', or 'B' indicating
611 the expected copy of EC running firmware.
612
613 Returns:
614 True if the current EC running copy matches; otherwise, False.
615 """
616 lines = self.faft_client.run_shell_command_get_output('ectool version')
617 pattern = re.compile("Firmware copy: (.*)")
618 for line in lines:
619 matched = pattern.match(line)
620 if matched and matched.group(1) == expected_copy:
621 return True
622 return False
623
624
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800625 def check_root_part_on_non_recovery(self, part):
626 """Check the partition number of root device and on normal/dev boot.
627
628 Returns:
629 True if the root device matched and on normal/dev boot;
630 otherwise, False.
631 """
632 return self.root_part_checker(part) and \
633 self.crossystem_checker({
634 'mainfw_type': ('normal', 'developer'),
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800635 })
636
637
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800638 def _join_part(self, dev, part):
639 """Return a concatenated string of device and partition number.
640
641 Args:
642 dev: A string of device, e.g.'/dev/sda'.
643 part: A string of partition number, e.g.'3'.
644
645 Returns:
646 A concatenated string of device and partition number, e.g.'/dev/sda3'.
647
648 >>> seq = FAFTSequence()
649 >>> seq._join_part('/dev/sda', '3')
650 '/dev/sda3'
651 >>> seq._join_part('/dev/mmcblk0', '2')
652 '/dev/mmcblk0p2'
653 """
654 if 'mmcblk' in dev:
655 return dev + 'p' + part
656 else:
657 return dev + part
658
659
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800660 def copy_kernel_and_rootfs(self, from_part, to_part):
661 """Copy kernel and rootfs from from_part to to_part.
662
663 Args:
664 from_part: A string of partition number to be copied from.
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800665 to_part: A string of partition number to be copied to.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800666 """
667 root_dev = self.faft_client.get_root_dev()
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800668 logging.info('Copying kernel from %s to %s. Please wait...' %
669 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800670 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800671 (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
672 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
673 logging.info('Copying rootfs from %s to %s. Please wait...' %
674 (from_part, to_part))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800675 self.faft_client.run_shell_command('dd if=%s of=%s bs=4M' %
Tom Wai-Hong Tamf2103be2011-11-10 07:26:56 +0800676 (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
677 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800678
679
680 def ensure_kernel_boot(self, part):
681 """Ensure the request kernel boot.
682
683 If not, it duplicates the current kernel to the requested kernel
684 and sets the requested higher priority to ensure it boot.
685
686 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800687 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800688 """
689 if not self.root_part_checker(part):
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800690 if self.faft_client.diff_kernel_a_b():
691 self.copy_kernel_and_rootfs(
692 from_part=self.OTHER_KERNEL_MAP[part],
693 to_part=part)
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800694 self.run_faft_step({
695 'userspace_action': (self.reset_and_prioritize_kernel, part),
696 })
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800697
698
Vic Yang416f2032012-08-28 10:18:03 +0800699 def set_hardware_write_protect(self, enabled):
Vic Yang2cabf812012-08-28 02:39:04 +0800700 """Set hardware write protect pin.
701
702 Args:
703 enable: True if asserting write protect pin. Otherwise, False.
704 """
705 self.servo.set('fw_wp_vref', self.client_attr.wp_voltage)
706 self.servo.set('fw_wp_en', 'on')
Vic Yang416f2032012-08-28 10:18:03 +0800707 self.servo.set('fw_wp', 'on' if enabled else 'off')
708
709
710 def set_EC_write_protect_and_reboot(self, enabled):
711 """Set EC write protect status and reboot to take effect.
712
713 EC write protect is only activated if both hardware write protect pin
714 is asserted and software write protect flag is set. Also, a reboot is
715 required for write protect to take effect.
716
717 Since the software write protect flag cannot be unset if hardware write
718 protect pin is asserted, we need to deasserted the pin first if we are
719 deactivating write protect. Similarly, a reboot is required before we
720 can modify the software flag.
721
722 This method asserts/deasserts hardware write protect pin first, and
723 set corresponding EC software write protect flag.
724
725 Args:
726 enable: True if activating EC write protect. Otherwise, False.
727 """
728 self.set_hardware_write_protect(enabled)
729 if enabled:
730 # Set write protect flag and reboot to take effect.
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800731 self.ec.send_command("flashwp enable")
Vic Yang416f2032012-08-28 10:18:03 +0800732 self.sync_and_ec_reboot()
733 else:
734 # Reboot after deasserting hardware write protect pin to deactivate
735 # write protect. And then remove software write protect flag.
736 self.sync_and_ec_reboot()
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800737 self.ec.send_command("flashwp disable")
Vic Yang2cabf812012-08-28 02:39:04 +0800738
739
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800740 def send_ctrl_d_to_dut(self):
741 """Send Ctrl-D key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800742 if self._customized_key_commands['ctrl_d']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800743 logging.info('running the customized Ctrl-D key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800744 os.system(self._customized_key_commands['ctrl_d'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800745 else:
746 self.servo.ctrl_d()
747
748
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800749 def send_ctrl_u_to_dut(self):
750 """Send Ctrl-U key to DUT.
751
752 Raises:
753 error.TestError: if a non-Chrome EC device or no Ctrl-U command given
754 on a no-build-in-keyboard device.
755 """
756 if self._customized_key_commands['ctrl_u']:
757 logging.info('running the customized Ctrl-U key command')
758 os.system(self._customized_key_commands['ctrl_u'])
759 elif self.check_ec_capability(['keyboard'], suppress_warning=True):
760 self.ec.key_down('<ctrl_l>')
761 self.ec.key_down('u')
762 self.ec.key_up('u')
763 self.ec.key_up('<ctrl_l>')
764 elif self.client_attr.has_keyboard:
765 raise error.TestError(
766 "Can't send Ctrl-U to DUT without using Chrome EC.")
767 else:
768 raise error.TestError(
769 "Should specify the ctrl_u_cmd argument.")
770
771
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800772 def send_enter_to_dut(self):
773 """Send Enter key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800774 if self._customized_key_commands['enter']:
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800775 logging.info('running the customized Enter key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800776 os.system(self._customized_key_commands['enter'])
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800777 else:
778 self.servo.enter_key()
779
780
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800781 def send_space_to_dut(self):
782 """Send Space key to DUT."""
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800783 if self._customized_key_commands['space']:
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800784 logging.info('running the customized Space key command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800785 os.system(self._customized_key_commands['space'])
Tom Wai-Hong Tam9e61e662012-08-01 15:10:07 +0800786 else:
787 # Send the alternative key combinaton of space key to servo.
788 self.servo.ctrl_refresh_key()
789
790
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800791 def wait_fw_screen_and_ctrl_d(self):
792 """Wait for firmware warning screen and press Ctrl-D."""
793 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam1db43832011-12-09 10:50:56 +0800794 self.send_ctrl_d_to_dut()
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800795
796
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800797 def wait_fw_screen_and_ctrl_u(self):
798 """Wait for firmware warning screen and press Ctrl-U."""
799 time.sleep(self.FIRMWARE_SCREEN_DELAY)
800 self.send_ctrl_u_to_dut()
801
802
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800803 def wait_fw_screen_and_trigger_recovery(self, need_dev_transition=False):
804 """Wait for firmware warning screen and trigger recovery boot."""
805 time.sleep(self.FIRMWARE_SCREEN_DELAY)
806 self.send_enter_to_dut()
807
808 # For Alex/ZGB, there is a dev warning screen in text mode.
809 # Skip it by pressing Ctrl-D.
810 if need_dev_transition:
811 time.sleep(self.TEXT_SCREEN_DELAY)
812 self.send_ctrl_d_to_dut()
813
814
Mike Truty49153d82012-08-21 22:27:30 -0500815 def wait_fw_screen_and_unplug_usb(self):
816 """Wait for firmware warning screen and then unplug the servo USB."""
Tom Wai-Hong Tama79574c2012-02-07 09:29:03 +0800817 time.sleep(self.USB_LOAD_DELAY)
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800818 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
819 time.sleep(self.USB_PLUG_DELAY)
Mike Truty49153d82012-08-21 22:27:30 -0500820
821
822 def wait_fw_screen_and_plug_usb(self):
823 """Wait for firmware warning screen and then unplug and plug the USB."""
824 self.wait_fw_screen_and_unplug_usb()
Tom Wai-Hong Tam5d2f4702011-12-06 10:42:31 +0800825 self.servo.set('usb_mux_sel1', 'dut_sees_usbkey')
826
827
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800828 def wait_fw_screen_and_press_power(self):
829 """Wait for firmware warning screen and press power button."""
830 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tam7317c042012-08-14 11:59:06 +0800831 # While the firmware screen, the power button probing loop sleeps
832 # 0.25 second on every scan. Use the normal delay (1.2 second) for
833 # power press.
834 self.servo.power_normal_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800835
836
Tom Wai-Hong Tam4f5e5922012-07-27 16:23:15 +0800837 def wait_longer_fw_screen_and_press_power(self):
838 """Wait for firmware screen without timeout and press power button."""
839 time.sleep(self.DEV_SCREEN_TIMEOUT)
840 self.wait_fw_screen_and_press_power()
841
842
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800843 def wait_fw_screen_and_close_lid(self):
844 """Wait for firmware warning screen and close lid."""
845 time.sleep(self.FIRMWARE_SCREEN_DELAY)
846 self.servo.lid_close()
847
848
Tom Wai-Hong Tam473cfa72012-07-27 17:16:57 +0800849 def wait_longer_fw_screen_and_close_lid(self):
850 """Wait for firmware screen without timeout and close lid."""
851 time.sleep(self.FIRMWARE_SCREEN_DELAY)
852 self.wait_fw_screen_and_close_lid()
853
854
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800855 def setup_tried_fwb(self, tried_fwb):
856 """Setup for fw B tried state.
857
858 It makes sure the system in the requested fw B tried state. If not, it
859 tries to do so.
860
861 Args:
862 tried_fwb: True if requested in tried_fwb=1; False if tried_fwb=0.
863 """
864 if tried_fwb:
865 if not self.crossystem_checker({'tried_fwb': '1'}):
866 logging.info(
867 'Firmware is not booted with tried_fwb. Reboot into it.')
868 self.run_faft_step({
869 'userspace_action': self.faft_client.set_try_fw_b,
870 })
871 else:
872 if not self.crossystem_checker({'tried_fwb': '0'}):
873 logging.info(
874 'Firmware is booted with tried_fwb. Reboot to clear.')
875 self.run_faft_step({})
876
877
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800878 def enable_rec_mode_and_reboot(self):
879 """Switch to rec mode and reboot.
880
881 This method emulates the behavior of the old physical recovery switch,
882 i.e. switch ON + reboot + switch OFF, and the new keyboard controlled
883 recovery mode, i.e. just press Power + Esc + Refresh.
884 """
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800885 if self._customized_key_commands['rec_reboot']:
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800886 logging.info('running the customized rec reboot command')
Tom Wai-Hong Tamadbec3e2012-10-15 14:20:15 +0800887 os.system(self._customized_key_commands['rec_reboot'])
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800888 elif self.client_attr.chrome_ec:
Vic Yang81273092012-08-21 15:57:09 +0800889 # Cold reset to clear EC_IN_RW signal
Vic Yanga7250662012-08-31 04:00:08 +0800890 self.servo.set('cold_reset', 'on')
891 time.sleep(self.COLD_RESET_DELAY)
892 self.servo.set('cold_reset', 'off')
893 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800894 self.ec.send_command("reboot ap-off")
Vic Yang611dd852012-08-02 15:36:31 +0800895 time.sleep(self.EC_BOOT_DELAY)
Tom Wai-Hong Tam6019a1a2012-10-12 14:03:34 +0800896 self.ec.send_command("hostevent set 0x4000")
Vic Yang611dd852012-08-02 15:36:31 +0800897 self.servo.power_short_press()
Tom Wai-Hong Tamac943172012-08-01 10:38:39 +0800898 else:
899 self.servo.enable_recovery_mode()
900 self.cold_reboot()
901 time.sleep(self.EC_REBOOT_DELAY)
902 self.servo.disable_recovery_mode()
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800903
904
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800905 def enable_dev_mode_and_reboot(self):
906 """Switch to developer mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800907 if self.client_attr.keyboard_dev:
908 self.enable_keyboard_dev_mode()
909 else:
910 self.servo.enable_development_mode()
911 self.faft_client.run_shell_command(
912 'chromeos-firmwareupdate --mode todev && reboot')
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800913
914
Tom Wai-Hong Tam0b9e6d72012-07-31 20:54:06 +0800915 def enable_normal_mode_and_reboot(self):
916 """Switch to normal mode and reboot."""
Vic Yange7553162012-06-20 16:20:47 +0800917 if self.client_attr.keyboard_dev:
918 self.disable_keyboard_dev_mode()
919 else:
920 self.servo.disable_development_mode()
921 self.faft_client.run_shell_command(
922 'chromeos-firmwareupdate --mode tonormal && reboot')
923
924
925 def wait_fw_screen_and_switch_keyboard_dev_mode(self, dev):
926 """Wait for firmware screen and then switch into or out of dev mode.
927
928 Args:
929 dev: True if switching into dev mode. Otherwise, False.
930 """
931 time.sleep(self.FIRMWARE_SCREEN_DELAY)
932 if dev:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800933 self.send_ctrl_d_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800934 else:
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800935 self.send_enter_to_dut()
Tom Wai-Hong Tam1408f172012-07-31 15:06:21 +0800936 time.sleep(self.FIRMWARE_SCREEN_DELAY)
Tom Wai-Hong Tamfe314ac2012-07-25 14:14:17 +0800937 self.send_enter_to_dut()
Vic Yange7553162012-06-20 16:20:47 +0800938
939
940 def enable_keyboard_dev_mode(self):
941 logging.info("Enabling keyboard controlled developer mode")
Tom Wai-Hong Tamf1a17d72012-07-26 11:39:52 +0800942 # Plug out USB disk for preventing recovery boot without warning
943 self.servo.set('usb_mux_sel1', 'servo_sees_usbkey')
Vic Yange7553162012-06-20 16:20:47 +0800944 # Rebooting EC with rec mode on. Should power on AP.
Tom Wai-Hong Tama373f802012-07-31 21:16:48 +0800945 self.enable_rec_mode_and_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800946 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800947 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=True)
Vic Yange7553162012-06-20 16:20:47 +0800948
949
950 def disable_keyboard_dev_mode(self):
951 logging.info("Disabling keyboard controlled developer mode")
Tom Wai-Hong Tamb0b3f412012-08-13 17:17:06 +0800952 if not self.client_attr.chrome_ec:
Vic Yang611dd852012-08-02 15:36:31 +0800953 self.servo.disable_recovery_mode()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +0800954 self.cold_reboot()
Tom Wai-Hong Tam8c54eb82012-08-01 10:31:07 +0800955 self.wait_for_client_offline()
Vic Yange7553162012-06-20 16:20:47 +0800956 self.wait_fw_screen_and_switch_keyboard_dev_mode(dev=False)
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +0800957
958
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800959 def setup_dev_mode(self, dev_mode):
960 """Setup for development mode.
961
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800962 It makes sure the system in the requested normal/dev mode. If not, it
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800963 tries to do so.
964
965 Args:
966 dev_mode: True if requested in dev mode; False if normal mode.
967 """
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800968 # Change the default firmware_action for dev mode passing the fw screen.
969 self.register_faft_template({
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800970 'firmware_action': (self.wait_fw_screen_and_ctrl_d if dev_mode
971 else None),
972 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800973 if dev_mode:
Vic Yange7553162012-06-20 16:20:47 +0800974 if (not self.client_attr.keyboard_dev and
975 not self.crossystem_checker({'devsw_cur': '1'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800976 logging.info('Dev switch is not on. Now switch it on.')
977 self.servo.enable_development_mode()
978 if not self.crossystem_checker({'devsw_boot': '1',
979 'mainfw_type': 'developer'}):
980 logging.info('System is not in dev mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800981 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800982 'userspace_action': None if self.client_attr.keyboard_dev
983 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800984 'chromeos-firmwareupdate --mode todev && reboot'),
Vic Yange7553162012-06-20 16:20:47 +0800985 'reboot_action': self.enable_keyboard_dev_mode if
986 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800987 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800988 else:
Vic Yange7553162012-06-20 16:20:47 +0800989 if (not self.client_attr.keyboard_dev and
990 not self.crossystem_checker({'devsw_cur': '0'})):
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +0800991 logging.info('Dev switch is not off. Now switch it off.')
992 self.servo.disable_development_mode()
993 if not self.crossystem_checker({'devsw_boot': '0',
994 'mainfw_type': 'normal'}):
995 logging.info('System is not in normal mode. Reboot into it.')
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +0800996 self.run_faft_step({
Vic Yange7553162012-06-20 16:20:47 +0800997 'userspace_action': None if self.client_attr.keyboard_dev
998 else (self.faft_client.run_shell_command,
Tom Wai-Hong Tamc7ecfca2011-12-06 11:12:31 +0800999 'chromeos-firmwareupdate --mode tonormal && reboot'),
Vic Yange7553162012-06-20 16:20:47 +08001000 'reboot_action': self.disable_keyboard_dev_mode if
1001 self.client_attr.keyboard_dev else None,
Tom Wai-Hong Tamfd590c92011-11-25 11:50:57 +08001002 })
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001003
1004
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001005 def setup_kernel(self, part):
1006 """Setup for kernel test.
1007
1008 It makes sure both kernel A and B bootable and the current boot is
1009 the requested kernel part.
1010
1011 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001012 part: A string of kernel partition number or 'a'/'b'.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001013 """
1014 self.ensure_kernel_boot(part)
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +08001015 if self.faft_client.diff_kernel_a_b():
1016 self.copy_kernel_and_rootfs(from_part=part,
1017 to_part=self.OTHER_KERNEL_MAP[part])
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001018 self.reset_and_prioritize_kernel(part)
1019
1020
1021 def reset_and_prioritize_kernel(self, part):
1022 """Make the requested partition highest priority.
1023
1024 This function also reset kerenl A and B to bootable.
1025
1026 Args:
Tom Wai-Hong Tama9c1a502011-11-10 06:39:26 +08001027 part: A string of partition number to be prioritized.
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001028 """
1029 root_dev = self.faft_client.get_root_dev()
1030 # Reset kernel A and B to bootable.
1031 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1032 (self.KERNEL_MAP['a'], root_dev))
1033 self.faft_client.run_shell_command('cgpt add -i%s -P1 -S1 -T0 %s' %
1034 (self.KERNEL_MAP['b'], root_dev))
1035 # Set kernel part highest priority.
1036 self.faft_client.run_shell_command('cgpt prioritize -i%s %s' %
1037 (self.KERNEL_MAP[part], root_dev))
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001038 # Safer to sync and wait until the cgpt status written to the disk.
1039 self.faft_client.run_shell_command('sync')
1040 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +08001041
1042
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001043 def warm_reboot(self):
1044 """Request a warm reboot.
1045
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001046 A wrapper for underlying servo warm reset.
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001047 """
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001048 # Use cold reset if the warm reset is broken.
1049 if self.client_attr.broken_warm_reset:
Gediminas Ramanauskase021e152012-09-04 19:10:59 -07001050 logging.info('broken_warm_reset is True. Cold rebooting instead.')
1051 self.cold_reboot()
Tom Wai-Hong Tamb06f0802012-07-31 16:27:50 +08001052 else:
1053 self.servo.warm_reset()
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001054
1055
1056 def cold_reboot(self):
1057 """Request a cold reboot.
1058
1059 A wrapper for underlying servo cold reset.
1060 """
Tom Wai-Hong Tama276d0a2012-08-22 11:15:17 +08001061 if self.client_attr.platform == 'Parrot':
1062 self.servo.set('pwr_button', 'press')
1063 self.servo.set('cold_reset', 'on')
1064 self.servo.set('cold_reset', 'off')
1065 time.sleep(self.POWER_BTN_DELAY)
1066 self.servo.set('pwr_button', 'release')
Tom Wai-Hong Tamb8a91392012-09-27 10:45:32 +08001067 elif self.check_ec_capability(suppress_warning=True):
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001068 # We don't use servo.cold_reset() here because software sync is
1069 # not yet finished, and device may or may not come up after cold
1070 # reset. Pressing power button before firmware comes up solves this.
1071 #
1072 # The correct behavior should be (not work now):
1073 # - If rebooting EC with rec mode on, power on AP and it boots
1074 # into recovery mode.
1075 # - If rebooting EC with rec mode off, power on AP for software
1076 # sync. Then AP checks if lid open or not. If lid open, continue;
1077 # otherwise, shut AP down and need servo for a power button
1078 # press.
1079 self.servo.set('cold_reset', 'on')
1080 self.servo.set('cold_reset', 'off')
1081 time.sleep(self.POWER_BTN_DELAY)
1082 self.servo.power_short_press()
1083 else:
1084 self.servo.cold_reset()
1085
1086
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001087 def sync_and_warm_reboot(self):
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001088 """Request the client sync and do a warm reboot.
1089
1090 This is the default reboot action on FAFT.
1091 """
1092 self.faft_client.run_shell_command('sync')
Tom Wai-Hong Tam6a863ba2011-12-08 10:13:28 +08001093 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001094 self.warm_reboot()
Tom Wai-Hong Tamf1e34972011-11-02 17:07:04 +08001095
1096
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001097 def sync_and_cold_reboot(self):
1098 """Request the client sync and do a cold reboot.
1099
1100 This reboot action is used to reset EC for recovery mode.
1101 """
1102 self.faft_client.run_shell_command('sync')
1103 time.sleep(self.SYNC_DELAY)
Tom Wai-Hong Tam7ad99ab2012-07-30 19:30:51 +08001104 self.cold_reboot()
Tom Wai-Hong Tamb21b6b42012-07-26 10:46:30 +08001105
1106
Vic Yangaeb10392012-08-28 09:25:09 +08001107 def sync_and_ec_reboot(self, args=''):
1108 """Request the client sync and do a EC triggered reboot.
1109
1110 Args:
1111 args: Arguments passed to "ectool reboot_ec". Including:
1112 RO: jump to EC RO firmware.
1113 RW: jump to EC RW firmware.
1114 cold: Cold/hard reboot.
1115 """
Vic Yang59cac9c2012-05-21 15:28:42 +08001116 self.faft_client.run_shell_command('sync')
1117 time.sleep(self.SYNC_DELAY)
Vic Yangaeb10392012-08-28 09:25:09 +08001118 # Since EC reboot happens immediately, delay before actual reboot to
1119 # allow FAFT client returning.
1120 self.faft_client.run_shell_command('(sleep %d; ectool reboot_ec %s)&' %
1121 (self.EC_REBOOT_DELAY, args))
Vic Yangf86728a2012-07-30 10:44:07 +08001122 time.sleep(self.EC_REBOOT_DELAY)
1123 self.check_lid_and_power_on()
1124
1125
Tom Wai-Hong Tamc8f2ca02012-09-14 11:18:01 +08001126 def full_power_off_and_on(self):
1127 """Shutdown the device by pressing power button and power on again."""
1128 # Press power button to trigger Chrome OS normal shutdown process.
1129 self.servo.power_normal_press()
1130 time.sleep(self.FULL_POWER_OFF_DELAY)
1131 # Short press power button to boot DUT again.
1132 self.servo.power_short_press()
1133
1134
Vic Yangf86728a2012-07-30 10:44:07 +08001135 def check_lid_and_power_on(self):
1136 """
1137 On devices with EC software sync, system powers on after EC reboots if
1138 lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
1139 This method checks lid switch state and presses power button if
1140 necessary.
1141 """
1142 if self.servo.get("lid_open") == "no":
1143 time.sleep(self.SOFTWARE_SYNC_DELAY)
1144 self.servo.power_short_press()
Vic Yang59cac9c2012-05-21 15:28:42 +08001145
1146
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001147 def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
1148 """Modify the kernel header magic in USB stick.
1149
1150 The kernel header magic is the first 8-byte of kernel partition.
1151 We modify it to make it fail on kernel verification check.
1152
1153 Args:
1154 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1155 from_magic: A string of magic which we change it from.
1156 to_magic: A string of magic which we change it to.
1157
1158 Raises:
1159 error.TestError: if failed to change magic.
1160 """
1161 assert len(from_magic) == 8
1162 assert len(to_magic) == 8
Tom Wai-Hong Tama1d9a0f2011-12-23 09:13:33 +08001163 # USB image only contains one kernel.
1164 kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001165 read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
1166 current_magic = utils.system_output(read_cmd)
1167 if current_magic == to_magic:
1168 logging.info("The kernel magic is already %s." % current_magic)
1169 return
1170 if current_magic != from_magic:
1171 raise error.TestError("Invalid kernel image on USB: wrong magic.")
1172
1173 logging.info('Modify the kernel magic in USB, from %s to %s.' %
1174 (from_magic, to_magic))
1175 write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
1176 " 2>/dev/null" % (to_magic, kernel_part))
1177 utils.system(write_cmd)
1178
1179 if utils.system_output(read_cmd) != to_magic:
1180 raise error.TestError("Failed to write new magic.")
1181
1182
1183 def corrupt_usb_kernel(self, usb_dev):
1184 """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
1185
1186 Args:
1187 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1188 """
1189 self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
1190 self.CORRUPTED_MAGIC)
1191
1192
1193 def restore_usb_kernel(self, usb_dev):
1194 """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1195
1196 Args:
1197 usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1198 """
1199 self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1200 self.CHROMEOS_MAGIC)
1201
1202
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001203 def _call_action(self, action_tuple, check_status=False):
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001204 """Call the action function with/without arguments.
1205
1206 Args:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001207 action_tuple: A function, or a tuple (function, args, error_msg),
1208 in which, args and error_msg are optional. args is
1209 either a value or a tuple if multiple arguments.
1210 check_status: Check the return value of action function. If not
1211 succeed, raises a TestFail exception.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001212
1213 Returns:
1214 The result value of the action function.
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001215
1216 Raises:
1217 error.TestError: An error when the action function is not callable.
1218 error.TestFail: When check_status=True, action function not succeed.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001219 """
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001220 action = action_tuple
1221 args = ()
1222 error_msg = 'Not succeed'
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001223 if isinstance(action_tuple, tuple):
1224 action = action_tuple[0]
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001225 if len(action_tuple) >= 2:
1226 args = action_tuple[1]
1227 if not isinstance(args, tuple):
1228 args = (args,)
1229 if len(action_tuple) >= 3:
Tom Wai-Hong Tamff560882012-10-15 16:50:06 +08001230 error_msg = action_tuple[2]
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001231
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001232 if action is None:
1233 return
1234
1235 if not callable(action):
1236 raise error.TestError('action is not callable!')
1237
1238 info_msg = 'calling %s' % str(action)
1239 if args:
1240 info_msg += ' with args %s' % str(args)
1241 logging.info(info_msg)
1242 ret = action(*args)
1243
1244 if check_status and not ret:
1245 raise error.TestFail('%s: %s returning %s' %
1246 (error_msg, info_msg, str(ret)))
1247 return ret
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001248
1249
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001250 def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1251 post_power_action=None):
1252 """Run shutdown_action(), which makes DUT shutdown, and power it on.
1253
1254 Args:
1255 shutdown_action: a function which makes DUT shutdown, like pressing
1256 power key.
1257 pre_power_action: a function which is called before next power on.
1258 post_power_action: a function which is called after next power on.
1259
1260 Raises:
1261 error.TestFail: if the shutdown_action() failed to turn DUT off.
1262 """
1263 self._call_action(shutdown_action)
1264 logging.info('Wait to ensure DUT shut down...')
1265 try:
1266 self.wait_for_client()
1267 raise error.TestFail(
1268 'Should shut the device down after calling %s.' %
1269 str(shutdown_action))
1270 except AssertionError:
1271 logging.info(
1272 'DUT is surely shutdown. We are going to power it on again...')
1273
1274 if pre_power_action:
1275 self._call_action(pre_power_action)
Tom Wai-Hong Tam610262a2012-01-12 14:16:53 +08001276 self.servo.power_short_press()
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001277 if post_power_action:
1278 self._call_action(post_power_action)
1279
1280
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001281 def register_faft_template(self, template):
1282 """Register FAFT template, the default FAFT_STEP of each step.
1283
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001284 Any missing field falls back to the original faft_template.
1285
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001286 Args:
1287 template: A FAFT_STEP dict.
1288 """
Tom Wai-Hong Tam109f63c2011-12-08 14:58:27 +08001289 self._faft_template.update(template)
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001290
1291
1292 def register_faft_sequence(self, sequence):
1293 """Register FAFT sequence.
1294
1295 Args:
1296 sequence: A FAFT_SEQUENCE array which consisted of FAFT_STEP dicts.
1297 """
1298 self._faft_sequence = sequence
1299
1300
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001301 def run_faft_step(self, step, no_reboot=False):
1302 """Run a single FAFT step.
1303
1304 Any missing field falls back to faft_template. An empty step means
1305 running the default faft_template.
1306
1307 Args:
1308 step: A FAFT_STEP dict.
1309 no_reboot: True to prevent running reboot_action and firmware_action.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001310
1311 Raises:
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001312 error.TestError: An error when the given step is not valid.
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001313 """
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001314 FAFT_STEP_KEYS = ('state_checker', 'userspace_action', 'reboot_action',
1315 'firmware_action', 'install_deps_after_boot')
1316
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001317 test = {}
1318 test.update(self._faft_template)
1319 test.update(step)
1320
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001321 for key in test:
1322 if key not in FAFT_STEP_KEYS:
Tom Wai-Hong Tam78709592011-12-19 11:16:50 +08001323 raise error.TestError('Invalid key in FAFT step: %s', key)
Tom Wai-Hong Tamd8445dc2011-12-15 09:00:04 +08001324
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001325 if test['state_checker']:
Tom Wai-Hong Tamfc700b52012-09-13 21:33:52 +08001326 self._call_action(test['state_checker'], check_status=True)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001327
1328 self._call_action(test['userspace_action'])
1329
1330 # Don't run reboot_action and firmware_action if no_reboot is True.
1331 if not no_reboot:
1332 self._call_action(test['reboot_action'])
1333 self.wait_for_client_offline()
1334 self._call_action(test['firmware_action'])
1335
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001336 try:
1337 if 'install_deps_after_boot' in test:
1338 self.wait_for_client(
1339 install_deps=test['install_deps_after_boot'])
1340 else:
1341 self.wait_for_client()
1342 except AssertionError:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001343 logging.info('wait_for_client() timed out.')
Vic Yang8eaf5ad2012-09-13 14:05:37 +08001344 self.reset_client()
1345 raise
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001346
1347
1348 def run_faft_sequence(self):
1349 """Run FAFT sequence which was previously registered."""
Tom Wai-Hong Tama70f0fe2011-09-02 18:28:47 +08001350 sequence = self._faft_sequence
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001351 index = 1
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001352 for step in sequence:
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001353 logging.info('======== Running FAFT sequence step %d ========' %
1354 index)
Tom Wai-Hong Tam2c50dff2011-11-11 07:01:01 +08001355 # Don't reboot in the last step.
1356 self.run_faft_step(step, no_reboot=(step is sequence[-1]))
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +08001357 index += 1
ctchang38ae4922012-09-03 17:01:16 +08001358
1359
ctchang38ae4922012-09-03 17:01:16 +08001360 def get_current_firmware_sha(self):
1361 """Get current firmware sha of body and vblock.
1362
1363 Returns:
1364 Current firmware sha follows the order (
1365 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1366 """
1367 current_firmware_sha = (self.faft_client.get_firmware_sig_sha('a'),
1368 self.faft_client.get_firmware_sha('a'),
1369 self.faft_client.get_firmware_sig_sha('b'),
1370 self.faft_client.get_firmware_sha('b'))
1371 return current_firmware_sha
1372
1373
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001374 def is_firmware_changed(self):
1375 """Check if the current firmware changed, by comparing its SHA.
ctchang38ae4922012-09-03 17:01:16 +08001376
1377 Returns:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001378 True if it is changed, otherwise Flase.
ctchang38ae4922012-09-03 17:01:16 +08001379 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001380 # Device may not be rebooted after test.
1381 self.faft_client.reload_firmware()
ctchang38ae4922012-09-03 17:01:16 +08001382
1383 current_sha = self.get_current_firmware_sha()
1384
1385 if current_sha == self._backup_firmware_sha:
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001386 return False
ctchang38ae4922012-09-03 17:01:16 +08001387 else:
ctchang38ae4922012-09-03 17:01:16 +08001388 corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1389 corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1390 corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1391 corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001392 logging.info("Firmware changed:")
1393 logging.info('VBOOTA is changed: %s' % corrupt_VBOOTA)
1394 logging.info('VBOOTB is changed: %s' % corrupt_VBOOTB)
1395 logging.info('FVMAIN is changed: %s' % corrupt_FVMAIN)
1396 logging.info('FVMAINB is changed: %s' % corrupt_FVMAINB)
1397 return True
ctchang38ae4922012-09-03 17:01:16 +08001398
1399
1400 def backup_firmware(self, suffix='.original'):
1401 """Backup firmware to file, and then send it to host.
1402
1403 Args:
1404 suffix: a string appended to backup file name
1405 """
1406 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001407 self.faft_client.dump_firmware(os.path.join(remote_temp_dir, 'bios'))
1408 self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1409 os.path.join(self.resultsdir, 'bios' + suffix))
ctchang38ae4922012-09-03 17:01:16 +08001410
1411 self._backup_firmware_sha = self.get_current_firmware_sha()
1412 logging.info('Backup firmware stored in %s with suffix %s' % (
1413 self.resultsdir, suffix))
1414
1415
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001416 def is_firmware_saved(self):
1417 """Check if a firmware saved (called backup_firmware before).
1418
1419 Returns:
1420 True if the firmware is backuped; otherwise False.
1421 """
1422 return self._backup_firmware_sha != ()
1423
1424
ctchang38ae4922012-09-03 17:01:16 +08001425 def restore_firmware(self, suffix='.original'):
1426 """Restore firmware from host in resultsdir.
1427
1428 Args:
1429 suffix: a string appended to backup file name
1430 """
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001431 if not self.is_firmware_changed():
ctchang38ae4922012-09-03 17:01:16 +08001432 return
1433
1434 # Backup current corrupted firmware.
1435 self.backup_firmware(suffix='.corrupt')
1436
1437 # Restore firmware.
1438 remote_temp_dir = self.faft_client.create_temp_dir()
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001439 self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1440 os.path.join(remote_temp_dir, 'bios'))
ctchang38ae4922012-09-03 17:01:16 +08001441
Chun-ting Chang9380c2c2012-10-05 17:31:05 +08001442 self.faft_client.write_firmware(os.path.join(remote_temp_dir, 'bios'))
Tom Wai-Hong Tame6232342012-09-24 16:18:01 +08001443 self.sync_and_warm_reboot()
1444 self.wait_for_client_offline()
1445 self.wait_for_client()
1446
ctchang38ae4922012-09-03 17:01:16 +08001447 logging.info('Successfully restore firmware.')
Chun-ting Changf91ee0f2012-09-17 18:31:54 +08001448
1449
1450 def setup_firmwareupdate_shellball(self, shellball=None):
1451 """Deside a shellball to use in firmware update test.
1452
1453 Check if there is a given shellball, and it is a shell script. Then,
1454 send it to the remote host. Otherwise, use
1455 /usr/sbin/chromeos-firmwareupdate.
1456
1457 Args:
1458 shellball: path of a shellball or default to None.
1459
1460 Returns:
1461 Path of shellball in remote host.
1462 If use default shellball, reutrn None.
1463 """
1464 updater_path = None
1465 if shellball:
1466 # Determine the firmware file is a shellball or a raw binary.
1467 is_shellball = (utils.system_output("file %s" % shellball).find(
1468 "shell script") != -1)
1469 if is_shellball:
1470 logging.info('Device will update firmware with shellball %s'
1471 % shellball)
1472 temp_dir = self.faft_client.create_temp_dir('shellball_')
1473 temp_shellball = os.path.join(temp_dir, 'updater.sh')
1474 self._client.send_file(shellball, temp_shellball)
1475 updater_path = temp_shellball
1476 else:
1477 raise error.TestFail(
1478 'The given shellball is not a shell script.')
1479 return updater_path