diff options
Diffstat (limited to 'include/lib/el3_runtime/pubsub.h')
-rw-r--r-- | include/lib/el3_runtime/pubsub.h | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/include/lib/el3_runtime/pubsub.h b/include/lib/el3_runtime/pubsub.h new file mode 100644 index 0000000..cbd8ecc --- /dev/null +++ b/include/lib/el3_runtime/pubsub.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PUBSUB_H +#define PUBSUB_H + +#ifdef __LINKER__ + +/* For the linker ... */ +#define __pubsub_start_sym(event) __pubsub_##event##_start +#define __pubsub_end_sym(event) __pubsub_##event##_end +#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. + */ +#if defined(USE_ARM_LINK) +#define REGISTER_PUBSUB_EVENT(event) \ + __pubsub_start_sym(event) +0 FIXED \ + { \ + *(__pubsub_section(event)) \ + } \ + __pubsub_end_sym(event) +0 FIXED EMPTY 0 \ + { \ + /* placeholder */ \ + } +#else +#define REGISTER_PUBSUB_EVENT(event) \ + __pubsub_start_sym(event) = .; \ + KEEP(*(__pubsub_section(event))); \ + __pubsub_end_sym(event) = . +#endif + +#else /* __LINKER__ */ + +/* For the compiler ... */ + +#include <assert.h> +#include <cdefs.h> +#include <stddef.h> + +#include <arch_helpers.h> + +#if defined(USE_ARM_LINK) +#define __pubsub_start_sym(event) Load$$__pubsub_##event##_start$$Base +#define __pubsub_end_sym(event) Load$$__pubsub_##event##_end$$Base +#else +#define __pubsub_start_sym(event) __pubsub_##event##_start +#define __pubsub_end_sym(event) __pubsub_##event##_end +#endif + +#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. + * + * The extern declaration is there to satisfy MISRA C-2012 rule 8.4. + */ +#define SUBSCRIBE_TO_EVENT(event, func) \ + extern pubsub_cb_t __cb_func_##func##event __pubsub_section(event); \ + 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 */ |