VirtualBox

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

Last change on this file since 70047 was 70047, checked in by vboxsync, 7 years ago

VBoxGuest-netbsd.c: give io bus space members their usual names.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/* $Id: VBoxGuest-netbsd.c 70047 2017-12-09 01:39:16Z 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/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 iVMMDevMemResId;
94 bus_space_handle_t VMMDevMemHandle;
95
96 /** Size of the memory area. */
97 bus_size_t VMMDevMemSize;
98 /** Mapping of the register space */
99 bus_addr_t pMMIOBase;
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_MAPREG_START, 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_MAPREG_START+4, PCI_MAPREG_TYPE_MEM, BUS_SPACE_MAP_LINEAR,
292 &sc->iVMMDevMemResId, &sc->VMMDevMemHandle,
293 &sc->pMMIOBase, &sc->VMMDevMemSize) == 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->iVMMDevMemResId,
301 sc->VMMDevMemHandle),
302 sc->VMMDevMemSize,
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 VBoxGuestNetBSDWsmAttach(sc);
319
320 g_SC = sc;
321 return;
322 }
323 VGDrvCommonDeleteDevExt(&g_DevExt);
324 }
325 else
326 {
327 aprint_error_dev(sc->sc_dev, "init failed\n");
328 }
329 bus_space_unmap(sc->iVMMDevMemResId, sc->VMMDevMemHandle, sc->VMMDevMemSize);
330 }
331 else
332 {
333 aprint_error_dev(sc->sc_dev, "MMIO mapping failed\n");
334 }
335 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
336 }
337 else
338 {
339 aprint_error_dev(sc->sc_dev, "IO mapping failed\n");
340 }
341
342 RTR0Term();
343 return;
344}
345
346
347/**
348 * Sets IRQ for VMMDev.
349 *
350 * @returns NetBSD error code.
351 * @param vboxguest Pointer to the state info structure.
352 * @param pa Pointer to the PCI attach arguments.
353 */
354static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *sc, struct pci_attach_args *pa)
355{
356 int iResId = 0;
357 int rc = 0;
358 const char *intrstr;
359#if __NetBSD_Prereq__(6, 99, 39)
360 char intstrbuf[100];
361#endif
362
363 LogFlow((DEVICE_NAME ": %s\n", __func__));
364
365 if (pci_intr_map(pa, &sc->ih))
366 {
367 aprint_error_dev(sc->sc_dev, "couldn't map interrupt.\n");
368 return VERR_DEV_IO_ERROR;
369 }
370
371 intrstr = pci_intr_string(sc->sc_pc, sc->ih
372#if __NetBSD_Prereq__(6, 99, 39)
373 , intstrbuf, sizeof(intstrbuf)
374#endif
375 );
376 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
377
378 sc->pfnIrqHandler = pci_intr_establish(sc->sc_pc, sc->ih, IPL_BIO, VBoxGuestNetBSDISR, sc);
379 if (sc->pfnIrqHandler == NULL)
380 {
381 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n");
382 return VERR_DEV_IO_ERROR;
383 }
384
385 return VINF_SUCCESS;
386}
387
388
389/*
390 * Optionally attach wsmouse(4) device as a child.
391 */
392static void VBoxGuestNetBSDWsmAttach(vboxguest_softc *sc)
393{
394 struct wsmousedev_attach_args am = { &vboxguest_wsm_accessops, sc };
395
396 PVBOXGUESTSESSION session = NULL;
397 VMMDevReqMouseStatus *req = NULL;
398 int rc;
399
400 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &session);
401 if (RT_FAILURE(rc))
402 goto fail;
403
404 rc = VbglR0GRAlloc((VMMDevRequestHeader **)&req, sizeof(*req),
405 VMMDevReq_GetMouseStatus);
406 if (RT_FAILURE(rc))
407 goto fail;
408
409 sc->sc_wsmousedev = config_found_ia(sc->sc_dev, "wsmousedev", &am, wsmousedevprint);
410 if (sc->sc_wsmousedev == NULL)
411 goto fail;
412
413 sc->sc_session = session;
414 sc->sc_vmmmousereq = req;
415
416 tpcalib_init(&sc->sc_tpcalib);
417 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
418 &vboxguest_wsm_default_calib, 0, 0);
419 return;
420
421 fail:
422 if (session != NULL)
423 VGDrvCommonCloseSession(&g_DevExt, session);
424 if (req != NULL)
425 VbglR0GRFree((VMMDevRequestHeader *)req);
426}
427
428
429static int VBoxGuestNetBSDDetach(device_t self, int flags)
430{
431 vboxguest_softc *sc;
432 sc = device_private(self);
433
434 LogFlow((DEVICE_NAME ": %s\n", __func__));
435
436 if (cUsers > 0)
437 return EBUSY;
438
439 if ((sc->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
440 return 0;
441
442 /*
443 * Reverse what we did in VBoxGuestNetBSDAttach.
444 */
445 if (sc->sc_vmmmousereq != NULL)
446 VbglR0GRFree((VMMDevRequestHeader *)sc->sc_vmmmousereq);
447
448 VBoxGuestNetBSDRemoveIRQ(sc);
449
450 VGDrvCommonDeleteDevExt(&g_DevExt);
451
452 bus_space_unmap(sc->iVMMDevMemResId, sc->VMMDevMemHandle, sc->VMMDevMemSize);
453 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
454
455 RTR0Term();
456
457 return config_detach_children(self, flags);
458}
459
460
461/**
462 * Removes IRQ for VMMDev.
463 *
464 * @param vboxguest Opaque pointer to the state info structure.
465 */
466static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc)
467{
468 LogFlow((DEVICE_NAME ": %s\n", __func__));
469
470 if (sc->pfnIrqHandler)
471 {
472 pci_intr_disestablish(sc->sc_pc, sc->pfnIrqHandler);
473 }
474}
475
476
477/**
478 * Interrupt service routine.
479 *
480 * @returns Whether the interrupt was from VMMDev.
481 * @param pvState Opaque pointer to the device state.
482 */
483static int VBoxGuestNetBSDISR(void *pvState)
484{
485 LogFlow((DEVICE_NAME ": %s: pvState=%p\n", __func__, pvState));
486
487 bool fOurIRQ = VGDrvCommonISR(&g_DevExt);
488
489 return fOurIRQ ? 0 : 1;
490}
491
492
493/*
494 * Called by VGDrvCommonISR() if mouse position changed
495 */
496void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
497{
498 vboxguest_softc *sc = g_SC;
499
500 LogFlow((DEVICE_NAME ": %s\n", __func__));
501
502 /*
503 * Wake up poll waiters.
504 */
505 selnotify(&g_SelInfo, 0, 0);
506
507 if (sc->sc_vmmmousereq != NULL) {
508 int x, y;
509 int rc;
510
511 sc->sc_vmmmousereq->mouseFeatures = 0;
512 sc->sc_vmmmousereq->pointerXPos = 0;
513 sc->sc_vmmmousereq->pointerYPos = 0;
514
515 rc = VbglR0GRPerform(&sc->sc_vmmmousereq->header);
516 if (RT_FAILURE(rc))
517 return;
518
519 tpcalib_trans(&sc->sc_tpcalib,
520 sc->sc_vmmmousereq->pointerXPos,
521 sc->sc_vmmmousereq->pointerYPos,
522 &x, &y);
523
524 wsmouse_input(sc->sc_wsmousedev,
525 0, /* buttons */
526 x, y,
527 0, 0, /* z, w */
528 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
529 }
530}
531
532
533static int VBoxGuestNetBSDSetMouseStatus(vboxguest_softc *sc, uint32_t fStatus)
534{
535 VBGLIOCSETMOUSESTATUS Req;
536 int rc;
537
538 VBGLREQHDR_INIT(&Req.Hdr, SET_MOUSE_STATUS);
539 Req.u.In.fStatus = fStatus;
540 rc = VGDrvCommonIoCtl(VBGL_IOCTL_SET_MOUSE_STATUS,
541 &g_DevExt,
542 sc->sc_session,
543 &Req.Hdr, sizeof(Req));
544 if (RT_SUCCESS(rc))
545 rc = Req.Hdr.rc;
546
547 return rc;
548}
549
550
551static int
552VBoxGuestNetBSDWsmEnable(void *cookie)
553{
554 vboxguest_softc *sc = cookie;
555 int rc;
556
557 rc = VBoxGuestNetBSDSetMouseStatus(sc, VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
558 | VMMDEV_MOUSE_NEW_PROTOCOL);
559 if (RT_FAILURE(rc))
560 return RTErrConvertToErrno(rc);
561
562 return 0;
563}
564
565
566static void
567VBoxGuestNetBSDWsmDisable(void *cookie)
568{
569 vboxguest_softc *sc = cookie;
570 VBoxGuestNetBSDSetMouseStatus(sc, 0);
571}
572
573
574static int
575VBoxGuestNetBSDWsmIOCtl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
576{
577 vboxguest_softc *sc = cookie;
578
579 switch (cmd) {
580 case WSMOUSEIO_GTYPE:
581 *(u_int *)data = WSMOUSE_TYPE_TPANEL;
582 break;
583
584 case WSMOUSEIO_SCALIBCOORDS:
585 case WSMOUSEIO_GCALIBCOORDS:
586 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
587
588 default:
589 return EPASSTHROUGH;
590 }
591 return 0;
592}
593
594
595/**
596 * File open handler
597 *
598 */
599static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process)
600{
601 int rc;
602 vboxguest_softc *sc;
603 struct vboxguest_fdata *fdata;
604 file_t *fp;
605 int fd, error;
606
607 LogFlow((DEVICE_NAME ": %s\n", __func__));
608
609 if ((sc = device_lookup_private(&vboxguest_cd, minor(device))) == NULL)
610 {
611 printf("device_lookup_private failed\n");
612 return (ENXIO);
613 }
614
615 if ((sc->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
616 {
617 aprint_error_dev(sc->sc_dev, "device not configured\n");
618 return (ENXIO);
619 }
620
621 fdata = kmem_alloc(sizeof(*fdata), KM_SLEEP);
622 if (fdata == NULL)
623 {
624 return (ENOMEM);
625 }
626
627 fdata->sc = sc;
628
629 if ((error = fd_allocfile(&fp, &fd)) != 0)
630 {
631 kmem_free(fdata, sizeof(*fdata));
632 return error;
633 }
634
635 /*
636 * Create a new session.
637 */
638 rc = VGDrvCommonCreateUserSession(&g_DevExt, &fdata->session);
639 if (! RT_SUCCESS(rc))
640 {
641 aprint_error_dev(sc->sc_dev, "VBox session creation failed\n");
642 closef(fp); /* ??? */
643 kmem_free(fdata, sizeof(*fdata));
644 return RTErrConvertToErrno(rc);
645 }
646 ASMAtomicIncU32(&cUsers);
647 return fd_clone(fp, fd, flags, &vboxguest_fileops, fdata);
648
649}
650
651/**
652 * File close handler
653 *
654 */
655static int VBoxGuestNetBSDClose(struct file *fp)
656{
657 struct vboxguest_fdata *fdata = fp->f_data;
658 vboxguest_softc *sc = fdata->sc;
659
660 LogFlow((DEVICE_NAME ": %s\n", __func__));
661
662 VGDrvCommonCloseSession(&g_DevExt, fdata->session);
663 ASMAtomicDecU32(&cUsers);
664
665 kmem_free(fdata, sizeof(*fdata));
666
667 return 0;
668}
669
670/**
671 * IOCTL handler
672 *
673 */
674static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long command, void *data)
675{
676 struct vboxguest_fdata *fdata = fp->f_data;
677
678 if (VBGL_IOCTL_IS_FAST(command))
679 return VGDrvCommonIoCtlFast(command, &g_DevExt, fdata->session);
680
681 return VBoxGuestNetBSDIOCtlSlow(fdata, command, data);
682}
683
684static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_fdata *fdata, u_long command, void *data)
685{
686 vboxguest_softc *sc = fdata->sc;
687 size_t cbReq = IOCPARM_LEN(command);
688 PVBGLREQHDR pHdr = NULL;
689 void *pvUser = NULL;
690 int err, rc;
691
692 LogFlow(("%s: command=%#lx data=%p\n", __func__, command, data));
693
694 /*
695 * Buffered request?
696 */
697 if ((command & IOC_DIRMASK) == IOC_INOUT)
698 {
699 /* will be validated by VGDrvCommonIoCtl() */
700 pHdr = (PVBGLREQHDR)data;
701 }
702
703 /*
704 * Big unbuffered request? "data" is the userland pointer.
705 */
706 else if ((command & IOC_DIRMASK) == IOC_VOID && cbReq != 0)
707 {
708 /*
709 * Read the header, validate it and figure out how much that
710 * needs to be buffered.
711 */
712 VBGLREQHDR Hdr;
713
714 if (RT_UNLIKELY(cbReq < sizeof(Hdr)))
715 return ENOTTY;
716
717 pvUser = data;
718 err = copyin(pvUser, &Hdr, sizeof(Hdr));
719 if (RT_UNLIKELY(err != 0))
720 return err;
721
722 if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
723 return ENOTTY;
724
725 if (cbReq > 16 * _1M)
726 return EINVAL;
727
728 if (Hdr.cbOut == 0)
729 Hdr.cbOut = Hdr.cbIn;
730
731 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr) || Hdr.cbIn > cbReq
732 || Hdr.cbOut < sizeof(Hdr) || Hdr.cbOut > cbReq))
733 return EINVAL;
734
735 /*
736 * Allocate buffer and copy in the data.
737 */
738 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
739
740 pHdr = (PVBGLREQHDR)RTMemTmpAlloc(cbReq);
741 if (RT_UNLIKELY(pHdr == NULL))
742 {
743 LogRel(("%s: command=%#lx data=%p: unable to allocate %zu bytes\n",
744 __func__, command, data, cbReq));
745 return ENOMEM;
746 }
747
748 err = copyin(pvUser, pHdr, Hdr.cbIn);
749 if (err != 0)
750 {
751 RTMemTmpFree(pHdr);
752 return err;
753 }
754
755 if (Hdr.cbIn < cbReq)
756 memset((uint8_t *)pHdr + Hdr.cbIn, '\0', cbReq - Hdr.cbIn);
757 }
758
759 /*
760 * Process the IOCtl.
761 */
762 rc = VGDrvCommonIoCtl(command, &g_DevExt, fdata->session, pHdr, cbReq);
763 if (RT_SUCCESS(rc))
764 {
765 err = 0;
766
767 /*
768 * If unbuffered, copy back the result before returning.
769 */
770 if (pvUser != NULL)
771 {
772 size_t cbOut = pHdr->cbOut;
773 if (cbOut > cbReq)
774 {
775 LogRel(("%s: command=%#lx data=%p: too much output: %zu > %zu\n",
776 __func__, command, data, cbOut, cbReq));
777 cbOut = cbReq;
778 }
779
780 err = copyout(pHdr, pvUser, cbOut);
781 RTMemTmpFree(pHdr);
782 }
783 }
784 else
785 {
786 LogRel(("%s: command=%#lx data=%p: error %Rrc\n",
787 __func__, command, data, rc));
788
789 if (pvUser != NULL)
790 RTMemTmpFree(pHdr);
791
792 err = RTErrConvertToErrno(rc);
793 }
794
795 return err;
796}
797
798static int VBoxGuestNetBSDPoll(struct file *fp, int events)
799{
800 struct vboxguest_fdata *fdata = fp->f_data;
801 vboxguest_softc *sc = fdata->sc;
802
803 int rc = 0;
804 int events_processed;
805
806 uint32_t u32CurSeq;
807
808 LogFlow((DEVICE_NAME ": %s\n", __func__));
809
810 u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
811 if (fdata->session->u32MousePosChangedSeq != u32CurSeq)
812 {
813 events_processed = events & (POLLIN | POLLRDNORM);
814 fdata->session->u32MousePosChangedSeq = u32CurSeq;
815 }
816 else
817 {
818 events_processed = 0;
819
820 selrecord(curlwp, &g_SelInfo);
821 }
822
823 return events_processed;
824}
825
826
827/**
828 * @note This code is duplicated on other platforms with variations, so please
829 * keep them all up to date when making changes!
830 */
831int VBOXCALL VBoxGuestIDC(void *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq)
832{
833 /*
834 * Simple request validation (common code does the rest).
835 */
836 int rc;
837 if ( RT_VALID_PTR(pReqHdr)
838 && cbReq >= sizeof(*pReqHdr))
839 {
840 /*
841 * All requests except the connect one requires a valid session.
842 */
843 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
844 if (pSession)
845 {
846 if ( RT_VALID_PTR(pSession)
847 && pSession->pDevExt == &g_DevExt)
848 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
849 else
850 rc = VERR_INVALID_HANDLE;
851 }
852 else if (uReq == VBGL_IOCTL_IDC_CONNECT)
853 {
854 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
855 if (RT_SUCCESS(rc))
856 {
857 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
858 if (RT_FAILURE(rc))
859 VGDrvCommonCloseSession(&g_DevExt, pSession);
860 }
861 }
862 else
863 rc = VERR_INVALID_HANDLE;
864 }
865 else
866 rc = VERR_INVALID_POINTER;
867 return rc;
868}
869
870
871MODULE(MODULE_CLASS_DRIVER, vboxguest, "pci");
872
873static const struct cfiattrdata wsmousedevcf_iattrdata = {
874 "wsmousedev", 1, {
875 { "mux", "0", 0 },
876 }
877};
878
879/* device vboxguest: wsmousedev */
880static const struct cfiattrdata * const vboxguest_attrs[] = { &wsmousedevcf_iattrdata, NULL };
881CFDRIVER_DECL(vboxguest, DV_DULL, vboxguest_attrs);
882
883static struct cfdriver * const cfdriver_ioconf_vboxguest[] = {
884 &vboxguest_cd, NULL
885};
886
887
888static const struct cfparent vboxguest_pspec = {
889 "pci", "pci", DVUNIT_ANY
890};
891static int vboxguest_loc[] = { -1, -1 };
892
893
894static const struct cfparent wsmousedev_pspec = {
895 "wsmousedev", "vboxguest", DVUNIT_ANY
896};
897static int wsmousedev_loc[] = { 0 };
898
899
900static struct cfdata cfdata_ioconf_vboxguest[] = {
901 /* vboxguest0 at pci? dev ? function ? */
902 {
903 .cf_name = "vboxguest",
904 .cf_atname = "vboxguest",
905 .cf_unit = 0, /* Only unit 0 is ever used */
906 .cf_fstate = FSTATE_NOTFOUND,
907 .cf_loc = vboxguest_loc,
908 .cf_flags = 0,
909 .cf_pspec = &vboxguest_pspec,
910 },
911
912 /* wsmouse* at vboxguest? */
913 { "wsmouse", "wsmouse", 0, FSTATE_STAR, wsmousedev_loc, 0, &wsmousedev_pspec },
914
915 { NULL, NULL, 0, 0, NULL, 0, NULL }
916};
917
918static struct cfattach * const vboxguest_cfattachinit[] = {
919 &vboxguest_ca, NULL
920};
921
922static const struct cfattachinit cfattach_ioconf_vboxguest[] = {
923 { "vboxguest", vboxguest_cfattachinit },
924 { NULL, NULL }
925};
926
927static int
928vboxguest_modcmd(modcmd_t cmd, void *opaque)
929{
930 devmajor_t bmajor, cmajor;
931 register_t retval;
932 int error;
933
934 LogFlow((DEVICE_NAME ": %s\n", __func__));
935
936 switch (cmd)
937 {
938 case MODULE_CMD_INIT:
939 error = config_init_component(cfdriver_ioconf_vboxguest,
940 cfattach_ioconf_vboxguest,
941 cfdata_ioconf_vboxguest);
942 if (error)
943 break;
944
945 bmajor = cmajor = NODEVMAJOR;
946 error = devsw_attach("vboxguest",
947 NULL, &bmajor,
948 &g_VBoxGuestNetBSDChrDevSW, &cmajor);
949 if (error)
950 {
951 if (error == EEXIST)
952 error = 0; /* maybe built-in ... improve eventually */
953 else
954 break;
955 }
956
957 error = do_sys_mknod(curlwp, "/dev/vboxguest",
958 0666|S_IFCHR, makedev(cmajor, 0),
959 &retval, UIO_SYSSPACE);
960 if (error == EEXIST)
961 error = 0;
962 break;
963
964 case MODULE_CMD_FINI:
965 error = config_fini_component(cfdriver_ioconf_vboxguest,
966 cfattach_ioconf_vboxguest,
967 cfdata_ioconf_vboxguest);
968 if (error)
969 break;
970
971 devsw_detach(NULL, &g_VBoxGuestNetBSDChrDevSW);
972 break;
973
974 default:
975 return ENOTTY;
976 }
977 return error;
978}
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