3 * VBoxGuest - Linux specifics.
5 * Note. Unfortunately, the difference between this and SUPDrv-linux.c is
6 * a little bit too big to be helpful.
10 * Copyright (C) 2006-2017 Oracle Corporation
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
31 /*********************************************************************************************************************************
33 *********************************************************************************************************************************/
34 #define LOG_GROUP LOG_GROUP_SUP_DRV
36 #include "the-linux-kernel.h"
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
39 # define VBOXGUEST_WITH_INPUT_DRIVER
42 #include "VBoxGuestInternal.h"
43 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
44 # include <linux/input.h>
46 #include <linux/miscdevice.h>
47 #include <linux/poll.h>
48 #include <VBox/version.h>
49 #include "revision-generated.h"
51 #include <iprt/assert.h>
54 #include <iprt/initterm.h>
57 #include <iprt/process.h>
58 #include <iprt/spinlock.h>
59 #include <iprt/semaphore.h>
60 #include <iprt/string.h>
64 /*********************************************************************************************************************************
65 * Defined Constants And Macros *
66 *********************************************************************************************************************************/
67 /** The device name. */
68 #define DEVICE_NAME "vboxguest"
69 /** The device name for the device node open to everyone. */
70 #define DEVICE_NAME_USER "vboxuser"
71 /** The name of the PCI driver */
72 #define DRIVER_NAME DEVICE_NAME
75 /* 2.4.x compatibility macros that may or may not be defined. */
77 # define irqreturn_t void
78 # define IRQ_RETVAL(n)
82 /*********************************************************************************************************************************
83 * Internal Functions *
84 *********************************************************************************************************************************/
85 static void vgdrvLinuxTermPci(struct pci_dev
*pPciDev
);
86 static int vgdrvLinuxProbePci(struct pci_dev
*pPciDev
, const struct pci_device_id
*id
);
87 static int vgdrvLinuxModInit(void);
88 static void vgdrvLinuxModExit(void);
89 static int vgdrvLinuxOpen(struct inode
*pInode
, struct file
*pFilp
);
90 static int vgdrvLinuxRelease(struct inode
*pInode
, struct file
*pFilp
);
91 #ifdef HAVE_UNLOCKED_IOCTL
92 static long vgdrvLinuxIOCtl(struct file
*pFilp
, unsigned int uCmd
, unsigned long ulArg
);
94 static int vgdrvLinuxIOCtl(struct inode
*pInode
, struct file
*pFilp
, unsigned int uCmd
, unsigned long ulArg
);
96 static int vgdrvLinuxIOCtlSlow(struct file
*pFilp
, unsigned int uCmd
, unsigned long ulArg
, PVBOXGUESTSESSION pSession
);
97 static int vgdrvLinuxFAsync(int fd
, struct file
*pFile
, int fOn
);
98 static unsigned int vgdrvLinuxPoll(struct file
*pFile
, poll_table
*pPt
);
99 static ssize_t
vgdrvLinuxRead(struct file
*pFile
, char *pbBuf
, size_t cbRead
, loff_t
*poff
);
102 /*********************************************************************************************************************************
104 *********************************************************************************************************************************/
106 * Device extention & session data association structure.
108 static VBOXGUESTDEVEXT g_DevExt
;
109 /** The PCI device. */
110 static struct pci_dev
*g_pPciDev
= NULL
;
111 /** The base of the I/O port range. */
112 static RTIOPORT g_IOPortBase
;
113 /** The base of the MMIO range. */
114 static RTHCPHYS g_MMIOPhysAddr
= NIL_RTHCPHYS
;
115 /** The size of the MMIO range as seen by PCI. */
116 static uint32_t g_cbMMIO
;
117 /** The pointer to the mapping of the MMIO range. */
118 static void *g_pvMMIOBase
;
119 /** Wait queue used by polling. */
120 static wait_queue_head_t g_PollEventQueue
;
121 /** Asynchronous notification stuff. */
122 static struct fasync_struct
*g_pFAsyncQueue
;
123 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
124 /** Pre-allocated mouse status VMMDev request for use in the IRQ
126 static VMMDevReqMouseStatus
*g_pMouseStatusReq
;
128 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
129 /** Whether we've create the logger or not. */
130 static volatile bool g_fLoggerCreated
;
131 /** Release logger group settings. */
132 static char g_szLogGrp
[128];
133 /** Release logger flags settings. */
134 static char g_szLogFlags
[128];
135 /** Release logger destination settings. */
136 static char g_szLogDst
[128];
138 /** Debug logger group settings. */
139 static char g_szDbgLogGrp
[128];
140 /** Debug logger flags settings. */
141 static char g_szDbgLogFlags
[128];
142 /** Debug logger destination settings. */
143 static char g_szDbgLogDst
[128];
147 /** The input device handle */
148 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
149 static struct input_dev
*g_pInputDevice
= NULL
;
152 /** The file_operations structure. */
153 static struct file_operations g_FileOps
=
156 open
: vgdrvLinuxOpen
,
157 release
: vgdrvLinuxRelease
,
158 #ifdef HAVE_UNLOCKED_IOCTL
159 unlocked_ioctl
: vgdrvLinuxIOCtl
,
161 ioctl
: vgdrvLinuxIOCtl
,
163 fasync
: vgdrvLinuxFAsync
,
164 read
: vgdrvLinuxRead
,
165 poll
: vgdrvLinuxPoll
,
169 /** The miscdevice structure. */
170 static struct miscdevice g_MiscDevice
=
172 minor
: MISC_DYNAMIC_MINOR
,
177 /** The file_operations structure for the user device.
178 * @remarks For the time being we'll be using the same implementation as
179 * /dev/vboxguest here. */
180 static struct file_operations g_FileOpsUser
=
183 open
: vgdrvLinuxOpen
,
184 release
: vgdrvLinuxRelease
,
185 #ifdef HAVE_UNLOCKED_IOCTL
186 unlocked_ioctl
: vgdrvLinuxIOCtl
,
188 ioctl
: vgdrvLinuxIOCtl
,
192 /** The miscdevice structure for the user device. */
193 static struct miscdevice g_MiscDeviceUser
=
195 minor
: MISC_DYNAMIC_MINOR
,
196 name
: DEVICE_NAME_USER
,
197 fops
: &g_FileOpsUser
,
201 /** PCI hotplug structure. */
202 static const struct pci_device_id
203 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
209 vendor
: VMMDEV_VENDORID
,
210 device
: VMMDEV_DEVICEID
217 MODULE_DEVICE_TABLE(pci
, g_VBoxGuestPciId
);
219 /** Structure for registering the PCI driver. */
220 static struct pci_driver g_PciDriver
=
223 id_table
: g_VBoxGuestPciId
,
224 probe
: vgdrvLinuxProbePci
,
225 remove
: vgdrvLinuxTermPci
228 static PVBOXGUESTSESSION g_pKernelSession
= NULL
;
233 * Converts a VBox status code to a linux error code.
235 * @returns corresponding negative linux error code.
236 * @param rc supdrv error code (SUPDRV_ERR_* defines).
238 static int vgdrvLinuxConvertToNegErrno(int rc
)
242 return -RTErrConvertToErrno(rc
);
245 case VERR_HGCM_SERVICE_NOT_FOUND
: return -ESRCH
;
246 case VINF_HGCM_CLIENT_REJECTED
: return 0;
247 case VERR_HGCM_INVALID_CMD_ADDRESS
: return -EFAULT
;
248 case VINF_HGCM_ASYNC_EXECUTE
: return 0;
249 case VERR_HGCM_INTERNAL
: return -EPROTO
;
250 case VERR_HGCM_INVALID_CLIENT_ID
: return -EINVAL
;
251 case VINF_HGCM_SAVE_STATE
: return 0;
252 /* No reason to return this to a guest */
253 // case VERR_HGCM_SERVICE_EXISTS: return -EEXIST;
255 AssertMsgFailed(("Unhandled error code %Rrc\n", rc
));
262 * Does the PCI detection and init of the device.
264 * @returns 0 on success, negated errno on failure.
266 static int vgdrvLinuxProbePci(struct pci_dev
*pPciDev
, const struct pci_device_id
*id
)
271 AssertReturn(!g_pPciDev
, -EINVAL
);
272 rc
= pci_enable_device(pPciDev
);
275 /* I/O Ports are mandatory, the MMIO bit is not. */
276 g_IOPortBase
= pci_resource_start(pPciDev
, 0);
277 if (g_IOPortBase
!= 0)
280 * Map the register address space.
282 g_MMIOPhysAddr
= pci_resource_start(pPciDev
, 1);
283 g_cbMMIO
= pci_resource_len(pPciDev
, 1);
284 if (request_mem_region(g_MMIOPhysAddr
, g_cbMMIO
, DEVICE_NAME
) != NULL
)
286 g_pvMMIOBase
= ioremap(g_MMIOPhysAddr
, g_cbMMIO
);
289 /** @todo why aren't we requesting ownership of the I/O ports as well? */
294 /* failure cleanup path */
295 LogRel((DEVICE_NAME
": ioremap failed; MMIO Addr=%RHp cb=%#x\n", g_MMIOPhysAddr
, g_cbMMIO
));
297 release_mem_region(g_MMIOPhysAddr
, g_cbMMIO
);
301 LogRel((DEVICE_NAME
": failed to obtain adapter memory\n"));
304 g_MMIOPhysAddr
= NIL_RTHCPHYS
;
310 LogRel((DEVICE_NAME
": did not find expected hardware resources\n"));
313 pci_disable_device(pPciDev
);
316 LogRel((DEVICE_NAME
": could not enable device: %d\n", rc
));
322 * Clean up the usage of the PCI device.
324 static void vgdrvLinuxTermPci(struct pci_dev
*pPciDev
)
329 iounmap(g_pvMMIOBase
);
332 release_mem_region(g_MMIOPhysAddr
, g_cbMMIO
);
333 g_MMIOPhysAddr
= NIL_RTHCPHYS
;
336 pci_disable_device(pPciDev
);
342 * Interrupt service routine.
344 * @returns In 2.4 it returns void.
345 * In 2.6 we indicate whether we've handled the IRQ or not.
347 * @param iIrq The IRQ number.
348 * @param pvDevId The device ID, a pointer to g_DevExt.
349 * @param pRegs Register set. Removed in 2.6.19.
351 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && !defined(DOXYGEN_RUNNING)
352 static irqreturn_t
vgdrvLinuxISR(int iIrq
, void *pvDevId
)
354 static irqreturn_t
vgdrvLinuxISR(int iIrq
, void *pvDevId
, struct pt_regs
*pRegs
)
357 bool fTaken
= VGDrvCommonISR(&g_DevExt
);
358 return IRQ_RETVAL(fTaken
);
363 * Registers the ISR and initializes the poll wait queue.
365 static int __init
vgdrvLinuxInitISR(void)
369 init_waitqueue_head(&g_PollEventQueue
);
370 rc
= request_irq(g_pPciDev
->irq
,
372 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
381 LogRel((DEVICE_NAME
": could not request IRQ %d: err=%d\n", g_pPciDev
->irq
, rc
));
389 * Deregisters the ISR.
391 static void vgdrvLinuxTermISR(void)
393 free_irq(g_pPciDev
->irq
, &g_DevExt
);
397 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
400 * Reports the mouse integration status to the host.
402 * Calls the kernel IOCtl to report mouse status to the host on behalf of
403 * our kernel session.
405 * @param fStatus The mouse status to report.
407 static int vgdrvLinuxSetMouseStatus(uint32_t fStatus
)
410 VBGLIOCSETMOUSESTATUS Req
;
411 VBGLREQHDR_INIT(&Req
.Hdr
, SET_MOUSE_STATUS
);
412 Req
.u
.In
.fStatus
= fStatus
;
413 rc
= VGDrvCommonIoCtl(VBGL_IOCTL_SET_MOUSE_STATUS
, &g_DevExt
, g_pKernelSession
, &Req
.Hdr
, sizeof(Req
));
421 * Called when the input device is first opened.
423 * Sets up absolute mouse reporting.
425 static int vboxguestOpenInputDevice(struct input_dev
*pDev
)
427 int rc
= vgdrvLinuxSetMouseStatus(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
| VMMDEV_MOUSE_NEW_PROTOCOL
);
436 * Called if all open handles to the input device are closed.
438 * Disables absolute reporting.
440 static void vboxguestCloseInputDevice(struct input_dev
*pDev
)
443 vgdrvLinuxSetMouseStatus(0);
448 * Creates the kernel input device.
450 static int __init
vgdrvLinuxCreateInputDevice(void)
452 int rc
= VbglR0GRAlloc((VMMDevRequestHeader
**)&g_pMouseStatusReq
, sizeof(*g_pMouseStatusReq
), VMMDevReq_GetMouseStatus
);
455 g_pInputDevice
= input_allocate_device();
458 g_pInputDevice
->id
.bustype
= BUS_PCI
;
459 g_pInputDevice
->id
.vendor
= VMMDEV_VENDORID
;
460 g_pInputDevice
->id
.product
= VMMDEV_DEVICEID
;
461 g_pInputDevice
->id
.version
= VBOX_SHORT_VERSION
;
462 g_pInputDevice
->open
= vboxguestOpenInputDevice
;
463 g_pInputDevice
->close
= vboxguestCloseInputDevice
;
464 # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
465 g_pInputDevice
->cdev
.dev
= &g_pPciDev
->dev
;
467 g_pInputDevice
->dev
.parent
= &g_pPciDev
->dev
;
469 rc
= input_register_device(g_pInputDevice
);
472 /* Do what one of our competitors apparently does as that works. */
473 ASMBitSet(g_pInputDevice
->evbit
, EV_ABS
);
474 ASMBitSet(g_pInputDevice
->evbit
, EV_KEY
);
476 ASMBitSet(g_pInputDevice
->evbit
, EV_SYN
);
478 input_set_abs_params(g_pInputDevice
, ABS_X
, VMMDEV_MOUSE_RANGE_MIN
, VMMDEV_MOUSE_RANGE_MAX
, 0, 0);
479 input_set_abs_params(g_pInputDevice
, ABS_Y
, VMMDEV_MOUSE_RANGE_MIN
, VMMDEV_MOUSE_RANGE_MAX
, 0, 0);
480 ASMBitSet(g_pInputDevice
->keybit
, BTN_MOUSE
);
481 /** @todo this string should be in a header file somewhere. */
482 g_pInputDevice
->name
= "VirtualBox mouse integration";
486 input_free_device(g_pInputDevice
);
490 VbglR0GRFree(&g_pMouseStatusReq
->header
);
491 g_pMouseStatusReq
= NULL
;
500 * Terminates the kernel input device.
502 static void vgdrvLinuxTermInputDevice(void)
504 VbglR0GRFree(&g_pMouseStatusReq
->header
);
505 g_pMouseStatusReq
= NULL
;
507 /* See documentation of input_register_device(): input_free_device()
508 * should not be called after a device has been registered. */
509 input_unregister_device(g_pInputDevice
);
512 #endif /* VBOXGUEST_WITH_INPUT_DRIVER */
516 * Creates the device nodes.
518 * @returns 0 on success, negated errno on failure.
520 static int __init
vgdrvLinuxInitDeviceNodes(void)
523 * The full feature device node.
525 int rc
= misc_register(&g_MiscDevice
);
529 * The device node intended to be accessible by all users.
531 rc
= misc_register(&g_MiscDeviceUser
);
534 LogRel((DEVICE_NAME
": misc_register failed for %s (rc=%d)\n", DEVICE_NAME_USER
, rc
));
535 misc_deregister(&g_MiscDevice
);
538 LogRel((DEVICE_NAME
": misc_register failed for %s (rc=%d)\n", DEVICE_NAME
, rc
));
544 * Deregisters the device nodes.
546 static void vgdrvLinuxTermDeviceNodes(void)
548 misc_deregister(&g_MiscDevice
);
549 misc_deregister(&g_MiscDeviceUser
);
556 * @returns appropriate status code.
558 static int __init
vgdrvLinuxModInit(void)
560 static const char * const s_apszGroups
[] = VBOX_LOGGROUP_NAMES
;
561 PRTLOGGER pRelLogger
;
565 * Initialize IPRT first.
570 printk(KERN_ERR DEVICE_NAME
": RTR0Init failed, rc=%d.\n", rc
);
575 * Create the release log.
576 * (We do that here instead of common code because we want to log
577 * early failures using the LogRel macro.)
579 rc
= RTLogCreate(&pRelLogger
, 0 /* fFlags */, "all",
580 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups
), s_apszGroups
,
581 RTLOGDEST_STDOUT
| RTLOGDEST_DEBUGGER
| RTLOGDEST_USER
, NULL
);
584 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
585 RTLogGroupSettings(pRelLogger
, g_szLogGrp
);
586 RTLogFlags(pRelLogger
, g_szLogFlags
);
587 RTLogDestinations(pRelLogger
, g_szLogDst
);
589 RTLogRelSetDefaultInstance(pRelLogger
);
591 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
592 g_fLoggerCreated
= true;
596 * Locate and initialize the PCI device.
598 rc
= pci_register_driver(&g_PciDriver
);
599 if (rc
>= 0 && g_pPciDev
)
602 * Register the interrupt service routine for it.
604 rc
= vgdrvLinuxInitISR();
608 * Call the common device extension initializer.
610 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
611 VBOXOSTYPE enmOSType
= VBOXOSTYPE_Linux26
;
612 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_AMD64)
613 VBOXOSTYPE enmOSType
= VBOXOSTYPE_Linux26_x64
;
614 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_X86)
615 VBOXOSTYPE enmOSType
= VBOXOSTYPE_Linux24
;
616 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_AMD64)
617 VBOXOSTYPE enmOSType
= VBOXOSTYPE_Linux24_x64
;
619 # warning "huh? which arch + version is this?"
620 VBOXOSTYPE enmOsType
= VBOXOSTYPE_Linux
;
622 rc
= VGDrvCommonInitDevExt(&g_DevExt
,
627 VMMDEV_EVENT_MOUSE_POSITION_CHANGED
);
631 * Create the kernel session for this driver.
633 rc
= VGDrvCommonCreateKernelSession(&g_DevExt
, &g_pKernelSession
);
637 * Create the kernel input device.
639 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
640 rc
= vgdrvLinuxCreateInputDevice();
645 * Finally, create the device nodes.
647 rc
= vgdrvLinuxInitDeviceNodes();
650 /* some useful information for the user but don't show this on the console */
651 LogRel((DEVICE_NAME
": misc device minor %d, IRQ %d, I/O port %RTiop, MMIO at %RHp (size 0x%x)\n",
652 g_MiscDevice
.minor
, g_pPciDev
->irq
, g_IOPortBase
, g_MMIOPhysAddr
, g_cbMMIO
));
653 printk(KERN_DEBUG DEVICE_NAME
": Successfully loaded version "
654 VBOX_VERSION_STRING
" (interface " RT_XSTR(VMMDEV_VERSION
) ")\n");
659 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
660 vgdrvLinuxTermInputDevice();
664 LogRel((DEVICE_NAME
": vboxguestCreateInputDevice failed with rc=%Rrc\n", rc
));
665 rc
= RTErrConvertFromErrno(rc
);
668 VGDrvCommonCloseSession(&g_DevExt
, g_pKernelSession
);
670 VGDrvCommonDeleteDevExt(&g_DevExt
);
674 LogRel((DEVICE_NAME
": VGDrvCommonInitDevExt failed with rc=%Rrc\n", rc
));
675 rc
= RTErrConvertFromErrno(rc
);
682 LogRel((DEVICE_NAME
": PCI device not found, probably running on physical hardware.\n"));
685 pci_unregister_driver(&g_PciDriver
);
686 RTLogDestroy(RTLogRelSetDefaultInstance(NULL
));
687 RTLogDestroy(RTLogSetDefaultInstance(NULL
));
696 static void __exit
vgdrvLinuxModExit(void)
699 * Inverse order of init.
701 vgdrvLinuxTermDeviceNodes();
702 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
703 vgdrvLinuxTermInputDevice();
705 VGDrvCommonCloseSession(&g_DevExt
, g_pKernelSession
);
706 VGDrvCommonDeleteDevExt(&g_DevExt
);
708 pci_unregister_driver(&g_PciDriver
);
709 RTLogDestroy(RTLogRelSetDefaultInstance(NULL
));
710 RTLogDestroy(RTLogSetDefaultInstance(NULL
));
716 * Device open. Called on open /dev/vboxdrv
718 * @param pInode Pointer to inode info structure.
719 * @param pFilp Associated file pointer.
721 static int vgdrvLinuxOpen(struct inode
*pInode
, struct file
*pFilp
)
724 PVBOXGUESTSESSION pSession
;
725 Log((DEVICE_NAME
": pFilp=%p pid=%d/%d %s\n", pFilp
, RTProcSelf(), current
->pid
, current
->comm
));
728 * Call common code to create the user session. Associate it with
729 * the file so we can access it in the other methods.
731 rc
= VGDrvCommonCreateUserSession(&g_DevExt
, &pSession
);
734 pFilp
->private_data
= pSession
;
735 if (MINOR(pInode
->i_rdev
) == g_MiscDeviceUser
.minor
)
736 pSession
->fUserSession
= true;
739 Log(("vgdrvLinuxOpen: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
740 &g_DevExt
, pSession
, rc
, vgdrvLinuxConvertToNegErrno(rc
), RTProcSelf(), current
->pid
, current
->comm
));
741 return vgdrvLinuxConvertToNegErrno(rc
);
748 * @param pInode Pointer to inode info structure.
749 * @param pFilp Associated file pointer.
751 static int vgdrvLinuxRelease(struct inode
*pInode
, struct file
*pFilp
)
753 Log(("vgdrvLinuxRelease: pFilp=%p pSession=%p pid=%d/%d %s\n",
754 pFilp
, pFilp
->private_data
, RTProcSelf(), current
->pid
, current
->comm
));
756 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
757 /* This housekeeping was needed in older kernel versions to ensure that
758 * the file pointer didn't get left on the polling queue. */
759 vgdrvLinuxFAsync(-1, pFilp
, 0);
761 VGDrvCommonCloseSession(&g_DevExt
, (PVBOXGUESTSESSION
)pFilp
->private_data
);
762 pFilp
->private_data
= NULL
;
768 * Device I/O Control entry point.
770 * @param pFilp Associated file pointer.
771 * @param uCmd The function specified to ioctl().
772 * @param ulArg The argument specified to ioctl().
774 #if defined(HAVE_UNLOCKED_IOCTL) || defined(DOXYGEN_RUNNING)
775 static long vgdrvLinuxIOCtl(struct file
*pFilp
, unsigned int uCmd
, unsigned long ulArg
)
777 static int vgdrvLinuxIOCtl(struct inode
*pInode
, struct file
*pFilp
, unsigned int uCmd
, unsigned long ulArg
)
780 PVBOXGUESTSESSION pSession
= (PVBOXGUESTSESSION
)pFilp
->private_data
;
782 #ifndef HAVE_UNLOCKED_IOCTL
786 #if 0 /* no fast I/O controls defined atm. */
787 if (RT_LIKELY( ( uCmd
== SUP_IOCTL_FAST_DO_RAW_RUN
788 || uCmd
== SUP_IOCTL_FAST_DO_HM_RUN
789 || uCmd
== SUP_IOCTL_FAST_DO_NOP
)
790 && pSession
->fUnrestricted
== true))
791 rc
= VGDrvCommonIoCtlFast(uCmd
, ulArg
, &g_DevExt
, pSession
);
794 rc
= vgdrvLinuxIOCtlSlow(pFilp
, uCmd
, ulArg
, pSession
);
796 #ifndef HAVE_UNLOCKED_IOCTL
804 * Device I/O Control entry point, slow variant.
806 * @param pFilp Associated file pointer.
807 * @param uCmd The function specified to ioctl().
808 * @param ulArg The argument specified to ioctl().
809 * @param pSession The session instance.
811 static int vgdrvLinuxIOCtlSlow(struct file
*pFilp
, unsigned int uCmd
, unsigned long ulArg
, PVBOXGUESTSESSION pSession
)
818 Log6(("vgdrvLinuxIOCtlSlow: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp
, uCmd
, (void *)ulArg
, RTProcSelf(), current
->pid
));
823 if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr
, ulArg
, sizeof(Hdr
))))
825 Log(("vgdrvLinuxIOCtlSlow: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg
, uCmd
));
828 if (RT_UNLIKELY(Hdr
.uVersion
!= VBGLREQHDR_VERSION
))
830 Log(("vgdrvLinuxIOCtlSlow: bad header version %#x; uCmd=%#x\n", Hdr
.uVersion
, uCmd
));
835 * Buffer the request.
836 * Note! The header is revalidated by the common code.
838 cbBuf
= RT_MAX(Hdr
.cbIn
, Hdr
.cbOut
);
839 if (RT_UNLIKELY(cbBuf
> _1M
*16))
841 Log(("vgdrvLinuxIOCtlSlow: too big cbBuf=%#x; uCmd=%#x\n", cbBuf
, uCmd
));
844 if (RT_UNLIKELY( Hdr
.cbIn
< sizeof(Hdr
)
845 || (cbBuf
!= _IOC_SIZE(uCmd
) && _IOC_SIZE(uCmd
) != 0)))
847 Log(("vgdrvLinuxIOCtlSlow: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf
, _IOC_SIZE(uCmd
), uCmd
));
850 pHdr
= RTMemAlloc(cbBuf
);
851 if (RT_UNLIKELY(!pHdr
))
853 LogRel(("vgdrvLinuxIOCtlSlow: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf
, uCmd
));
856 if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr
, ulArg
, Hdr
.cbIn
)))
858 Log(("vgdrvLinuxIOCtlSlow: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg
, Hdr
.cbIn
, uCmd
));
862 if (Hdr
.cbIn
< cbBuf
)
863 RT_BZERO((uint8_t *)pHdr
+ Hdr
.cbIn
, cbBuf
- Hdr
.cbIn
);
868 rc
= VGDrvCommonIoCtl(uCmd
, &g_DevExt
, pSession
, pHdr
, cbBuf
);
871 * Copy ioctl data and output buffer back to user space.
875 uint32_t cbOut
= pHdr
->cbOut
;
876 if (RT_UNLIKELY(cbOut
> cbBuf
))
878 LogRel(("vgdrvLinuxIOCtlSlow: too much output! %#x > %#x; uCmd=%#x!\n", cbOut
, cbBuf
, uCmd
));
881 if (RT_FAILURE(RTR0MemUserCopyTo(ulArg
, pHdr
, cbOut
)))
883 /* this is really bad! */
884 LogRel(("vgdrvLinuxIOCtlSlow: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg
, cbOut
, uCmd
));
890 Log(("vgdrvLinuxIOCtlSlow: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp
, uCmd
, (void *)ulArg
, rc
));
895 Log6(("vgdrvLinuxIOCtlSlow: returns %d (pid=%d/%d)\n", rc
, RTProcSelf(), current
->pid
));
901 * @note This code is duplicated on other platforms with variations, so please
902 * keep them all up to date when making changes!
904 int VBOXCALL
VBoxGuestIDC(void *pvSession
, uintptr_t uReq
, PVBGLREQHDR pReqHdr
, size_t cbReq
)
907 * Simple request validation (common code does the rest).
910 if ( RT_VALID_PTR(pReqHdr
)
911 && cbReq
>= sizeof(*pReqHdr
))
914 * All requests except the connect one requires a valid session.
916 PVBOXGUESTSESSION pSession
= (PVBOXGUESTSESSION
)pvSession
;
919 if ( RT_VALID_PTR(pSession
)
920 && pSession
->pDevExt
== &g_DevExt
)
921 rc
= VGDrvCommonIoCtl(uReq
, &g_DevExt
, pSession
, pReqHdr
, cbReq
);
923 rc
= VERR_INVALID_HANDLE
;
925 else if (uReq
== VBGL_IOCTL_IDC_CONNECT
)
927 rc
= VGDrvCommonCreateKernelSession(&g_DevExt
, &pSession
);
930 rc
= VGDrvCommonIoCtl(uReq
, &g_DevExt
, pSession
, pReqHdr
, cbReq
);
932 VGDrvCommonCloseSession(&g_DevExt
, pSession
);
936 rc
= VERR_INVALID_HANDLE
;
939 rc
= VERR_INVALID_POINTER
;
942 EXPORT_SYMBOL(VBoxGuestIDC
);
946 * Asynchronous notification activation method.
948 * @returns 0 on success, negative errno on failure.
950 * @param fd The file descriptor.
951 * @param pFile The file structure.
952 * @param fOn On/off indicator.
954 static int vgdrvLinuxFAsync(int fd
, struct file
*pFile
, int fOn
)
956 return fasync_helper(fd
, pFile
, fOn
, &g_pFAsyncQueue
);
963 * This returns ready to read if the mouse pointer mode or the pointer position
964 * has changed since last call to read.
966 * @returns 0 if no changes, POLLIN | POLLRDNORM if there are unseen changes.
968 * @param pFile The file structure.
969 * @param pPt The poll table.
971 * @remarks This is probably not really used, X11 is said to use the fasync
974 static unsigned int vgdrvLinuxPoll(struct file
*pFile
, poll_table
*pPt
)
976 PVBOXGUESTSESSION pSession
= (PVBOXGUESTSESSION
)pFile
->private_data
;
977 uint32_t u32CurSeq
= ASMAtomicUoReadU32(&g_DevExt
.u32MousePosChangedSeq
);
978 unsigned int fMask
= pSession
->u32MousePosChangedSeq
!= u32CurSeq
979 ? POLLIN
| POLLRDNORM
981 poll_wait(pFile
, &g_PollEventQueue
, pPt
);
987 * Read to go with our poll/fasync response.
989 * @returns 1 or -EINVAL.
991 * @param pFile The file structure.
992 * @param pbBuf The buffer to read into.
993 * @param cbRead The max number of bytes to read.
994 * @param poff The current file position.
996 * @remarks This is probably not really used as X11 lets the driver do its own
997 * event reading. The poll condition is therefore also cleared when we
998 * see VMMDevReq_GetMouseStatus in vgdrvIoCtl_VMMRequest.
1000 static ssize_t
vgdrvLinuxRead(struct file
*pFile
, char *pbBuf
, size_t cbRead
, loff_t
*poff
)
1002 PVBOXGUESTSESSION pSession
= (PVBOXGUESTSESSION
)pFile
->private_data
;
1003 uint32_t u32CurSeq
= ASMAtomicUoReadU32(&g_DevExt
.u32MousePosChangedSeq
);
1009 * Fake a single byte read if we're not up to date with the current mouse position.
1011 if ( pSession
->u32MousePosChangedSeq
!= u32CurSeq
1014 pSession
->u32MousePosChangedSeq
= u32CurSeq
;
1022 void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt
)
1024 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
1030 * Wake up everyone that's in a poll() and post anyone that has
1031 * subscribed to async notifications.
1033 Log3(("VGDrvNativeISRMousePollEvent: wake_up_all\n"));
1034 wake_up_all(&g_PollEventQueue
);
1035 Log3(("VGDrvNativeISRMousePollEvent: kill_fasync\n"));
1036 kill_fasync(&g_pFAsyncQueue
, SIGIO
, POLL_IN
);
1037 #ifdef VBOXGUEST_WITH_INPUT_DRIVER
1038 /* Report events to the kernel input device */
1039 g_pMouseStatusReq
->mouseFeatures
= 0;
1040 g_pMouseStatusReq
->pointerXPos
= 0;
1041 g_pMouseStatusReq
->pointerYPos
= 0;
1042 rc
= VbglR0GRPerform(&g_pMouseStatusReq
->header
);
1045 input_report_abs(g_pInputDevice
, ABS_X
,
1046 g_pMouseStatusReq
->pointerXPos
);
1047 input_report_abs(g_pInputDevice
, ABS_Y
,
1048 g_pMouseStatusReq
->pointerYPos
);
1050 input_sync(g_pInputDevice
);
1054 Log3(("VGDrvNativeISRMousePollEvent: done\n"));
1058 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1060 /** log and dbg_log parameter setter. */
1061 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1062 static int vgdrvLinuxParamLogGrpSet(const char *pszValue
, const struct kernel_param
*pParam
)
1064 static int vgdrvLinuxParamLogGrpSet(const char *pszValue
, struct kernel_param
*pParam
)
1067 if (g_fLoggerCreated
)
1069 PRTLOGGER pLogger
= pParam
->name
[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1071 RTLogGroupSettings(pLogger
, pszValue
);
1073 else if (pParam
->name
[0] != 'd')
1074 strlcpy(&g_szLogGrp
[0], pszValue
, sizeof(g_szLogGrp
));
1079 /** log and dbg_log parameter getter. */
1080 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1081 static int vgdrvLinuxParamLogGrpGet(char *pszBuf
, const struct kernel_param
*pParam
)
1083 static int vgdrvLinuxParamLogGrpGet(char *pszBuf
, struct kernel_param
*pParam
)
1086 PRTLOGGER pLogger
= pParam
->name
[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1089 RTLogGetGroupSettings(pLogger
, pszBuf
, _4K
);
1090 return strlen(pszBuf
);
1094 /** log and dbg_log_flags parameter setter. */
1095 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1096 static int vgdrvLinuxParamLogFlagsSet(const char *pszValue
, const struct kernel_param
*pParam
)
1098 static int vgdrvLinuxParamLogFlagsSet(const char *pszValue
, struct kernel_param
*pParam
)
1101 if (g_fLoggerCreated
)
1103 PRTLOGGER pLogger
= pParam
->name
[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1105 RTLogFlags(pLogger
, pszValue
);
1107 else if (pParam
->name
[0] != 'd')
1108 strlcpy(&g_szLogFlags
[0], pszValue
, sizeof(g_szLogFlags
));
1112 /** log and dbg_log_flags parameter getter. */
1113 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1114 static int vgdrvLinuxParamLogFlagsGet(char *pszBuf
, const struct kernel_param
*pParam
)
1116 static int vgdrvLinuxParamLogFlagsGet(char *pszBuf
, struct kernel_param
*pParam
)
1119 PRTLOGGER pLogger
= pParam
->name
[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1122 RTLogGetFlags(pLogger
, pszBuf
, _4K
);
1123 return strlen(pszBuf
);
1127 /** log and dbg_log_dest parameter setter. */
1128 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1129 static int vgdrvLinuxParamLogDstSet(const char *pszValue
, const struct kernel_param
*pParam
)
1131 static int vgdrvLinuxParamLogDstSet(const char *pszValue
, struct kernel_param
*pParam
)
1134 if (g_fLoggerCreated
)
1136 PRTLOGGER pLogger
= pParam
->name
[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1138 RTLogDestinations(pLogger
, pszValue
);
1140 else if (pParam
->name
[0] != 'd')
1141 strlcpy(&g_szLogDst
[0], pszValue
, sizeof(g_szLogDst
));
1145 /** log and dbg_log_dest parameter getter. */
1146 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1147 static int vgdrvLinuxParamLogDstGet(char *pszBuf
, const struct kernel_param
*pParam
)
1149 static int vgdrvLinuxParamLogDstGet(char *pszBuf
, struct kernel_param
*pParam
)
1152 PRTLOGGER pLogger
= pParam
->name
[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1155 RTLogGetDestinations(pLogger
, pszBuf
, _4K
);
1156 return strlen(pszBuf
);
1160 /** r3_log_to_host parameter setter. */
1161 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1162 static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue
, const struct kernel_param
*pParam
)
1164 static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue
, struct kernel_param
*pParam
)
1167 if ( pszValue
== NULL
1168 || *pszValue
== '\0'
1173 || ( (*pszValue
== 'o' || *pszValue
== 'O')
1174 && (*pszValue
== 'f' || *pszValue
== 'F') )
1176 g_DevExt
.fLoggingEnabled
= false;
1178 g_DevExt
.fLoggingEnabled
= true;
1182 /** r3_log_to_host parameter getter. */
1183 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
1184 static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf
, const struct kernel_param
*pParam
)
1186 static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf
, struct kernel_param
*pParam
)
1189 strcpy(pszBuf
, g_DevExt
.fLoggingEnabled
? "enabled" : "disabled");
1190 return strlen(pszBuf
);
1195 * Define module parameters.
1197 module_param_call(log
, vgdrvLinuxParamLogGrpSet
, vgdrvLinuxParamLogGrpGet
, NULL
, 0664);
1198 module_param_call(log_flags
, vgdrvLinuxParamLogFlagsSet
, vgdrvLinuxParamLogFlagsGet
, NULL
, 0664);
1199 module_param_call(log_dest
, vgdrvLinuxParamLogDstSet
, vgdrvLinuxParamLogDstGet
, NULL
, 0664);
1201 module_param_call(dbg_log
, vgdrvLinuxParamLogGrpSet
, vgdrvLinuxParamLogGrpGet
, NULL
, 0664);
1202 module_param_call(dbg_log_flags
, vgdrvLinuxParamLogFlagsSet
, vgdrvLinuxParamLogFlagsGet
, NULL
, 0664);
1203 module_param_call(dbg_log_dest
, vgdrvLinuxParamLogDstSet
, vgdrvLinuxParamLogDstGet
, NULL
, 0664);
1205 module_param_call(r3_log_to_host
, vgdrvLinuxParamR3LogToHostSet
, vgdrvLinuxParamR3LogToHostGet
, NULL
, 0664);
1207 #endif /* 2.6.0 and later */
1210 module_init(vgdrvLinuxModInit
);
1211 module_exit(vgdrvLinuxModExit
);
1213 MODULE_AUTHOR(VBOX_VENDOR
);
1214 MODULE_DESCRIPTION(VBOX_PRODUCT
" Guest Additions for Linux Module");
1215 MODULE_LICENSE("GPL");
1216 #ifdef MODULE_VERSION
1217 MODULE_VERSION(VBOX_VERSION_STRING
" r" RT_XSTR(VBOX_SVN_REV
));