xref: /optee_os/core/kernel/notif.c (revision d237e616e155e6127ff2399ac5cf90655624b0e9)
12828809eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
22828809eSJens Wiklander /*
3*d237e616SJens Wiklander  * Copyright (c) 2021-2024, Linaro Limited
42828809eSJens Wiklander  */
52828809eSJens Wiklander 
6*d237e616SJens Wiklander #include <initcall.h>
7c2d44948SJens Wiklander #include <kernel/mutex.h>
82828809eSJens Wiklander #include <kernel/notif.h>
9*d237e616SJens Wiklander #include <kernel/panic.h>
10c2d44948SJens Wiklander #include <kernel/spinlock.h>
112828809eSJens Wiklander #include <kernel/thread.h>
12*d237e616SJens Wiklander #include <kernel/virtualization.h>
134199b52fSJens Wiklander #include <mm/core_memprot.h>
142828809eSJens Wiklander #include <optee_rpc_cmd.h>
152828809eSJens Wiklander #include <types_ext.h>
162828809eSJens Wiklander 
17c2d44948SJens Wiklander #if defined(CFG_CORE_ASYNC_NOTIF)
18*d237e616SJens Wiklander struct notif_data {
19*d237e616SJens Wiklander 	bool notif_started;
20*d237e616SJens Wiklander };
21*d237e616SJens Wiklander 
22c2d44948SJens Wiklander static struct mutex notif_mutex = MUTEX_INITIALIZER;
234199b52fSJens Wiklander static unsigned int notif_lock __nex_data = SPINLOCK_UNLOCK;
24*d237e616SJens Wiklander 
25*d237e616SJens Wiklander static struct notif_data default_notif_data;
26*d237e616SJens Wiklander static unsigned int notif_data_id __nex_bss;
27c2d44948SJens Wiklander 
28c2d44948SJens Wiklander SLIST_HEAD(notif_driver_head, notif_driver);
294199b52fSJens Wiklander static struct notif_driver_head notif_driver_head __nex_data =
30c2d44948SJens Wiklander 	SLIST_HEAD_INITIALIZER(&notif_driver_head);
31c2d44948SJens Wiklander 
32*d237e616SJens Wiklander static struct notif_data *get_notif_data(struct guest_partition *prtn)
33c2d44948SJens Wiklander {
34*d237e616SJens Wiklander 	if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) {
35*d237e616SJens Wiklander 		assert(prtn);
36*d237e616SJens Wiklander 		return virt_get_guest_spec_data(prtn, notif_data_id);
37*d237e616SJens Wiklander 	}
38*d237e616SJens Wiklander 	return &default_notif_data;
39*d237e616SJens Wiklander }
40*d237e616SJens Wiklander 
41*d237e616SJens Wiklander bool notif_async_is_started(uint16_t guest_id)
42*d237e616SJens Wiklander {
43*d237e616SJens Wiklander 	struct guest_partition *prtn = virt_get_guest(guest_id);
44c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
45c2d44948SJens Wiklander 	bool ret = false;
46c2d44948SJens Wiklander 
47*d237e616SJens Wiklander 	if (!IS_ENABLED(CFG_NS_VIRTUALIZATION) || prtn) {
48*d237e616SJens Wiklander 		struct notif_data *ndata = get_notif_data(prtn);
49c2d44948SJens Wiklander 
50*d237e616SJens Wiklander 		old_itr_status = cpu_spin_lock_xsave(&notif_lock);
51*d237e616SJens Wiklander 		ret = ndata->notif_started;
52*d237e616SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
53*d237e616SJens Wiklander 	}
54*d237e616SJens Wiklander 
55*d237e616SJens Wiklander 	virt_put_guest(prtn);
56c2d44948SJens Wiklander 	return ret;
57c2d44948SJens Wiklander }
58c2d44948SJens Wiklander 
59c2d44948SJens Wiklander void notif_register_driver(struct notif_driver *ndrv)
60c2d44948SJens Wiklander {
61c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
62c2d44948SJens Wiklander 
63fc59f3d8SJens Wiklander 	assert(is_nexus(ndrv) && is_unpaged(ndrv->atomic_cb));
644199b52fSJens Wiklander 
65c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
66c2d44948SJens Wiklander 
67c2d44948SJens Wiklander 	SLIST_INSERT_HEAD(&notif_driver_head, ndrv, link);
68c2d44948SJens Wiklander 
69c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
70c2d44948SJens Wiklander }
71c2d44948SJens Wiklander 
72c2d44948SJens Wiklander void notif_unregister_driver(struct notif_driver *ndrv)
73c2d44948SJens Wiklander {
74c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
75c2d44948SJens Wiklander 
76c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
77c2d44948SJens Wiklander 
78c2d44948SJens Wiklander 	SLIST_REMOVE(&notif_driver_head, ndrv, notif_driver, link);
79c2d44948SJens Wiklander 
80c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
81c2d44948SJens Wiklander }
82c2d44948SJens Wiklander 
83*d237e616SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev, uint16_t guest_id)
84c2d44948SJens Wiklander {
85*d237e616SJens Wiklander 	struct guest_partition *prtn = virt_get_guest(guest_id);
86*d237e616SJens Wiklander 	struct notif_data *ndata = get_notif_data(prtn);
87c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
88*d237e616SJens Wiklander 	uint32_t old_itr_status = 0;
89c2d44948SJens Wiklander 
90c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
91c2d44948SJens Wiklander 
92*d237e616SJens Wiklander 	switch (ev) {
93*d237e616SJens Wiklander 	case NOTIF_EVENT_STARTED:
94*d237e616SJens Wiklander 		if (ndata->notif_started) {
95c2d44948SJens Wiklander 			DMSG("Already started");
96c2d44948SJens Wiklander 			goto out;
97c2d44948SJens Wiklander 		}
98*d237e616SJens Wiklander 		ndata->notif_started = true;
99*d237e616SJens Wiklander 		break;
100*d237e616SJens Wiklander 	case NOTIF_EVENT_SHUTDOWN:
101*d237e616SJens Wiklander 		break;
102*d237e616SJens Wiklander 	default:
103*d237e616SJens Wiklander 		EMSG("Unknown event %d", (int)ev);
104*d237e616SJens Wiklander 		panic();
105*d237e616SJens Wiklander 	}
106c2d44948SJens Wiklander 
107c2d44948SJens Wiklander 	SLIST_FOREACH(nd, &notif_driver_head, link)
108c2d44948SJens Wiklander 		if (nd->atomic_cb)
109*d237e616SJens Wiklander 			nd->atomic_cb(nd, ev, guest_id);
110c2d44948SJens Wiklander 
111c2d44948SJens Wiklander out:
112c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
113*d237e616SJens Wiklander 	virt_put_guest(prtn);
114c2d44948SJens Wiklander }
115c2d44948SJens Wiklander 
116c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev)
117c2d44948SJens Wiklander {
118*d237e616SJens Wiklander 	struct guest_partition *prtn = virt_get_current_guest();
119*d237e616SJens Wiklander 	struct notif_data *ndata = get_notif_data(prtn);
120c2d44948SJens Wiklander 	uint32_t old_itr_status = 0;
121c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
122c2d44948SJens Wiklander 	struct notif_driver *nd_tmp = NULL;
123c2d44948SJens Wiklander 
124c2d44948SJens Wiklander 	assert(ev == NOTIF_EVENT_DO_BOTTOM_HALF || ev == NOTIF_EVENT_STOPPED);
125c2d44948SJens Wiklander 
126c2d44948SJens Wiklander 	/* Serialize all yielding notifications */
127c2d44948SJens Wiklander 	mutex_lock(&notif_mutex);
128c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
129c2d44948SJens Wiklander 
130*d237e616SJens Wiklander 	if (!ndata || !ndata->notif_started) {
131c2d44948SJens Wiklander 		DMSG("Not started ev %d", (int)ev);
132c2d44948SJens Wiklander 		goto out;
133c2d44948SJens Wiklander 	}
134c2d44948SJens Wiklander 
135c2d44948SJens Wiklander 	if (ev == NOTIF_EVENT_STOPPED)
136*d237e616SJens Wiklander 		ndata->notif_started = false;
137c2d44948SJens Wiklander 
138c2d44948SJens Wiklander 	SLIST_FOREACH_SAFE(nd, &notif_driver_head, link, nd_tmp) {
139c2d44948SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
140c2d44948SJens Wiklander 
141c2d44948SJens Wiklander 		if (nd->yielding_cb)
142c2d44948SJens Wiklander 			nd->yielding_cb(nd, ev);
143c2d44948SJens Wiklander 
144c2d44948SJens Wiklander 		old_itr_status = cpu_spin_lock_xsave(&notif_lock);
145c2d44948SJens Wiklander 
146*d237e616SJens Wiklander 		if (ev == NOTIF_EVENT_STOPPED && ndata->notif_started) {
147c2d44948SJens Wiklander 			DMSG("Started again while stopping");
148c2d44948SJens Wiklander 			goto out;
149c2d44948SJens Wiklander 		}
150c2d44948SJens Wiklander 	}
151c2d44948SJens Wiklander 
152c2d44948SJens Wiklander out:
153c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
154c2d44948SJens Wiklander 	mutex_unlock(&notif_mutex);
155*d237e616SJens Wiklander 	virt_put_guest(prtn);
156c2d44948SJens Wiklander }
157c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/
158c2d44948SJens Wiklander 
159450f8adaSGavin Liu static TEE_Result notif_rpc(uint32_t func, uint32_t value1, uint32_t value2)
1602828809eSJens Wiklander {
161450f8adaSGavin Liu 	struct thread_param params =
162450f8adaSGavin Liu 		THREAD_PARAM_VALUE(IN, func, value1, value2);
1632828809eSJens Wiklander 
1642828809eSJens Wiklander 	return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, &params);
1652828809eSJens Wiklander }
1662828809eSJens Wiklander 
1672828809eSJens Wiklander TEE_Result notif_wait(uint32_t value)
1682828809eSJens Wiklander {
169450f8adaSGavin Liu 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value, 0);
1702828809eSJens Wiklander }
1712828809eSJens Wiklander 
1722828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value)
1732828809eSJens Wiklander {
174450f8adaSGavin Liu 	return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value, 0);
175450f8adaSGavin Liu }
176450f8adaSGavin Liu 
177450f8adaSGavin Liu TEE_Result notif_wait_timeout(uint32_t value, uint32_t timeout_ms)
178450f8adaSGavin Liu {
179450f8adaSGavin Liu 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value, timeout_ms);
1802828809eSJens Wiklander }
181*d237e616SJens Wiklander 
182*d237e616SJens Wiklander #ifdef CFG_NS_VIRTUALIZATION
183*d237e616SJens Wiklander static TEE_Result nex_init_notif(void)
184*d237e616SJens Wiklander {
185*d237e616SJens Wiklander 	return virt_add_guest_spec_data(&notif_data_id,
186*d237e616SJens Wiklander 					sizeof(struct notif_data), NULL);
187*d237e616SJens Wiklander }
188*d237e616SJens Wiklander nex_early_init(nex_init_notif);
189*d237e616SJens Wiklander #endif
190