VirtualBox

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

Last change on this file since 21408 was 21408, checked in by vboxsync, 15 years ago

OSE header

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