BL31: Introduce Publish and Subscribe framework
authorJeenu Viswambharan <jeenu.viswambharan@arm.com>
Fri, 22 Sep 2017 07:32:10 +0000 (08:32 +0100)
committerJeenu Viswambharan <jeenu.viswambharan@arm.com>
Mon, 23 Oct 2017 07:15:11 +0000 (08:15 +0100)
This light-weight framework enables some EL3 components to publish
events which other EL3 components can subscribe to. Publisher can
optionally pass opaque data for subscribers. The order in which
subscribers are called is not defined.

Firmware design updated.

Change-Id: I24a3a70b2b1dedcb1f73cf48313818aebf75ebb6
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
bl31/bl31.ld.S
bl32/sp_min/sp_min.ld.S
docs/firmware-design.rst
include/lib/el3_runtime/pubsub.h [new file with mode: 0644]
include/lib/el3_runtime/pubsub_events.h [new file with mode: 0644]

index 48861f408badfa54dd859b5eb7b10422d62b9e4c..9ff774b6252813602bec13220841259fd9cd1215 100644 (file)
@@ -62,6 +62,10 @@ SECTIONS
         KEEP(*(cpu_ops))
         __CPU_OPS_END__ = .;
 
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <pubsub_events.h>
+
         . = NEXT(4096);
         __RODATA_END__ = .;
     } >RAM
@@ -95,6 +99,10 @@ SECTIONS
         KEEP(*(cpu_ops))
         __CPU_OPS_END__ = .;
 
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <pubsub_events.h>
+
         *(.vectors)
         __RO_END_UNALIGNED__ = .;
         /*
index d0fb4a03d184a48fcc22e6bac3fafdb816dbbc62..fc44d5248897dbc7381b84a55a53f5294523d34c 100644 (file)
@@ -50,6 +50,10 @@ SECTIONS
         KEEP(*(cpu_ops))
         __CPU_OPS_END__ = .;
 
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <pubsub_events.h>
+
         . = NEXT(4096);
         __RODATA_END__ = .;
     } >RAM
@@ -75,6 +79,10 @@ SECTIONS
         KEEP(*(cpu_ops))
         __CPU_OPS_END__ = .;
 
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <pubsub_events.h>
+
         *(.vectors)
         __RO_END_UNALIGNED__ = .;
 
index 07905975f784c0f76e3307fc763932b8482b11dd..8851065a1ae4a425f1a12a88b9ec1dec435ee37d 100644 (file)
@@ -2258,6 +2258,87 @@ should consider the trade-off between memory footprint and security.
 This build flag is disabled by default, minimising memory footprint. On ARM
 platforms, it is enabled.
 
+Publish and Subscribe Framework
+-------------------------------
+
+The Publish and Subscribe Framework allows EL3 components to define and publish
+events, to which other EL3 components can subscribe.
+
+The following macros are provided by the framework:
+
+-  ``REGISTER_PUBSUB_EVENT(event)``: Defines an event, and takes one argument,
+   the event name, which must be a valid C identifier. All calls to
+   ``REGISTER_PUBSUB_EVENT`` macro must be placed in the file
+   ``pubsub_events.h``.
+
+-  ``PUBLISH_EVENT_ARG(event, arg)``: Publishes a defined event, by iterating
+   subscribed handlers and calling them in turn. The handlers will be passed the
+   parameter ``arg``. The expected use-case is to broadcast an event.
+
+-  ``PUBLISH_EVENT(event)``: Like ``PUBLISH_EVENT_ARG``, except that the value
+   ``NULL`` is passed to subscribed handlers.
+
+-  ``SUBSCRIBE_TO_EVENT(event, handler)``: Registers the ``handler`` to
+   subscribe to ``event``. The handler will be executed whenever the ``event``
+   is published.
+
+-  ``for_each_subscriber(event, subscriber)``: Iterates through all handlers
+   subscribed for ``event``. ``subscriber`` must be a local variable of type
+   ``pubsub_cb_t *``, and will point to each subscribed handler in turn during
+   iteration. This macro can be used for those patterns that none of the
+   ``PUBLISH_EVENT_*()`` macros cover.
+
+Publishing an event that wasn't defined using ``REGISTER_PUBSUB_EVENT`` will
+result in build error. Subscribing to an undefined event however won't.
+
+Subscribed handlers must be of type ``pubsub_cb_t``, with following function
+signature:
+
+::
+
+   typedef void* (*pubsub_cb_t)(const void *arg);
+
+There may be arbitrary number of handlers registered to the same event. The
+order in which subscribed handlers are notified when that event is published is
+not defined. Subscribed handlers may be executed in any order; handlers should
+not assume any relative ordering amongst them.
+
+Publishing an event on a PE will result in subscribed handlers executing on that
+PE only; it won't cause handlers to execute on a different PE.
+
+Note that publishing an event on a PE blocks until all the subscribed handlers
+finish executing on the PE.
+
+Publish and Subscribe Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A publisher that wants to publish event ``foo`` would:
+
+-  Define the event ``foo`` in the ``pubsub_events.h``.
+
+   ::
+
+      REGISTER_PUBSUB_EVENT(foo);
+
+-  Depending on the nature of event, use one of ``PUBLISH_EVENT_*()`` macros to
+   publish the event at the appropriate path and time of execution.
+
+A subscriber that wants to subscribe to event ``foo`` published above would
+implement:
+
+::
+
+   void *foo_handler(const void *arg)
+   {
+        void *result;
+
+        /* Do handling ... */
+
+        return result;
+   }
+
+   SUBSCRIBE_TO_EVENT(foo, foo_handler);
+
 Performance Measurement Framework
 ---------------------------------
 
diff --git a/include/lib/el3_runtime/pubsub.h b/include/lib/el3_runtime/pubsub.h
new file mode 100644 (file)
index 0000000..9a85480
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PUBSUB_H__
+#define __PUBSUB_H__
+
+#define __pubsub_start_sym(event)      __pubsub_##event##_start
+#define __pubsub_end_sym(event)                __pubsub_##event##_end
+
+#ifdef __LINKER__
+
+/* For the linker ... */
+
+#define __pubsub_section(event)                __pubsub_##event
+
+/*
+ * REGISTER_PUBSUB_EVENT has a different definition between linker and compiler
+ * contexts. In linker context, this collects pubsub sections for each event,
+ * placing guard symbols around each.
+ */
+#define REGISTER_PUBSUB_EVENT(event) \
+       __pubsub_start_sym(event) = .; \
+       KEEP(*(__pubsub_section(event))); \
+       __pubsub_end_sym(event) = .
+
+#else /* __LINKER__ */
+
+/* For the compiler ... */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cdefs.h>
+#include <stddef.h>
+
+#define __pubsub_section(event)                __section("__pubsub_" #event)
+
+/*
+ * In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols
+ * exported by the linker required for the other pubsub macros to work.
+ */
+#define REGISTER_PUBSUB_EVENT(event) \
+       extern pubsub_cb_t __pubsub_start_sym(event)[]; \
+       extern pubsub_cb_t __pubsub_end_sym(event)[]
+
+/*
+ * Have the function func called back when the specified event happens. This
+ * macro places the function address into the pubsub section, which is picked up
+ * and invoked by the invoke_pubsubs() function via. the PUBLISH_EVENT* macros.
+ */
+#define SUBSCRIBE_TO_EVENT(event, func) \
+       pubsub_cb_t __cb_func_##func##event __pubsub_section(event) = func
+
+/*
+ * Iterate over subscribed handlers for a defined event. 'event' is the name of
+ * the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'.
+ */
+#define for_each_subscriber(event, subscriber) \
+       for (subscriber = __pubsub_start_sym(event); \
+                       subscriber < __pubsub_end_sym(event); \
+                       subscriber++)
+
+/*
+ * Publish a defined event supplying an argument. All subscribed handlers are
+ * invoked, but the return value of handlers are ignored for now.
+ */
+#define PUBLISH_EVENT_ARG(event, arg) \
+       do { \
+               pubsub_cb_t *subscriber; \
+               for_each_subscriber(event, subscriber) { \
+                       (*subscriber)(arg); \
+               } \
+       } while (0)
+
+/* Publish a defined event with NULL argument */
+#define PUBLISH_EVENT(event)   PUBLISH_EVENT_ARG(event, NULL)
+
+/* Subscriber callback type */
+typedef void* (*pubsub_cb_t)(const void *arg);
+
+#endif /* __LINKER__ */
+#endif /* __PUBSUB_H__ */
diff --git a/include/lib/el3_runtime/pubsub_events.h b/include/lib/el3_runtime/pubsub_events.h
new file mode 100644 (file)
index 0000000..8ef1a11
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pubsub.h>
+
+/*
+ * This file defines a list of pubsub events, declared using
+ * REGISTER_PUBSUB_EVENT() macro.
+ */