diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S index 48861f4..9ff774b 100644 --- a/bl31/bl31.ld.S +++ b/bl31/bl31.ld.S @@ -62,6 +62,10 @@ KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; + /* Place pubsub sections for events */ + . = ALIGN(8); +#include + . = NEXT(4096); __RODATA_END__ = .; } >RAM @@ -95,6 +99,10 @@ KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; + /* Place pubsub sections for events */ + . = ALIGN(8); +#include + *(.vectors) __RO_END_UNALIGNED__ = .; /* diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S index d0fb4a0..fc44d52 100644 --- a/bl32/sp_min/sp_min.ld.S +++ b/bl32/sp_min/sp_min.ld.S @@ -50,6 +50,10 @@ KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; + /* Place pubsub sections for events */ + . = ALIGN(8); +#include + . = NEXT(4096); __RODATA_END__ = .; } >RAM @@ -75,6 +79,10 @@ KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; + /* Place pubsub sections for events */ + . = ALIGN(8); +#include + *(.vectors) __RO_END_UNALIGNED__ = .; diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst index 0790597..8851065 100644 --- a/docs/firmware-design.rst +++ b/docs/firmware-design.rst @@ -2258,6 +2258,87 @@ 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 index 0000000..9a85480 --- /dev/null +++ b/include/lib/el3_runtime/pubsub.h @@ -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 +#include +#include +#include + +#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 index 0000000..8ef1a11 --- /dev/null +++ b/include/lib/el3_runtime/pubsub_events.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +/* + * This file defines a list of pubsub events, declared using + * REGISTER_PUBSUB_EVENT() macro. + */