From 1ba7fbdc9a7d7dc4609c61e15a20944274395715 Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Fri, 9 Dec 2016 15:06:35 +0000 Subject: [PATCH] doc: documenting Platforms and Modules Adding documentation for Platforms and Modules API. --- doc/index.rst | 1 + doc/modules.rst | 196 ++++++++++++++++++++++++++++++++++++++++++++++- doc/platform.rst | 112 +++++++++++++++++++++++++++ doc/target.rst | 4 +- 4 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 doc/platform.rst diff --git a/doc/index.rst b/doc/index.rst index 482eeb8..2c6d72f 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -19,6 +19,7 @@ Contents: target modules instrumentation + platform connection Indices and tables diff --git a/doc/modules.rst b/doc/modules.rst index 8dc27bd..8835663 100644 --- a/doc/modules.rst +++ b/doc/modules.rst @@ -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) + diff --git a/doc/platform.rst b/doc/platform.rst new file mode 100644 index 0000000..c3220a6 --- /dev/null +++ b/doc/platform.rst @@ -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. + diff --git a/doc/target.rst b/doc/target.rst index 7ee8d44..d14942e 100644 --- a/doc/target.rst +++ b/doc/target.rst @@ -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.