VirtualBox

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

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

VBoxGuest-linux.cpp: Build fix. bugref:9105

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