xref: /optee_os/core/kernel/notif.c (revision 718cc2b59de71e86a139608cc10051512d4caaa3)
12828809eSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
22828809eSJens Wiklander /*
3d237e616SJens Wiklander  * Copyright (c) 2021-2024, Linaro Limited
42828809eSJens Wiklander  */
52828809eSJens Wiklander 
6d237e616SJens Wiklander #include <initcall.h>
7c2d44948SJens Wiklander #include <kernel/mutex.h>
82828809eSJens Wiklander #include <kernel/notif.h>
9d237e616SJens Wiklander #include <kernel/panic.h>
10c2d44948SJens Wiklander #include <kernel/spinlock.h>
112828809eSJens Wiklander #include <kernel/thread.h>
12d237e616SJens 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)
18d237e616SJens Wiklander struct notif_data {
19d237e616SJens Wiklander 	bool notif_started;
20d237e616SJens Wiklander };
21d237e616SJens Wiklander 
22c2d44948SJens Wiklander static struct mutex notif_mutex = MUTEX_INITIALIZER;
234199b52fSJens Wiklander static unsigned int notif_lock __nex_data = SPINLOCK_UNLOCK;
24d237e616SJens Wiklander 
25d237e616SJens Wiklander static struct notif_data default_notif_data;
26d237e616SJens 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 
get_notif_data(struct guest_partition * prtn)32d237e616SJens Wiklander static struct notif_data *get_notif_data(struct guest_partition *prtn)
33c2d44948SJens Wiklander {
34d237e616SJens Wiklander 	if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) {
35d237e616SJens Wiklander 		assert(prtn);
36d237e616SJens Wiklander 		return virt_get_guest_spec_data(prtn, notif_data_id);
37d237e616SJens Wiklander 	}
38d237e616SJens Wiklander 	return &default_notif_data;
39d237e616SJens Wiklander }
40d237e616SJens Wiklander 
notif_async_is_started(uint16_t guest_id)41d237e616SJens Wiklander bool notif_async_is_started(uint16_t guest_id)
42d237e616SJens Wiklander {
43d237e616SJens 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 
47d237e616SJens Wiklander 	if (!IS_ENABLED(CFG_NS_VIRTUALIZATION) || prtn) {
48d237e616SJens Wiklander 		struct notif_data *ndata = get_notif_data(prtn);
49c2d44948SJens Wiklander 
50d237e616SJens Wiklander 		old_itr_status = cpu_spin_lock_xsave(&notif_lock);
51d237e616SJens Wiklander 		ret = ndata->notif_started;
52d237e616SJens Wiklander 		cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
53d237e616SJens Wiklander 	}
54d237e616SJens Wiklander 
55d237e616SJens Wiklander 	virt_put_guest(prtn);
56c2d44948SJens Wiklander 	return ret;
57c2d44948SJens Wiklander }
58c2d44948SJens Wiklander 
notif_register_driver(struct notif_driver * ndrv)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 
notif_unregister_driver(struct notif_driver * ndrv)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 
notif_deliver_atomic_event(enum notif_event ev,uint16_t guest_id)83d237e616SJens Wiklander void notif_deliver_atomic_event(enum notif_event ev, uint16_t guest_id)
84c2d44948SJens Wiklander {
85d237e616SJens Wiklander 	struct guest_partition *prtn = virt_get_guest(guest_id);
86d237e616SJens Wiklander 	struct notif_data *ndata = get_notif_data(prtn);
87c2d44948SJens Wiklander 	struct notif_driver *nd = NULL;
88d237e616SJens Wiklander 	uint32_t old_itr_status = 0;
89c2d44948SJens Wiklander 
90c2d44948SJens Wiklander 	old_itr_status = cpu_spin_lock_xsave(&notif_lock);
91c2d44948SJens Wiklander 
92d237e616SJens Wiklander 	switch (ev) {
93d237e616SJens Wiklander 	case NOTIF_EVENT_STARTED:
94d237e616SJens Wiklander 		if (ndata->notif_started) {
95c2d44948SJens Wiklander 			DMSG("Already started");
96c2d44948SJens Wiklander 			goto out;
97c2d44948SJens Wiklander 		}
98d237e616SJens Wiklander 		ndata->notif_started = true;
99d237e616SJens Wiklander 		break;
100d237e616SJens Wiklander 	case NOTIF_EVENT_SHUTDOWN:
101d237e616SJens Wiklander 		break;
102d237e616SJens Wiklander 	default:
103d237e616SJens Wiklander 		EMSG("Unknown event %d", (int)ev);
104d237e616SJens Wiklander 		panic();
105d237e616SJens Wiklander 	}
106c2d44948SJens Wiklander 
107c2d44948SJens Wiklander 	SLIST_FOREACH(nd, &notif_driver_head, link)
108c2d44948SJens Wiklander 		if (nd->atomic_cb)
109d237e616SJens Wiklander 			nd->atomic_cb(nd, ev, guest_id);
110c2d44948SJens Wiklander 
111c2d44948SJens Wiklander out:
112c2d44948SJens Wiklander 	cpu_spin_unlock_xrestore(&notif_lock, old_itr_status);
113d237e616SJens Wiklander 	virt_put_guest(prtn);
114c2d44948SJens Wiklander }
115c2d44948SJens Wiklander 
notif_deliver_event(enum notif_event ev)116c2d44948SJens Wiklander void notif_deliver_event(enum notif_event ev)
117c2d44948SJens Wiklander {
118d237e616SJens Wiklander 	struct guest_partition *prtn = virt_get_current_guest();
119d237e616SJens 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 
130d237e616SJens 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)
136d237e616SJens 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 
146d237e616SJens 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);
155d237e616SJens Wiklander 	virt_put_guest(prtn);
156c2d44948SJens Wiklander }
157*718cc2b5SVolodymyr Babchuk 
158*718cc2b5SVolodymyr Babchuk #ifdef CFG_NS_VIRTUALIZATION
nex_init_notif(void)159*718cc2b5SVolodymyr Babchuk static TEE_Result nex_init_notif(void)
160*718cc2b5SVolodymyr Babchuk {
161*718cc2b5SVolodymyr Babchuk 	return virt_add_guest_spec_data(&notif_data_id,
162*718cc2b5SVolodymyr Babchuk 					sizeof(struct notif_data), NULL);
163*718cc2b5SVolodymyr Babchuk }
164*718cc2b5SVolodymyr Babchuk nex_early_init(nex_init_notif);
165*718cc2b5SVolodymyr Babchuk #endif
166*718cc2b5SVolodymyr Babchuk 
167c2d44948SJens Wiklander #endif /*CFG_CORE_ASYNC_NOTIF*/
168c2d44948SJens Wiklander 
notif_rpc(uint32_t func,uint32_t value1,uint32_t value2)169450f8adaSGavin Liu static TEE_Result notif_rpc(uint32_t func, uint32_t value1, uint32_t value2)
1702828809eSJens Wiklander {
171450f8adaSGavin Liu 	struct thread_param params =
172450f8adaSGavin Liu 		THREAD_PARAM_VALUE(IN, func, value1, value2);
1732828809eSJens Wiklander 
1742828809eSJens Wiklander 	return thread_rpc_cmd(OPTEE_RPC_CMD_NOTIFICATION, 1, &params);
1752828809eSJens Wiklander }
1762828809eSJens Wiklander 
notif_wait(uint32_t value)1772828809eSJens Wiklander TEE_Result notif_wait(uint32_t value)
1782828809eSJens Wiklander {
179450f8adaSGavin Liu 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value, 0);
1802828809eSJens Wiklander }
1812828809eSJens Wiklander 
notif_send_sync(uint32_t value)1822828809eSJens Wiklander TEE_Result notif_send_sync(uint32_t value)
1832828809eSJens Wiklander {
184450f8adaSGavin Liu 	return notif_rpc(OPTEE_RPC_NOTIFICATION_SEND, value, 0);
185450f8adaSGavin Liu }
186450f8adaSGavin Liu 
notif_wait_timeout(uint32_t value,uint32_t timeout_ms)187450f8adaSGavin Liu TEE_Result notif_wait_timeout(uint32_t value, uint32_t timeout_ms)
188450f8adaSGavin Liu {
189450f8adaSGavin Liu 	return notif_rpc(OPTEE_RPC_NOTIFICATION_WAIT, value, timeout_ms);
1902828809eSJens Wiklander }
191d237e616SJens Wiklander 
192