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