Commit e4bd0f73 authored by Matt Hart's avatar Matt Hart Committed by Neil Williams

Add support for u-boot usb mass storage flashing for warp7

- new deploy strategy for u-boot ums images
- use existing u-boot support to start the ums
- use existing udev support to wait for the ums device

Change-Id: I476862989bc98fc1c73fbf2086805a8633c76b29
(cherry picked from commit 624b0778)
parent f672dcc0
......@@ -666,11 +666,12 @@ class BootloaderCommandsAction(Action):
description = "send commands to bootloader"
summary = "interactive bootloader"
def __init__(self):
def __init__(self, expect_final=True):
super(BootloaderCommandsAction, self).__init__()
self.params = None
self.timeout = Timeout(self.name, BOOTLOADER_DEFAULT_CMD_TIMEOUT)
self.method = ""
self.expect_final = expect_final
def validate(self):
super(BootloaderCommandsAction, self).validate()
......@@ -704,7 +705,7 @@ class BootloaderCommandsAction(Action):
raise InfrastructureError('matched a bootloader error message')
i += 1
if final_message:
if final_message and self.expect_final:
connection.prompt_str = final_message
self.wait(connection, max_end_time)
......
......@@ -43,6 +43,8 @@ from lava_dispatcher.connections.lxc import ConnectLxc
from lava_dispatcher.connections.serial import ConnectDevice
from lava_dispatcher.power import ResetDevice
from lava_dispatcher.utils.strings import map_kernel_uboot
from lava_dispatcher.utils.storage import FlashUBootUMSAction
from lava_dispatcher.utils.udev import WaitDevicePathAction
class UBoot(Boot):
......@@ -109,10 +111,18 @@ class UBootRetry(BootAction):
def populate(self, parameters):
self.internal_pipeline = Pipeline(parent=self, job=self.job, parameters=parameters)
self.method_params = self.job.device['actions']['boot']['methods']['u-boot']['parameters']
self.usb_mass_device = self.method_params.get('uboot_mass_storage_device', None)
# establish a new connection before trying the reset
self.internal_pipeline.add_action(ResetDevice())
self.internal_pipeline.add_action(BootloaderInterruptAction())
self.internal_pipeline.add_action(BootloaderCommandsAction())
if self.method_params.get('uboot_ums_flash', False):
self.internal_pipeline.add_action(BootloaderCommandsAction(expect_final=False))
self.internal_pipeline.add_action(WaitDevicePathAction(self.usb_mass_device))
self.internal_pipeline.add_action(FlashUBootUMSAction(self.usb_mass_device))
self.internal_pipeline.add_action(ResetDevice())
else:
self.internal_pipeline.add_action(BootloaderCommandsAction())
if self.has_prompts(parameters):
self.internal_pipeline.add_action(AutoLoginAction())
if self.test_has_shell(parameters):
......
......@@ -33,4 +33,5 @@ from lava_dispatcher.actions.deploy.nbd import Nbd
from lava_dispatcher.actions.deploy.nfs import Nfs
from lava_dispatcher.actions.deploy.ssh import Ssh
from lava_dispatcher.actions.deploy.tftp import Tftp
from lava_dispatcher.actions.deploy.uboot_ums import UBootUMS
from lava_dispatcher.actions.deploy.vemsd import VExpressMsd
# Copyright (C) 2018 Linaro Limited
#
# Author: Matthew Hart <matthew.hart@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>.
from lava_dispatcher.logical import Deployment
from lava_dispatcher.action import Pipeline
from lava_dispatcher.actions.deploy import DeployAction
from lava_dispatcher.actions.deploy.environment import DeployDeviceEnvironment
from lava_dispatcher.actions.deploy.overlay import OverlayAction
from lava_dispatcher.actions.deploy.apply_overlay import ApplyOverlayImage
from lava_dispatcher.actions.deploy.download import DownloaderAction
# pylint: disable=too-many-return-statements,too-many-instance-attributes,missing-docstring
class UBootUMS(Deployment):
"""
Strategy class for a UBoot USB Mass Storage deployment.
Downloads the relevant parts, and applies the test overlay into the image.
"""
compatibility = 1
name = 'uboot-ums'
def __init__(self, parent, parameters):
super(UBootUMS, self).__init__(parent)
self.action = UBootUMSAction()
self.action.section = self.action_type
self.action.job = self.job
parent.add_action(self.action, parameters)
@classmethod
def accepts(cls, device, parameters):
if 'to' not in parameters:
return False, '"to" is not in deploy parameters'
if parameters['to'] != 'u-boot-ums':
return False, '"to" parameter is not "u-boot-ums"'
if 'deploy' not in device['actions']:
return False, '"deploy" is not in the device configuration actions'
if 'image' not in parameters:
return False, '"image" was not in the deploy parameters'
if 'u-boot-ums' in device['actions']['deploy']['methods']:
return True, 'accepted'
return False, '"u-boot-ums" was not in the device configuration deploy methods"'
class UBootUMSAction(DeployAction): # pylint:disable=too-many-instance-attributes
name = "uboot-ums-deploy"
description = "download image and deploy using uboot mass storage emulation"
summary = "uboot-ums deployment"
def __init__(self):
super(UBootUMSAction, self).__init__()
def populate(self, parameters):
self.internal_pipeline = Pipeline(parent=self, job=self.job, parameters=parameters)
path = self.mkdtemp()
self.internal_pipeline.add_action(DownloaderAction('image', path=path))
if self.test_needs_overlay(parameters):
self.internal_pipeline.add_action(OverlayAction())
self.internal_pipeline.add_action(ApplyOverlayImage())
if self.test_needs_deployment(parameters):
self.internal_pipeline.add_action(DeployDeviceEnvironment())
actions:
boot:
connections: {lxc: null, serial: null}
methods:
minimal: null
ssh: null
u-boot:
nbd:
commands: [setenv autoload no, setenv initrd_high 0xffffffff, setenv fdt_high
0xffffffff, dhcp, 'setenv serverip {SERVER_IP}', 'tftp {KERNEL_ADDR}
{KERNEL}', 'tftp {RAMDISK_ADDR} {RAMDISK}', 'setenv initrd_size ${filesize}',
'tftp {DTB_ADDR} {DTB}', 'setenv bootargs '' rw nbd.server={NBDSERVERIP}
nbd.port={NBDSERVERPORT} root=/dev/ram0 ramdisk_size=16384 rootdelay=7 ip=dhcp
verbose earlyprintk systemd.log_color=false ${extraargs} rw''', '{BOOTX}']
nfs:
commands: [setenv autoload no, setenv initrd_high 0xffffffff, setenv fdt_high
0xffffffff, dhcp, 'setenv serverip {SERVER_IP}', 'tftp {KERNEL_ADDR}
{KERNEL}', 'tftp {RAMDISK_ADDR} {RAMDISK}', 'setenv initrd_size ${filesize}',
'tftp {DTB_ADDR} {DTB}', 'setenv bootargs '' root=/dev/nfs rw nfsroot={NFS_SERVER_IP}:{NFSROOTFS},tcp,hard,intr ip=dhcp''',
'{BOOTX}']
parameters: {bootloader_prompt: =>, interrupt_char: '', interrupt_prompt: Hit
any key to stop autoboot, mkimage_arch: arm, needs_interrupt: true, uboot_mass_storage_device: /dev/vde,
uboot_ums_flash: true}
ramdisk:
commands: [setenv autoload no, setenv initrd_high 0xffffffff, setenv fdt_high
0xffffffff, dhcp, 'setenv serverip {SERVER_IP}', 'tftp {KERNEL_ADDR}
{KERNEL}', 'tftp {RAMDISK_ADDR} {RAMDISK}', 'setenv initrd_size ${filesize}',
'tftp {DTB_ADDR} {DTB}', setenv bootargs ' root=/dev/ram0 ip=dhcp', '{BOOTX}']
sata:
commands: [scsi scan, setenv autoload no, 'load scsi {ROOT_PART} {KERNEL_ADDR}
{KERNEL}', 'load scsi {ROOT_PART} {RAMDISK_ADDR} {RAMDISK}; setenv initrd_size
${filesize}', 'load scsi {ROOT_PART} {DTB_ADDR} {DTB}', 'setenv bootargs
'' root={ROOT} ip=dhcp''', '{BOOTX}']
ums:
commands: [ums 0 mmc 0]
usb:
commands: [usb start, setenv autoload no, 'load usb 0:{ROOT_PART} {KERNEL_ADDR}
{KERNEL}', 'load usb 0:{ROOT_PART} {RAMDISK_ADDR} {RAMDISK}', 'setenv
initrd_size ${filesize}', 'load usb 0:{ROOT_PART} {DTB_ADDR} {DTB}',
' root={ROOT} ip=dhcp', '{BOOTX}']
deploy:
connections: {lxc: null, serial: null}
methods:
lxc: null
nbd: null
ssh:
host: ''
identity_file: dynamic_vm_keys/lava
options: [-o, Compression=yes, -o, PasswordAuthentication=no, -o, LogLevel=FATAL]
port: 22
user: root
tftp: null
u-boot-ums: null
parameters: {add_header: u-boot, append_dtb: false, mkimage_arch: arm64, use_xip: false}
commands: {connect: telnet lava-dev 7008, hard_reset: /root/reboot_port.sh 1, power_off: 'curl
-s -o /dev/null http://192.168.25.38/30000/00', power_on: 'curl -s -o /dev/null
http://192.168.25.38/30000/01'}
constants:
default-shell-prompt: 'lava-test: # '
grub: {interrupt-character: c, interrupt-prompt: Press enter to boot the selected
OS}
grub-efi:
error-messages: [Undefined OpCode Exception PC at, Synchronous Exception at]
interrupt-character: c
interrupt-prompt: Press enter to boot the selected OS
ipxe:
error-messages: [No configuration methods succeeded, Connection timed out]
interrupt-prompt: Press Ctrl-B for the iPXE command line
interrupt_ctrl_list: [b]
kernel-start-message: Linux version [0-9]
shutdown-message: The system is going down for reboot NOW
u-boot:
error-messages: [Resetting CPU, Must RESET board to recover, TIMEOUT, Retry count
exceeded, 'ERROR: The remote end did not respond in time.']
final-message: Starting kernel
interrupt-character: ' '
interrupt-prompt: Hit any key to stop autoboot
device_type: imx7s-warp
parameters: {pass: null}
timeouts:
actions:
apply-overlay-image: {minutes: 2}
auto-login-action: {minutes: 2}
boot-image-retry: {minutes: 2}
boot-qemu-image: {minutes: 2}
bootloader-action: {minutes: 3}
bootloader-commands: {minutes: 3}
bootloader-interrupt: {seconds: 30}
bootloader-retry: {minutes: 3}
dd-image: {minutes: 10}
download-retry: {minutes: 5}
flash-uboot-ums: {minutes: 20}
http-download: {minutes: 5}
lava-test-shell: {minutes: 3}
nfs-deploy: {minutes: 10}
power-off: {seconds: 5}
u-boot-interrupt: {seconds: 30}
uboot-action: {minutes: 3}
uboot-retry: {minutes: 3}
umount-retry: {seconds: 45}
connections:
auto-login-action: {minutes: 2}
bootloader-commands: {seconds: 30}
bootloader-interrupt: {seconds: 30}
dd-image: {minutes: 10}
lava-test-shell: {seconds: 10}
u-boot-interrupt: {seconds: 30}
uboot-retry: {seconds: 30}
\ No newline at end of file
- class: actions.deploy.uboot_ums.UBootUMSAction
name: uboot-ums-deploy
pipeline:
- class: actions.deploy.download.DownloaderAction
name: download-retry
pipeline:
- {class: actions.deploy.download.HttpDownloadAction, name: http-download}
- class: actions.deploy.overlay.OverlayAction
name: lava-overlay
pipeline:
- {class: actions.deploy.overlay.SshAuthorize, name: ssh-authorize}
- {class: actions.deploy.overlay.VlandOverlayAction, name: lava-vland-overlay}
- {class: actions.deploy.overlay.MultinodeOverlayAction, name: lava-multinode-overlay}
- class: actions.deploy.testdef.TestDefinitionAction
name: test-definition
pipeline:
- {class: actions.deploy.testdef.GitRepoAction, name: git-repo-action}
- {class: actions.deploy.testdef.TestOverlayAction, name: test-overlay}
- {class: actions.deploy.testdef.TestInstallAction, name: test-install-overlay}
- {class: actions.deploy.testdef.TestRunnerAction, name: test-runscript-overlay}
- {class: actions.deploy.overlay.CompressOverlay, name: compress-overlay}
- {class: actions.deploy.overlay.PersistentNFSOverlay, name: persistent-nfs-overlay}
- {class: actions.deploy.apply_overlay.ApplyOverlayImage, name: apply-overlay-image}
- {class: actions.deploy.environment.DeployDeviceEnvironment, name: deploy-device-env}
- class: actions.boot.u_boot.UBootAction
name: uboot-action
pipeline:
- {class: actions.boot.u_boot.UBootSecondaryMedia, name: uboot-from-media}
- {class: actions.boot.BootloaderCommandOverlay, name: bootloader-overlay}
- {class: connections.serial.ConnectDevice, name: connect-device}
- class: actions.boot.u_boot.UBootRetry
name: uboot-retry
pipeline:
- class: power.ResetDevice
name: reset-device
pipeline:
- {class: power.PDUReboot, name: pdu-reboot}
- {class: actions.boot.BootloaderInterruptAction, name: bootloader-interrupt}
- {class: actions.boot.BootloaderCommandsAction, name: bootloader-commands}
- {class: utils.udev.WaitDevicePathAction, name: wait-device-path}
- {class: utils.storage.FlashUBootUMSAction, name: flash-uboot-ums}
- class: power.ResetDevice
name: reset-device
pipeline:
- {class: power.PDUReboot, name: pdu-reboot}
- {class: actions.boot.AutoLoginAction, name: auto-login-action}
- {class: shell.ExpectShellSession, name: expect-shell-connection}
- {class: actions.boot.environment.ExportDeviceEnvironment, name: export-device-env}
- class: actions.test.shell.TestShellRetry
name: lava-test-retry
pipeline:
- {class: actions.test.shell.TestShellAction, name: lava-test-shell}
- class: power.FinalizeAction
name: finalize
pipeline:
- {class: power.PowerOff, name: power-off}
- {class: power.ReadFeedback, name: read-feedback}
device_type: imx7s-warp
job_name: imx7s-warp-dd-flash
timeouts:
job:
minutes: 40
action:
minutes: 20
priority: high
visibility: public
actions:
- deploy:
timeout:
minutes: 5
to: u-boot-ums
os: oe
image:
url: http://snapshots.linaro.org/openembedded/mbl/linaro-master/imx7s-warp/70/rpb/rpb-console-image-imx7s-warp-20180131170405-70.rootfs.sdcard.gz
compression: gz
root_partition: 1
- boot:
method: u-boot
commands: ums
auto_login:
login_prompt: 'imx7s-warp login:'
username: 'root'
prompts:
- 'root@imx7s-warp:~#'
timeout:
minutes: 20
- test:
timeout:
minutes: 5
definitions:
- repository: http://git.linaro.org/lava-team/lava-functional-tests.git
from: git
path: lava-test-shell/smoke-tests-basic.yaml
name: smoke-tests
\ No newline at end of file
# Copyright (C) 2018 Linaro Limited
#
# Author: Matthew Hart <matthew.hart@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 os
import unittest
from lava_dispatcher.device import NewDevice
from lava_dispatcher.parser import JobParser
from lava_dispatcher.test.test_basic import Factory, StdoutTestCase
from lava_dispatcher.test.utils import DummyLogger
from lava_dispatcher.utils.shell import infrastructure_error
class UBootUMSFactory(Factory): # pylint: disable=too-few-public-methods
"""
Not Model based, this is not a Django factory.
Factory objects are dispatcher based classes, independent
of any database objects.
"""
def create_warp7_job(self, filename, output_dir='/tmp/'): # pylint: disable=no-self-use
device = NewDevice(os.path.join(os.path.dirname(__file__), '../devices/imx7s-warp-01.yaml'))
bbb_yaml = os.path.join(os.path.dirname(__file__), filename)
with open(bbb_yaml) as sample_job_data:
parser = JobParser()
job = parser.parse(sample_job_data, device, 4212, None, "",
output_dir=output_dir)
job.logger = DummyLogger()
return job
class TestUbootUMSAction(StdoutTestCase): # pylint: disable=too-many-public-methods
def setUp(self):
super(TestUbootUMSAction, self).setUp()
self.factory = UBootUMSFactory()
@unittest.skipIf(infrastructure_error('dd'), "dd not installed")
def test_ums_action(self):
job = self.factory.create_warp7_job('sample_jobs/warp7-ums.yaml')
self.assertIsNotNone(job)
description_ref = self.pipeline_reference('uboot-ums.yaml', job=job)
self.assertEqual(description_ref, job.pipeline.describe(False))
self.assertIsNone(job.validate())
self.assertEqual(job.device['device_type'], 'imx7s-warp')
uboot = [action for action in job.pipeline.actions if action.name == 'uboot-action'][0]
retry = [action for action in uboot.internal_pipeline.actions if action.name == 'uboot-retry'][0]
flash = [action for action in retry.internal_pipeline.actions if action.name == 'flash-uboot-ums'][0]
self.assertEqual("ums", flash.parameters['commands'])
self.assertEqual("/dev/vde", flash.usb_mass_device)
# Copyright (C) 2018 Linaro Limited
#
# Author: Matthew Hart <matthew.hart@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>.
from lava_dispatcher.action import (
Action,
InfrastructureError,
JobError,
ConfigurationError,
Timeout)
from lava_dispatcher.utils.constants import BOOTLOADER_DEFAULT_CMD_TIMEOUT
import time
class FlashUBootUMSAction(Action):
"""
Write the image file to USB Mass Storage
"""
name = "flash-uboot-ums"
description = "Write the image file to USB Mass Storage"
summary = "USB Mass storage flash"
def __init__(self, usb_mass_device):
super(FlashUBootUMSAction, self).__init__()
self.params = None
self.usb_mass_device = usb_mass_device
def validate(self):
super(FlashUBootUMSAction, self).validate()
self.params = self.job.device['actions']['boot']['methods'][self.parameters['method']]['parameters']
if self.params.get('uboot_mass_storage_device', False):
self.ums_device = self.params['uboot_mass_storage_device']
else:
raise JobError("uboot_mass_storage_device is not set")
def run(self, connection, max_end_time, args=None):
image_file = self.get_namespace_data(action='download-action', label='image', key='file')
cmd = 'dd if={} of={} bs=1M oflag=sync conv=fsync'.format(image_file, self.usb_mass_device)
if not self.run_command(cmd.split(' '), allow_silent=True):
raise JobError("writing to the USB mass storage device failed")
connection.sendcontrol('c')
return connection
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment