VirtualBox

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

Last change on this file since 35263 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1/* $Rev: 33540 $ */
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-2009 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 * Some lines of code to disable the local APIC on x86_64 machines taken
20 * from a Mandriva patch by Gwenole Beauchesne <gbeauchesne@mandriva.com>.
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_SUP_DRV
27#include "the-linux-kernel.h"
28#include "VBoxGuestInternal.h"
29#include <linux/miscdevice.h>
30#include <linux/poll.h>
31#include "version-generated.h"
32#include "product-generated.h"
33
34#include <iprt/assert.h>
35#include <iprt/asm.h>
36#include <iprt/err.h>
37#include <iprt/initterm.h>
38#include <iprt/mem.h>
39#include <iprt/mp.h>
40#include <iprt/process.h>
41#include <iprt/spinlock.h>
42#include <iprt/semaphore.h>
43#include <VBox/log.h>
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49/** The device name. */
50#define DEVICE_NAME "vboxguest"
51/** The device name for the device node open to everyone.. */
52#define DEVICE_NAME_USER "vboxuser"
53
54
55#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
56# define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
57# define PCI_DEV_PUT(x) pci_dev_put(x)
58#else
59# define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
60# define PCI_DEV_PUT(x) do {} while(0)
61#endif
62
63/* 2.4.x compatibility macros that may or may not be defined. */
64#ifndef IRQ_RETVAL
65# define irqreturn_t void
66# define IRQ_RETVAL(n)
67#endif
68
69
70/*******************************************************************************
71* Internal Functions *
72*******************************************************************************/
73static int vboxguestLinuxModInit(void);
74static void vboxguestLinuxModExit(void);
75static int vboxguestLinuxOpen(struct inode *pInode, struct file *pFilp);
76static int vboxguestLinuxRelease(struct inode *pInode, struct file *pFilp);
77#ifdef HAVE_UNLOCKED_IOCTL
78static long vboxguestLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
79#else
80static int vboxguestLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
81#endif
82static int vboxguestFAsync(int fd, struct file *pFile, int fOn);
83static unsigned int vboxguestPoll(struct file *pFile, poll_table *pPt);
84static ssize_t vboxguestRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff);
85
86
87/*******************************************************************************
88* Global Variables *
89*******************************************************************************/
90/**
91 * Device extention & session data association structure.
92 */
93static VBOXGUESTDEVEXT g_DevExt;
94/** The PCI device. */
95static struct pci_dev *g_pPciDev;
96/** The base of the I/O port range. */
97static RTIOPORT g_IOPortBase;
98/** The base of the MMIO range. */
99static RTHCPHYS g_MMIOPhysAddr = NIL_RTHCPHYS;
100/** The size of the MMIO range as seen by PCI. */
101static uint32_t g_cbMMIO;
102/** The pointer to the mapping of the MMIO range. */
103static void *g_pvMMIOBase;
104/** Wait queue used by polling. */
105static wait_queue_head_t g_PollEventQueue;
106/** Asynchronous notification stuff. */
107static struct fasync_struct *g_pFAsyncQueue;
108#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
109/** Whether we've create the logger or not. */
110static volatile bool g_fLoggerCreated;
111/** Release logger group settings. */
112static char g_szLogGrp[128];
113/** Release logger flags settings. */
114static char g_szLogFlags[128];
115/** Release logger destination settings. */
116static char g_szLogDst[128];
117# if 0
118/** Debug logger group settings. */
119static char g_szDbgLogGrp[128];
120/** Debug logger flags settings. */
121static char g_szDbgLogFlags[128];
122/** Debug logger destination settings. */
123static char g_szDbgLogDst[128];
124# endif
125#endif
126
127/** Our file node major id.
128 * Either set dynamically at run time or statically at compile time. */
129#ifdef CONFIG_VBOXGUEST_MAJOR
130static unsigned int g_iModuleMajor = CONFIG_VBOXGUEST_MAJOR;
131#else
132static unsigned int g_iModuleMajor = 0;
133#endif
134#ifdef CONFIG_VBOXADD_MAJOR
135# error "CONFIG_VBOXADD_MAJOR -> CONFIG_VBOXGUEST_MAJOR"
136#endif
137
138/** The file_operations structure. */
139static struct file_operations g_FileOps =
140{
141 owner: THIS_MODULE,
142 open: vboxguestLinuxOpen,
143 release: vboxguestLinuxRelease,
144#ifdef HAVE_UNLOCKED_IOCTL
145 unlocked_ioctl: vboxguestLinuxIOCtl,
146#else
147 ioctl: vboxguestLinuxIOCtl,
148#endif
149 fasync: vboxguestFAsync,
150 read: vboxguestRead,
151 poll: vboxguestPoll,
152 llseek: no_llseek,
153};
154
155/** The miscdevice structure. */
156static struct miscdevice g_MiscDevice =
157{
158 minor: MISC_DYNAMIC_MINOR,
159 name: DEVICE_NAME,
160 fops: &g_FileOps,
161};
162
163/** The file_operations structure for the user device.
164 * @remarks For the time being we'll be using the same implementation as
165 * /dev/vboxguest here. */
166static struct file_operations g_FileOpsUser =
167{
168 owner: THIS_MODULE,
169 open: vboxguestLinuxOpen,
170 release: vboxguestLinuxRelease,
171#ifdef HAVE_UNLOCKED_IOCTL
172 unlocked_ioctl: vboxguestLinuxIOCtl,
173#else
174 ioctl: vboxguestLinuxIOCtl,
175#endif
176};
177
178/** The miscdevice structure for the user device. */
179static struct miscdevice g_MiscDeviceUser =
180{
181 minor: MISC_DYNAMIC_MINOR,
182 name: DEVICE_NAME_USER,
183 fops: &g_FileOpsUser,
184};
185
186
187/** PCI hotplug structure. */
188static const struct pci_device_id __devinitdata g_VBoxGuestPciId[] =
189{
190 {
191 vendor: VMMDEV_VENDORID,
192 device: VMMDEV_DEVICEID
193 },
194 {
195 /* empty entry */
196 }
197};
198MODULE_DEVICE_TABLE(pci, g_VBoxGuestPciId);
199
200
201/**
202 * Converts a VBox status code to a linux error code.
203 *
204 * @returns corresponding negative linux error code.
205 * @param rc supdrv error code (SUPDRV_ERR_* defines).
206 */
207static int vboxguestLinuxConvertToNegErrno(int rc)
208{
209 if ( rc > -1000
210 && rc < 1000)
211 return -RTErrConvertToErrno(rc);
212 switch (rc)
213 {
214 case VERR_HGCM_SERVICE_NOT_FOUND: return -ESRCH;
215 case VINF_HGCM_CLIENT_REJECTED: return 0;
216 case VERR_HGCM_INVALID_CMD_ADDRESS: return -EFAULT;
217 case VINF_HGCM_ASYNC_EXECUTE: return 0;
218 case VERR_HGCM_INTERNAL: return -EPROTO;
219 case VERR_HGCM_INVALID_CLIENT_ID: return -EINVAL;
220 case VINF_HGCM_SAVE_STATE: return 0;
221 /* No reason to return this to a guest */
222 // case VERR_HGCM_SERVICE_EXISTS: return -EEXIST;
223 default:
224 AssertMsgFailed(("Unhandled error code %Rrc\n", rc));
225 return -EPROTO;
226 }
227}
228
229
230
231/**
232 * Does the PCI detection and init of the device.
233 *
234 * @returns 0 on success, negated errno on failure.
235 */
236static int __init vboxguestLinuxInitPci(void)
237{
238 struct pci_dev *pPciDev;
239 int rc;
240
241 pPciDev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, NULL);
242 if (pPciDev)
243 {
244 rc = pci_enable_device(pPciDev);
245 if (rc >= 0)
246 {
247 /* I/O Ports are mandatory, the MMIO bit is not. */
248 g_IOPortBase = pci_resource_start(pPciDev, 0);
249 if (g_IOPortBase != 0)
250 {
251 /*
252 * Map the register address space.
253 */
254 g_MMIOPhysAddr = pci_resource_start(pPciDev, 1);
255 g_cbMMIO = pci_resource_len(pPciDev, 1);
256 if (request_mem_region(g_MMIOPhysAddr, g_cbMMIO, DEVICE_NAME) != NULL)
257 {
258 g_pvMMIOBase = ioremap(g_MMIOPhysAddr, g_cbMMIO);
259 if (g_pvMMIOBase)
260 {
261 /** @todo why aren't we requesting ownership of the I/O ports as well? */
262 g_pPciDev = pPciDev;
263 return 0;
264 }
265
266 /* failure cleanup path */
267 LogRel((DEVICE_NAME ": ioremap failed; MMIO Addr=%RHp cb=%#x\n", g_MMIOPhysAddr, g_cbMMIO));
268 rc = -ENOMEM;
269 release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
270 }
271 else
272 {
273 LogRel((DEVICE_NAME ": failed to obtain adapter memory\n"));
274 rc = -EBUSY;
275 }
276 g_MMIOPhysAddr = NIL_RTHCPHYS;
277 g_cbMMIO = 0;
278 g_IOPortBase = 0;
279 }
280 else
281 {
282 LogRel((DEVICE_NAME ": did not find expected hardware resources\n"));
283 rc = -ENXIO;
284 }
285 pci_disable_device(pPciDev);
286 }
287 else
288 LogRel((DEVICE_NAME ": could not enable device: %d\n", rc));
289 PCI_DEV_PUT(pPciDev);
290 }
291 else
292 {
293 printk(KERN_ERR DEVICE_NAME ": VirtualBox Guest PCI device not found.\n");
294 rc = -ENODEV;
295 }
296 return rc;
297}
298
299
300/**
301 * Clean up the usage of the PCI device.
302 */
303static void vboxguestLinuxTermPci(void)
304{
305 struct pci_dev *pPciDev = g_pPciDev;
306 g_pPciDev = NULL;
307 if (pPciDev)
308 {
309 iounmap(g_pvMMIOBase);
310 g_pvMMIOBase = NULL;
311
312 release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
313 g_MMIOPhysAddr = NIL_RTHCPHYS;
314 g_cbMMIO = 0;
315
316 pci_disable_device(pPciDev);
317 }
318}
319
320
321/**
322 * Interrupt service routine.
323 *
324 * @returns In 2.4 it returns void.
325 * In 2.6 we indicate whether we've handled the IRQ or not.
326 *
327 * @param iIrq The IRQ number.
328 * @param pvDevId The device ID, a pointer to g_DevExt.
329 * @param pvRegs Register set. Removed in 2.6.19.
330 */
331#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
332static irqreturn_t vboxguestLinuxISR(int iIrrq, void *pvDevId)
333#else
334static irqreturn_t vboxguestLinuxISR(int iIrrq, void *pvDevId, struct pt_regs *pRegs)
335#endif
336{
337 bool fTaken = VBoxGuestCommonISR(&g_DevExt);
338 return IRQ_RETVAL(fTaken);
339}
340
341
342/**
343 * Registers the ISR and initializes the poll wait queue.
344 */
345static int __init vboxguestLinuxInitISR(void)
346{
347 int rc;
348
349 init_waitqueue_head(&g_PollEventQueue);
350 rc = request_irq(g_pPciDev->irq,
351 vboxguestLinuxISR,
352#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
353 IRQF_SHARED,
354#else
355 SA_SHIRQ,
356#endif
357 DEVICE_NAME,
358 &g_DevExt);
359 if (rc)
360 {
361 LogRel((DEVICE_NAME ": could not request IRQ %d: err=%d\n", g_pPciDev->irq, rc));
362 return rc;
363 }
364 return 0;
365}
366
367
368/**
369 * Deregisters the ISR.
370 */
371static void vboxguestLinuxTermISR(void)
372{
373 free_irq(g_pPciDev->irq, &g_DevExt);
374}
375
376
377/**
378 * Creates the device nodes.
379 *
380 * @returns 0 on success, negated errno on failure.
381 */
382static int __init vboxguestLinuxInitDeviceNodes(void)
383{
384 int rc;
385
386 /*
387 * The full feature device node.
388 */
389 if (g_iModuleMajor > 0)
390 {
391 rc = register_chrdev(g_iModuleMajor, DEVICE_NAME, &g_FileOps);
392 if (rc < 0)
393 {
394 LogRel((DEVICE_NAME ": register_chrdev failed: g_iModuleMajor: %d, rc: %d\n", g_iModuleMajor, rc));
395 return rc;
396 }
397 }
398 else
399 {
400 rc = misc_register(&g_MiscDevice);
401 if (rc)
402 {
403 LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME, rc));
404 return rc;
405 }
406 }
407
408 /*
409 * The device node intended to be accessible by all users.
410 */
411 rc = misc_register(&g_MiscDeviceUser);
412 if (rc)
413 {
414 LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME_USER, rc));
415 if (g_iModuleMajor > 0)
416 unregister_chrdev(g_iModuleMajor, DEVICE_NAME);
417 else
418 misc_deregister(&g_MiscDevice);
419 return rc;
420 }
421
422 return 0;
423}
424
425
426/**
427 * Deregisters the device nodes.
428 */
429static void vboxguestLinuxTermDeviceNodes(void)
430{
431 if (g_iModuleMajor > 0)
432 unregister_chrdev(g_iModuleMajor, DEVICE_NAME);
433 else
434 misc_deregister(&g_MiscDevice);
435 misc_deregister(&g_MiscDeviceUser);
436}
437
438
439
440/**
441 * Initialize module.
442 *
443 * @returns appropriate status code.
444 */
445static int __init vboxguestLinuxModInit(void)
446{
447 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
448 PRTLOGGER pRelLogger;
449 int rc;
450
451 /*
452 * Initialize IPRT first.
453 */
454 rc = RTR0Init(0);
455 if (RT_FAILURE(rc))
456 {
457 printk(KERN_ERR DEVICE_NAME ": RTR0Init failed, rc=%d.\n", rc);
458 return -EINVAL;
459 }
460
461 /*
462 * Create the release log.
463 * (We do that here instead of common code because we want to log
464 * early failures using the LogRel macro.)
465 */
466 rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
467 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
468 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER | RTLOGDEST_USER, NULL);
469 if (RT_SUCCESS(rc))
470 {
471#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
472 RTLogGroupSettings(pRelLogger, g_szLogGrp);
473 RTLogFlags(pRelLogger, g_szLogFlags);
474 RTLogDestinations(pRelLogger, g_szLogDst);
475#endif
476 RTLogRelSetDefaultInstance(pRelLogger);
477 }
478#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
479 g_fLoggerCreated = true;
480#endif
481
482 /*
483 * Locate and initialize the PCI device.
484 */
485 rc = vboxguestLinuxInitPci();
486 if (rc >= 0)
487 {
488 /*
489 * Register the interrupt service routine for it.
490 */
491 rc = vboxguestLinuxInitISR();
492 if (rc >= 0)
493 {
494 /*
495 * Call the common device extension initializer.
496 */
497#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
498 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26;
499#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_AMD64)
500 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26_x64;
501#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_X86)
502 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24;
503#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_AMD64)
504 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24_x64;
505#else
506# warning "huh? which arch + version is this?"
507 VBOXOSTYPE enmOsType = VBOXOSTYPE_Linux;
508#endif
509 rc = VBoxGuestInitDevExt(&g_DevExt,
510 g_IOPortBase,
511 g_pvMMIOBase,
512 g_cbMMIO,
513 enmOSType,
514 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
515 if (RT_SUCCESS(rc))
516 {
517 /*
518 * Finally, create the device nodes.
519 */
520 rc = vboxguestLinuxInitDeviceNodes();
521 if (rc >= 0)
522 {
523 /* some useful information for the user but don't show this on the console */
524 LogRel((DEVICE_NAME ": major %d, IRQ %d, I/O port %RTiop, MMIO at %RHp (size 0x%x)\n",
525 g_iModuleMajor, g_pPciDev->irq, g_IOPortBase, g_MMIOPhysAddr, g_cbMMIO));
526 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
527 VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
528 return rc;
529 }
530
531 /* bail out */
532 VBoxGuestDeleteDevExt(&g_DevExt);
533 }
534 else
535 {
536 LogRel((DEVICE_NAME ": VBoxGuestInitDevExt failed with rc=%Rrc\n", rc));
537 rc = RTErrConvertFromErrno(rc);
538 }
539 vboxguestLinuxTermISR();
540 }
541 vboxguestLinuxTermPci();
542 }
543 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
544 RTLogDestroy(RTLogSetDefaultInstance(NULL));
545 RTR0Term();
546 return rc;
547}
548
549
550/**
551 * Unload the module.
552 */
553static void __exit vboxguestLinuxModExit(void)
554{
555 /*
556 * Inverse order of init.
557 */
558 vboxguestLinuxTermDeviceNodes();
559 VBoxGuestDeleteDevExt(&g_DevExt);
560 vboxguestLinuxTermISR();
561 vboxguestLinuxTermPci();
562 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
563 RTLogDestroy(RTLogSetDefaultInstance(NULL));
564 RTR0Term();
565}
566
567
568/**
569 * Device open. Called on open /dev/vboxdrv
570 *
571 * @param pInode Pointer to inode info structure.
572 * @param pFilp Associated file pointer.
573 */
574static int vboxguestLinuxOpen(struct inode *pInode, struct file *pFilp)
575{
576 int rc;
577 PVBOXGUESTSESSION pSession;
578 Log((DEVICE_NAME ": pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
579
580 /*
581 * Call common code to create the user session. Associate it with
582 * the file so we can access it in the other methods.
583 */
584 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
585 if (RT_SUCCESS(rc))
586 pFilp->private_data = pSession;
587
588 Log(("vboxguestLinuxOpen: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
589 &g_DevExt, pSession, rc, vboxguestLinuxConvertToNegErrno(rc),
590 RTProcSelf(), current->pid, current->comm));
591 return vboxguestLinuxConvertToNegErrno(rc);
592}
593
594
595/**
596 * Close device.
597 *
598 * @param pInode Pointer to inode info structure.
599 * @param pFilp Associated file pointer.
600 */
601static int vboxguestLinuxRelease(struct inode *pInode, struct file *pFilp)
602{
603 Log(("vboxguestLinuxRelease: pFilp=%p pSession=%p pid=%d/%d %s\n",
604 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
605
606 VBoxGuestCloseSession(&g_DevExt, (PVBOXGUESTSESSION)pFilp->private_data);
607 pFilp->private_data = NULL;
608 return 0;
609}
610
611
612/**
613 * Device I/O Control entry point.
614 *
615 * @param pFilp Associated file pointer.
616 * @param uCmd The function specified to ioctl().
617 * @param ulArg The argument specified to ioctl().
618 */
619#ifdef HAVE_UNLOCKED_IOCTL
620static long vboxguestLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
621#else
622static int vboxguestLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
623#endif
624{
625 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFilp->private_data;
626 uint32_t cbData = _IOC_SIZE(uCmd);
627 void *pvBufFree;
628 void *pvBuf;
629 int rc;
630 uint64_t au64Buf[32/sizeof(uint64_t)];
631
632 Log6(("vboxguestLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
633
634 /*
635 * Buffer the request.
636 */
637 if (cbData <= sizeof(au64Buf))
638 {
639 pvBufFree = NULL;
640 pvBuf = &au64Buf[0];
641 }
642 else
643 {
644 pvBufFree = pvBuf = RTMemTmpAlloc(cbData);
645 if (RT_UNLIKELY(!pvBuf))
646 {
647 LogRel((DEVICE_NAME "::IOCtl: RTMemTmpAlloc failed to alloc %u bytes.\n", cbData));
648 return -ENOMEM;
649 }
650 }
651 if (RT_LIKELY(copy_from_user(pvBuf, (void *)ulArg, cbData) == 0))
652 {
653 /*
654 * Process the IOCtl.
655 */
656 size_t cbDataReturned;
657 rc = VBoxGuestCommonIOCtl(uCmd, &g_DevExt, pSession, pvBuf, cbData, &cbDataReturned);
658
659 /*
660 * Copy ioctl data and output buffer back to user space.
661 */
662 if (RT_SUCCESS(rc))
663 {
664 rc = 0;
665 if (RT_UNLIKELY(cbDataReturned > cbData))
666 {
667 LogRel((DEVICE_NAME "::IOCtl: too much output data %u expected %u\n", cbDataReturned, cbData));
668 cbDataReturned = cbData;
669 }
670 if (cbDataReturned > 0)
671 {
672 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pvBuf, cbDataReturned) != 0))
673 {
674 LogRel((DEVICE_NAME "::IOCtl: copy_to_user failed; pvBuf=%p ulArg=%p cbDataReturned=%u uCmd=%d\n",
675 pvBuf, (void *)ulArg, cbDataReturned, uCmd, rc));
676 rc = -EFAULT;
677 }
678 }
679 }
680 else
681 {
682 Log(("vboxguestLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
683 rc = -rc; Assert(rc > 0); /* Positive returns == negated VBox error status codes. */
684 }
685 }
686 else
687 {
688 Log((DEVICE_NAME "::IOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, cbData, uCmd));
689 rc = -EFAULT;
690 }
691 if (pvBufFree)
692 RTMemFree(pvBufFree);
693
694 Log6(("vboxguestLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
695 return rc;
696}
697
698
699/**
700 * Asynchronous notification activation method.
701 *
702 * @returns 0 on success, negative errno on failure.
703 *
704 * @param fd The file descriptor.
705 * @param pFile The file structure.
706 * @param fOn On/off indicator.
707 */
708static int vboxguestFAsync(int fd, struct file *pFile, int fOn)
709{
710 return fasync_helper(fd, pFile, fOn, &g_pFAsyncQueue);
711}
712
713
714/**
715 * Poll function.
716 *
717 * This returns ready to read if the mouse pointer mode or the pointer position
718 * has changed since last call to read.
719 *
720 * @returns 0 if no changes, POLLIN | POLLRDNORM if there are unseen changes.
721 *
722 * @param pFile The file structure.
723 * @param pPt The poll table.
724 *
725 * @remarks This is probably not really used, X11 is said to use the fasync
726 * interface instead.
727 */
728static unsigned int vboxguestPoll(struct file *pFile, poll_table *pPt)
729{
730 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
731 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
732 unsigned int fMask = pSession->u32MousePosChangedSeq != u32CurSeq
733 ? POLLIN | POLLRDNORM
734 : 0;
735 poll_wait(pFile, &g_PollEventQueue, pPt);
736 return fMask;
737}
738
739
740/**
741 * Read to go with our poll/fasync response.
742 *
743 * @returns 1 or -EINVAL.
744 *
745 * @param pFile The file structure.
746 * @param pbBuf The buffer to read into.
747 * @param cbRead The max number of bytes to read.
748 * @param poff The current file position.
749 *
750 * @remarks This is probably not really used as X11 lets the driver do its own
751 * event reading. The poll condition is therefore also cleared when we
752 * see VMMDevReq_GetMouseStatus in VBoxGuestCommonIOCtl_VMMRequest.
753 */
754static ssize_t vboxguestRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff)
755{
756 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
757 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
758
759 if (*poff != 0)
760 return -EINVAL;
761
762 /*
763 * Fake a single byte read if we're not up to date with the current mouse position.
764 */
765 if ( pSession->u32MousePosChangedSeq != u32CurSeq
766 && cbRead > 0)
767 {
768 pSession->u32MousePosChangedSeq = u32CurSeq;
769 pbBuf[0] = 0;
770 return 1;
771 }
772 return 0;
773}
774
775
776void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
777{
778 NOREF(pDevExt);
779
780 /*
781 * Wake up everyone that's in a poll() and post anyone that has
782 * subscribed to async notifications.
783 */
784 Log(("VBoxGuestNativeISRMousePollEvent: wake_up_all\n"));
785 wake_up_all(&g_PollEventQueue);
786 Log(("VBoxGuestNativeISRMousePollEvent: kill_fasync\n"));
787 kill_fasync(&g_pFAsyncQueue, SIGIO, POLL_IN);
788 Log(("VBoxGuestNativeISRMousePollEvent: done\n"));
789}
790
791
792/* Common code that depend on g_DevExt. */
793#include "VBoxGuestIDC-unix.c.h"
794
795EXPORT_SYMBOL(VBoxGuestIDCOpen);
796EXPORT_SYMBOL(VBoxGuestIDCClose);
797EXPORT_SYMBOL(VBoxGuestIDCCall);
798
799
800#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
801
802/** log and dbg_log parameter setter. */
803static int vboxguestLinuxParamLogGrpSet(const char *pszValue, struct kernel_param *pParam)
804{
805 if (g_fLoggerCreated)
806 {
807 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelDefaultInstance();
808 if (pLogger)
809 RTLogGroupSettings(pLogger, pszValue);
810 }
811 else if (pParam->name[0] != 'd')
812 strlcpy(&g_szLogGrp[0], pszValue, sizeof(g_szLogGrp));
813
814 return 0;
815}
816
817
818/** log and dbg_log parameter getter. */
819static int vboxguestLinuxParamLogGrpGet(char *pszBuf, struct kernel_param *pParam)
820{
821 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelDefaultInstance();
822 *pszBuf = '\0';
823 if (pLogger)
824 RTLogGetGroupSettings(pLogger, pszBuf, _4K);
825 return strlen(pszBuf);
826}
827
828
829/** log and dbg_log_flags parameter setter. */
830static int vboxguestLinuxParamLogFlagsSet(const char *pszValue, struct kernel_param *pParam)
831{
832 if (g_fLoggerCreated)
833 {
834 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelDefaultInstance();
835 if (pLogger)
836 RTLogFlags(pLogger, pszValue);
837 }
838 else if (pParam->name[0] != 'd')
839 strlcpy(&g_szLogFlags[0], pszValue, sizeof(g_szLogFlags));
840 return 0;
841}
842
843
844/** log and dbg_log_flags parameter getter. */
845static int vboxguestLinuxParamLogFlagsGet(char *pszBuf, struct kernel_param *pParam)
846{
847 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelDefaultInstance();
848 *pszBuf = '\0';
849 if (pLogger)
850 RTLogGetFlags(pLogger, pszBuf, _4K);
851 return strlen(pszBuf);
852}
853
854
855/** log and dbg_log_dest parameter setter. */
856static int vboxguestLinuxParamLogDstSet(const char *pszValue, struct kernel_param *pParam)
857{
858 if (g_fLoggerCreated)
859 {
860 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelDefaultInstance();
861 if (pLogger)
862 RTLogDestinations(pLogger, pszValue);
863 }
864 else if (pParam->name[0] != 'd')
865 strlcpy(&g_szLogDst[0], pszValue, sizeof(g_szLogDst));
866 return 0;
867}
868
869
870/** log and dbg_log_dest parameter getter. */
871static int vboxguestLinuxParamLogDstGet(char *pszBuf, struct kernel_param *pParam)
872{
873 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelDefaultInstance();
874 *pszBuf = '\0';
875 if (pLogger)
876 RTLogGetDestinations(pLogger, pszBuf, _4K);
877 return strlen(pszBuf);
878}
879
880/*
881 * Define module parameters.
882 */
883module_param_call(log, vboxguestLinuxParamLogGrpSet, vboxguestLinuxParamLogGrpGet, NULL, 0664);
884module_param_call(log_flags, vboxguestLinuxParamLogFlagsSet, vboxguestLinuxParamLogFlagsGet, NULL, 0664);
885module_param_call(log_dest, vboxguestLinuxParamLogDstSet, vboxguestLinuxParamLogDstGet, NULL, 0664);
886# ifdef LOG_ENABLED
887module_param_call(dbg_log, vboxguestLinuxParamLogGrpSet, vboxguestLinuxParamLogGrpGet, NULL, 0664);
888module_param_call(dbg_log_flags, vboxguestLinuxParamLogFlagsSet, vboxguestLinuxParamLogFlagsGet, NULL, 0664);
889module_param_call(dbg_log_dest, vboxguestLinuxParamLogDstSet, vboxguestLinuxParamLogDstGet, NULL, 0664);
890# endif
891
892#endif /* 2.6.0 and later */
893
894
895module_init(vboxguestLinuxModInit);
896module_exit(vboxguestLinuxModExit);
897
898MODULE_AUTHOR(VBOX_VENDOR);
899MODULE_DESCRIPTION(VBOX_PRODUCT " Guest Additions for Linux Module");
900MODULE_LICENSE("GPL");
901#ifdef MODULE_VERSION
902MODULE_VERSION(VBOX_VERSION_STRING);
903#endif
904
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use