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 #include <string.h>
8
9 #include <atomic.h>
10 #include <panic.h>
11 #include <partition.h>
12 #include <scheduler.h>
13 #include <spinlock.h>
14 #include <vic.h>
15 #include <virq.h>
16
17 #include "event_handlers.h"
18 #include "msgqueue.h"
19 #include "msgqueue_common.h"
20
21 bool_result_t
msgqueue_send(msgqueue_t * msgqueue,size_t size,gvaddr_t data,bool push)22 msgqueue_send(msgqueue_t *msgqueue, size_t size, gvaddr_t data, bool push)
23 {
24 kernel_or_gvaddr_t data_union;
25 data_union.guest_addr = data;
26
27 return msgqueue_send_msg(msgqueue, size, data_union, push, false);
28 }
29
30 receive_info_result_t
msgqueue_receive(msgqueue_t * msgqueue,gvaddr_t buffer,size_t max_size)31 msgqueue_receive(msgqueue_t *msgqueue, gvaddr_t buffer, size_t max_size)
32 {
33 kernel_or_gvaddr_t buffer_union;
34 buffer_union.guest_addr = buffer;
35
36 return msgqueue_receive_msg(msgqueue, buffer_union, max_size, false);
37 }
38
39 void
msgqueue_flush(msgqueue_t * msgqueue)40 msgqueue_flush(msgqueue_t *msgqueue)
41 {
42 msgqueue_flush_queue(msgqueue);
43 }
44
45 error_t
msgqueue_configure_send(msgqueue_t * msgqueue,count_t notfull_thd,count_t notfull_delay)46 msgqueue_configure_send(msgqueue_t *msgqueue, count_t notfull_thd,
47 count_t notfull_delay)
48 {
49 error_t ret = OK;
50
51 assert(msgqueue != NULL);
52
53 if (notfull_delay != MSGQUEUE_DELAY_UNCHANGED) {
54 ret = ERROR_UNIMPLEMENTED;
55 goto out;
56 }
57
58 if ((notfull_thd >= msgqueue->queue_depth) &&
59 (notfull_thd != MSGQUEUE_THRESHOLD_UNCHANGED)) {
60 ret = ERROR_ARGUMENT_INVALID;
61 goto out;
62 }
63
64 spinlock_acquire(&msgqueue->lock);
65
66 if (notfull_thd != MSGQUEUE_THRESHOLD_UNCHANGED) {
67 msgqueue->notfull_thd = notfull_thd;
68
69 if (msgqueue->count <= msgqueue->notfull_thd) {
70 (void)virq_assert(&msgqueue->send_source, false);
71 } else {
72 (void)virq_clear(&msgqueue->send_source);
73 }
74 }
75 spinlock_release(&msgqueue->lock);
76 out:
77 return ret;
78 }
79
80 error_t
msgqueue_configure_receive(msgqueue_t * msgqueue,count_t notempty_thd,count_t notempty_delay)81 msgqueue_configure_receive(msgqueue_t *msgqueue, count_t notempty_thd,
82 count_t notempty_delay)
83 {
84 error_t ret = OK;
85
86 assert(msgqueue != NULL);
87
88 if (notempty_delay != MSGQUEUE_DELAY_UNCHANGED) {
89 ret = ERROR_UNIMPLEMENTED;
90 goto out;
91 }
92
93 if ((notempty_thd == 0U) ||
94 ((notempty_thd > msgqueue->queue_depth) &&
95 (notempty_thd != MSGQUEUE_THRESHOLD_MAXIMUM) &&
96 (notempty_thd != MSGQUEUE_THRESHOLD_UNCHANGED))) {
97 ret = ERROR_ARGUMENT_INVALID;
98 goto out;
99 }
100
101 spinlock_acquire(&msgqueue->lock);
102
103 if (notempty_thd == MSGQUEUE_THRESHOLD_MAXIMUM) {
104 msgqueue->notempty_thd = msgqueue->queue_depth;
105 } else if (notempty_thd != MSGQUEUE_THRESHOLD_UNCHANGED) {
106 msgqueue->notempty_thd = notempty_thd;
107
108 if (msgqueue->count >= msgqueue->notempty_thd) {
109 (void)virq_assert(&msgqueue->rcv_source, false);
110 } else {
111 (void)virq_clear(&msgqueue->rcv_source);
112 }
113 } else {
114 // Nothing to do. Value stays the same.
115 }
116
117 spinlock_release(&msgqueue->lock);
118 out:
119 return ret;
120 }
121
122 error_t
msgqueue_bind_send(msgqueue_t * msgqueue,vic_t * vic,virq_t virq)123 msgqueue_bind_send(msgqueue_t *msgqueue, vic_t *vic, virq_t virq)
124 {
125 return msgqueue_bind(msgqueue, vic, virq, &msgqueue->send_source,
126 VIRQ_TRIGGER_MSGQUEUE_TX);
127 }
128
129 error_t
msgqueue_bind_receive(msgqueue_t * msgqueue,vic_t * vic,virq_t virq)130 msgqueue_bind_receive(msgqueue_t *msgqueue, vic_t *vic, virq_t virq)
131 {
132 return msgqueue_bind(msgqueue, vic, virq, &msgqueue->rcv_source,
133 VIRQ_TRIGGER_MSGQUEUE_RX);
134 }
135
136 void
msgqueue_unbind_send(msgqueue_t * msgqueue)137 msgqueue_unbind_send(msgqueue_t *msgqueue)
138 {
139 msgqueue_unbind(&msgqueue->send_source);
140 }
141
142 void
msgqueue_unbind_receive(msgqueue_t * msgqueue)143 msgqueue_unbind_receive(msgqueue_t *msgqueue)
144 {
145 msgqueue_unbind(&msgqueue->rcv_source);
146 }
147
148 error_t
msgqueue_handle_object_create_msgqueue(msgqueue_create_t params)149 msgqueue_handle_object_create_msgqueue(msgqueue_create_t params)
150 {
151 msgqueue_t *msgqueue = params.msgqueue;
152 assert(msgqueue != NULL);
153 spinlock_init(&msgqueue->lock);
154
155 return OK;
156 }
157
158 error_t
msgqueue_configure(msgqueue_t * msgqueue,size_t max_msg_size,count_t queue_depth)159 msgqueue_configure(msgqueue_t *msgqueue, size_t max_msg_size,
160 count_t queue_depth)
161 {
162 error_t ret = OK;
163
164 assert(msgqueue != NULL);
165
166 if ((queue_depth != 0U) && (max_msg_size != 0U) &&
167 (queue_depth < MSGQUEUE_MAX_QUEUE_DEPTH) &&
168 (max_msg_size < MSGQUEUE_MAX_MAX_MSG_SIZE)) {
169 msgqueue->max_msg_size = max_msg_size;
170 msgqueue->queue_depth = queue_depth;
171 } else {
172 ret = ERROR_ARGUMENT_INVALID;
173 }
174
175 return ret;
176 }
177
178 error_t
msgqueue_handle_object_activate_msgqueue(msgqueue_t * msgqueue)179 msgqueue_handle_object_activate_msgqueue(msgqueue_t *msgqueue)
180 {
181 error_t ret = OK;
182
183 assert(msgqueue != NULL);
184 assert(msgqueue->buf == NULL);
185
186 if ((msgqueue->queue_depth == 0U) || (msgqueue->max_msg_size == 0U)) {
187 ret = ERROR_OBJECT_CONFIG;
188 goto out;
189 }
190
191 // Message queue size consists of the message maximum size, a field to
192 // know the exact size of the message and how many messages can the
193 // queue contain.
194 size_t queue_size = (msgqueue->max_msg_size + sizeof(size_t)) *
195 msgqueue->queue_depth;
196 partition_t *partition = msgqueue->header.partition;
197
198 void_ptr_result_t res =
199 partition_alloc(partition, queue_size, alignof(size_t));
200 if (res.e != OK) {
201 ret = res.e;
202 goto out;
203 }
204
205 msgqueue->buf = (uint8_t *)res.r;
206 msgqueue->count = 0U;
207 msgqueue->queue_size = queue_size;
208 msgqueue->head = 0U;
209 msgqueue->tail = 0U;
210 msgqueue->notfull_thd = msgqueue->queue_depth - 1U;
211 msgqueue->notempty_thd = 1U;
212
213 out:
214 return ret;
215 }
216
217 void
msgqueue_handle_object_deactivate_msgqueue(msgqueue_t * msgqueue)218 msgqueue_handle_object_deactivate_msgqueue(msgqueue_t *msgqueue)
219 {
220 assert(msgqueue != NULL);
221
222 if (msgqueue->buf != NULL) {
223 error_t ret;
224 partition_t *partition = msgqueue->header.partition;
225
226 ret = partition_free(partition, msgqueue->buf,
227 msgqueue->queue_size);
228
229 if (ret != OK) {
230 panic("Error freeing msgqueue buffer");
231 }
232 msgqueue->buf = NULL;
233 }
234
235 vic_unbind(&msgqueue->send_source);
236 vic_unbind(&msgqueue->rcv_source);
237 }
238