VirtualBox

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

Last change on this file since 96459 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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