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