VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c@ 75584

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

VBoxGuest-linux.c,VBoxGuest-solaris.c: Setup the IRQ after calling VGDrvCommonInitDevExt so that it's ready for it, like everyone else does it. Linux was also tearing down IRQs after common code terminated, this was also reverted (solaris got this right already).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.8 KB
Line 
1/* $Rev: 75584 $ */
2/** @file
3 * VBoxGuest - Linux specifics.
4 *
5 * Note. Unfortunately, the difference between this and SUPDrv-linux.c is
6 * a little bit too big to be helpful.
7 */
8
9/*
10 * Copyright (C) 2006-2017 Oracle Corporation
11 *
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.
19 *
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.
25 *
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.
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35
36#include "the-linux-kernel.h"
37
38#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
39# define VBOXGUEST_WITH_INPUT_DRIVER
40#endif
41
42#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
43# define CONST_4_15 const
44#else
45# define CONST_4_15
46#endif
47
48#include "VBoxGuestInternal.h"
49#ifdef VBOXGUEST_WITH_INPUT_DRIVER
50# include <linux/input.h>
51#endif
52#include <linux/miscdevice.h>
53#include <linux/poll.h>
54#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
55# include <linux/tty.h>
56#endif
57#include <VBox/version.h>
58#include "revision-generated.h"
59
60#include <iprt/assert.h>
61#include <iprt/asm.h>
62#include <iprt/ctype.h>
63#include <iprt/err.h>
64#include <iprt/initterm.h>
65#include <iprt/mem.h>
66#include <iprt/mp.h>
67#include <iprt/process.h>
68#include <iprt/spinlock.h>
69#include <iprt/semaphore.h>
70#include <iprt/string.h>
71#include <VBox/log.h>
72
73
74/*********************************************************************************************************************************
75* Defined Constants And Macros *
76*********************************************************************************************************************************/
77/** The device name. */
78#define DEVICE_NAME "vboxguest"
79/** The device name for the device node open to everyone. */
80#define DEVICE_NAME_USER "vboxuser"
81/** The name of the PCI driver */
82#define DRIVER_NAME DEVICE_NAME
83
84
85/* 2.4.x compatibility macros that may or may not be defined. */
86#ifndef IRQ_RETVAL
87# define irqreturn_t void
88# define IRQ_RETVAL(n)
89#endif
90
91/* uidgid.h was introduced in 3.5.0. */
92#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
93# define kgid_t gid_t
94# define kuid_t uid_t
95#endif
96
97
98/*********************************************************************************************************************************
99* Internal Functions *
100*********************************************************************************************************************************/
101static void vgdrvLinuxTermPci(struct pci_dev *pPciDev);
102static int vgdrvLinuxProbePci(struct pci_dev *pPciDev, const struct pci_device_id *id);
103static int vgdrvLinuxModInit(void);
104static void vgdrvLinuxModExit(void);
105static int vgdrvLinuxOpen(struct inode *pInode, struct file *pFilp);
106static int vgdrvLinuxRelease(struct inode *pInode, struct file *pFilp);
107#ifdef HAVE_UNLOCKED_IOCTL
108static long vgdrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
109#else
110static int vgdrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
111#endif
112static int vgdrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PVBOXGUESTSESSION pSession);
113static int vgdrvLinuxFAsync(int fd, struct file *pFile, int fOn);
114static unsigned int vgdrvLinuxPoll(struct file *pFile, poll_table *pPt);
115static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff);
116
117
118/*********************************************************************************************************************************
119* Global Variables *
120*********************************************************************************************************************************/
121/**
122 * Device extention & session data association structure.
123 */
124static VBOXGUESTDEVEXT g_DevExt;
125/** The PCI device. */
126static struct pci_dev *g_pPciDev = NULL;
127/** The base of the I/O port range. */
128static RTIOPORT g_IOPortBase;
129/** The base of the MMIO range. */
130static RTHCPHYS g_MMIOPhysAddr = NIL_RTHCPHYS;
131/** The size of the MMIO range as seen by PCI. */
132static uint32_t g_cbMMIO;
133/** The pointer to the mapping of the MMIO range. */
134static void *g_pvMMIOBase;
135/** Wait queue used by polling. */
136static wait_queue_head_t g_PollEventQueue;
137/** Asynchronous notification stuff. */
138static struct fasync_struct *g_pFAsyncQueue;
139#ifdef VBOXGUEST_WITH_INPUT_DRIVER
140/** Pre-allocated mouse status VMMDev request for use in the IRQ
141 * handler. */
142static VMMDevReqMouseStatus *g_pMouseStatusReq;
143#endif
144#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
145/** Whether we've create the logger or not. */
146static volatile bool g_fLoggerCreated;
147/** Release logger group settings. */
148static char g_szLogGrp[128];
149/** Release logger flags settings. */
150static char g_szLogFlags[128];
151/** Release logger destination settings. */
152static char g_szLogDst[128];
153# if 0
154/** Debug logger group settings. */
155static char g_szDbgLogGrp[128];
156/** Debug logger flags settings. */
157static char g_szDbgLogFlags[128];
158/** Debug logger destination settings. */
159static char g_szDbgLogDst[128];
160# endif
161#endif
162
163/** The input device handle */
164#ifdef VBOXGUEST_WITH_INPUT_DRIVER
165static struct input_dev *g_pInputDevice = NULL;
166#endif
167
168/** The file_operations structure. */
169static struct file_operations g_FileOps =
170{
171 owner: THIS_MODULE,
172 open: vgdrvLinuxOpen,
173 release: vgdrvLinuxRelease,
174#ifdef HAVE_UNLOCKED_IOCTL
175 unlocked_ioctl: vgdrvLinuxIOCtl,
176#else
177 ioctl: vgdrvLinuxIOCtl,
178#endif
179 fasync: vgdrvLinuxFAsync,
180 read: vgdrvLinuxRead,
181 poll: vgdrvLinuxPoll,
182 llseek: no_llseek,
183};
184
185/** The miscdevice structure. */
186static struct miscdevice g_MiscDevice =
187{
188 minor: MISC_DYNAMIC_MINOR,
189 name: DEVICE_NAME,
190 fops: &g_FileOps,
191};
192
193/** The file_operations structure for the user device.
194 * @remarks For the time being we'll be using the same implementation as
195 * /dev/vboxguest here. */
196static struct file_operations g_FileOpsUser =
197{
198 owner: THIS_MODULE,
199 open: vgdrvLinuxOpen,
200 release: vgdrvLinuxRelease,
201#ifdef HAVE_UNLOCKED_IOCTL
202 unlocked_ioctl: vgdrvLinuxIOCtl,
203#else
204 ioctl: vgdrvLinuxIOCtl,
205#endif
206};
207
208/** The miscdevice structure for the user device. */
209static struct miscdevice g_MiscDeviceUser =
210{
211 minor: MISC_DYNAMIC_MINOR,
212 name: DEVICE_NAME_USER,
213 fops: &g_FileOpsUser,
214};
215
216
217/** PCI hotplug structure. */
218static const struct pci_device_id g_VBoxGuestPciId[] =
219{
220 {
221 vendor: VMMDEV_VENDORID,
222 device: VMMDEV_DEVICEID
223 },
224 {
225 /* empty entry */
226 }
227};
228
229MODULE_DEVICE_TABLE(pci, g_VBoxGuestPciId);
230
231/** Structure for registering the PCI driver. */
232static struct pci_driver g_PciDriver =
233{
234 name: DRIVER_NAME,
235 id_table: g_VBoxGuestPciId,
236 probe: vgdrvLinuxProbePci,
237 remove: vgdrvLinuxTermPci
238};
239
240#ifdef VBOXGUEST_WITH_INPUT_DRIVER
241/** Kernel IDC session to ourselves for use with the mouse events. */
242static PVBOXGUESTSESSION g_pKernelSession = NULL;
243#endif
244
245
246
247/**
248 * Converts a VBox status code to a linux error code.
249 *
250 * @returns corresponding negative linux error code.
251 * @param rc supdrv error code (SUPDRV_ERR_* defines).
252 */
253static int vgdrvLinuxConvertToNegErrno(int rc)
254{
255 if ( rc > -1000
256 && rc < 1000)
257 return -RTErrConvertToErrno(rc);
258 switch (rc)
259 {
260 case VERR_HGCM_SERVICE_NOT_FOUND: return -ESRCH;
261 case VINF_HGCM_CLIENT_REJECTED: return 0;
262 case VERR_HGCM_INVALID_CMD_ADDRESS: return -EFAULT;
263 case VINF_HGCM_ASYNC_EXECUTE: return 0;
264 case VERR_HGCM_INTERNAL: return -EPROTO;
265 case VERR_HGCM_INVALID_CLIENT_ID: return -EINVAL;
266 case VINF_HGCM_SAVE_STATE: return 0;
267 /* No reason to return this to a guest */
268 // case VERR_HGCM_SERVICE_EXISTS: return -EEXIST;
269 default:
270 AssertMsgFailed(("Unhandled error code %Rrc\n", rc));
271 return -EPROTO;
272 }
273}
274
275
276/**
277 * Does the PCI detection and init of the device.
278 *
279 * @returns 0 on success, negated errno on failure.
280 */
281static int vgdrvLinuxProbePci(struct pci_dev *pPciDev, const struct pci_device_id *id)
282{
283 int rc;
284
285 NOREF(id);
286 AssertReturn(!g_pPciDev, -EINVAL);
287 rc = pci_enable_device(pPciDev);
288 if (rc >= 0)
289 {
290 /* I/O Ports are mandatory, the MMIO bit is not. */
291 g_IOPortBase = pci_resource_start(pPciDev, 0);
292 if (g_IOPortBase != 0)
293 {
294 /*
295 * Map the register address space.
296 */
297 g_MMIOPhysAddr = pci_resource_start(pPciDev, 1);
298 g_cbMMIO = pci_resource_len(pPciDev, 1);
299 if (request_mem_region(g_MMIOPhysAddr, g_cbMMIO, DEVICE_NAME) != NULL)
300 {
301 g_pvMMIOBase = ioremap(g_MMIOPhysAddr, g_cbMMIO);
302 if (g_pvMMIOBase)
303 {
304 /** @todo why aren't we requesting ownership of the I/O ports as well? */
305 g_pPciDev = pPciDev;
306 return 0;
307 }
308
309 /* failure cleanup path */
310 LogRel((DEVICE_NAME ": ioremap failed; MMIO Addr=%RHp cb=%#x\n", g_MMIOPhysAddr, g_cbMMIO));
311 rc = -ENOMEM;
312 release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
313 }
314 else
315 {
316 LogRel((DEVICE_NAME ": failed to obtain adapter memory\n"));
317 rc = -EBUSY;
318 }
319 g_MMIOPhysAddr = NIL_RTHCPHYS;
320 g_cbMMIO = 0;
321 g_IOPortBase = 0;
322 }
323 else
324 {
325 LogRel((DEVICE_NAME ": did not find expected hardware resources\n"));
326 rc = -ENXIO;
327 }
328 pci_disable_device(pPciDev);
329 }
330 else
331 LogRel((DEVICE_NAME ": could not enable device: %d\n", rc));
332 return rc;
333}
334
335
336/**
337 * Clean up the usage of the PCI device.
338 */
339static void vgdrvLinuxTermPci(struct pci_dev *pPciDev)
340{
341 g_pPciDev = NULL;
342 if (pPciDev)
343 {
344 iounmap(g_pvMMIOBase);
345 g_pvMMIOBase = NULL;
346
347 release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
348 g_MMIOPhysAddr = NIL_RTHCPHYS;
349 g_cbMMIO = 0;
350
351 pci_disable_device(pPciDev);
352 }
353}
354
355
356/**
357 * Interrupt service routine.
358 *
359 * @returns In 2.4 it returns void.
360 * In 2.6 we indicate whether we've handled the IRQ or not.
361 *
362 * @param iIrq The IRQ number.
363 * @param pvDevId The device ID, a pointer to g_DevExt.
364 * @param pRegs Register set. Removed in 2.6.19.
365 */
366#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && !defined(DOXYGEN_RUNNING)
367static irqreturn_t vgdrvLinuxISR(int iIrq, void *pvDevId)
368#else
369static irqreturn_t vgdrvLinuxISR(int iIrq, void *pvDevId, struct pt_regs *pRegs)
370#endif
371{
372 bool fTaken = VGDrvCommonISR(&g_DevExt);
373 return IRQ_RETVAL(fTaken);
374}
375
376
377/**
378 * Registers the ISR and initializes the poll wait queue.
379 */
380static int __init vgdrvLinuxInitISR(void)
381{
382 int rc;
383
384 init_waitqueue_head(&g_PollEventQueue);
385 rc = request_irq(g_pPciDev->irq,
386 vgdrvLinuxISR,
387#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
388 IRQF_SHARED,
389#else
390 SA_SHIRQ,
391#endif
392 DEVICE_NAME,
393 &g_DevExt);
394 if (rc)
395 {
396 LogRel((DEVICE_NAME ": could not request IRQ %d: err=%d\n", g_pPciDev->irq, rc));
397 return rc;
398 }
399 return 0;
400}
401
402
403/**
404 * Deregisters the ISR.
405 */
406static void vgdrvLinuxTermISR(void)
407{
408 free_irq(g_pPciDev->irq, &g_DevExt);
409}
410
411
412#ifdef VBOXGUEST_WITH_INPUT_DRIVER
413
414/**
415 * Reports the mouse integration status to the host.
416 *
417 * Calls the kernel IOCtl to report mouse status to the host on behalf of
418 * our kernel session.
419 *
420 * @param fStatus The mouse status to report.
421 */
422static int vgdrvLinuxSetMouseStatus(uint32_t fStatus)
423{
424 int rc;
425 VBGLIOCSETMOUSESTATUS Req;
426 VBGLREQHDR_INIT(&Req.Hdr, SET_MOUSE_STATUS);
427 Req.u.In.fStatus = fStatus;
428 rc = VGDrvCommonIoCtl(VBGL_IOCTL_SET_MOUSE_STATUS, &g_DevExt, g_pKernelSession, &Req.Hdr, sizeof(Req));
429 if (RT_SUCCESS(rc))
430 rc = Req.Hdr.rc;
431 return rc;
432}
433
434
435/**
436 * Called when the input device is first opened.
437 *
438 * Sets up absolute mouse reporting.
439 */
440static int vboxguestOpenInputDevice(struct input_dev *pDev)
441{
442 int rc = vgdrvLinuxSetMouseStatus(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL);
443 if (RT_FAILURE(rc))
444 return ENODEV;
445 NOREF(pDev);
446 return 0;
447}
448
449
450/**
451 * Called if all open handles to the input device are closed.
452 *
453 * Disables absolute reporting.
454 */
455static void vboxguestCloseInputDevice(struct input_dev *pDev)
456{
457 NOREF(pDev);
458 vgdrvLinuxSetMouseStatus(0);
459}
460
461
462/**
463 * Creates the kernel input device.
464 */
465static int __init vgdrvLinuxCreateInputDevice(void)
466{
467 int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&g_pMouseStatusReq, sizeof(*g_pMouseStatusReq), VMMDevReq_GetMouseStatus);
468 if (RT_SUCCESS(rc))
469 {
470 g_pInputDevice = input_allocate_device();
471 if (g_pInputDevice)
472 {
473 g_pInputDevice->id.bustype = BUS_PCI;
474 g_pInputDevice->id.vendor = VMMDEV_VENDORID;
475 g_pInputDevice->id.product = VMMDEV_DEVICEID;
476 g_pInputDevice->id.version = VBOX_SHORT_VERSION;
477 g_pInputDevice->open = vboxguestOpenInputDevice;
478 g_pInputDevice->close = vboxguestCloseInputDevice;
479# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
480 g_pInputDevice->cdev.dev = &g_pPciDev->dev;
481# else
482 g_pInputDevice->dev.parent = &g_pPciDev->dev;
483# endif
484 rc = input_register_device(g_pInputDevice);
485 if (rc == 0)
486 {
487 /* Do what one of our competitors apparently does as that works. */
488 ASMBitSet(g_pInputDevice->evbit, EV_ABS);
489 ASMBitSet(g_pInputDevice->evbit, EV_KEY);
490# ifdef EV_SYN
491 ASMBitSet(g_pInputDevice->evbit, EV_SYN);
492# endif
493 input_set_abs_params(g_pInputDevice, ABS_X, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
494 input_set_abs_params(g_pInputDevice, ABS_Y, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
495 ASMBitSet(g_pInputDevice->keybit, BTN_MOUSE);
496 /** @todo this string should be in a header file somewhere. */
497 g_pInputDevice->name = "VirtualBox mouse integration";
498 return 0;
499 }
500
501 input_free_device(g_pInputDevice);
502 }
503 else
504 rc = -ENOMEM;
505 VbglR0GRFree(&g_pMouseStatusReq->header);
506 g_pMouseStatusReq = NULL;
507 }
508 else
509 rc = -ENOMEM;
510 return rc;
511}
512
513
514/**
515 * Terminates the kernel input device.
516 */
517static void vgdrvLinuxTermInputDevice(void)
518{
519 VbglR0GRFree(&g_pMouseStatusReq->header);
520 g_pMouseStatusReq = NULL;
521
522 /* See documentation of input_register_device(): input_free_device()
523 * should not be called after a device has been registered. */
524 input_unregister_device(g_pInputDevice);
525}
526
527#endif /* VBOXGUEST_WITH_INPUT_DRIVER */
528
529/**
530 * Creates the device nodes.
531 *
532 * @returns 0 on success, negated errno on failure.
533 */
534static int __init vgdrvLinuxInitDeviceNodes(void)
535{
536 /*
537 * The full feature device node.
538 */
539 int rc = misc_register(&g_MiscDevice);
540 if (!rc)
541 {
542 /*
543 * The device node intended to be accessible by all users.
544 */
545 rc = misc_register(&g_MiscDeviceUser);
546 if (!rc)
547 return 0;
548 LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME_USER, rc));
549 misc_deregister(&g_MiscDevice);
550 }
551 else
552 LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME, rc));
553 return rc;
554}
555
556
557/**
558 * Deregisters the device nodes.
559 */
560static void vgdrvLinuxTermDeviceNodes(void)
561{
562 misc_deregister(&g_MiscDevice);
563 misc_deregister(&g_MiscDeviceUser);
564}
565
566
567/**
568 * Initialize module.
569 *
570 * @returns appropriate status code.
571 */
572static int __init vgdrvLinuxModInit(void)
573{
574 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
575 PRTLOGGER pRelLogger;
576 int rc;
577
578 /*
579 * Initialize IPRT first.
580 */
581 rc = RTR0Init(0);
582 if (RT_FAILURE(rc))
583 {
584 printk(KERN_ERR DEVICE_NAME ": RTR0Init failed, rc=%d.\n", rc);
585 return -EINVAL;
586 }
587
588 /*
589 * Create the release log.
590 * (We do that here instead of common code because we want to log
591 * early failures using the LogRel macro.)
592 */
593 rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
594 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
595 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER | RTLOGDEST_USER, NULL);
596 if (RT_SUCCESS(rc))
597 {
598#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
599 RTLogGroupSettings(pRelLogger, g_szLogGrp);
600 RTLogFlags(pRelLogger, g_szLogFlags);
601 RTLogDestinations(pRelLogger, g_szLogDst);
602#endif
603 RTLogRelSetDefaultInstance(pRelLogger);
604 }
605#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
606 g_fLoggerCreated = true;
607#endif
608
609 /*
610 * Locate and initialize the PCI device.
611 */
612 rc = pci_register_driver(&g_PciDriver);
613 if (rc >= 0 && g_pPciDev)
614 {
615 /*
616 * Call the common device extension initializer.
617 */
618#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
619 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26;
620#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_AMD64)
621 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26_x64;
622#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_X86)
623 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24;
624#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_AMD64)
625 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24_x64;
626#else
627# warning "huh? which arch + version is this?"
628 VBOXOSTYPE enmOsType = VBOXOSTYPE_Linux;
629#endif
630 rc = VGDrvCommonInitDevExt(&g_DevExt,
631 g_IOPortBase,
632 g_pvMMIOBase,
633 g_cbMMIO,
634 enmOSType,
635 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
636 if (RT_SUCCESS(rc))
637 {
638 /*
639 * Register the interrupt service routine for it now that g_DevExt can handle IRQs.
640 */
641 rc = vgdrvLinuxInitISR();
642 if (rc >= 0) /** @todo r=bird: status check differs from that inside vgdrvLinuxInitISR. */
643 {
644#ifdef VBOXGUEST_WITH_INPUT_DRIVER
645 /*
646 * Create the kernel session for this driver.
647 */
648 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &g_pKernelSession);
649 if (RT_SUCCESS(rc))
650 {
651 /*
652 * Create the kernel input device.
653 */
654 rc = vgdrvLinuxCreateInputDevice();
655 if (rc >= 0)
656 {
657#endif
658 /*
659 * Read host configuration.
660 */
661 VGDrvCommonProcessOptionsFromHost(&g_DevExt);
662
663 /*
664 * Finally, create the device nodes.
665 */
666 rc = vgdrvLinuxInitDeviceNodes();
667 if (rc >= 0)
668 {
669 /* some useful information for the user but don't show this on the console */
670 LogRel((DEVICE_NAME ": misc device minor %d, IRQ %d, I/O port %RTiop, MMIO at %RHp (size 0x%x)\n",
671 g_MiscDevice.minor, g_pPciDev->irq, g_IOPortBase, g_MMIOPhysAddr, g_cbMMIO));
672 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
673 VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
674 return rc;
675 }
676
677 /* bail out */
678#ifdef VBOXGUEST_WITH_INPUT_DRIVER
679 vgdrvLinuxTermInputDevice();
680 }
681 else
682 {
683 LogRel((DEVICE_NAME ": vboxguestCreateInputDevice failed with rc=%Rrc\n", rc));
684 rc = RTErrConvertFromErrno(rc);
685 }
686 VGDrvCommonCloseSession(&g_DevExt, g_pKernelSession);
687 }
688#endif
689 vgdrvLinuxTermISR();
690 }
691 VGDrvCommonDeleteDevExt(&g_DevExt);
692 }
693 else
694 {
695 LogRel((DEVICE_NAME ": VGDrvCommonInitDevExt failed with rc=%Rrc\n", rc));
696 rc = RTErrConvertFromErrno(rc);
697 }
698 }
699 else
700 {
701 LogRel((DEVICE_NAME ": PCI device not found, probably running on physical hardware.\n"));
702 rc = -ENODEV;
703 }
704 pci_unregister_driver(&g_PciDriver);
705 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
706 RTLogDestroy(RTLogSetDefaultInstance(NULL));
707 RTR0Term();
708 return rc;
709}
710
711
712/**
713 * Unload the module.
714 */
715static void __exit vgdrvLinuxModExit(void)
716{
717 /*
718 * Inverse order of init.
719 */
720 vgdrvLinuxTermDeviceNodes();
721#ifdef VBOXGUEST_WITH_INPUT_DRIVER
722 vgdrvLinuxTermInputDevice();
723 VGDrvCommonCloseSession(&g_DevExt, g_pKernelSession);
724#endif
725 vgdrvLinuxTermISR();
726 VGDrvCommonDeleteDevExt(&g_DevExt);
727 pci_unregister_driver(&g_PciDriver);
728 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
729 RTLogDestroy(RTLogSetDefaultInstance(NULL));
730 RTR0Term();
731}
732
733
734/**
735 * Get the process user ID.
736 *
737 * @returns UID.
738 */
739DECLINLINE(RTUID) vgdrvLinuxGetUid(void)
740{
741#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
742# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
743 return from_kuid(current_user_ns(), current->cred->uid);
744# else
745 return current->cred->uid;
746# endif
747#else
748 return current->uid;
749#endif
750}
751
752
753/**
754 * Checks if the given group number is zero or not.
755 *
756 * @returns true / false.
757 * @param gid The group to check for.
758 */
759DECLINLINE(bool) vgdrvLinuxIsGroupZero(kgid_t gid)
760{
761#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
762 return from_kgid(current_user_ns(), gid);
763#else
764 return gid == 0;
765#endif
766}
767
768
769/**
770 * Searches the effective group and supplementary groups for @a gid.
771 *
772 * @returns true if member, false if not.
773 * @param gid The group to check for.
774 */
775DECLINLINE(RTGID) vgdrvLinuxIsInGroupEff(kgid_t gid)
776{
777 return in_egroup_p(gid) != 0;
778}
779
780
781/**
782 * Check if we can positively or negatively determine that the process is
783 * running under a login on the physical machine console.
784 *
785 * Havne't found a good way to figure this out for graphical sessions, so this
786 * is mostly pointless. But let us try do what we can do.
787 *
788 * @returns VMMDEV_REQUESTOR_CON_XXX.
789 */
790static uint32_t vgdrvLinuxRequestorOnConsole(void)
791{
792 uint32_t fRet = VMMDEV_REQUESTOR_CON_DONT_KNOW;
793
794#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) /* First with tty_kref_put(). */
795 /*
796 * Check for tty0..63, ASSUMING that these are only used for the physical console.
797 */
798 struct tty_struct *pTty = get_current_tty();
799 if (pTty)
800 {
801# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
802 const char *pszName = tty_name(pTty);
803# else
804 char szBuf[64];
805 const char *pszName = tty_name(pTty, szBuf);
806# endif
807 if ( pszName
808 && pszName[0] == 't'
809 && pszName[1] == 't'
810 && pszName[2] == 'y'
811 && RT_C_IS_DIGIT(pszName[3])
812 && ( pszName[4] == '\0'
813 || ( RT_C_IS_DIGIT(pszName[4])
814 && pszName[5] == '\0'
815 && (pszName[3] - '0') * 10 + (pszName[4] - '0') <= 63)) )
816 fRet = VMMDEV_REQUESTOR_CON_YES;
817 tty_kref_put(pTty);
818 }
819#endif
820
821 return fRet;
822}
823
824
825/**
826 * Device open. Called on open /dev/vboxdrv
827 *
828 * @param pInode Pointer to inode info structure.
829 * @param pFilp Associated file pointer.
830 */
831static int vgdrvLinuxOpen(struct inode *pInode, struct file *pFilp)
832{
833 int rc;
834 PVBOXGUESTSESSION pSession;
835 uint32_t fRequestor;
836 Log((DEVICE_NAME ": pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
837
838 /*
839 * Figure out the requestor flags.
840 * ASSUMES that the gid of /dev/vboxuser is what we should consider the special vbox group.
841 */
842 fRequestor = VMMDEV_REQUESTOR_USERMODE | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
843 if (vgdrvLinuxGetUid() == 0)
844 fRequestor |= VMMDEV_REQUESTOR_USR_ROOT;
845 else
846 fRequestor |= VMMDEV_REQUESTOR_USR_USER;
847 if (MINOR(pInode->i_rdev) == g_MiscDeviceUser.minor)
848 {
849 fRequestor |= VMMDEV_REQUESTOR_USER_DEVICE;
850 if (vgdrvLinuxIsGroupZero(pInode->i_gid) && vgdrvLinuxIsInGroupEff(pInode->i_gid))
851 fRequestor |= VMMDEV_REQUESTOR_GRP_VBOX;
852 }
853 fRequestor |= vgdrvLinuxRequestorOnConsole();
854
855 /*
856 * Call common code to create the user session. Associate it with
857 * the file so we can access it in the other methods.
858 */
859 rc = VGDrvCommonCreateUserSession(&g_DevExt, fRequestor, &pSession);
860 if (RT_SUCCESS(rc))
861 pFilp->private_data = pSession;
862
863 Log(("vgdrvLinuxOpen: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
864 &g_DevExt, pSession, rc, vgdrvLinuxConvertToNegErrno(rc), RTProcSelf(), current->pid, current->comm));
865 return vgdrvLinuxConvertToNegErrno(rc);
866}
867
868
869/**
870 * Close device.
871 *
872 * @param pInode Pointer to inode info structure.
873 * @param pFilp Associated file pointer.
874 */
875static int vgdrvLinuxRelease(struct inode *pInode, struct file *pFilp)
876{
877 Log(("vgdrvLinuxRelease: pFilp=%p pSession=%p pid=%d/%d %s\n",
878 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
879
880#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
881 /* This housekeeping was needed in older kernel versions to ensure that
882 * the file pointer didn't get left on the polling queue. */
883 vgdrvLinuxFAsync(-1, pFilp, 0);
884#endif
885 VGDrvCommonCloseSession(&g_DevExt, (PVBOXGUESTSESSION)pFilp->private_data);
886 pFilp->private_data = NULL;
887 return 0;
888}
889
890
891/**
892 * Device I/O Control entry point.
893 *
894 * @param pFilp Associated file pointer.
895 * @param uCmd The function specified to ioctl().
896 * @param ulArg The argument specified to ioctl().
897 */
898#if defined(HAVE_UNLOCKED_IOCTL) || defined(DOXYGEN_RUNNING)
899static long vgdrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
900#else
901static int vgdrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
902#endif
903{
904 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFilp->private_data;
905 int rc;
906#ifndef HAVE_UNLOCKED_IOCTL
907 unlock_kernel();
908#endif
909
910#if 0 /* no fast I/O controls defined atm. */
911 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
912 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
913 || uCmd == SUP_IOCTL_FAST_DO_NOP)
914 && pSession->fUnrestricted == true))
915 rc = VGDrvCommonIoCtlFast(uCmd, ulArg, &g_DevExt, pSession);
916 else
917#endif
918 rc = vgdrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
919
920#ifndef HAVE_UNLOCKED_IOCTL
921 lock_kernel();
922#endif
923 return rc;
924}
925
926
927/**
928 * Device I/O Control entry point, slow variant.
929 *
930 * @param pFilp Associated file pointer.
931 * @param uCmd The function specified to ioctl().
932 * @param ulArg The argument specified to ioctl().
933 * @param pSession The session instance.
934 */
935static int vgdrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PVBOXGUESTSESSION pSession)
936{
937 int rc;
938 VBGLREQHDR Hdr;
939 PVBGLREQHDR pHdr;
940 uint32_t cbBuf;
941
942 Log6(("vgdrvLinuxIOCtlSlow: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
943
944 /*
945 * Read the header.
946 */
947 if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
948 {
949 Log(("vgdrvLinuxIOCtlSlow: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
950 return -EFAULT;
951 }
952 if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
953 {
954 Log(("vgdrvLinuxIOCtlSlow: bad header version %#x; uCmd=%#x\n", Hdr.uVersion, uCmd));
955 return -EINVAL;
956 }
957
958 /*
959 * Buffer the request.
960 * Note! The header is revalidated by the common code.
961 */
962 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
963 if (RT_UNLIKELY(cbBuf > _1M*16))
964 {
965 Log(("vgdrvLinuxIOCtlSlow: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
966 return -E2BIG;
967 }
968 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
969 || (cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd) != 0)))
970 {
971 Log(("vgdrvLinuxIOCtlSlow: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
972 return -EINVAL;
973 }
974 pHdr = RTMemAlloc(cbBuf);
975 if (RT_UNLIKELY(!pHdr))
976 {
977 LogRel(("vgdrvLinuxIOCtlSlow: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
978 return -ENOMEM;
979 }
980 if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
981 {
982 Log(("vgdrvLinuxIOCtlSlow: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
983 RTMemFree(pHdr);
984 return -EFAULT;
985 }
986 if (Hdr.cbIn < cbBuf)
987 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
988
989 /*
990 * Process the IOCtl.
991 */
992 rc = VGDrvCommonIoCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
993
994 /*
995 * Copy ioctl data and output buffer back to user space.
996 */
997 if (RT_SUCCESS(rc))
998 {
999 uint32_t cbOut = pHdr->cbOut;
1000 if (RT_UNLIKELY(cbOut > cbBuf))
1001 {
1002 LogRel(("vgdrvLinuxIOCtlSlow: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
1003 cbOut = cbBuf;
1004 }
1005 if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
1006 {
1007 /* this is really bad! */
1008 LogRel(("vgdrvLinuxIOCtlSlow: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
1009 rc = -EFAULT;
1010 }
1011 }
1012 else
1013 {
1014 Log(("vgdrvLinuxIOCtlSlow: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
1015 rc = -EINVAL;
1016 }
1017 RTMemFree(pHdr);
1018
1019 Log6(("vgdrvLinuxIOCtlSlow: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
1020 return rc;
1021}
1022
1023
1024/**
1025 * @note This code is duplicated on other platforms with variations, so please
1026 * keep them all up to date when making changes!
1027 */
1028int VBOXCALL VBoxGuestIDC(void *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq)
1029{
1030 /*
1031 * Simple request validation (common code does the rest).
1032 */
1033 int rc;
1034 if ( RT_VALID_PTR(pReqHdr)
1035 && cbReq >= sizeof(*pReqHdr))
1036 {
1037 /*
1038 * All requests except the connect one requires a valid session.
1039 */
1040 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
1041 if (pSession)
1042 {
1043 if ( RT_VALID_PTR(pSession)
1044 && pSession->pDevExt == &g_DevExt)
1045 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
1046 else
1047 rc = VERR_INVALID_HANDLE;
1048 }
1049 else if (uReq == VBGL_IOCTL_IDC_CONNECT)
1050 {
1051 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
1052 if (RT_SUCCESS(rc))
1053 {
1054 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
1055 if (RT_FAILURE(rc))
1056 VGDrvCommonCloseSession(&g_DevExt, pSession);
1057 }
1058 }
1059 else
1060 rc = VERR_INVALID_HANDLE;
1061 }
1062 else
1063 rc = VERR_INVALID_POINTER;
1064 return rc;
1065}
1066EXPORT_SYMBOL(VBoxGuestIDC);
1067
1068
1069/**
1070 * Asynchronous notification activation method.
1071 *
1072 * @returns 0 on success, negative errno on failure.
1073 *
1074 * @param fd The file descriptor.
1075 * @param pFile The file structure.
1076 * @param fOn On/off indicator.
1077 */
1078static int vgdrvLinuxFAsync(int fd, struct file *pFile, int fOn)
1079{
1080 return fasync_helper(fd, pFile, fOn, &g_pFAsyncQueue);
1081}
1082
1083
1084/**
1085 * Poll function.
1086 *
1087 * This returns ready to read if the mouse pointer mode or the pointer position
1088 * has changed since last call to read.
1089 *
1090 * @returns 0 if no changes, POLLIN | POLLRDNORM if there are unseen changes.
1091 *
1092 * @param pFile The file structure.
1093 * @param pPt The poll table.
1094 *
1095 * @remarks This is probably not really used, X11 is said to use the fasync
1096 * interface instead.
1097 */
1098static unsigned int vgdrvLinuxPoll(struct file *pFile, poll_table *pPt)
1099{
1100 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
1101 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
1102 unsigned int fMask = pSession->u32MousePosChangedSeq != u32CurSeq
1103 ? POLLIN | POLLRDNORM
1104 : 0;
1105 poll_wait(pFile, &g_PollEventQueue, pPt);
1106 return fMask;
1107}
1108
1109
1110/**
1111 * Read to go with our poll/fasync response.
1112 *
1113 * @returns 1 or -EINVAL.
1114 *
1115 * @param pFile The file structure.
1116 * @param pbBuf The buffer to read into.
1117 * @param cbRead The max number of bytes to read.
1118 * @param poff The current file position.
1119 *
1120 * @remarks This is probably not really used as X11 lets the driver do its own
1121 * event reading. The poll condition is therefore also cleared when we
1122 * see VMMDevReq_GetMouseStatus in vgdrvIoCtl_VMMRequest.
1123 */
1124static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff)
1125{
1126 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
1127 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
1128
1129 if (*poff != 0)
1130 return -EINVAL;
1131
1132 /*
1133 * Fake a single byte read if we're not up to date with the current mouse position.
1134 */
1135 if ( pSession->u32MousePosChangedSeq != u32CurSeq
1136 && cbRead > 0)
1137 {
1138 pSession->u32MousePosChangedSeq = u32CurSeq;
1139 pbBuf[0] = 0;
1140 return 1;
1141 }
1142 return 0;
1143}
1144
1145
1146void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
1147{
1148#ifdef VBOXGUEST_WITH_INPUT_DRIVER
1149 int rc;
1150#endif
1151 NOREF(pDevExt);
1152
1153 /*
1154 * Wake up everyone that's in a poll() and post anyone that has
1155 * subscribed to async notifications.
1156 */
1157 Log3(("VGDrvNativeISRMousePollEvent: wake_up_all\n"));
1158 wake_up_all(&g_PollEventQueue);
1159 Log3(("VGDrvNativeISRMousePollEvent: kill_fasync\n"));
1160 kill_fasync(&g_pFAsyncQueue, SIGIO, POLL_IN);
1161#ifdef VBOXGUEST_WITH_INPUT_DRIVER
1162 /* Report events to the kernel input device */
1163 g_pMouseStatusReq->mouseFeatures = 0;
1164 g_pMouseStatusReq->pointerXPos = 0;
1165 g_pMouseStatusReq->pointerYPos = 0;
1166 rc = VbglR0GRPerform(&g_pMouseStatusReq->header);
1167 if (RT_SUCCESS(rc))
1168 {
1169 input_report_abs(g_pInputDevice, ABS_X,
1170 g_pMouseStatusReq->pointerXPos);
1171 input_report_abs(g_pInputDevice, ABS_Y,
1172 g_pMouseStatusReq->pointerYPos);
1173# ifdef EV_SYN
1174 input_sync(g_pInputDevice);
1175# endif
1176 }
1177#endif
1178 Log3(("VGDrvNativeISRMousePollEvent: done\n"));
1179}
1180
1181
1182bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
1183{
1184 RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue);
1185 return false;
1186}
1187
1188
1189#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1190
1191/** log and dbg_log parameter setter. */
1192static int vgdrvLinuxParamLogGrpSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
1193{
1194 if (g_fLoggerCreated)
1195 {
1196 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1197 if (pLogger)
1198 RTLogGroupSettings(pLogger, pszValue);
1199 }
1200 else if (pParam->name[0] != 'd')
1201 strlcpy(&g_szLogGrp[0], pszValue, sizeof(g_szLogGrp));
1202
1203 return 0;
1204}
1205
1206/** log and dbg_log parameter getter. */
1207static int vgdrvLinuxParamLogGrpGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
1208{
1209 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1210 *pszBuf = '\0';
1211 if (pLogger)
1212 RTLogGetGroupSettings(pLogger, pszBuf, _4K);
1213 return strlen(pszBuf);
1214}
1215
1216
1217/** log and dbg_log_flags parameter setter. */
1218static int vgdrvLinuxParamLogFlagsSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
1219{
1220 if (g_fLoggerCreated)
1221 {
1222 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1223 if (pLogger)
1224 RTLogFlags(pLogger, pszValue);
1225 }
1226 else if (pParam->name[0] != 'd')
1227 strlcpy(&g_szLogFlags[0], pszValue, sizeof(g_szLogFlags));
1228 return 0;
1229}
1230
1231/** log and dbg_log_flags parameter getter. */
1232static int vgdrvLinuxParamLogFlagsGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
1233{
1234 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1235 *pszBuf = '\0';
1236 if (pLogger)
1237 RTLogGetFlags(pLogger, pszBuf, _4K);
1238 return strlen(pszBuf);
1239}
1240
1241
1242/** log and dbg_log_dest parameter setter. */
1243static int vgdrvLinuxParamLogDstSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
1244{
1245 if (g_fLoggerCreated)
1246 {
1247 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1248 if (pLogger)
1249 RTLogDestinations(pLogger, pszValue);
1250 }
1251 else if (pParam->name[0] != 'd')
1252 strlcpy(&g_szLogDst[0], pszValue, sizeof(g_szLogDst));
1253 return 0;
1254}
1255
1256/** log and dbg_log_dest parameter getter. */
1257static int vgdrvLinuxParamLogDstGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
1258{
1259 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1260 *pszBuf = '\0';
1261 if (pLogger)
1262 RTLogGetDestinations(pLogger, pszBuf, _4K);
1263 return strlen(pszBuf);
1264}
1265
1266
1267/** r3_log_to_host parameter setter. */
1268static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
1269{
1270 g_DevExt.fLoggingEnabled = VBDrvCommonIsOptionValueTrue(pszValue);
1271 return 0;
1272}
1273
1274/** r3_log_to_host parameter getter. */
1275static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
1276{
1277 strcpy(pszBuf, g_DevExt.fLoggingEnabled ? "enabled" : "disabled");
1278 return strlen(pszBuf);
1279}
1280
1281
1282/*
1283 * Define module parameters.
1284 */
1285module_param_call(log, vgdrvLinuxParamLogGrpSet, vgdrvLinuxParamLogGrpGet, NULL, 0664);
1286module_param_call(log_flags, vgdrvLinuxParamLogFlagsSet, vgdrvLinuxParamLogFlagsGet, NULL, 0664);
1287module_param_call(log_dest, vgdrvLinuxParamLogDstSet, vgdrvLinuxParamLogDstGet, NULL, 0664);
1288# ifdef LOG_ENABLED
1289module_param_call(dbg_log, vgdrvLinuxParamLogGrpSet, vgdrvLinuxParamLogGrpGet, NULL, 0664);
1290module_param_call(dbg_log_flags, vgdrvLinuxParamLogFlagsSet, vgdrvLinuxParamLogFlagsGet, NULL, 0664);
1291module_param_call(dbg_log_dest, vgdrvLinuxParamLogDstSet, vgdrvLinuxParamLogDstGet, NULL, 0664);
1292# endif
1293module_param_call(r3_log_to_host, vgdrvLinuxParamR3LogToHostSet, vgdrvLinuxParamR3LogToHostGet, NULL, 0664);
1294
1295#endif /* 2.6.0 and later */
1296
1297
1298module_init(vgdrvLinuxModInit);
1299module_exit(vgdrvLinuxModExit);
1300
1301MODULE_AUTHOR(VBOX_VENDOR);
1302MODULE_DESCRIPTION(VBOX_PRODUCT " Guest Additions for Linux Module");
1303MODULE_LICENSE("GPL");
1304#ifdef MODULE_VERSION
1305MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
1306#endif
1307
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