xref: /optee_os/core/kernel/notif.c (revision c2d449482de098f1c894b94f338440e5a327813d)
12828809eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
22828809eSJens Wiklander /*
32828809eSJens Wiklander  * Copyright (c) 2021, Linaro Limited
42828809eSJens Wiklander  */
52828809eSJens Wiklander 
6*c2d44948SJens Wiklander #include <bitstring.h>
7*c2d44948SJens Wiklander #include <drivers/gic.h>
8*c2d44948SJens Wiklander #include <kernel/interrupt.h>
9*c2d44948SJens Wiklander #include <kernel/mutex.h>
102828809eSJens Wiklander #include <kernel/notif.h>
11*c2d44948SJens Wiklander #include <kernel/spinlock.h>
122828809eSJens Wiklander #include <kernel/thread.h>
132828809eSJens Wiklander #include <optee_rpc_cmd.h>
14*c2d44948SJens Wiklander #include <sm/optee_smc.h>
152828809eSJens Wiklander #include <types_ext.h>
162828809eSJens Wiklander 
17*c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
18*c2d44948SJens Wiklander static struct mutex notif_mutex = MUTEX_INITIALIZER;
19*c2d44948SJens Wiklander static unsigned int notif_lock = SPINLOCK_UNLOCK;
20*c2d44948SJens Wiklander 
21*c2d44948SJens Wiklander SLIST_HEAD(notif_driver_head, notif_driver);
22*c2d44948SJens Wiklander static struct notif_driver_head notif_driver_head =
23*c2d44948SJens Wiklander 	SLIST_HEAD_INITIALIZER(&notif_driver_head);
24*c2d44948SJens Wiklander 
25*c2d44948SJens Wiklander static bitstr_t bit_decl(notif_values, NOTIF_ASYNC_VALUE_MAX + 1);
26*c2d44948SJens Wiklander static bitstr_t bit_decl(notif_alloc_values, NOTIF_ASYNC_VALUE_MAX + 1);
27*c2d44948SJens Wiklander static bool notif_started;
28*c2d44948SJens Wiklander 
29*c2d44948SJens Wiklander TEE_Result notif_alloc_async_value(uint32_t *val)
30*c2d44948SJens Wiklander {
31*c2d44948SJens Wiklander 	static bool alloc_values_inited;
32*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
33*c2d44948SJens Wiklander 	int bit = 0;
34*c2d44948SJens Wiklander 
35*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
36*c2d44948SJens Wiklander 
37*c2d44948SJens Wiklander 	if (!alloc_values_inited) {
38*c2d44948SJens Wiklander 		bit_set(notif_alloc_values, NOTIF_VALUE_DO_BOTTOM_HALF);
39*c2d44948SJens Wiklander 		alloc_values_inited = true;
40*c2d44948SJens Wiklander 	}
41*c2d44948SJens Wiklander 
42*c2d44948SJens Wiklander 	bit_ffc(notif_alloc_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
43*c2d44948SJens Wiklander 	if (bit >= 0) {
44*c2d44948SJens Wiklander 		*val = bit;
45*c2d44948SJens Wiklander 		bit_set(notif_alloc_values, bit);
46*c2d44948SJens Wiklander 	}
47*c2d44948SJens Wiklander 
48*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
49*c2d44948SJens Wiklander 
50*c2d44948SJens Wiklander 	if (bit < 0)
51*c2d44948SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
52*c2d44948SJens Wiklander 
53*c2d44948SJens Wiklander 	return TEE_SUCCESS;
54*c2d44948SJens Wiklander }
55*c2d44948SJens Wiklander 
56*c2d44948SJens Wiklander void notif_free_async_value(uint32_t val)
57*c2d44948SJens Wiklander {
58*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
59*c2d44948SJens Wiklander 
60*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
61*c2d44948SJens Wiklander 
62*c2d44948SJens Wiklander 	assert(val < NOTIF_ASYNC_VALUE_MAX);
63*c2d44948SJens Wiklander 	assert(bit_test(notif_alloc_values, val));
64*c2d44948SJens Wiklander 	bit_clear(notif_alloc_values, val);
65*c2d44948SJens Wiklander 
66*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
67*c2d44948SJens Wiklander }
68*c2d44948SJens Wiklander 
69*c2d44948SJens Wiklander uint32_t notif_get_value(bool *value_valid, bool *value_pending)
70*c2d44948SJens Wiklander {
71*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
72*c2d44948SJens Wiklander 	uint32_t res = 0;
73*c2d44948SJens Wiklander 	int bit = 0;
74*c2d44948SJens Wiklander 
75*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
76*c2d44948SJens Wiklander 
77*c2d44948SJens Wiklander 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
78*c2d44948SJens Wiklander 	*value_valid = (bit >= 0);
79*c2d44948SJens Wiklander 	if (!*value_valid) {
80*c2d44948SJens Wiklander 		*value_pending = false;
81*c2d44948SJens Wiklander 		goto out;
82*c2d44948SJens Wiklander 	}
83*c2d44948SJens Wiklander 
84*c2d44948SJens Wiklander 	res = bit;
85*c2d44948SJens Wiklander 	bit_clear(notif_values, res);
86*c2d44948SJens Wiklander 	bit_ffs(notif_values, (int)NOTIF_ASYNC_VALUE_MAX + 1, &bit);
87*c2d44948SJens Wiklander 	*value_pending = (bit >= 0);
88*c2d44948SJens Wiklander out:
89*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
90*c2d44948SJens Wiklander 
91*c2d44948SJens Wiklander 	return res;
92*c2d44948SJens Wiklander }
93*c2d44948SJens Wiklander 
94*c2d44948SJens Wiklander void notif_send_async(uint32_t value)
95*c2d44948SJens Wiklander {
96*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
97*c2d44948SJens Wiklander 
98*c2d44948SJens Wiklander 	COMPILE_TIME_ASSERT(NOTIF_VALUE_DO_BOTTOM_HALF ==
99*c2d44948SJens Wiklander 			    OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF);
100*c2d44948SJens Wiklander 	COMPILE_TIME_ASSERT(CFG_CORE_ASYNC_NOTIF_GIC_INTID >= GIC_SPI_BASE);
101*c2d44948SJens Wiklander 
102*c2d44948SJens Wiklander 	assert(value <= NOTIF_ASYNC_VALUE_MAX);
103*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
104*c2d44948SJens Wiklander 
105*c2d44948SJens Wiklander 	DMSG("0x%"PRIx32, value);
106*c2d44948SJens Wiklander 	bit_set(notif_values, value);
107*c2d44948SJens Wiklander 	itr_raise_pi(CFG_CORE_ASYNC_NOTIF_GIC_INTID);
108*c2d44948SJens Wiklander 
109*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
110*c2d44948SJens Wiklander }
111*c2d44948SJens Wiklander 
112*c2d44948SJens Wiklander bool notif_async_is_started(void)
113*c2d44948SJens Wiklander {
114*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
115*c2d44948SJens Wiklander 	bool ret = false;
116*c2d44948SJens Wiklander 
117*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
118*c2d44948SJens Wiklander 	ret = notif_started;
119*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
120*c2d44948SJens Wiklander 
121*c2d44948SJens Wiklander 	return ret;
122*c2d44948SJens Wiklander }
123*c2d44948SJens Wiklander 
124*c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv)
125*c2d44948SJens Wiklander {
126*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
127*c2d44948SJens Wiklander 
128*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
129*c2d44948SJens Wiklander 
130*c2d44948SJens Wiklander 	SLIST_INSERT_HEAD(&notif_driver_head, ndrv, link);
131*c2d44948SJens Wiklander 
132*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
133*c2d44948SJens Wiklander }
134*c2d44948SJens Wiklander 
135*c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv)
136*c2d44948SJens Wiklander {
137*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
138*c2d44948SJens Wiklander 
139*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
140*c2d44948SJens Wiklander 
141*c2d44948SJens Wiklander 	SLIST_REMOVE(&notif_driver_head, ndrv, notif_driver, link);
142*c2d44948SJens Wiklander 
143*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
144*c2d44948SJens Wiklander }
145*c2d44948SJens Wiklander 
146*c2d44948SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev)
147*c2d44948SJens Wiklander {
148*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
149*c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
150*c2d44948SJens Wiklander 
151*c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_STARTED);
152*c2d44948SJens Wiklander 
153*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
154*c2d44948SJens Wiklander 
155*c2d44948SJens Wiklander 	if (notif_started) {
156*c2d44948SJens Wiklander 		DMSG("Already started");
157*c2d44948SJens Wiklander 		goto out;
158*c2d44948SJens Wiklander 	}
159*c2d44948SJens Wiklander 	notif_started = true;
160*c2d44948SJens Wiklander 
161*c2d44948SJens Wiklander 	SLIST_FOREACH(nd, &notif_driver_head, link)
162*c2d44948SJens Wiklander 		if (nd->atomic_cb)
163*c2d44948SJens Wiklander 			nd->atomic_cb(nd, ev);
164*c2d44948SJens Wiklander 
165*c2d44948SJens Wiklander out:
166*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
167*c2d44948SJens Wiklander }
168*c2d44948SJens Wiklander 
169*c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev)
170*c2d44948SJens Wiklander {
171*c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
172*c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
173*c2d44948SJens Wiklander 	struct notif_driver *nd_tmp = NULL;
174*c2d44948SJens Wiklander 
175*c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED);
176*c2d44948SJens Wiklander 
177*c2d44948SJens Wiklander 	/* Serialize all yielding notifications */
178*c2d44948SJens Wiklander 	mutex_lock(&notif_mutex);
179*c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
180*c2d44948SJens Wiklander 
181*c2d44948SJens Wiklander 	if (!notif_started) {
182*c2d44948SJens Wiklander 		DMSG("Not started ev %d", (int)ev);
183*c2d44948SJens Wiklander 		goto out;
184*c2d44948SJens Wiklander 	}
185*c2d44948SJens Wiklander 
186*c2d44948SJens Wiklander 	if (ev == NOTIF_EVENT_STOPPED)
187*c2d44948SJens Wiklander 		notif_started = false;
188*c2d44948SJens Wiklander 
189*c2d44948SJens Wiklander 	SLIST_FOREACH_SAFE(nd, &notif_driver_head, link, nd_tmp) {
190*c2d44948SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
191*c2d44948SJens Wiklander 
192*c2d44948SJens Wiklander 		if (nd->yielding_cb)
193*c2d44948SJens Wiklander 			nd->yielding_cb(nd, ev);
194*c2d44948SJens Wiklander 
195*c2d44948SJens Wiklander 		old_itr_status = cpu_spin_lock_xsave(&notif_lock);
196*c2d44948SJens Wiklander 
197*c2d44948SJens Wiklander 		if (ev == NOTIF_EVENT_STOPPED && notif_started) {
198*c2d44948SJens Wiklander 			DMSG("Started again while stopping");
199*c2d44948SJens Wiklander 			goto out;
200*c2d44948SJens Wiklander 		}
201*c2d44948SJens Wiklander 	}
202*c2d44948SJens Wiklander 
203*c2d44948SJens Wiklander out:
204*c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
205*c2d44948SJens Wiklander 	mutex_unlock(&notif_mutex);
206*c2d44948SJens Wiklander }
207*c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/
208*c2d44948SJens Wiklander 
2092828809eSJens Wiklander static TEE_Result notif_rpc(uint32_t func, uint32_t value)
2102828809eSJens Wiklander {
2112828809eSJens Wiklander 	struct thread_param params = THREAD_PARAM_VALUE(IN, func, value, 0);
2122828809eSJens Wiklander 
2132828809eSJens Wiklander 	return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, &params);
2142828809eSJens Wiklander }
2152828809eSJens Wiklander 
2162828809eSJens Wiklander TEE_Result notif_wait(uint32_t value)
2172828809eSJens Wiklander {
2182828809eSJens Wiklander 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value);
2192828809eSJens Wiklander }
2202828809eSJens Wiklander 
2212828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value)
2222828809eSJens Wiklander {
2232828809eSJens Wiklander 	return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value);
2242828809eSJens Wiklander }
225