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