VirtualBox

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

Last change on this file since 76444 was 76444, checked in by vboxsync, 6 years ago

VBoxGuest-netbsd.c: Fix kauth check for wheel group membership.

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

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