1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #include <assert.h>
6 #include <hyptypes.h>
7 
8 #include <hypcall_def.h>
9 #include <hyprights.h>
10 
11 #include <atomic.h>
12 #include <compiler.h>
13 #include <cspace.h>
14 #include <cspace_lookup.h>
15 #include <object.h>
16 #include <spinlock.h>
17 #include <thread.h>
18 
19 #include "msgqueue.h"
20 #include "msgqueue_common.h"
21 
22 error_t
hypercall_msgqueue_bind_send_virq(cap_id_t msgqueue_cap,cap_id_t vic_cap,virq_t virq)23 hypercall_msgqueue_bind_send_virq(cap_id_t msgqueue_cap, cap_id_t vic_cap,
24 				  virq_t virq)
25 {
26 	error_t	  err;
27 	cspace_t *cspace = cspace_get_self();
28 
29 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
30 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_BIND_SEND);
31 	if (compiler_unexpected(p.e != OK)) {
32 		err = p.e;
33 		goto out;
34 	}
35 	msgqueue_t *msgqueue = p.r;
36 
37 	vic_ptr_result_t v =
38 		cspace_lookup_vic(cspace, vic_cap, CAP_RIGHTS_VIC_BIND_SOURCE);
39 	if (compiler_unexpected(v.e != OK)) {
40 		err = v.e;
41 		goto out_msgqueue_release;
42 	}
43 	vic_t *vic = v.r;
44 
45 	err = msgqueue_bind_send(msgqueue, vic, virq);
46 
47 	object_put_vic(vic);
48 out_msgqueue_release:
49 	object_put_msgqueue(msgqueue);
50 out:
51 	return err;
52 }
53 
54 error_t
hypercall_msgqueue_bind_receive_virq(cap_id_t msgqueue_cap,cap_id_t vic_cap,virq_t virq)55 hypercall_msgqueue_bind_receive_virq(cap_id_t msgqueue_cap, cap_id_t vic_cap,
56 				     virq_t virq)
57 {
58 	error_t	  err;
59 	cspace_t *cspace = cspace_get_self();
60 
61 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
62 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_BIND_RECEIVE);
63 	if (compiler_unexpected(p.e != OK)) {
64 		err = p.e;
65 		goto out;
66 	}
67 	msgqueue_t *msgqueue = p.r;
68 
69 	vic_ptr_result_t v =
70 		cspace_lookup_vic(cspace, vic_cap, CAP_RIGHTS_VIC_BIND_SOURCE);
71 	if (compiler_unexpected(v.e != OK)) {
72 		err = v.e;
73 		goto out_msgqueue_release;
74 	}
75 	vic_t *vic = v.r;
76 
77 	err = msgqueue_bind_receive(msgqueue, vic, virq);
78 
79 	object_put_vic(vic);
80 out_msgqueue_release:
81 	object_put_msgqueue(msgqueue);
82 out:
83 	return err;
84 }
85 
86 error_t
hypercall_msgqueue_unbind_send_virq(cap_id_t msgqueue_cap)87 hypercall_msgqueue_unbind_send_virq(cap_id_t msgqueue_cap)
88 {
89 	error_t	  err	 = OK;
90 	cspace_t *cspace = cspace_get_self();
91 
92 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
93 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_BIND_SEND);
94 	if (compiler_unexpected(p.e != OK)) {
95 		err = p.e;
96 		goto out;
97 	}
98 	msgqueue_t *msgqueue = p.r;
99 
100 	msgqueue_unbind_send(msgqueue);
101 
102 	object_put_msgqueue(msgqueue);
103 out:
104 	return err;
105 }
106 
107 error_t
hypercall_msgqueue_unbind_receive_virq(cap_id_t msgqueue_cap)108 hypercall_msgqueue_unbind_receive_virq(cap_id_t msgqueue_cap)
109 {
110 	error_t	  err	 = OK;
111 	cspace_t *cspace = cspace_get_self();
112 
113 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
114 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_BIND_RECEIVE);
115 	if (compiler_unexpected(p.e != OK)) {
116 		err = p.e;
117 		goto out;
118 	}
119 	msgqueue_t *msgqueue = p.r;
120 
121 	msgqueue_unbind_receive(msgqueue);
122 
123 	object_put_msgqueue(msgqueue);
124 out:
125 	return err;
126 }
127 
128 hypercall_msgqueue_send_result_t
hypercall_msgqueue_send(cap_id_t msgqueue_cap,size_t size,user_ptr_t data,msgqueue_send_flags_t send_flags)129 hypercall_msgqueue_send(cap_id_t msgqueue_cap, size_t size, user_ptr_t data,
130 			msgqueue_send_flags_t send_flags)
131 {
132 	hypercall_msgqueue_send_result_t ret	= { 0 };
133 	cspace_t			*cspace = cspace_get_self();
134 
135 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
136 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_SEND);
137 	if (compiler_unexpected(p.e != OK)) {
138 		ret.error = p.e;
139 		goto out;
140 	}
141 	msgqueue_t *msgqueue = p.r;
142 
143 	bool push = msgqueue_send_flags_get_push(&send_flags);
144 
145 	bool_result_t res = msgqueue_send(msgqueue, size, (gvaddr_t)data, push);
146 
147 	ret.error    = res.e;
148 	ret.not_full = res.r;
149 
150 	object_put_msgqueue(msgqueue);
151 out:
152 	return ret;
153 }
154 
155 hypercall_msgqueue_receive_result_t
hypercall_msgqueue_receive(cap_id_t msgqueue_cap,user_ptr_t buffer,size_t buf_size)156 hypercall_msgqueue_receive(cap_id_t msgqueue_cap, user_ptr_t buffer,
157 			   size_t buf_size)
158 {
159 	hypercall_msgqueue_receive_result_t ret	   = { 0 };
160 	cspace_t			   *cspace = cspace_get_self();
161 
162 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
163 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_RECEIVE);
164 	if (compiler_unexpected(p.e != OK)) {
165 		ret.error = p.e;
166 		goto out;
167 	}
168 	msgqueue_t *msgqueue = p.r;
169 
170 	receive_info_result_t res;
171 	res = msgqueue_receive(msgqueue, (gvaddr_t)buffer, buf_size);
172 
173 	ret.error     = res.e;
174 	ret.size      = res.r.size;
175 	ret.not_empty = res.r.notempty;
176 
177 	object_put_msgqueue(msgqueue);
178 out:
179 	return ret;
180 }
181 
182 error_t
hypercall_msgqueue_flush(cap_id_t msgqueue_cap)183 hypercall_msgqueue_flush(cap_id_t msgqueue_cap)
184 {
185 	error_t	  err;
186 	cspace_t *cspace = cspace_get_self();
187 
188 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
189 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_RECEIVE);
190 	if (compiler_unexpected(p.e != OK)) {
191 		err = p.e;
192 		goto out;
193 	}
194 	msgqueue_t *msgqueue = p.r;
195 
196 	msgqueue_flush(msgqueue);
197 	err = OK;
198 
199 	object_put_msgqueue(msgqueue);
200 out:
201 	return err;
202 }
203 
204 error_t
hypercall_msgqueue_configure_send(cap_id_t msgqueue_cap,count_t not_full_thres,count_t not_full_holdoff)205 hypercall_msgqueue_configure_send(cap_id_t msgqueue_cap, count_t not_full_thres,
206 				  count_t not_full_holdoff)
207 {
208 	error_t	  err;
209 	cspace_t *cspace = cspace_get_self();
210 
211 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
212 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_SEND);
213 	if (compiler_unexpected(p.e != OK)) {
214 		err = p.e;
215 		goto out;
216 	}
217 	msgqueue_t *msgqueue = p.r;
218 
219 	err = msgqueue_configure_send(msgqueue, not_full_thres,
220 				      not_full_holdoff);
221 
222 	object_put_msgqueue(msgqueue);
223 out:
224 	return err;
225 }
226 
227 error_t
hypercall_msgqueue_configure_receive(cap_id_t msgqueue_cap,count_t not_empty_thres,count_t not_empty_holdoff)228 hypercall_msgqueue_configure_receive(cap_id_t msgqueue_cap,
229 				     count_t  not_empty_thres,
230 				     count_t  not_empty_holdoff)
231 {
232 	error_t	  err;
233 	cspace_t *cspace = cspace_get_self();
234 
235 	msgqueue_ptr_result_t p = cspace_lookup_msgqueue(
236 		cspace, msgqueue_cap, CAP_RIGHTS_MSGQUEUE_RECEIVE);
237 	if (compiler_unexpected(p.e != OK)) {
238 		err = p.e;
239 		goto out;
240 	}
241 	msgqueue_t *msgqueue = p.r;
242 
243 	err = msgqueue_configure_receive(msgqueue, not_empty_thres,
244 					 not_empty_holdoff);
245 
246 	object_put_msgqueue(msgqueue);
247 out:
248 	return err;
249 }
250 
251 error_t
hypercall_msgqueue_configure(cap_id_t msgqueue_cap,msgqueue_create_info_t create_info)252 hypercall_msgqueue_configure(cap_id_t		    msgqueue_cap,
253 			     msgqueue_create_info_t create_info)
254 {
255 	error_t	      err;
256 	cspace_t     *cspace = cspace_get_self();
257 	object_type_t type;
258 
259 	object_ptr_result_t o = cspace_lookup_object_any(
260 		cspace, msgqueue_cap, CAP_RIGHTS_GENERIC_OBJECT_ACTIVATE,
261 		&type);
262 	if (compiler_unexpected(o.e != OK)) {
263 		err = o.e;
264 		goto out;
265 	}
266 	if (type != OBJECT_TYPE_MSGQUEUE) {
267 		err = ERROR_CSPACE_WRONG_OBJECT_TYPE;
268 		goto out_msgqueue_release;
269 	}
270 
271 	msgqueue_t *target_msgqueue = o.r.msgqueue;
272 
273 	spinlock_acquire(&target_msgqueue->header.lock);
274 
275 	size_t max_msg_size =
276 		msgqueue_create_info_get_max_msg_size(&create_info);
277 	count_t queue_depth =
278 		msgqueue_create_info_get_queue_depth(&create_info);
279 
280 	if (atomic_load_relaxed(&target_msgqueue->header.state) ==
281 	    OBJECT_STATE_INIT) {
282 		err = msgqueue_configure(target_msgqueue, max_msg_size,
283 					 queue_depth);
284 	} else {
285 		err = ERROR_OBJECT_STATE;
286 	}
287 
288 	spinlock_release(&target_msgqueue->header.lock);
289 out_msgqueue_release:
290 	object_put(type, o.r);
291 out:
292 	return err;
293 }
294