=== modified file 'lava_dispatcher/config.py'
@@ -97,6 +97,13 @@
fastboot_command = schema.StringOption()
shared_working_directory = schema.StringOption(default=None)
+ uefi_image_filename = schema.StringOption(default=None)
+ vexpress_uefi_path = schema.StringOption(default=None)
+ vexpress_uefi_backup_path = schema.StringOption(default=None)
+ vexpress_stop_autoboot_prompt = schema.StringOption(
+ default='Press Enter to stop auto boot...')
+ vexpress_usb_mass_storage_device = schema.StringOption(default=None)
+
class OptionDescriptor(object):
def __init__(self, name):
self.name = name
=== modified file 'lava_dispatcher/default-config/lava-dispatcher/device-types/vexpress-tc2.conf'
@@ -1,3 +1,5 @@
+client_type = vexpress
+
boot_cmds = 2
boot_cmds_android = 3
@@ -15,3 +17,11 @@
fstab.partitions
init.rc
fstab.arm-versatileexpress
+
+uefi_image_filename = uefi_v2p-ca15-tc2.bin
+
+vexpress_uefi_path = SOFTWARE/TC2/uefi.bin
+
+vexpress_uefi_backup_path = SOFTWARE/TC2/backup-uefi.bin
+
+vexpress_usb_mass_storage_device = /dev/disk/by-label/VEMSD
=== modified file 'lava_dispatcher/device/master.py'
@@ -112,6 +112,17 @@
system = download_image(system, self.context, sdir, decompress=False)
data = download_image(userdata, self.context, sdir, decompress=False)
+ with self._as_master() as master:
+ self._format_testpartition(master, 'ext4')
+ self._deploy_android_tarballs(master, boot, system, data)
+
+ if master.has_partition_with_label('userdata') and \
+ master.has_partition_with_label('sdcard'):
+ _purge_linaro_android_sdcard(master)
+
+ self.deployment_data = Target.android_deployment_data
+
+ def _deploy_android_tarballs(self, master, boot, system, data):
tmpdir = self.context.config.lava_image_tmpdir
url = self.context.config.lava_image_url
@@ -123,17 +134,9 @@
system_url = '/'.join(u.strip('/') for u in [url, system])
data_url = '/'.join(u.strip('/') for u in [url, data])
- with self._as_master() as master:
- self._format_testpartition(master, 'ext4')
- _deploy_linaro_android_boot(master, boot_url, self)
- _deploy_linaro_android_system(master, system_url)
- _deploy_linaro_android_data(master, data_url)
-
- if master.has_partition_with_label('userdata') and \
- master.has_partition_with_label('sdcard'):
- _purge_linaro_android_sdcard(master)
-
- self.deployment_data = Target.android_deployment_data
+ _deploy_linaro_android_boot(master, boot_url, self)
+ _deploy_linaro_android_system(master, system_url)
+ _deploy_linaro_android_data(master, data_url)
def deploy_linaro_prebuilt(self, image):
self.boot_master_image()
@@ -402,9 +405,9 @@
self.proc.sendline("hardreset")
self.proc.empty_buffer()
- def _enter_uboot(self):
+ def _enter_bootloader(self):
if self.proc.expect(self.config.interrupt_boot_prompt) != 0:
- raise Exception("Failed to enter uboot")
+ raise Exception("Failed to enter bootloader")
self.proc.sendline(self.config.interrupt_boot_command)
def _boot_linaro_image(self):
@@ -421,11 +424,11 @@
def _boot(self, boot_cmds):
try:
self._soft_reboot()
- self._enter_uboot()
+ self._enter_bootloader()
except:
- logging.exception("_enter_uboot failed")
+ logging.exception("_enter_bootloader failed")
self._hard_reboot()
- self._enter_uboot()
+ self._enter_bootloader()
self.proc.sendline(boot_cmds[0])
for line in range(1, len(boot_cmds)):
self.proc.expect(self.config.bootloader_prompt, timeout=300)
=== added file 'lava_dispatcher/device/vexpress.py'
@@ -0,0 +1,193 @@
+# Copyright (C) 2013 Linaro Limited
+#
+# Author: Antonio Terceiro <antonio.terceiro@linaro.org>
+#
+# This file is part of LAVA Dispatcher.
+#
+# LAVA Dispatcher is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LAVA Dispatcher is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along
+# with this program; if not, see <http://www.gnu.org/licenses>.
+
+import pexpect
+import os
+import logging
+from time import sleep
+from contextlib import contextmanager
+
+from lava_dispatcher.device.master import MasterImageTarget
+from lava_dispatcher.errors import CriticalError
+
+class VexpressTarget(MasterImageTarget):
+
+ def __init__(self, context, config):
+ super(VexpressTarget, self).__init__(context, config)
+
+ self.test_uefi = None
+
+ if (self.config.uefi_image_filename is None or
+ self.config.vexpress_uefi_path is None or
+ self.config.vexpress_uefi_backup_path is None or
+ self.config.vexpress_usb_mass_storage_device is None):
+
+ raise CriticalError(
+ "Versatile Express devices must specify all "
+ "of the following configuration variables: "
+ "uefi_image_filename, vexpress_uefi_path, "
+ "vexpress_uefi_backup_path, and "
+ "vexpress_usb_mass_storage_device")
+
+ ##################################################################
+ # methods inherited from MasterImageTarget and overriden here
+ ##################################################################
+
+ def _soft_reboot(self):
+ """
+ The Vexpress board only displays the prompt to interrupt the MCC when
+ it is power-cycled, so we must always do a hard reset in practice.
+
+ When a soft reboot is requested, though, at least we sync the disks
+ before sending the hard reset.
+ """
+ # Try to C-c the running process, if any
+ self.proc.sendcontrol('c')
+ # Flush file system buffers
+ self.proc.sendline('sync')
+
+ self._hard_reboot()
+
+ def _enter_bootloader(self):
+ with self._mcc_setup() as mount_point:
+ self._install_test_uefi(mount_point)
+
+ super(VexpressTarget, self)._enter_bootloader()
+
+ def _wait_for_master_boot(self):
+ with self._mcc_setup() as mount_point:
+ self._restore_uefi_backup(mount_point)
+
+ super(VexpressTarget, self)._wait_for_master_boot()
+
+ def _deploy_android_tarballs(self, master, boot, system, data):
+ super(VexpressTarget, self)._deploy_android_tarballs(master, boot,
+ system, data)
+ # android images have boot files inside boot/ in the tarball
+ uefi_on_image = os.path.join('boot', self.config.uefi_image_filename)
+ self._extract_uefi_from_tarball(boot, uefi_on_image)
+
+ def _deploy_tarballs(self, boot_tgz, root_tgz):
+ super(VexpressTarget, self)._deploy_tarballs(boot_tgz, root_tgz)
+ uefi_on_image = self.config.uefi_image_filename
+ self._extract_uefi_from_tarball(boot_tgz, uefi_on_image)
+
+ ##################################################################
+ # implementation-specific methods
+ ##################################################################
+
+ @contextmanager
+ def _mcc_setup(self):
+ """
+ This method will manage the context for manipulating the USB mass
+ storage device, and pass the mount point where the USB MSD is mounted
+ to the inner block.
+
+ Example:
+
+ with self._mcc_setup() as mount_point:
+ do_stuff_with(mount_point)
+
+
+ This can be used for example to copy files from/to the USB MSD.
+ Mounting and unmounting is managed by this method, so the inner block
+ does not have to handle that.
+ """
+
+ mount_point = os.path.join(self.scratch_dir, 'vexpress-usb')
+ if not os.path.exists(mount_point):
+ os.makedirs(mount_point)
+
+ self._enter_mcc()
+ self._mount_usbmsd(mount_point)
+ try:
+ yield mount_point
+ finally:
+ self._umount_usbmsd(mount_point)
+ self._leave_mcc()
+
+ def _enter_mcc(self):
+ match_id = self.proc.expect([
+ self.config.vexpress_stop_autoboot_prompt,
+ pexpect.EOF, pexpect.TIMEOUT])
+ if match_id != 0:
+ msg = 'Unable to intercept MCC boot prompt'
+ logging.error(msg)
+ raise CriticalError(msg)
+ self.proc.sendline("")
+ self.proc.expect(['Cmd>'])
+
+ def _mount_usbmsd(self, mount_point):
+ self.proc.sendline("USB_ON")
+ self.proc.expect(['Cmd>'])
+
+ # wait a few seconds so that the kernel on the host detects the USB
+ # mass storage interface exposed by the Vexpress
+ sleep(5)
+
+ usb_device = self.config.vexpress_usb_mass_storage_device
+
+ self.context.run_command('mount %s %s' % (usb_device, mount_point))
+
+ def _umount_usbmsd(self, mount_point):
+ self.context.run_command('umount %s' % mount_point)
+
+ def _leave_mcc(self):
+ self.proc.sendline("reboot")
+
+ def _extract_uefi_from_tarball(self, tarball, uefi_on_image):
+ tmpdir = self.scratch_dir
+
+ # Android boot tarballs have the UEFI binary at boot/*.bin, while
+ # Ubuntu ones have it at ./*.bin
+ #
+ # --no-anchored matches the name inside any directory in the tarball.
+ self.context.run_command('tar --no-anchored -xaf %s -C %s %s' % (tarball, tmpdir,
+ uefi_on_image))
+
+ uefi_on_image = os.path.join(tmpdir, uefi_on_image)
+ test_uefi = os.path.join(tmpdir, 'uefi.bin')
+ self.context.run_command('mv %s %s' % (uefi_on_image, test_uefi))
+
+ self.test_uefi = test_uefi
+
+ def _restore_uefi_backup(self, mount_point):
+ uefi_path = self.config.vexpress_uefi_path
+ uefi = os.path.join(mount_point, uefi_path)
+ uefi_backup_path = self.config.vexpress_uefi_backup_path
+ uefi_backup = os.path.join(mount_point, uefi_backup_path)
+
+ if os.path.exists(uefi_backup):
+ # restore the uefi backup
+ self.context.run_command('cp %s %s' % (uefi_backup, uefi))
+ else:
+ # no existing backup yet means that this is the first time ever;
+ # the uefi in there is the good one, and we backup it up.
+ self.context.run_command('cp %s %s' % (uefi, uefi_backup))
+
+ def _install_test_uefi(self, mount_point):
+ uefi_path = self.config.vexpress_uefi_path
+ uefi = os.path.join(mount_point, uefi_path)
+ # FIXME what if self.test_uefi is not set, or points to an unexisting
+ # file?
+ self.context.run_command('cp %s %s' % (self.test_uefi, uefi))
+
+
+target_class = VexpressTarget