xref: /freebsd/sys/dev/vmware/vmci/vmci_event.c (revision 685dc743)
1 /*-
2  * Copyright (c) 2018 VMware, Inc.
3  *
4  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
5  */
6 
7 /* This file implements VMCI Event code. */
8 
9 #include <sys/cdefs.h>
10 #include "vmci.h"
11 #include "vmci_driver.h"
12 #include "vmci_event.h"
13 #include "vmci_kernel_api.h"
14 #include "vmci_kernel_defs.h"
15 #include "vmci_kernel_if.h"
16 
17 #define LGPFX		"vmci_event: "
18 #define EVENT_MAGIC	0xEABE0000
19 
20 struct vmci_subscription {
21 	vmci_id		id;
22 	int		ref_count;
23 	bool		run_delayed;
24 	vmci_event	destroy_event;
25 	vmci_event_type	event;
26 	vmci_event_cb	callback;
27 	void		*callback_data;
28 	vmci_list_item(vmci_subscription) subscriber_list_item;
29 };
30 
31 static struct	vmci_subscription *vmci_event_find(vmci_id sub_id);
32 static int	vmci_event_deliver(struct vmci_event_msg *event_msg);
33 static int	vmci_event_register_subscription(struct vmci_subscription *sub,
34 		    vmci_event_type event, uint32_t flags,
35 		    vmci_event_cb callback, void *callback_data);
36 static struct	vmci_subscription *vmci_event_unregister_subscription(
37 		    vmci_id sub_id);
38 
39 static vmci_list(vmci_subscription) subscriber_array[VMCI_EVENT_MAX];
40 static vmci_lock subscriber_lock;
41 
42 struct vmci_delayed_event_info {
43 	struct vmci_subscription *sub;
44 	uint8_t event_payload[sizeof(struct vmci_event_data_max)];
45 };
46 
47 struct vmci_event_ref {
48 	struct vmci_subscription	*sub;
49 	vmci_list_item(vmci_event_ref)	list_item;
50 };
51 
52 /*
53  *------------------------------------------------------------------------------
54  *
55  * vmci_event_init --
56  *
57  *     General init code.
58  *
59  * Results:
60  *     VMCI_SUCCESS on success, appropriate error code otherwise.
61  *
62  * Side effects:
63  *     None.
64  *
65  *------------------------------------------------------------------------------
66  */
67 
68 int
vmci_event_init(void)69 vmci_event_init(void)
70 {
71 	int i;
72 
73 	for (i = 0; i < VMCI_EVENT_MAX; i++)
74 		vmci_list_init(&subscriber_array[i]);
75 
76 	return (vmci_init_lock(&subscriber_lock, "VMCI Event subscriber lock"));
77 }
78 
79 /*
80  *------------------------------------------------------------------------------
81  *
82  * vmci_event_exit --
83  *
84  *     General exit code.
85  *
86  * Results:
87  *     None.
88  *
89  * Side effects:
90  *     None.
91  *
92  *------------------------------------------------------------------------------
93  */
94 
95 void
vmci_event_exit(void)96 vmci_event_exit(void)
97 {
98 	struct vmci_subscription *iter, *iter_2;
99 	vmci_event_type e;
100 
101 	/* We free all memory at exit. */
102 	for (e = 0; e < VMCI_EVENT_MAX; e++) {
103 		vmci_list_scan_safe(iter, &subscriber_array[e],
104 		    subscriber_list_item, iter_2) {
105 			/*
106 			 * We should never get here because all events should
107 			 * have been unregistered before we try to unload the
108 			 * driver module. Also, delayed callbacks could still
109 			 * be firing so this cleanup would not be safe. Still
110 			 * it is better to free the memory than not ... so we
111 			 * leave this code in just in case....
112 			 */
113 			ASSERT(false);
114 
115 			vmci_free_kernel_mem(iter, sizeof(*iter));
116 		}
117 	}
118 	vmci_cleanup_lock(&subscriber_lock);
119 }
120 
121 /*
122  *------------------------------------------------------------------------------
123  *
124  * vmci_event_sync --
125  *
126  *     Use this as a synchronization point when setting globals, for example,
127  *     during device shutdown.
128  *
129  * Results:
130  *     true.
131  *
132  * Side effects:
133  *     None.
134  *
135  *------------------------------------------------------------------------------
136  */
137 
138 void
vmci_event_sync(void)139 vmci_event_sync(void)
140 {
141 
142 	vmci_grab_lock_bh(&subscriber_lock);
143 	vmci_release_lock_bh(&subscriber_lock);
144 }
145 
146 /*
147  *------------------------------------------------------------------------------
148  *
149  * vmci_event_check_host_capabilities --
150  *
151  *     Verify that the host supports the hypercalls we need. If it does not,
152  *     try to find fallback hypercalls and use those instead.
153  *
154  * Results:
155  *     true if required hypercalls (or fallback hypercalls) are
156  *     supported by the host, false otherwise.
157  *
158  * Side effects:
159  *     None.
160  *
161  *------------------------------------------------------------------------------
162  */
163 
164 bool
vmci_event_check_host_capabilities(void)165 vmci_event_check_host_capabilities(void)
166 {
167 
168 	/* vmci_event does not require any hypercalls. */
169 	return (true);
170 }
171 
172 /*
173  *------------------------------------------------------------------------------
174  *
175  * vmci_event_get --
176  *
177  *     Gets a reference to the given struct vmci_subscription.
178  *
179  * Results:
180  *     None.
181  *
182  * Side effects:
183  *     None.
184  *
185  *------------------------------------------------------------------------------
186  */
187 
188 static void
vmci_event_get(struct vmci_subscription * entry)189 vmci_event_get(struct vmci_subscription *entry)
190 {
191 
192 	ASSERT(entry);
193 
194 	entry->ref_count++;
195 }
196 
197 /*
198  *------------------------------------------------------------------------------
199  *
200  * vmci_event_release --
201  *
202  *     Releases the given struct vmci_subscription.
203  *
204  * Results:
205  *     None.
206  *
207  * Side effects:
208  *     Fires the destroy event if the reference count has gone to zero.
209  *
210  *------------------------------------------------------------------------------
211  */
212 
213 static void
vmci_event_release(struct vmci_subscription * entry)214 vmci_event_release(struct vmci_subscription *entry)
215 {
216 
217 	ASSERT(entry);
218 	ASSERT(entry->ref_count > 0);
219 
220 	entry->ref_count--;
221 	if (entry->ref_count == 0)
222 		vmci_signal_event(&entry->destroy_event);
223 }
224 
225  /*
226  *------------------------------------------------------------------------------
227  *
228  * event_release_cb --
229  *
230  *     Callback to release the event entry reference. It is called by the
231  *     vmci_wait_on_event function before it blocks.
232  *
233  * Result:
234  *     None.
235  *
236  * Side effects:
237  *     None.
238  *
239  *------------------------------------------------------------------------------
240  */
241 
242 static int
event_release_cb(void * client_data)243 event_release_cb(void *client_data)
244 {
245 	struct vmci_subscription *sub = (struct vmci_subscription *)client_data;
246 
247 	ASSERT(sub);
248 
249 	vmci_grab_lock_bh(&subscriber_lock);
250 	vmci_event_release(sub);
251 	vmci_release_lock_bh(&subscriber_lock);
252 
253 	return (0);
254 }
255 
256 /*
257  *------------------------------------------------------------------------------
258  *
259  * vmci_event_find --
260  *
261  *     Find entry. Assumes lock is held.
262  *
263  * Results:
264  *     Entry if found, NULL if not.
265  *
266  * Side effects:
267  *     Increments the struct vmci_subscription refcount if an entry is found.
268  *
269  *------------------------------------------------------------------------------
270  */
271 
272 static struct vmci_subscription *
vmci_event_find(vmci_id sub_id)273 vmci_event_find(vmci_id sub_id)
274 {
275 	struct vmci_subscription *iter;
276 	vmci_event_type e;
277 
278 	for (e = 0; e < VMCI_EVENT_MAX; e++) {
279 		vmci_list_scan(iter, &subscriber_array[e],
280 		    subscriber_list_item) {
281 			if (iter->id == sub_id) {
282 				vmci_event_get(iter);
283 				return (iter);
284 			}
285 		}
286 	}
287 	return (NULL);
288 }
289 
290 /*
291  *------------------------------------------------------------------------------
292  *
293  * vmci_event_delayed_dispatch_cb --
294  *
295  *     Calls the specified callback in a delayed context.
296  *
297  * Results:
298  *     None.
299  *
300  * Side effects:
301  *     None.
302  *
303  *------------------------------------------------------------------------------
304  */
305 
306 static void
vmci_event_delayed_dispatch_cb(void * data)307 vmci_event_delayed_dispatch_cb(void *data)
308 {
309 	struct vmci_delayed_event_info *event_info;
310 	struct vmci_subscription *sub;
311 	struct vmci_event_data *ed;
312 
313 	event_info = (struct vmci_delayed_event_info *)data;
314 
315 	ASSERT(event_info);
316 	ASSERT(event_info->sub);
317 
318 	sub = event_info->sub;
319 	ed = (struct vmci_event_data *)event_info->event_payload;
320 
321 	sub->callback(sub->id, ed, sub->callback_data);
322 
323 	vmci_grab_lock_bh(&subscriber_lock);
324 	vmci_event_release(sub);
325 	vmci_release_lock_bh(&subscriber_lock);
326 
327 	vmci_free_kernel_mem(event_info, sizeof(*event_info));
328 }
329 
330 /*
331  *------------------------------------------------------------------------------
332  *
333  * vmci_event_deliver --
334  *
335  *     Actually delivers the events to the subscribers.
336  *
337  * Results:
338  *     None.
339  *
340  * Side effects:
341  *     The callback function for each subscriber is invoked.
342  *
343  *------------------------------------------------------------------------------
344  */
345 
346 static int
vmci_event_deliver(struct vmci_event_msg * event_msg)347 vmci_event_deliver(struct vmci_event_msg *event_msg)
348 {
349 	struct vmci_subscription *iter;
350 	int err = VMCI_SUCCESS;
351 
352 	vmci_list(vmci_event_ref) no_delay_list;
353 	vmci_list_init(&no_delay_list);
354 
355 	ASSERT(event_msg);
356 
357 	vmci_grab_lock_bh(&subscriber_lock);
358 	vmci_list_scan(iter, &subscriber_array[event_msg->event_data.event],
359 	    subscriber_list_item) {
360 		if (iter->run_delayed) {
361 			struct vmci_delayed_event_info *event_info;
362 			if ((event_info =
363 			    vmci_alloc_kernel_mem(sizeof(*event_info),
364 			    VMCI_MEMORY_ATOMIC)) == NULL) {
365 				err = VMCI_ERROR_NO_MEM;
366 				goto out;
367 			}
368 
369 			vmci_event_get(iter);
370 
371 			memset(event_info, 0, sizeof(*event_info));
372 			memcpy(event_info->event_payload,
373 			    VMCI_DG_PAYLOAD(event_msg),
374 			    (size_t)event_msg->hdr.payload_size);
375 			event_info->sub = iter;
376 			err =
377 			    vmci_schedule_delayed_work(
378 			    vmci_event_delayed_dispatch_cb, event_info);
379 			if (err != VMCI_SUCCESS) {
380 				vmci_event_release(iter);
381 				vmci_free_kernel_mem(
382 				    event_info, sizeof(*event_info));
383 				goto out;
384 			}
385 
386 		} else {
387 			struct vmci_event_ref *event_ref;
388 
389 			/*
390 			 * We construct a local list of subscribers and release
391 			 * subscriber_lock before invoking the callbacks. This
392 			 * is similar to delayed callbacks, but callbacks are
393 			 * invoked right away here.
394 			 */
395 			if ((event_ref = vmci_alloc_kernel_mem(
396 			    sizeof(*event_ref), VMCI_MEMORY_ATOMIC)) == NULL) {
397 				err = VMCI_ERROR_NO_MEM;
398 				goto out;
399 			}
400 
401 			vmci_event_get(iter);
402 			event_ref->sub = iter;
403 			vmci_list_insert(&no_delay_list, event_ref, list_item);
404 		}
405 	}
406 
407 out:
408 	vmci_release_lock_bh(&subscriber_lock);
409 
410 	if (!vmci_list_empty(&no_delay_list)) {
411 		struct vmci_event_data *ed;
412 		struct vmci_event_ref *iter;
413 		struct vmci_event_ref *iter_2;
414 
415 		vmci_list_scan_safe(iter, &no_delay_list, list_item, iter_2) {
416 			struct vmci_subscription *cur;
417 			uint8_t event_payload[sizeof(
418 			    struct vmci_event_data_max)];
419 
420 			cur = iter->sub;
421 
422 			/*
423 			 * We set event data before each callback to ensure
424 			 * isolation.
425 			 */
426 			memset(event_payload, 0, sizeof(event_payload));
427 			memcpy(event_payload, VMCI_DG_PAYLOAD(event_msg),
428 			    (size_t)event_msg->hdr.payload_size);
429 			ed = (struct vmci_event_data *)event_payload;
430 			cur->callback(cur->id, ed, cur->callback_data);
431 
432 			vmci_grab_lock_bh(&subscriber_lock);
433 			vmci_event_release(cur);
434 			vmci_release_lock_bh(&subscriber_lock);
435 			vmci_free_kernel_mem(iter, sizeof(*iter));
436 		}
437 	}
438 
439 	return (err);
440 }
441 
442 /*
443  *------------------------------------------------------------------------------
444  *
445  * vmci_event_dispatch --
446  *
447  *     Dispatcher for the VMCI_EVENT_RECEIVE datagrams. Calls all
448  *     subscribers for given event.
449  *
450  * Results:
451  *     VMCI_SUCCESS on success, error code otherwise.
452  *
453  * Side effects:
454  *     None.
455  *
456  *------------------------------------------------------------------------------
457  */
458 
459 int
vmci_event_dispatch(struct vmci_datagram * msg)460 vmci_event_dispatch(struct vmci_datagram *msg)
461 {
462 	struct vmci_event_msg *event_msg = (struct vmci_event_msg *)msg;
463 
464 	ASSERT(msg &&
465 	    msg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
466 	    msg->dst.resource == VMCI_EVENT_HANDLER);
467 
468 	if (msg->payload_size < sizeof(vmci_event_type) ||
469 	    msg->payload_size > sizeof(struct vmci_event_data_max))
470 		return (VMCI_ERROR_INVALID_ARGS);
471 
472 	if (!VMCI_EVENT_VALID(event_msg->event_data.event))
473 		return (VMCI_ERROR_EVENT_UNKNOWN);
474 
475 	vmci_event_deliver(event_msg);
476 
477 	return (VMCI_SUCCESS);
478 }
479 
480 /*
481  *------------------------------------------------------------------------------
482  *
483  * vmci_event_register_subscription --
484  *
485  *     Initialize and add subscription to subscriber list.
486  *
487  * Results:
488  *     VMCI_SUCCESS on success, error code otherwise.
489  *
490  * Side effects:
491  *     None.
492  *
493  *------------------------------------------------------------------------------
494  */
495 
496 static int
vmci_event_register_subscription(struct vmci_subscription * sub,vmci_event_type event,uint32_t flags,vmci_event_cb callback,void * callback_data)497 vmci_event_register_subscription(struct vmci_subscription *sub,
498     vmci_event_type event, uint32_t flags, vmci_event_cb callback,
499     void *callback_data)
500 {
501 #define VMCI_EVENT_MAX_ATTEMPTS	10
502 	static vmci_id subscription_id = 0;
503 	int result;
504 	uint32_t attempts = 0;
505 	bool success;
506 
507 	ASSERT(sub);
508 
509 	if (!VMCI_EVENT_VALID(event) || callback == NULL) {
510 		VMCI_LOG_DEBUG(LGPFX"Failed to subscribe to event"
511 		    " (type=%d) (callback=%p) (data=%p).\n",
512 		    event, callback, callback_data);
513 		return (VMCI_ERROR_INVALID_ARGS);
514 	}
515 
516 	if (!vmci_can_schedule_delayed_work()) {
517 		/*
518 		 * If the platform doesn't support delayed work callbacks then
519 		 * don't allow registration for them.
520 		 */
521 		if (flags & VMCI_FLAG_EVENT_DELAYED_CB)
522 			return (VMCI_ERROR_INVALID_ARGS);
523 		sub->run_delayed = false;
524 	} else {
525 		/*
526 		 * The platform supports delayed work callbacks. Honor the
527 		 * requested flags
528 		 */
529 		sub->run_delayed = (flags & VMCI_FLAG_EVENT_DELAYED_CB) ?
530 		    true : false;
531 	}
532 
533 	sub->ref_count = 1;
534 	sub->event = event;
535 	sub->callback = callback;
536 	sub->callback_data = callback_data;
537 
538 	vmci_grab_lock_bh(&subscriber_lock);
539 
540 	for (success = false, attempts = 0;
541 	    success == false && attempts < VMCI_EVENT_MAX_ATTEMPTS;
542 	    attempts++) {
543 		struct vmci_subscription *existing_sub = NULL;
544 
545 		/*
546 		 * We try to get an id a couple of time before claiming we are
547 		 * out of resources.
548 		 */
549 		sub->id = ++subscription_id;
550 
551 		/* Test for duplicate id. */
552 		existing_sub = vmci_event_find(sub->id);
553 		if (existing_sub == NULL) {
554 			/* We succeeded if we didn't find a duplicate. */
555 			success = true;
556 		} else
557 			vmci_event_release(existing_sub);
558 	}
559 
560 	if (success) {
561 		vmci_create_event(&sub->destroy_event);
562 		vmci_list_insert(&subscriber_array[event], sub,
563 		    subscriber_list_item);
564 		result = VMCI_SUCCESS;
565 	} else
566 		result = VMCI_ERROR_NO_RESOURCES;
567 
568 	vmci_release_lock_bh(&subscriber_lock);
569 	return (result);
570 #undef VMCI_EVENT_MAX_ATTEMPTS
571 }
572 
573 /*
574  *------------------------------------------------------------------------------
575  *
576  * vmci_event_unregister_subscription --
577  *
578  *     Remove subscription from subscriber list.
579  *
580  * Results:
581  *     struct vmci_subscription when found, NULL otherwise.
582  *
583  * Side effects:
584  *     None.
585  *
586  *------------------------------------------------------------------------------
587  */
588 
589 static struct vmci_subscription *
vmci_event_unregister_subscription(vmci_id sub_id)590 vmci_event_unregister_subscription(vmci_id sub_id)
591 {
592 	struct vmci_subscription *s;
593 
594 	if (!vmci_initialized_lock(&subscriber_lock))
595 		return NULL;
596 
597 	vmci_grab_lock_bh(&subscriber_lock);
598 	s = vmci_event_find(sub_id);
599 	if (s != NULL) {
600 		vmci_event_release(s);
601 		vmci_list_remove(s, subscriber_list_item);
602 	}
603 	vmci_release_lock_bh(&subscriber_lock);
604 
605 	if (s != NULL) {
606 		vmci_wait_on_event(&s->destroy_event, event_release_cb, s);
607 		vmci_destroy_event(&s->destroy_event);
608 	}
609 
610 	return (s);
611 }
612 
613 /*
614  *------------------------------------------------------------------------------
615  *
616  * vmci_event_subscribe --
617  *
618  *     Subscribe to given event. The callback specified can be fired in
619  *     different contexts depending on what flag is specified while registering.
620  *     If flags contains VMCI_FLAG_EVENT_NONE then the callback is fired with
621  *     the subscriber lock held (and BH context on the guest). If flags contain
622  *     VMCI_FLAG_EVENT_DELAYED_CB then the callback is fired with no locks held
623  *     in thread context. This is useful because other vmci_event functions can
624  *     be called, but it also increases the chances that an event will be
625  *     dropped.
626  *
627  * Results:
628  *     VMCI_SUCCESS on success, error code otherwise.
629  *
630  * Side effects:
631  *     None.
632  *
633  *------------------------------------------------------------------------------
634  */
635 
636 int
vmci_event_subscribe(vmci_event_type event,vmci_event_cb callback,void * callback_data,vmci_id * subscription_id)637 vmci_event_subscribe(vmci_event_type event, vmci_event_cb callback,
638     void *callback_data, vmci_id *subscription_id)
639 {
640 	int retval;
641 	uint32_t flags = VMCI_FLAG_EVENT_NONE;
642 	struct vmci_subscription *s = NULL;
643 
644 	if (subscription_id == NULL) {
645 		VMCI_LOG_DEBUG(LGPFX"Invalid subscription (NULL).\n");
646 		return (VMCI_ERROR_INVALID_ARGS);
647 	}
648 
649 	s = vmci_alloc_kernel_mem(sizeof(*s), VMCI_MEMORY_NORMAL);
650 	if (s == NULL)
651 		return (VMCI_ERROR_NO_MEM);
652 
653 	retval = vmci_event_register_subscription(s, event, flags,
654 	    callback, callback_data);
655 	if (retval < VMCI_SUCCESS) {
656 		vmci_free_kernel_mem(s, sizeof(*s));
657 		return (retval);
658 	}
659 
660 	*subscription_id = s->id;
661 	return (retval);
662 }
663 
664 /*
665  *------------------------------------------------------------------------------
666  *
667  * vmci_event_unsubscribe --
668  *
669  *     Unsubscribe to given event. Removes it from list and frees it.
670  *     Will return callback_data if requested by caller.
671  *
672  * Results:
673  *     VMCI_SUCCESS on success, error code otherwise.
674  *
675  * Side effects:
676  *     None.
677  *
678  *------------------------------------------------------------------------------
679  */
680 
681 int
vmci_event_unsubscribe(vmci_id sub_id)682 vmci_event_unsubscribe(vmci_id sub_id)
683 {
684 	struct vmci_subscription *s;
685 
686 	/*
687 	 * Return subscription. At this point we know noone else is accessing
688 	 * the subscription so we can free it.
689 	 */
690 	s = vmci_event_unregister_subscription(sub_id);
691 	if (s == NULL)
692 		return (VMCI_ERROR_NOT_FOUND);
693 	vmci_free_kernel_mem(s, sizeof(*s));
694 
695 	return (VMCI_SUCCESS);
696 }
697