1
0
mirror of https://github.com/ARM-software/devlib.git synced 2024-10-05 18:30:50 +01:00

doc: documenting Platforms and Modules

Adding documentation for Platforms and Modules API.
This commit is contained in:
Sergei Trofimov 2016-12-09 15:06:35 +00:00
parent b3cea0c0d2
commit 1ba7fbdc9a
4 changed files with 308 additions and 5 deletions

View File

@ -19,6 +19,7 @@ Contents:
target
modules
instrumentation
platform
connection
Indices and tables

View File

@ -1,3 +1,5 @@
.. _modules:
Modules
=======
@ -64,7 +66,7 @@ policies (governors). The ``devlib`` module exposes the following interface
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.set_governor(cpu, governor, **kwargs)
.. method:: target.cpufreq.set_governor(cpu, governor, \*\*kwargs)
Sets the governor for the specified cpu.
@ -83,7 +85,7 @@ policies (governors). The ``devlib`` module exposes the following interface
:param cpu: The cpu; could be a numeric or the corresponding string (e.g.
``1`` or ``"cpu1"``).
.. method:: target.cpufreq.set_governor_tunables(cpu, **kwargs)
.. method:: target.cpufreq.set_governor_tunables(cpu, \*\*kwargs)
Set the tunables for the current governor on the specified CPU.
@ -169,4 +171,192 @@ TODO
API
---
TODO
Generic Module API Description
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Modules implement discrete, optional pieces of functionality ("optional" in the
sense that the functionality may or may not be present on the target device, or
that it may or may not be necessary for a particular application).
Every module (ultimately) derives from :class:`Module` class. A module must
define the following class attributes:
:name: A unique name for the module. This cannot clash with any of the existing
names and must be a valid Python identifier, but is otherwise free-from.
:kind: This identifies the type of functionality a module implements, which in
turn determines the interface implemented by the module (all modules of
the same kind must expose a consistent interface). This must be a valid
Python identifier, but is otherwise free-form, though, where possible,
one should try to stick to an already-defined kind/interface, lest we end
up with a bunch of modules implementing similar functionality but
exposing slightly different interfaces.
.. note:: It is possible to omit ``kind`` when defining a module, in
which case the module's ``name`` will be treated as its
``kind`` as well.
:stage: This defines when the module will be installed into a :class:`Target`.
Currently, the following values are allowed:
:connected: The module is installed after a connection to the target has
been established. This is the default.
:early: The module will be installed when a :class:`Target` is first
created. This should be used for modules that do not rely on a
live connection to the target.
Additionally, a module must implement a static (or class) method :func:`probe`:
.. method:: Module.probe(target)
This method takes a :class:`Target` instance and returns ``True`` if this
module is supported by that target, or ``False`` otherwise.
.. note:: If the moudule ``stage`` is ``"early"``, this method cannot assume
that a connection has been established (i.e. it can only access
attrubutes of the Target that do not rely on a connection).
Installation and invocation
***************************
The default installation method will create an instance of a module (the
:class:`Target` instance being the sole argument) and assign it to the target
instance attribute named after the module's ``kind`` (or ``name`` if ``kind`` is
``None``).
It is possible to change the installation procedure for a module by overriding
the default :func:`install` method. The method must have the following
signature:
.. method:: Module.install(cls, target, **kwargs)
Install the module into the target instance.
Implementation and Usage Patterns
*********************************
There are two common ways to implement the above API, corresponding to the two
common uses for modules:
- If a module provides an interface to a particular set of functionality (e.g.
an OS subsystem), that module would typically derive directly form
:class:`Module` and would leave ``kind`` unassigned, so that it is accessed
by it name. Its instance's methods and attributes provide the interface for
interacting with its functionality. For examples of this type of module, see
the subsystem modules listed above (e.g. ``cpufreq``).
- If a module provides a platform- or infrastructure-specific implementation of
a common function, the module would derive from one of :class:`Module`
subclasses that define the interface for that function. In that case the
module would be accessible via the common ``kind`` defined its super. The
module would typically implement :func:`__call__` and be invoked directly. For
examples of this type of module, see common function interface definitions
below.
Common Function Interfaces
~~~~~~~~~~~~~~~~~~~~~~~~~~
This section documents :class:`Module` classes defining interface for common
functions. Classes derived from them provide concrete implementations for
specific platforms.
HardResetModule
***************
.. attribute:: HardResetModule.kind
"hard_reset"
.. method:: HardResetModule.__call__()
Must be implemented by derived classes.
Implements hard reset for a target devices. The equivalent of physically
power cycling the device. This may be used by client code in situatians
where the target becomes unresponsive and/or a regular reboot is not
possible.
BootModule
**********
.. attribute:: BootModule.kind
"hard_reset"
.. method:: BootModule.__call__()
Must be implemented by derived classes.
Implements a boot proceedure. This takes the device from (hard or soft)
reset to a booted state where the device is ready to accept connections. For
a lot of commercial devices the process is entirely automatic, however some
devices (e.g. development boards), my require additional steps, such as
interactions with the bootloader, in order to boot into the OS.
.. method:: Bootmodule.update(\*\*kwargs)
Update the boot settings. Some boot sequencies allow specifying settings
that will be utilized during boot (e.g. linux kernel boot command line). The
default implmentation will set each setting in ``kwargs`` as an attribute of
the boot module (or update the existing attribute).
FlashModule
***********
.. attribute:: FlashModule.kind
"flash"
.. method:: __call__(image_bundle=None, images=None, boot_config=None)
Must be implemented by derived classes.
Flash the target platform with the specified images.
:param image_bundle: A compressed bundle of image files with any associated
metadata. The format of the bundle is specific to a
particular implmentation.
:param images: A dict mapping image names/identifiers to the path on the
host file system of the corresponding image file. If both
this and ``image_bundle`` are specified, individual images
will override those in the bundle.
:param boot_config: Some platforms require specifying boot arguments at the
time of flashing the images, rather than during each
reboot. For other platforms, this will be ignored.
Module Registration
~~~~~~~~~~~~~~~~~~~
Modules are specified on :class:`Target` or :class:`Platform` creation by name.
In order to find the class associated with the name, the module needs to be
registered with ``devlib``. This is accomplished by passing the module class
into :func:`register_module` method once it is defined.
.. note:: If you're wiring a module to be included as part of ``devlib`` code
base, you can place the file with the module class under
``devlib/modules/`` in the source and it will be automatically
enumarated. There is no need to explicitly register it in that case.
The code snippet below illustrates an implementation of a hard reset function
for an "Acme" device.
.. code:: python
import os
from devlib import HardResetModule, register_module
class AcmeHardReset(HardResetModule):
name = 'acme_hard_reset'
def __call__(self):
# Assuming Acme board comes with a "reset-acme-board" utility
os.system('reset-acme-board {}'.format(self.target.name))
register_module(AcmeHardReset)

112
doc/platform.rst Normal file
View File

@ -0,0 +1,112 @@
.. _platform:
Platform
========
:class:`Platform`\ s describe the system underlying the OS. They encapsulate
hardware- and firmware-specific details. In most cases, the generic
:class:`Platform` class, which gets used if a platform is not explicitly
specified on :class:`Target` creation, will be sufficient. It will automatically
query as much platform information (such CPU topology, hardware model, etc) if
it was not specified explicitly by the user.
.. class:: Platform(name=None, core_names=None, core_clusters=None,\
big_core=None, model=None, modules=None)
:param name: A user-friendly identifier for the platform.
:param core_names: A list of CPU core names in the order they appear
registered with the OS. If they are not specified,
they will be queried at run time.
:param core_clusters: Alist with cluster ids of each core (starting with
0). If this is not specified, clusters will be
inferred from core names (cores with the same name are
assumed to be in a cluster).
:param big_core: The name of the big core in a big.LITTLE system. If this is
not specified it will be inferred (on systems with exactly
two clasters).
:param model: Model name of the hardware system. If this is not specified it
will be queried at run time.
:param modules: Modules with additional functionality supported by the
platfrom (e.g. for handling flashing, rebooting, etc). These
would be added to the Target's modules. (See :ref:`modules`\ ).
Versatile Express
-----------------
The generic platform may be extended to support hardware- or
infrastructure-specific functionality. Platforms exist for ARM
VersatileExpress-based :class:`Juno` and :class:`TC2` development boards. In
addition to the standard :class:`Platform` parameters above, these platfroms
support additional configuration:
.. class:: VersatileExpressPlatform
Normally, this would be instatiated via one of its derived classes
(:class:`Juno` or :class:`TC2`) that set appropriate defaults for some of
the parameters.
:param serial_port: Identifies the serial port (usual a /dev node) on which the
device is connected.
:param baudrate: Baud rate for the serial connection. This defaults to
``115200`` for :class:`Juno` and ``38400`` for
:class:`TC2`.
:param vemsd_mount: Mount point for the VEMSD (Versatile Express MicroSD card
that is used for board configuration files and firmware
images). This defaults to ``"/media/JUNO"`` for
:class:`Juno` and ``"/media/VEMSD"`` for :class:`TC2`,
though you would most likely need to change this for
your setup as it would depend both on the file system
label on the MicroSD card, and on how the card was
mounted on the host system.
:param hard_reset_method: Specifies the method for hard-resetting the devices
(e.g. if it becomes unresponsive and normal reboot
method doesn not work). Currently supported methods
are:
:dtr: reboot by toggling DTR line on the serial
connection (this is enabled via a DIP switch
on the board).
:reboottxt: reboot by writing a filed called
``reboot.txt`` to the root of the VEMSD
mount (this is enabled via board
configuration file).
This defaults to ``dtr`` for :class:`Juno` and
``reboottxt`` for :class:`TC2`.
:param bootloader: Specifies the bootloader configuration used by the board.
The following values are currently supported:
:uefi: Boot via UEFI menu, by selecting the entry
specified by ``uefi_entry`` paramter. If this
entry does not exist, it will be automatically
created based on values provided for ``image``,
``initrd``, ``fdt``, and ``bootargs`` parameters.
:uefi-shell: Boot by going via the UEFI shell.
:u-boot: Boot using Das U-Boot.
:bootmon: Boot directly via Versatile Express Bootmon
using the values provided for ``image``,
``initrd``, ``fdt``, and ``bootargs``
parameters.
This defaults to ``u-boot`` for :class:`Juno` and
``bootmon`` for :class:`TC2`.
:param flash_method: Specifies how the device is flashed. Currently, only
``"vemsd"`` method is supported, which flashes by
writing firmware images to an appropriate location on
the VEMSD.
:param image: Specfies the kernel image name for ``uefi`` or ``bootmon`` boot.
:param fdt: Specifies the device tree blob for ``uefi`` or ``bootmon`` boot.
:param initrd: Specifies the ramdisk image for ``uefi`` or ``bootmon`` boot.
:param bootargs: Specifies the boot arguments that will be pass to the
kernel by the bootloader.
:param uefi_entry: Then name of the UEFI entry to be used/created by
``uefi`` bootloader.
:param ready_timeout: Timeout, in seconds, for the time it takes the
platform to become ready to accept connections. Note:
this does not mean that the system is fully booted;
just that the services needed to establish a
connection (e.g. sshd or adbd) are up.

View File

@ -18,7 +18,7 @@ Target
available). If a :class:`Platform` instance is not specified on
:class:`Target` creation, one will be created automatically and it will
dynamically probe the device to discover as much about the underlying
hardware as it can.
hardware as it can. See also :ref:`platform`\ .
:param working_directory: This is primary location for on-target file system
interactions performed by ``devlib``. This location *must* be readable and
@ -53,7 +53,7 @@ Target
:param modules: a list of additional modules to be installed. Some modules will
try to install by default (if supported by the underlying target).
Current default modules are ``hotplug``, ``cpufreq``, ``cpuidle``,
``cgroups``, and ``hwmon``.
``cgroups``, and ``hwmon`` (See :ref:`modules`\ ).
See modules documentation for more detail.