summaryrefslogtreecommitdiffstats
path: root/include/lib/el3_runtime/pubsub.h
blob: 64fe5ccb4dbaeea158cf0170e0375d504224526a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * Copyright (c) 2017-2019, 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 */