diff options
author | davidcunado-arm <david.cunado@arm.com> | 2017-10-23 09:54:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-23 09:54:45 +0100 |
commit | 4c37ac89031da9b3be97f9a06440cfa1b530135d (patch) | |
tree | 57d35175d72f8ff523c0212ed180f68e52aac710 | |
parent | f911e229f3ab0481230cf1e03bc0c076707c9567 (diff) | |
parent | bd0c34778174aa4239ff96b448d0b6e1deeec4e2 (diff) | |
download | arm-trusted-firmware-4c37ac89031da9b3be97f9a06440cfa1b530135d.tar.gz |
Merge pull request #1132 from jeenu-arm/pubsub
Publish and Subscribe framework
-rw-r--r-- | bl31/bl31.ld.S | 8 | ||||
-rw-r--r-- | bl32/sp_min/sp_min.ld.S | 8 | ||||
-rw-r--r-- | docs/firmware-design.rst | 97 | ||||
-rw-r--r-- | include/lib/el3_runtime/pubsub.h | 84 | ||||
-rw-r--r-- | include/lib/el3_runtime/pubsub_events.h | 18 | ||||
-rw-r--r-- | lib/psci/psci_on.c | 3 |
6 files changed, 218 insertions, 0 deletions
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S index 48861f40..9ff774b6 100644 --- a/bl31/bl31.ld.S +++ b/bl31/bl31.ld.S @@ -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__ = .; /* diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S index d0fb4a03..fc44d524 100644 --- a/bl32/sp_min/sp_min.ld.S +++ b/bl32/sp_min/sp_min.ld.S @@ -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__ = .; diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst index 07905975..853e3901 100644 --- a/docs/firmware-design.rst +++ b/docs/firmware-design.rst @@ -2258,6 +2258,103 @@ 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); + +Available Events +~~~~~~~~~~~~~~~~ + +ARM Trusted Firmware core makes some events available by default. They're listed +below, along with information as to when they're published, and the arguments +passed to subscribed handlers. + +Other EL3 components that are conditionally compiled in may make their own +events available, but aren't documented here. + +- ``psci_cpu_on_finish`` + + - When: Published on a PE after it's finished its power-up sequence. + + - Argument: ``NULL``. + Performance Measurement Framework --------------------------------- diff --git a/include/lib/el3_runtime/pubsub.h b/include/lib/el3_runtime/pubsub.h new file mode 100644 index 00000000..9a854808 --- /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 <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 index 00000000..62550f81 --- /dev/null +++ b/include/lib/el3_runtime/pubsub_events.h @@ -0,0 +1,18 @@ +/* + * 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. + */ + +/* + * Event published after a CPU has been powered up and finished its + * initialization. + */ +REGISTER_PUBSUB_EVENT(psci_cpu_on_finish); diff --git a/lib/psci/psci_on.c b/lib/psci/psci_on.c index d3d0e2ff..53b044ec 100644 --- a/lib/psci/psci_on.c +++ b/lib/psci/psci_on.c @@ -11,6 +11,7 @@ #include <context_mgmt.h> #include <debug.h> #include <platform.h> +#include <pubsub_events.h> #include <stddef.h> #include "psci_private.h" @@ -188,6 +189,8 @@ void psci_cpu_on_finish(unsigned int cpu_idx, if (psci_spd_pm && psci_spd_pm->svc_on_finish) psci_spd_pm->svc_on_finish(0); + PUBLISH_EVENT(psci_cpu_on_finish); + /* Populate the mpidr field within the cpu node array */ /* This needs to be done only once */ psci_cpu_pd_nodes[cpu_idx].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK; |