BL31: Introduce Publish and Subscribe framework

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>
This commit is contained in:
Jeenu Viswambharan 2017-09-22 08:32:10 +01:00
parent f911e229f3
commit 8e743bcd6a
5 changed files with 193 additions and 0 deletions

View 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__ = .;
/*

View 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__ = .;

View 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
---------------------------------

View File

@ -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__ */

View File

@ -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.
*/