VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-netbsd.c@ 93516

Last change on this file since 93516 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.0 KB
Line 
1/* $Id: VBoxGuest-netbsd.c 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions Driver for NetBSD.
4 */
5
6/*
7 * Copyright (C) 2007-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/select.h>
34#include <sys/conf.h>
35#include <sys/kernel.h>
36#include <sys/kmem.h>
37#include <sys/module.h>
38#include <sys/device.h>
39#include <sys/bus.h>
40#include <sys/poll.h>
41#include <sys/proc.h>
42#include <sys/kauth.h>
43#include <sys/stat.h>
44#include <sys/selinfo.h>
45#include <sys/queue.h>
46#include <sys/lock.h>
47#include <sys/types.h>
48#include <sys/conf.h>
49#include <sys/malloc.h>
50#include <sys/uio.h>
51#include <sys/file.h>
52#include <sys/filedesc.h>
53#include <sys/vfs_syscalls.h>
54#include <dev/pci/pcivar.h>
55#include <dev/pci/pcireg.h>
56#include <dev/pci/pcidevs.h>
57
58#include <dev/wscons/wsconsio.h>
59#include <dev/wscons/wsmousevar.h>
60#include <dev/wscons/tpcalibvar.h>
61
62#ifdef PVM
63# undef PVM
64#endif
65#include "VBoxGuestInternal.h"
66#include <VBox/log.h>
67#include <iprt/err.h>
68#include <iprt/assert.h>
69#include <iprt/initterm.h>
70#include <iprt/process.h>
71#include <iprt/mem.h>
72#include <iprt/asm.h>
73
74
75/*********************************************************************************************************************************
76* Defined Constants And Macros *
77*********************************************************************************************************************************/
78/** The module name. */
79#define DEVICE_NAME "vboxguest"
80
81
82/*********************************************************************************************************************************
83* Structures and Typedefs *
84*********************************************************************************************************************************/
85typedef struct VBoxGuestDeviceState
86{
87 device_t sc_dev;
88 pci_chipset_tag_t sc_pc;
89
90 bus_space_tag_t sc_iot;
91 bus_space_handle_t sc_ioh;
92 bus_addr_t sc_iobase;
93 bus_size_t sc_iosize;
94
95 bus_space_tag_t sc_memt;
96 bus_space_handle_t sc_memh;
97
98 /** Size of the memory area. */
99 bus_size_t sc_memsize;
100
101 /** IRQ resource handle. */
102 pci_intr_handle_t ih;
103 /** Pointer to the IRQ handler. */
104 void *pfnIrqHandler;
105
106 /** Controller features, limits and status. */
107 u_int vboxguest_state;
108
109 device_t sc_wsmousedev;
110 VMMDevReqMouseStatus *sc_vmmmousereq;
111 PVBOXGUESTSESSION sc_session;
112 struct tpcalib_softc sc_tpcalib;
113} vboxguest_softc;
114
115
116struct vboxguest_fdata
117{
118 vboxguest_softc *sc;
119 PVBOXGUESTSESSION session;
120};
121
122#define VBOXGUEST_STATE_INITOK 1 << 0
123
124
125/*********************************************************************************************************************************
126* Internal Functions *
127*********************************************************************************************************************************/
128/*
129 * Driver(9) autoconf machinery.
130 */
131static int VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux);
132static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux);
133static void VBoxGuestNetBSDWsmAttach(vboxguest_softc *sc);
134static int VBoxGuestNetBSDDetach(device_t self, int flags);
135
136/*
137 * IRQ related functions.
138 */
139static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *sc, struct pci_attach_args *pa);
140static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc);
141static int VBoxGuestNetBSDISR(void *pvState);
142
143/*
144 * Character device file handlers.
145 */
146static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process);
147static int VBoxGuestNetBSDClose(struct file *fp);
148static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long cmd, void *addr);
149static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_fdata *fdata, u_long command, void *data);
150static int VBoxGuestNetBSDPoll(struct file *fp, int events);
151
152/*
153 * wsmouse(4) accessops
154 */
155static int VBoxGuestNetBSDWsmEnable(void *cookie);
156static void VBoxGuestNetBSDWsmDisable(void *cookie);
157static int VBoxGuestNetBSDWsmIOCtl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l);
158
159static int VBoxGuestNetBSDSetMouseStatus(vboxguest_softc *sc, uint32_t fStatus);
160
161
162/*********************************************************************************************************************************
163* Global Variables *
164*********************************************************************************************************************************/
165extern struct cfdriver vboxguest_cd; /* CFDRIVER_DECL */
166extern struct cfattach vboxguest_ca; /* CFATTACH_DECL */
167
168/*
169 * The /dev/vboxguest character device entry points.
170 */
171static struct cdevsw g_VBoxGuestNetBSDChrDevSW =
172{
173 VBoxGuestNetBSDOpen,
174 noclose,
175 noread,
176 nowrite,
177 noioctl,
178 nostop,
179 notty,
180 nopoll,
181 nommap,
182 nokqfilter,
183};
184
185static const struct fileops vboxguest_fileops = {
186 .fo_read = fbadop_read,
187 .fo_write = fbadop_write,
188 .fo_ioctl = VBoxGuestNetBSDIOCtl,
189 .fo_fcntl = fnullop_fcntl,
190 .fo_poll = VBoxGuestNetBSDPoll,
191 .fo_stat = fbadop_stat,
192 .fo_close = VBoxGuestNetBSDClose,
193 .fo_kqfilter = fnullop_kqfilter,
194 .fo_restart = fnullop_restart
195};
196
197
198const struct wsmouse_accessops vboxguest_wsm_accessops = {
199 VBoxGuestNetBSDWsmEnable,
200 VBoxGuestNetBSDWsmIOCtl,
201 VBoxGuestNetBSDWsmDisable,
202};
203
204
205static struct wsmouse_calibcoords vboxguest_wsm_default_calib = {
206 .minx = VMMDEV_MOUSE_RANGE_MIN,
207 .miny = VMMDEV_MOUSE_RANGE_MIN,
208 .maxx = VMMDEV_MOUSE_RANGE_MAX,
209 .maxy = VMMDEV_MOUSE_RANGE_MAX,
210 .samplelen = WSMOUSE_CALIBCOORDS_RESET,
211};
212
213/** Device extention & session data association structure. */
214static VBOXGUESTDEVEXT g_DevExt;
215
216static vboxguest_softc *g_SC;
217
218/** Reference counter */
219static volatile uint32_t cUsers;
220/** selinfo structure used for polling. */
221static struct selinfo g_SelInfo;
222
223
224CFATTACH_DECL_NEW(vboxguest, sizeof(vboxguest_softc),
225 VBoxGuestNetBSDMatch, VBoxGuestNetBSDAttach, VBoxGuestNetBSDDetach, NULL);
226
227
228static int VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux)
229{
230 const struct pci_attach_args *pa = aux;
231
232 if (RT_UNLIKELY(g_SC != NULL)) /* should not happen */
233 return 0;
234
235 if ( PCI_VENDOR(pa->pa_id) == VMMDEV_VENDORID
236 && PCI_PRODUCT(pa->pa_id) == VMMDEV_DEVICEID)
237 {
238 return 1;
239 }
240
241 return 0;
242}
243
244
245static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux)
246{
247 int rc = VINF_SUCCESS;
248 int iResId = 0;
249 vboxguest_softc *sc;
250 struct pci_attach_args *pa = aux;
251 bus_space_tag_t iot, memt;
252 bus_space_handle_t ioh, memh;
253 bus_dma_segment_t seg;
254 int ioh_valid, memh_valid;
255
256 KASSERT(g_SC == NULL);
257
258 cUsers = 0;
259
260 aprint_normal(": VirtualBox Guest\n");
261
262 sc = device_private(self);
263 sc->sc_dev = self;
264
265 /*
266 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
267 */
268 rc = RTR0Init(0);
269 if (RT_FAILURE(rc))
270 {
271 LogFunc(("RTR0Init failed.\n"));
272 aprint_error_dev(sc->sc_dev, "RTR0Init failed\n");
273 return;
274 }
275
276 sc->sc_pc = pa->pa_pc;
277
278 /*
279 * Allocate I/O port resource.
280 */
281 ioh_valid = (pci_mapreg_map(pa, PCI_BAR0,
282 PCI_MAPREG_TYPE_IO, 0,
283 &sc->sc_iot, &sc->sc_ioh,
284 &sc->sc_iobase, &sc->sc_iosize) == 0);
285
286 if (ioh_valid)
287 {
288
289 /*
290 * Map the MMIO region.
291 */
292 memh_valid = (pci_mapreg_map(pa, PCI_BAR1,
293 PCI_MAPREG_TYPE_MEM, BUS_SPACE_MAP_LINEAR,
294 &sc->sc_memt, &sc->sc_memh,
295 NULL, &sc->sc_memsize) == 0);
296 if (memh_valid)
297 {
298 /*
299 * Call the common device extension initializer.
300 */
301 rc = VGDrvCommonInitDevExt(&g_DevExt, sc->sc_iobase,
302 bus_space_vaddr(sc->sc_memt, sc->sc_memh),
303 sc->sc_memsize,
304#if ARCH_BITS == 64
305 VBOXOSTYPE_NetBSD_x64,
306#else
307 VBOXOSTYPE_NetBSD,
308#endif
309 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
310 if (RT_SUCCESS(rc))
311 {
312 /*
313 * Add IRQ of VMMDev.
314 */
315 rc = VBoxGuestNetBSDAddIRQ(sc, pa);
316 if (RT_SUCCESS(rc))
317 {
318 sc->vboxguest_state |= VBOXGUEST_STATE_INITOK;
319
320 /*
321 * Read host configuration.
322 */
323 VGDrvCommonProcessOptionsFromHost(&g_DevExt);
324
325 /*
326 * Attach wsmouse.
327 */
328 VBoxGuestNetBSDWsmAttach(sc);
329
330 g_SC = sc;
331 return;
332 }
333 VGDrvCommonDeleteDevExt(&g_DevExt);
334 }
335 else
336 {
337 aprint_error_dev(sc->sc_dev, "init failed\n");
338 }
339 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize);
340 }
341 else
342 {
343 aprint_error_dev(sc->sc_dev, "MMIO mapping failed\n");
344 }
345 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
346 }
347 else
348 {
349 aprint_error_dev(sc->sc_dev, "IO mapping failed\n");
350 }
351
352 RTR0Term();
353 return;
354}
355
356
357/**
358 * Sets IRQ for VMMDev.
359 *
360 * @returns NetBSD error code.
361 * @param sc Pointer to the state info structure.
362 * @param pa Pointer to the PCI attach arguments.
363 */
364static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *sc, struct pci_attach_args *pa)
365{
366 int iResId = 0;
367 int rc = 0;
368 const char *intrstr;
369#if __NetBSD_Prereq__(6, 99, 39)
370 char intstrbuf[100];
371#endif
372
373 LogFlow((DEVICE_NAME ": %s\n", __func__));
374
375 if (pci_intr_map(pa, &sc->ih))
376 {
377 aprint_error_dev(sc->sc_dev, "couldn't map interrupt.\n");
378 return VERR_DEV_IO_ERROR;
379 }
380
381 intrstr = pci_intr_string(sc->sc_pc, sc->ih
382#if __NetBSD_Prereq__(6, 99, 39)
383 , intstrbuf, sizeof(intstrbuf)
384#endif
385 );
386 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
387
388 sc->pfnIrqHandler = pci_intr_establish(sc->sc_pc, sc->ih, IPL_BIO, VBoxGuestNetBSDISR, sc);
389 if (sc->pfnIrqHandler == NULL)
390 {
391 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n");
392 return VERR_DEV_IO_ERROR;
393 }
394
395 return VINF_SUCCESS;
396}
397
398
399/*
400 * Optionally attach wsmouse(4) device as a child.
401 */
402static void VBoxGuestNetBSDWsmAttach(vboxguest_softc *sc)
403{
404 struct wsmousedev_attach_args am = { &vboxguest_wsm_accessops, sc };
405
406 PVBOXGUESTSESSION session = NULL;
407 VMMDevReqMouseStatus *req = NULL;
408 int rc;
409
410 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &session);
411 if (RT_FAILURE(rc))
412 goto fail;
413
414 rc = VbglR0GRAlloc((VMMDevRequestHeader **)&req, sizeof(*req),
415 VMMDevReq_GetMouseStatus);
416 if (RT_FAILURE(rc))
417 goto fail;
418
419#if __NetBSD_Prereq__(9,99,88)
420 sc->sc_wsmousedev = config_found(sc->sc_dev, &am, wsmousedevprint,
421 CFARGS(.iattr = "wsmousedev"));
422#elif __NetBSD_Prereq__(9,99,82)
423 sc->sc_wsmousedev = config_found(sc->sc_dev, &am, wsmousedevprint,
424 CFARG_IATTR, "wsmousedev",
425 CFARG_EOL);
426#else
427 sc->sc_wsmousedev = config_found_ia(sc->sc_dev, "wsmousedev",
428 &am, wsmousedevprint);
429#endif
430
431 if (sc->sc_wsmousedev == NULL)
432 goto fail;
433
434 sc->sc_session = session;
435 sc->sc_vmmmousereq = req;
436
437 tpcalib_init(&sc->sc_tpcalib);
438 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
439 &vboxguest_wsm_default_calib, 0, 0);
440 return;
441
442 fail:
443 if (session != NULL)
444 VGDrvCommonCloseSession(&g_DevExt, session);
445 if (req != NULL)
446 VbglR0GRFree((VMMDevRequestHeader *)req);
447}
448
449
450static int VBoxGuestNetBSDDetach(device_t self, int flags)
451{
452 vboxguest_softc *sc;
453 sc = device_private(self);
454
455 LogFlow((DEVICE_NAME ": %s\n", __func__));
456
457 if (cUsers > 0)
458 return EBUSY;
459
460 if ((sc->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
461 return 0;
462
463 /*
464 * Reverse what we did in VBoxGuestNetBSDAttach.
465 */
466 if (sc->sc_vmmmousereq != NULL)
467 VbglR0GRFree((VMMDevRequestHeader *)sc->sc_vmmmousereq);
468
469 VBoxGuestNetBSDRemoveIRQ(sc);
470
471 VGDrvCommonDeleteDevExt(&g_DevExt);
472
473 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize);
474 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
475
476 RTR0Term();
477
478 return config_detach_children(self, flags);
479}
480
481
482/**
483 * Removes IRQ for VMMDev.
484 *
485 * @param sc Opaque pointer to the state info structure.
486 */
487static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc)
488{
489 LogFlow((DEVICE_NAME ": %s\n", __func__));
490
491 if (sc->pfnIrqHandler)
492 {
493 pci_intr_disestablish(sc->sc_pc, sc->pfnIrqHandler);
494 }
495}
496
497
498/**
499 * Interrupt service routine.
500 *
501 * @returns Whether the interrupt was from VMMDev.
502 * @param pvState Opaque pointer to the device state.
503 */
504static int VBoxGuestNetBSDISR(void *pvState)
505{
506 LogFlow((DEVICE_NAME ": %s: pvState=%p\n", __func__, pvState));
507
508 bool fOurIRQ = VGDrvCommonISR(&g_DevExt);
509
510 return fOurIRQ ? 1 : 0;
511}
512
513
514/*
515 * Called by VGDrvCommonISR() if mouse position changed
516 */
517void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
518{
519 vboxguest_softc *sc = g_SC;
520
521 LogFlow((DEVICE_NAME ": %s\n", __func__));
522
523 /*
524 * Wake up poll waiters.
525 */
526 selnotify(&g_SelInfo, 0, 0);
527
528 if (sc->sc_vmmmousereq != NULL) {
529 int x, y;
530 int rc;
531
532 sc->sc_vmmmousereq->mouseFeatures = 0;
533 sc->sc_vmmmousereq->pointerXPos = 0;
534 sc->sc_vmmmousereq->pointerYPos = 0;
535
536 rc = VbglR0GRPerform(&sc->sc_vmmmousereq->header);
537 if (RT_FAILURE(rc))
538 return;
539
540 tpcalib_trans(&sc->sc_tpcalib,
541 sc->sc_vmmmousereq->pointerXPos,
542 sc->sc_vmmmousereq->pointerYPos,
543 &x, &y);
544
545 wsmouse_input(sc->sc_wsmousedev,
546 0, /* buttons */
547 x, y,
548 0, 0, /* z, w */
549 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
550 }
551}
552
553
554bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
555{
556 RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue);
557 return false;
558}
559
560
561static int VBoxGuestNetBSDSetMouseStatus(vboxguest_softc *sc, uint32_t fStatus)
562{
563 VBGLIOCSETMOUSESTATUS Req;
564 int rc;
565
566 VBGLREQHDR_INIT(&Req.Hdr, SET_MOUSE_STATUS);
567 Req.u.In.fStatus = fStatus;
568 rc = VGDrvCommonIoCtl(VBGL_IOCTL_SET_MOUSE_STATUS,
569 &g_DevExt,
570 sc->sc_session,
571 &Req.Hdr, sizeof(Req));
572 if (RT_SUCCESS(rc))
573 rc = Req.Hdr.rc;
574
575 return rc;
576}
577
578
579static int
580VBoxGuestNetBSDWsmEnable(void *cookie)
581{
582 vboxguest_softc *sc = cookie;
583 int rc;
584
585 rc = VBoxGuestNetBSDSetMouseStatus(sc, VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
586 | VMMDEV_MOUSE_NEW_PROTOCOL);
587 if (RT_FAILURE(rc))
588 return RTErrConvertToErrno(rc);
589
590 return 0;
591}
592
593
594static void
595VBoxGuestNetBSDWsmDisable(void *cookie)
596{
597 vboxguest_softc *sc = cookie;
598 VBoxGuestNetBSDSetMouseStatus(sc, 0);
599}
600
601
602static int
603VBoxGuestNetBSDWsmIOCtl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
604{
605 vboxguest_softc *sc = cookie;
606
607 switch (cmd) {
608 case WSMOUSEIO_GTYPE:
609 *(u_int *)data = WSMOUSE_TYPE_TPANEL;
610 break;
611
612 case WSMOUSEIO_SCALIBCOORDS:
613 case WSMOUSEIO_GCALIBCOORDS:
614 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
615
616 default:
617 return EPASSTHROUGH;
618 }
619 return 0;
620}
621
622
623/**
624 * File open handler
625 *
626 */
627static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *pLwp)
628{
629 vboxguest_softc *sc;
630 struct vboxguest_fdata *fdata;
631 file_t *fp;
632 int fd, error;
633
634 LogFlow((DEVICE_NAME ": %s\n", __func__));
635
636 if ((sc = device_lookup_private(&vboxguest_cd, minor(device))) == NULL)
637 {
638 printf("device_lookup_private failed\n");
639 return (ENXIO);
640 }
641
642 if ((sc->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
643 {
644 aprint_error_dev(sc->sc_dev, "device not configured\n");
645 return (ENXIO);
646 }
647
648 fdata = kmem_alloc(sizeof(*fdata), KM_SLEEP);
649 if (fdata != NULL)
650 {
651 fdata->sc = sc;
652
653 error = fd_allocfile(&fp, &fd);
654 if (error == 0)
655 {
656 /*
657 * Create a new session.
658 */
659 struct kauth_cred *pCred = pLwp->l_cred;
660 int fHaveCred = (pCred != NULL && pCred != NOCRED && pCred != FSCRED);
661 uint32_t fRequestor;
662 int fIsWheel;
663 int rc;
664
665 fRequestor = VMMDEV_REQUESTOR_USERMODE | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
666
667 /* uid */
668 if (fHaveCred && kauth_cred_geteuid(pCred) == (uid_t)0)
669 fRequestor |= VMMDEV_REQUESTOR_USR_ROOT;
670 else
671 fRequestor |= VMMDEV_REQUESTOR_USR_USER;
672
673 /* gid */
674 if (fHaveCred
675 && (kauth_cred_getegid(pCred) == (gid_t)0
676 || (kauth_cred_ismember_gid(pCred, 0, &fIsWheel) == 0
677 && fIsWheel)))
678 fRequestor |= VMMDEV_REQUESTOR_GRP_WHEEL;
679
680#if 0 /** @todo implement /dev/vboxuser */
681 if (!fUnrestricted)
682 fRequestor |= VMMDEV_REQUESTOR_USER_DEVICE;
683#else
684 fRequestor |= VMMDEV_REQUESTOR_NO_USER_DEVICE;
685#endif
686
687 /** @todo can we find out if pLwp is on the console? */
688 fRequestor |= VMMDEV_REQUESTOR_CON_DONT_KNOW;
689
690 rc = VGDrvCommonCreateUserSession(&g_DevExt, fRequestor, &fdata->session);
691 if (RT_SUCCESS(rc))
692 {
693 ASMAtomicIncU32(&cUsers);
694 return fd_clone(fp, fd, flags, &vboxguest_fileops, fdata);
695 }
696
697 aprint_error_dev(sc->sc_dev, "VBox session creation failed\n");
698 closef(fp); /* ??? */
699 error = RTErrConvertToErrno(rc);
700 }
701 kmem_free(fdata, sizeof(*fdata));
702 }
703 else
704 error = ENOMEM;
705 return error;
706}
707
708/**
709 * File close handler
710 *
711 */
712static int VBoxGuestNetBSDClose(struct file *fp)
713{
714 struct vboxguest_fdata *fdata = fp->f_data;
715 vboxguest_softc *sc = fdata->sc;
716
717 LogFlow((DEVICE_NAME ": %s\n", __func__));
718
719 VGDrvCommonCloseSession(&g_DevExt, fdata->session);
720 ASMAtomicDecU32(&cUsers);
721
722 kmem_free(fdata, sizeof(*fdata));
723
724 return 0;
725}
726
727/**
728 * IOCTL handler
729 *
730 */
731static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long command, void *data)
732{
733 struct vboxguest_fdata *fdata = fp->f_data;
734
735 if (VBGL_IOCTL_IS_FAST(command))
736 return VGDrvCommonIoCtlFast(command, &g_DevExt, fdata->session);
737
738 return VBoxGuestNetBSDIOCtlSlow(fdata, command, data);
739}
740
741static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_fdata *fdata, u_long command, void *data)
742{
743 vboxguest_softc *sc = fdata->sc;
744 size_t cbReq = IOCPARM_LEN(command);
745 PVBGLREQHDR pHdr = NULL;
746 void *pvUser = NULL;
747 int err, rc;
748
749 LogFlow(("%s: command=%#lx data=%p\n", __func__, command, data));
750
751 /*
752 * Buffered request?
753 */
754 if ((command & IOC_DIRMASK) == IOC_INOUT)
755 {
756 /* will be validated by VGDrvCommonIoCtl() */
757 pHdr = (PVBGLREQHDR)data;
758 }
759
760 /*
761 * Big unbuffered request? "data" is the userland pointer.
762 */
763 else if ((command & IOC_DIRMASK) == IOC_VOID && cbReq != 0)
764 {
765 /*
766 * Read the header, validate it and figure out how much that
767 * needs to be buffered.
768 */
769 VBGLREQHDR Hdr;
770
771 if (RT_UNLIKELY(cbReq < sizeof(Hdr)))
772 return ENOTTY;
773
774 pvUser = data;
775 err = copyin(pvUser, &Hdr, sizeof(Hdr));
776 if (RT_UNLIKELY(err != 0))
777 return err;
778
779 if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
780 return ENOTTY;
781
782 if (cbReq > 16 * _1M)
783 return EINVAL;
784
785 if (Hdr.cbOut == 0)
786 Hdr.cbOut = Hdr.cbIn;
787
788 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr) || Hdr.cbIn > cbReq
789 || Hdr.cbOut < sizeof(Hdr) || Hdr.cbOut > cbReq))
790 return EINVAL;
791
792 /*
793 * Allocate buffer and copy in the data.
794 */
795 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
796
797 pHdr = (PVBGLREQHDR)RTMemTmpAlloc(cbReq);
798 if (RT_UNLIKELY(pHdr == NULL))
799 {
800 LogRel(("%s: command=%#lx data=%p: unable to allocate %zu bytes\n",
801 __func__, command, data, cbReq));
802 return ENOMEM;
803 }
804
805 err = copyin(pvUser, pHdr, Hdr.cbIn);
806 if (err != 0)
807 {
808 RTMemTmpFree(pHdr);
809 return err;
810 }
811
812 if (Hdr.cbIn < cbReq)
813 memset((uint8_t *)pHdr + Hdr.cbIn, '\0', cbReq - Hdr.cbIn);
814 }
815
816 /*
817 * Process the IOCtl.
818 */
819 rc = VGDrvCommonIoCtl(command, &g_DevExt, fdata->session, pHdr, cbReq);
820 if (RT_SUCCESS(rc))
821 {
822 err = 0;
823
824 /*
825 * If unbuffered, copy back the result before returning.
826 */
827 if (pvUser != NULL)
828 {
829 size_t cbOut = pHdr->cbOut;
830 if (cbOut > cbReq)
831 {
832 LogRel(("%s: command=%#lx data=%p: too much output: %zu > %zu\n",
833 __func__, command, data, cbOut, cbReq));
834 cbOut = cbReq;
835 }
836
837 err = copyout(pHdr, pvUser, cbOut);
838 RTMemTmpFree(pHdr);
839 }
840 }
841 else
842 {
843 LogRel(("%s: command=%#lx data=%p: error %Rrc\n",
844 __func__, command, data, rc));
845
846 if (pvUser != NULL)
847 RTMemTmpFree(pHdr);
848
849 err = RTErrConvertToErrno(rc);
850 }
851
852 return err;
853}
854
855static int VBoxGuestNetBSDPoll(struct file *fp, int events)
856{
857 struct vboxguest_fdata *fdata = fp->f_data;
858 vboxguest_softc *sc = fdata->sc;
859
860 int rc = 0;
861 int events_processed;
862
863 uint32_t u32CurSeq;
864
865 LogFlow((DEVICE_NAME ": %s\n", __func__));
866
867 u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
868 if (fdata->session->u32MousePosChangedSeq != u32CurSeq)
869 {
870 events_processed = events & (POLLIN | POLLRDNORM);
871 fdata->session->u32MousePosChangedSeq = u32CurSeq;
872 }
873 else
874 {
875 events_processed = 0;
876
877 selrecord(curlwp, &g_SelInfo);
878 }
879
880 return events_processed;
881}
882
883
884/**
885 * @note This code is duplicated on other platforms with variations, so please
886 * keep them all up to date when making changes!
887 */
888int VBOXCALL VBoxGuestIDC(void *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq)
889{
890 /*
891 * Simple request validation (common code does the rest).
892 */
893 int rc;
894 if ( RT_VALID_PTR(pReqHdr)
895 && cbReq >= sizeof(*pReqHdr))
896 {
897 /*
898 * All requests except the connect one requires a valid session.
899 */
900 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
901 if (pSession)
902 {
903 if ( RT_VALID_PTR(pSession)
904 && pSession->pDevExt == &g_DevExt)
905 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
906 else
907 rc = VERR_INVALID_HANDLE;
908 }
909 else if (uReq == VBGL_IOCTL_IDC_CONNECT)
910 {
911 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
912 if (RT_SUCCESS(rc))
913 {
914 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
915 if (RT_FAILURE(rc))
916 VGDrvCommonCloseSession(&g_DevExt, pSession);
917 }
918 }
919 else
920 rc = VERR_INVALID_HANDLE;
921 }
922 else
923 rc = VERR_INVALID_POINTER;
924 return rc;
925}
926
927
928MODULE(MODULE_CLASS_DRIVER, vboxguest, "pci");
929
930/*
931 * XXX: See netbsd/vboxguest.ioconf for the details.
932*/
933#if 0
934#include "ioconf.c"
935#else
936
937static const struct cfiattrdata wsmousedevcf_iattrdata = {
938 "wsmousedev", 1, {
939 { "mux", "0", 0 },
940 }
941};
942
943/* device vboxguest: wsmousedev */
944static const struct cfiattrdata * const vboxguest_attrs[] = { &wsmousedevcf_iattrdata, NULL };
945CFDRIVER_DECL(vboxguest, DV_DULL, vboxguest_attrs);
946
947static struct cfdriver * const cfdriver_ioconf_vboxguest[] = {
948 &vboxguest_cd, NULL
949};
950
951
952static const struct cfparent vboxguest_pspec = {
953 "pci", "pci", DVUNIT_ANY
954};
955static int vboxguest_loc[] = { -1, -1 };
956
957
958static const struct cfparent wsmousedev_pspec = {
959 "wsmousedev", "vboxguest", DVUNIT_ANY
960};
961static int wsmousedev_loc[] = { 0 };
962
963
964static struct cfdata cfdata_ioconf_vboxguest[] = {
965 /* vboxguest0 at pci? dev ? function ? */
966 {
967 .cf_name = "vboxguest",
968 .cf_atname = "vboxguest",
969 .cf_unit = 0, /* Only unit 0 is ever used */
970 .cf_fstate = FSTATE_NOTFOUND,
971 .cf_loc = vboxguest_loc,
972 .cf_flags = 0,
973 .cf_pspec = &vboxguest_pspec,
974 },
975
976 /* wsmouse* at vboxguest? */
977 { "wsmouse", "wsmouse", 0, FSTATE_STAR, wsmousedev_loc, 0, &wsmousedev_pspec },
978
979 { NULL, NULL, 0, 0, NULL, 0, NULL }
980};
981
982static struct cfattach * const vboxguest_cfattachinit[] = {
983 &vboxguest_ca, NULL
984};
985
986static const struct cfattachinit cfattach_ioconf_vboxguest[] = {
987 { "vboxguest", vboxguest_cfattachinit },
988 { NULL, NULL }
989};
990#endif
991
992
993static int
994vboxguest_modcmd(modcmd_t cmd, void *opaque)
995{
996 devmajor_t bmajor, cmajor;
997#if !__NetBSD_Prereq__(8,99,46)
998 register_t retval;
999#endif
1000 int error;
1001
1002 LogFlow((DEVICE_NAME ": %s\n", __func__));
1003
1004 switch (cmd)
1005 {
1006 case MODULE_CMD_INIT:
1007 error = config_init_component(cfdriver_ioconf_vboxguest,
1008 cfattach_ioconf_vboxguest,
1009 cfdata_ioconf_vboxguest);
1010 if (error)
1011 break;
1012
1013 bmajor = cmajor = NODEVMAJOR;
1014 error = devsw_attach("vboxguest",
1015 NULL, &bmajor,
1016 &g_VBoxGuestNetBSDChrDevSW, &cmajor);
1017 if (error)
1018 {
1019 if (error == EEXIST)
1020 error = 0; /* maybe built-in ... improve eventually */
1021 else
1022 break;
1023 }
1024
1025 error = do_sys_mknod(curlwp, "/dev/vboxguest",
1026 0666|S_IFCHR, makedev(cmajor, 0),
1027#if !__NetBSD_Prereq__(8,99,46)
1028 &retval,
1029#endif
1030 UIO_SYSSPACE);
1031 if (error == EEXIST) {
1032 error = 0;
1033
1034 /*
1035 * Since NetBSD doesn't yet have a major reserved for
1036 * vboxguest, the (first free) major we get will
1037 * change when new devices are added, so an existing
1038 * /dev/vboxguest may now point to some other device,
1039 * creating confusion (tripped me up a few times).
1040 */
1041 aprint_normal("vboxguest: major %d:"
1042 " check existing /dev/vboxguest\n", cmajor);
1043 }
1044 break;
1045
1046 case MODULE_CMD_FINI:
1047 error = config_fini_component(cfdriver_ioconf_vboxguest,
1048 cfattach_ioconf_vboxguest,
1049 cfdata_ioconf_vboxguest);
1050 if (error)
1051 break;
1052
1053 devsw_detach(NULL, &g_VBoxGuestNetBSDChrDevSW);
1054 break;
1055
1056 default:
1057 return ENOTTY;
1058 }
1059 return error;
1060}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette