2017-03-06 11:10:25 +00:00
|
|
|
from collections import OrderedDict
|
|
|
|
from copy import copy
|
|
|
|
|
|
|
|
from devlib import (LinuxTarget, AndroidTarget, LocalLinuxTarget,
|
|
|
|
Platform, Juno, TC2, Gem5SimulationPlatform)
|
|
|
|
|
|
|
|
from wa.framework import pluginloader
|
|
|
|
from wa.framework.exception import PluginLoaderError
|
|
|
|
from wa.framework.plugin import Plugin, Parameter
|
2017-03-27 17:31:44 +01:00
|
|
|
from wa.framework.target.assistant import LinuxAssistant, AndroidAssistant
|
2017-03-06 11:10:25 +00:00
|
|
|
from wa.utils.types import list_of_strings, list_of_ints
|
2017-03-07 17:05:58 +00:00
|
|
|
from wa.utils.misc import isiterable
|
2017-03-06 11:10:25 +00:00
|
|
|
|
|
|
|
def get_target_descriptions(loader=pluginloader):
|
|
|
|
targets = {}
|
|
|
|
for cls in loader.list_target_descriptors():
|
|
|
|
descriptor = cls()
|
|
|
|
for desc in descriptor.get_descriptions():
|
|
|
|
if desc.name in targets:
|
|
|
|
msg = 'Duplicate target "{}" returned by {} and {}'
|
|
|
|
prev_dtor = targets[desc.name].source
|
2017-03-07 17:05:58 +00:00
|
|
|
raise PluginLoaderError(msg.format(desc.name, prev_dtor.name,
|
2017-03-06 11:10:25 +00:00
|
|
|
descriptor.name))
|
|
|
|
targets[desc.name] = desc
|
|
|
|
return targets.values()
|
|
|
|
|
|
|
|
|
2017-03-15 17:16:59 +00:00
|
|
|
def instantiate_target(tdesc, params, connect=None):
|
|
|
|
target_params = {p.name: p for p in tdesc.target_params}
|
|
|
|
platform_params = {p.name: p for p in tdesc.platform_params}
|
|
|
|
conn_params = {p.name: p for p in tdesc.conn_params}
|
2017-03-27 17:31:44 +01:00
|
|
|
assistant_params = {p.name: p for p in tdesc.assistant_params}
|
2017-03-15 17:16:59 +00:00
|
|
|
|
|
|
|
tp, pp, cp = {}, {}, {}
|
|
|
|
|
2017-04-12 14:18:25 +01:00
|
|
|
for supported_params, new_params in (target_params, tp), (platform_params, pp), (conn_params, cp):
|
|
|
|
for name, value in supported_params.iteritems():
|
|
|
|
if value.default:
|
|
|
|
new_params[name] = value.default
|
|
|
|
|
2017-03-15 17:16:59 +00:00
|
|
|
for name, value in params.iteritems():
|
|
|
|
if name in target_params:
|
|
|
|
tp[name] = value
|
|
|
|
elif name in platform_params:
|
|
|
|
pp[name] = value
|
|
|
|
elif name in conn_params:
|
|
|
|
cp[name] = value
|
2017-03-27 17:31:44 +01:00
|
|
|
elif name in assistant_params:
|
|
|
|
pass
|
2017-03-15 17:16:59 +00:00
|
|
|
else:
|
|
|
|
msg = 'Unexpected parameter for {}: {}'
|
|
|
|
raise ValueError(msg.format(tdesc.name, name))
|
|
|
|
|
|
|
|
tp['platform'] = (tdesc.platform or Platform)(**pp)
|
|
|
|
if cp:
|
|
|
|
tp['connection_settings'] = cp
|
|
|
|
if tdesc.connection:
|
|
|
|
tp['conn_cls'] = tdesc.connection
|
|
|
|
if connect is not None:
|
|
|
|
tp['connect'] = connect
|
|
|
|
|
|
|
|
return tdesc.target(**tp)
|
|
|
|
|
|
|
|
|
2017-03-27 17:31:44 +01:00
|
|
|
def instantiate_assistant(tdesc, params, target):
|
|
|
|
assistant_params = {}
|
|
|
|
for param in tdesc.assistant_params:
|
|
|
|
if param.name in params:
|
|
|
|
assistant_params[param.name] = params[param.name]
|
2017-04-12 14:18:25 +01:00
|
|
|
elif param.default:
|
|
|
|
assistant_params[param.name] = param.default
|
2017-03-27 17:31:44 +01:00
|
|
|
return tdesc.assistant(target, **assistant_params)
|
|
|
|
|
|
|
|
|
2017-03-06 11:10:25 +00:00
|
|
|
class TargetDescription(object):
|
|
|
|
|
|
|
|
def __init__(self, name, source, description=None, target=None, platform=None,
|
2017-03-27 17:31:44 +01:00
|
|
|
conn=None, assistant=None, target_params=None, platform_params=None,
|
|
|
|
conn_params=None, assistant_params=None):
|
2017-03-06 11:10:25 +00:00
|
|
|
self.name = name
|
|
|
|
self.source = source
|
|
|
|
self.description = description
|
|
|
|
self.target = target
|
|
|
|
self.platform = platform
|
|
|
|
self.connection = conn
|
2017-03-27 17:31:44 +01:00
|
|
|
self.assistant = assistant
|
2017-03-06 11:10:25 +00:00
|
|
|
self._set('target_params', target_params)
|
|
|
|
self._set('platform_params', platform_params)
|
|
|
|
self._set('conn_params', conn_params)
|
2017-04-26 13:56:12 +01:00
|
|
|
self._set('assistant_params', assistant_params)
|
2017-03-06 11:10:25 +00:00
|
|
|
|
2017-04-24 10:43:21 +01:00
|
|
|
def get_default_config(self):
|
2017-04-26 13:56:12 +01:00
|
|
|
param_attrs = ['target_params', 'platform_params',
|
|
|
|
'conn_params', 'assistant_params']
|
2017-04-24 10:43:21 +01:00
|
|
|
config = {}
|
|
|
|
for pattr in param_attrs:
|
|
|
|
for n, p in getattr(self, pattr).itervalues():
|
|
|
|
config[n] = p.default
|
|
|
|
return config
|
|
|
|
|
2017-03-06 11:10:25 +00:00
|
|
|
def _set(self, attr, vals):
|
|
|
|
if vals is None:
|
|
|
|
vals = {}
|
|
|
|
elif isiterable(vals):
|
|
|
|
if not hasattr(vals, 'iteritems'):
|
|
|
|
vals = {v.name: v for v in vals}
|
|
|
|
else:
|
|
|
|
msg = '{} must be iterable; got "{}"'
|
|
|
|
raise ValueError(msg.format(attr, vals))
|
|
|
|
setattr(self, attr, vals)
|
|
|
|
|
|
|
|
|
|
|
|
class TargetDescriptor(Plugin):
|
|
|
|
|
|
|
|
kind = 'target_descriptor'
|
|
|
|
|
|
|
|
def get_descriptions(self):
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
COMMON_TARGET_PARAMS = [
|
|
|
|
Parameter('working_directory', kind=str,
|
|
|
|
description='''
|
|
|
|
On-target working directory that will be used by WA. This
|
|
|
|
directory must be writable by the user WA logs in as without
|
|
|
|
the need for privilege elevation.
|
|
|
|
'''),
|
|
|
|
Parameter('executables_directory', kind=str,
|
|
|
|
description='''
|
|
|
|
On-target directory where WA will install its executable
|
|
|
|
binaries. This location must allow execution. This location does
|
|
|
|
*not* need to be writable by unprivileged users or rooted devices
|
|
|
|
(WA will install with elevated privileges as necessary).
|
|
|
|
'''),
|
|
|
|
Parameter('modules', kind=list_of_strings,
|
|
|
|
description='''
|
|
|
|
A list of additional modules to be installed for the target.
|
|
|
|
|
|
|
|
``devlib`` implements functionality for particular subsystems as
|
|
|
|
modules. A number of "default" modules (e.g. for cpufreq
|
|
|
|
subsystem) are loaded automatically, unless explicitly disabled.
|
|
|
|
If additional modules need to be loaded, they may be specified
|
|
|
|
using this parameter.
|
|
|
|
|
|
|
|
Please see ``devlab`` documentation for information on the available
|
|
|
|
modules.
|
|
|
|
'''),
|
2017-03-15 17:16:59 +00:00
|
|
|
Parameter('load_default_modules', kind=bool, default=True,
|
|
|
|
description='''
|
|
|
|
A number of modules (e.g. for working with the cpufreq subsystem) are
|
|
|
|
loaded by default when a Target is instantiated. Setting this to
|
|
|
|
``True`` would suppress that, ensuring that only the base Target
|
|
|
|
interface is initialized.
|
|
|
|
|
|
|
|
You may want to set this if there is a problem with one or more default
|
|
|
|
modules on your platform (e.g. your device is unrooted and cpufreq is
|
|
|
|
not accessible to unprivileged users), or if Target initialization is
|
|
|
|
taking too long for your platform.
|
|
|
|
'''),
|
2017-03-06 11:10:25 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
COMMON_PLATFORM_PARAMS = [
|
|
|
|
Parameter('core_names', kind=list_of_strings,
|
|
|
|
description='''
|
|
|
|
List of names of CPU cores in the order that they appear to the
|
|
|
|
kernel. If not specified, it will be inferred from the platform.
|
|
|
|
'''),
|
|
|
|
Parameter('core_clusters', kind=list_of_ints,
|
|
|
|
description='''
|
|
|
|
Cluster mapping corresponding to the cores in ``core_names``.
|
|
|
|
Cluster indexing starts at ``0``. If not specified, this will be
|
|
|
|
inferred from ``core_names`` -- consecutive cores with the same
|
|
|
|
name will be assumed to share a cluster.
|
|
|
|
'''),
|
|
|
|
Parameter('big_core', kind=str,
|
|
|
|
description='''
|
|
|
|
The name of the big cores in a big.LITTLE system. If not
|
|
|
|
specified, this will be inferred, either from the name (if one of
|
|
|
|
the names in ``core_names`` matches known big cores), or by
|
|
|
|
assuming that the last cluster is big.
|
|
|
|
'''),
|
|
|
|
Parameter('model', kind=str,
|
|
|
|
description='''
|
|
|
|
Hardware model of the platform. If not specified, an attempt will
|
|
|
|
be made to read it from target.
|
|
|
|
'''),
|
|
|
|
Parameter('modules', kind=list_of_strings,
|
|
|
|
description='''
|
|
|
|
An additional list of modules to be loaded into the target.
|
|
|
|
'''),
|
|
|
|
]
|
|
|
|
|
|
|
|
VEXPRESS_PLATFORM_PARAMS = [
|
|
|
|
Parameter('serial_port', kind=str,
|
|
|
|
description='''
|
|
|
|
The serial device/port on the host for the initial connection to
|
|
|
|
the target (used for early boot, flashing, etc).
|
|
|
|
'''),
|
|
|
|
Parameter('baudrate', kind=int,
|
|
|
|
description='''
|
|
|
|
Baud rate for the serial connection.
|
|
|
|
'''),
|
|
|
|
Parameter('vemsd_mount', kind=str,
|
|
|
|
description='''
|
|
|
|
VExpress MicroSD card mount location. This is a MicroSD card in
|
|
|
|
the VExpress device that is mounted on the host via USB. The card
|
|
|
|
contains configuration files for the platform and firmware and
|
|
|
|
kernel images to be flashed.
|
|
|
|
'''),
|
|
|
|
Parameter('bootloader', kind=str,
|
|
|
|
allowed_values=['uefi', 'uefi-shell', 'u-boot', 'bootmon'],
|
|
|
|
description='''
|
|
|
|
Selects the bootloader mechanism used by the board. Depending on
|
|
|
|
firmware version, a number of possible boot mechanisms may be use.
|
|
|
|
|
|
|
|
Please see ``devlib`` documentation for descriptions.
|
|
|
|
'''),
|
|
|
|
Parameter('hard_reset_method', kind=str,
|
|
|
|
allowed_values=['dtr', 'reboottxt'],
|
|
|
|
description='''
|
|
|
|
There are a couple of ways to reset VersatileExpress board if the
|
|
|
|
software running on the board becomes unresponsive. Both require
|
|
|
|
configuration to be enabled (please see ``devlib`` documentation).
|
|
|
|
|
|
|
|
``dtr``: toggle the DTR line on the serial connection
|
|
|
|
``reboottxt``: create ``reboot.txt`` in the root of the VEMSD mount.
|
|
|
|
|
|
|
|
'''),
|
|
|
|
]
|
|
|
|
|
|
|
|
GEM5_PLATFORM_PARAMS = [
|
|
|
|
Parameter('host_output_dir', kind=str, mandatory=True,
|
|
|
|
description='''
|
|
|
|
Path on the host where gem5 output (e.g. stats file) will be placed.
|
|
|
|
'''),
|
|
|
|
Parameter('gem5_bin', kind=str, mandatory=True,
|
|
|
|
description='''
|
|
|
|
Path to the gem5 binary
|
|
|
|
'''),
|
|
|
|
Parameter('gem5_args', kind=str, mandatory=True,
|
|
|
|
description='''
|
|
|
|
Arguments to be passed to the gem5 binary
|
|
|
|
'''),
|
|
|
|
Parameter('gem5_virtio', kind=str, mandatory=True,
|
|
|
|
description='''
|
|
|
|
VirtIO device setup arguments to be passed to gem5. VirtIO is used
|
|
|
|
to transfer files between the simulation and the host.
|
|
|
|
'''),
|
|
|
|
]
|
|
|
|
|
2017-03-27 17:31:44 +01:00
|
|
|
# name --> (target_class, params_list, defaults, assistant_class)
|
2017-03-06 11:10:25 +00:00
|
|
|
TARGETS = {
|
|
|
|
'linux': (LinuxTarget, COMMON_TARGET_PARAMS, None),
|
|
|
|
'android': (AndroidTarget, COMMON_TARGET_PARAMS +
|
|
|
|
[Parameter('package_data_directory', kind=str, default='/data/data',
|
|
|
|
description='''
|
|
|
|
Directory containing Android data
|
|
|
|
'''),
|
|
|
|
], None),
|
|
|
|
'local': (LocalLinuxTarget, COMMON_TARGET_PARAMS, None),
|
|
|
|
}
|
|
|
|
|
2017-03-27 17:31:44 +01:00
|
|
|
# name --> assistant
|
|
|
|
ASSISTANTS = {
|
|
|
|
'linux': LinuxAssistant,
|
|
|
|
'android': AndroidAssistant,
|
|
|
|
'local': LinuxAssistant,
|
|
|
|
}
|
|
|
|
|
2017-03-06 11:10:25 +00:00
|
|
|
# name --> (platform_class, params_list, defaults)
|
|
|
|
PLATFORMS = {
|
|
|
|
'generic': (Platform, COMMON_PLATFORM_PARAMS, None),
|
|
|
|
'juno': (Juno, COMMON_PLATFORM_PARAMS + VEXPRESS_PLATFORM_PARAMS,
|
|
|
|
{
|
|
|
|
'vemsd_mount': '/media/JUNO',
|
|
|
|
'baudrate': 115200,
|
|
|
|
'bootloader': 'u-boot',
|
|
|
|
'hard_reset_method': 'dtr',
|
|
|
|
}),
|
|
|
|
'tc2': (TC2, COMMON_PLATFORM_PARAMS + VEXPRESS_PLATFORM_PARAMS,
|
|
|
|
{
|
|
|
|
'vemsd_mount': '/media/VEMSD',
|
|
|
|
'baudrate': 38400,
|
|
|
|
'bootloader': 'bootmon',
|
|
|
|
'hard_reset_method': 'reboottxt',
|
|
|
|
}),
|
|
|
|
'gem5': (Gem5SimulationPlatform, GEM5_PLATFORM_PARAMS, None),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class DefaultTargetDescriptor(TargetDescriptor):
|
|
|
|
|
|
|
|
name = 'devlib_targets'
|
|
|
|
|
|
|
|
description = """
|
|
|
|
The default target descriptor that provides descriptions in the form
|
|
|
|
<platform>_<target>.
|
|
|
|
|
|
|
|
These map directly onto ``Target``\ s and ``Platform``\ s supplied by ``devlib``.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
def get_descriptions(self):
|
|
|
|
result = []
|
|
|
|
for target_name, target_tuple in TARGETS.iteritems():
|
|
|
|
target, target_params = self._get_item(target_tuple)
|
2017-03-27 17:31:44 +01:00
|
|
|
assistant = ASSISTANTS[target_name]
|
2017-03-06 11:10:25 +00:00
|
|
|
for platform_name, platform_tuple in PLATFORMS.iteritems():
|
|
|
|
platform, platform_params = self._get_item(platform_tuple)
|
|
|
|
|
|
|
|
name = '{}_{}'.format(platform_name, target_name)
|
|
|
|
td = TargetDescription(name, self)
|
|
|
|
td.target = target
|
|
|
|
td.platform = platform
|
2017-03-27 17:31:44 +01:00
|
|
|
td.assistant = assistant
|
2017-03-06 11:10:25 +00:00
|
|
|
td.target_params = target_params
|
|
|
|
td.platform_params = platform_params
|
2017-03-27 17:31:44 +01:00
|
|
|
td.assistant_params = assistant.parameters
|
2017-03-06 11:10:25 +00:00
|
|
|
result.append(td)
|
|
|
|
return result
|
|
|
|
|
|
|
|
def _get_item(self, item_tuple):
|
|
|
|
cls, params, defaults = item_tuple
|
|
|
|
if not defaults:
|
|
|
|
return cls, params
|
|
|
|
|
|
|
|
param_map = OrderedDict((p.name, copy(p)) for p in params)
|
|
|
|
for name, value in defaults.iteritems():
|
|
|
|
if name not in param_map:
|
|
|
|
raise ValueError('Unexpected default "{}"'.format(name))
|
|
|
|
param_map[name].default = value
|
|
|
|
return cls, param_map.values()
|