VirtualBox

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

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

VBoxGuest-netbsd.cpp: Correctly set requestor. bugref:9105

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