VirtualBox

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

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

Linux HostDrivers/Additions: fixed missing symbol RTMemAllocZVar(); rebranding

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