VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/module/vboxmod.c@ 18032

Last change on this file since 18032 was 17962, checked in by vboxsync, 16 years ago

small cosmetical fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.5 KB
Line 
1/** @file
2 * vboxadd -- VirtualBox Guest Additions for Linux
3 */
4
5/*
6 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20
21#include "the-linux-kernel.h"
22#include "version-generated.h"
23
24/* #define IRQ_DEBUG */
25/* #define IOCTL_DEBUG */
26#ifdef IOCTL_DEBUG
27# define IOCTL_ENTRY(name, arg) \
28do { \
29 Log(("IOCTL_ENTRY: %s, 0x%x\n", (name), (arg))); \
30} while(0)
31# define IOCTL_EXIT(name, arg) \
32do { \
33 Log(("IOCTL_EXIT: %s, 0x%x\n", (name), (arg))); \
34} while(0)
35#else
36# define IOCTL_ENTRY(name, arg) do { } while(0)
37# define IOCTL_EXIT(name, arg) do { } while(0)
38#endif
39#ifdef IOCTL_LOG_DEBUG
40# define IOCTL_LOG_ENTRY(arg) \
41do { \
42 Log(("IOCTL_ENTRY: Log, 0x%x\n", (arg))); \
43} while(0)
44# define IOCTL_LOG_EXIT(arg) \
45do { \
46 Log(("IOCTL_EXIT: Log, 0x%x\n", (arg))); \
47} while(0)
48#else
49# define IOCTL_LOG_ENTRY(arg) do { } while(0)
50# define IOCTL_LOG_EXIT(arg) do { } while(0)
51#endif
52#ifdef IOCTL_VMM_DEBUG
53# define IOCTL_VMM_ENTRY(arg) \
54do { \
55 Log(("IOCTL_ENTRY: VMMDevReq, 0x%x\n", (arg))); \
56} while(0)
57# define IOCTL_VMM_EXIT(arg) \
58do { \
59 Log(("IOCTL_EXIT: VMMDevReq, 0x%x\n", (arg))); \
60} while(0)
61#else
62# define IOCTL_VMM_ENTRY(arg) do { } while(0)
63# define IOCTL_VMM_EXIT(arg) do { } while(0)
64#endif
65
66#include "vboxmod.h"
67#include "waitcompat.h"
68
69#include <VBox/log.h>
70#include <VBox/VBoxDev.h>
71#include <iprt/asm.h>
72#include <iprt/assert.h>
73#include <iprt/memobj.h>
74#include <linux/miscdevice.h>
75#include <linux/poll.h>
76
77#define xstr(s) str(s)
78#define str(s) #s
79
80MODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
81MODULE_AUTHOR("Sun Microsystems, Inc.");
82MODULE_LICENSE("GPL");
83#ifdef MODULE_VERSION
84MODULE_VERSION(VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")");
85#endif
86
87/** device extension structure (we only support one device instance) */
88static VBoxDevice *vboxDev = NULL;
89/** our file node major id (set dynamically) */
90#ifdef CONFIG_VBOXADD_MAJOR
91static unsigned int vbox_major = CONFIG_VBOXADD_MAJOR;
92#else
93static unsigned int vbox_major = 0;
94#endif
95
96DECLVBGL (void *) vboxadd_cmc_open (void)
97{
98 return vboxDev;
99}
100
101DECLVBGL (void) vboxadd_cmc_close (void *opaque)
102{
103 (void) opaque;
104}
105
106EXPORT_SYMBOL (vboxadd_cmc_open);
107EXPORT_SYMBOL (vboxadd_cmc_close);
108
109
110#define MAX_HGCM_CONNECTIONS 1024
111
112/**
113 * Structure for keeping track of HGCM connections owned by user space processes, so that
114 * we can close the connection if a process does not clean up properly (for example if it
115 * was terminated too abruptly).
116 */
117/* We just define a fixed number of these so far. This can be changed if it ever becomes
118 a problem. */
119static struct
120{
121 /** Open file structure that this connection handle is associated with */
122 struct file *filp;
123 /** HGCM connection ID */
124 uint32_t client_id;
125} hgcm_connections[MAX_HGCM_CONNECTIONS]
126=
127{
128 { 0 }
129};
130
131/**
132 * Register an HGCM connection as being connected with a given file descriptor, so that it
133 * will be closed automatically when that file descriptor is.
134 *
135 * @returns 0 on success or Linux kernel error number
136 * @param clientID the client ID of the HGCM connection
137 * @param filep the file structure that the connection is to be associated with
138 */
139static int vboxadd_register_hgcm_connection(uint32_t client_id, struct file *filp)
140{
141 int i;
142 bool found = false;
143
144 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i)
145 {
146 Assert(hgcm_connections[i].client_id != client_id);
147 }
148 for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i)
149 {
150 if (ASMAtomicCmpXchgU32(&hgcm_connections[i].client_id, client_id, 0))
151 {
152 hgcm_connections[i].filp = filp;
153 found = true;
154 }
155 }
156 return found ? 0 : -ENFILE; /* Any ideas for a better error code? */
157}
158
159/**
160 * Unregister an HGCM connection associated with a given file descriptor without closing
161 * the connection.
162 *
163 * @returns 0 on success or Linux kernel error number
164 * @param clientID the client ID of the HGCM connection
165 */
166static int vboxadd_unregister_hgcm_connection_no_close(uint32_t client_id)
167{
168 int i;
169 bool found = false;
170
171 for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i)
172 {
173 if (hgcm_connections[i].client_id == client_id)
174 {
175 hgcm_connections[i].filp = NULL;
176 hgcm_connections[i].client_id = 0;
177 found = true;
178 }
179 }
180 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i)
181 {
182 Assert(hgcm_connections[i].client_id != client_id);
183 }
184 return found ? 0 : -ENOENT;
185}
186
187/**
188 * Unregister all HGCM connections associated with a given file descriptor, closing
189 * the connections in the process. This should be called when a file descriptor is
190 * closed.
191 *
192 * @returns 0 on success or Linux kernel error number
193 * @param clientID the client ID of the HGCM connection
194 */
195static int vboxadd_unregister_all_hgcm_connections(struct file *filp)
196{
197 int i;
198
199 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i)
200 {
201 if (hgcm_connections[i].filp == filp)
202 {
203 VBoxGuestHGCMDisconnectInfo infoDisconnect;
204 infoDisconnect.u32ClientID = hgcm_connections[i].client_id;
205 vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
206 &infoDisconnect);
207 hgcm_connections[i].filp = NULL;
208 hgcm_connections[i].client_id = 0;
209 }
210 }
211 return 0;
212}
213
214/**
215 * File open handler
216 *
217 */
218static int vboxadd_open(struct inode *inode, struct file *filp)
219{
220 /* no checks required */
221 return 0;
222}
223
224static void
225vboxadd_wait_for_event (VBoxGuestWaitEventInfo *info)
226{
227 long timeleft;
228 uint32_t cInterruptions = vboxDev->u32GuestInterruptions;
229 uint32_t in_mask = info->u32EventMaskIn;
230
231 info->u32Result = VBOXGUEST_WAITEVENT_OK;
232 if (RT_INDEFINITE_WAIT != info->u32TimeoutIn)
233 {
234 timeleft = wait_event_interruptible_timeout
235 (vboxDev->eventq,
236 (vboxDev->u32Events & in_mask)
237 || (vboxDev->u32GuestInterruptions != cInterruptions),
238 msecs_to_jiffies (info->u32TimeoutIn)
239 );
240 if (vboxDev->u32GuestInterruptions != cInterruptions)
241 {
242 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
243 }
244 if (timeleft < 0)
245 {
246 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
247 }
248 if (timeleft == 0)
249 {
250 info->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
251 }
252 }
253 else
254 {
255 if (wait_event_interruptible(vboxDev->eventq,
256 (vboxDev->u32Events & in_mask)
257 || (vboxDev->u32GuestInterruptions != cInterruptions)
258 )
259 )
260 {
261 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
262 }
263 }
264 info->u32EventFlagsOut = vboxDev->u32Events & in_mask;
265 vboxDev->u32Events &= ~in_mask;
266}
267
268/**
269 * IOCtl handler - wait for an event from the host.
270 *
271 * @returns Linux kernel return code
272 * @param ptr User space pointer to a structure describing the event
273 */
274static int vboxadd_wait_event(void *ptr)
275{
276 int rc = 0;
277 VBoxGuestWaitEventInfo info;
278
279 if (copy_from_user (&info, ptr, sizeof (info)))
280 {
281 LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not get event info\n"));
282 rc = -EFAULT;
283 }
284
285 if (0 == rc)
286 {
287 vboxadd_wait_for_event (&info);
288
289 if (copy_to_user (ptr, &info, sizeof (info)))
290 {
291 LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not put out_mask\n"));
292 rc = -EFAULT;
293 }
294 }
295 return 0;
296}
297
298/**
299 * IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
300 * succeeds, it will be associated with the file structure used to open it, so that it will be
301 * automatically shut down again if the file descriptor is closed.
302 *
303 * @returns 0 on success, or a Linux kernel errno value
304 * @param filp the file structure with which the application opened the driver
305 * @param userspace_info userspace pointer to the hgcm connection information
306 * (VBoxGuestHGCMConnectInfo structure)
307 * @retval userspace_info userspace pointer to the hgcm connection information
308 */
309static int vboxadd_hgcm_connect(struct file *filp, unsigned long userspace_info)
310{
311 VBoxGuestHGCMConnectInfo info;
312 int rc = 0;
313
314 if (copy_from_user ((void *)&info, (void *)userspace_info,
315 sizeof (info)) != 0)
316 {
317 LogFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: can not get connection info\n"));
318 rc = -EFAULT;
319 }
320 info.u32ClientID = 0;
321 if (rc >= 0)
322 {
323 int vrc = vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_CONNECT,
324 &info);
325 rc = RT_FAILURE(vrc) ? -RTErrConvertToErrno(vrc)
326 : -RTErrConvertToErrno(info.result);
327 if (rc < 0)
328 LogFunc(("hgcm connection failed. internal ioctl result %Rrc, hgcm result %Rrc\n",
329 vrc, info.result));
330 if (rc >= 0 && info.result < 0)
331 rc = info.result;
332 }
333 if (rc >= 0)
334 {
335 /* Register that the connection is associated with this file pointer. */
336 LogFunc(("Connected, client ID %u\n", info.u32ClientID));
337 rc = vboxadd_register_hgcm_connection(info.u32ClientID, filp);
338 if (rc < 0)
339 LogFunc(("failed to register the HGCM connection\n"));
340 }
341 if ( rc >= 0
342 && copy_to_user ((void *)userspace_info, (void *)&info,
343 sizeof(info)) != 0)
344 {
345 LogFunc (("failed to return the connection structure\n"));
346 rc = -EFAULT;
347 }
348 if (rc < 0)
349 /* Unregister again, as we didn't get as far as informing userspace. */
350 vboxadd_unregister_hgcm_connection_no_close(info.u32ClientID);
351 if (rc < 0 && info.u32ClientID != 0)
352 {
353 /* Disconnect the hgcm connection again, as we told userspace it failed. */
354 VBoxGuestHGCMDisconnectInfo infoDisconnect;
355 infoDisconnect.u32ClientID = info.u32ClientID;
356 vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
357 &infoDisconnect);
358 }
359 return rc;
360}
361
362/**
363 * IOCTL handler. Disconnect a specific HGCM connection.
364 *
365 * @returns 0 on success, or a Linux kernel errno value
366 * @param filp the file structure with which the application opened the driver
367 * @param userspace_info userspace pointer to the hgcm connection information
368 * (VBoxGuestHGCMConnectInfo structure)
369 * @retval userspace_info userspace pointer to the hgcm connection information
370 */
371static int vboxadd_hgcm_disconnect(struct file *filp, unsigned long userspace_info)
372{
373 int rc = 0, vrc = VINF_SUCCESS;
374
375 VBoxGuestHGCMDisconnectInfo info;
376 if (copy_from_user((void *)&info, (void *)userspace_info, sizeof (info)) != 0)
377 {
378 LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: can not get info\n"));
379 rc = -EFAULT;
380 }
381 if (rc >= 0)
382 {
383 vrc = vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info);
384 rc = -RTErrConvertToErrno(vrc);
385 }
386 if ( rc >= 0
387 && copy_to_user((void *)userspace_info, (void *)&info, sizeof(info)) != 0)
388 {
389 LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: failed to return the connection structure\n"));
390 rc = -EFAULT;
391 }
392 return rc;
393}
394
395/** Bounce buffer structure for hcgm guest-host data copies. */
396typedef struct hgcm_bounce_buffer
397{
398 /** Kernel memory address. */
399 void *pKernel;
400 /** User memory address. */
401 void *pUser;
402 /** Buffer size. */
403 size_t cb;
404} hgcm_bounce_buffer;
405
406/** Create a bounce buffer in kernel space for user space memory. */
407static int vboxadd_hgcm_alloc_buffer(hgcm_bounce_buffer **ppBuf, void *pUser,
408 size_t cb, bool copy)
409{
410 hgcm_bounce_buffer *pBuf = NULL;
411 void *pKernel = NULL;
412 int rc = 0;
413
414 AssertPtrReturn(ppBuf, -EINVAL);
415 AssertPtrReturn(pUser, -EINVAL);
416
417 pBuf = kmalloc(sizeof(*pBuf), GFP_KERNEL);
418 if (pBuf == NULL)
419 rc = -ENOMEM;
420 if (rc >= 0)
421 {
422 pKernel = kmalloc(cb, GFP_KERNEL);
423 if (pKernel == NULL)
424 rc = -ENOMEM;
425 }
426 if ( rc >= 0
427 && copy
428 && copy_from_user(pKernel, pUser, cb) != 0)
429 rc = -EFAULT;
430 if (rc >= 0)
431 {
432 pBuf->pKernel = pKernel;
433 pBuf->pUser = pUser;
434 pBuf->cb = cb;
435 *ppBuf = pBuf;
436 }
437 else
438 {
439 kfree(pBuf);
440 kfree(pKernel);
441 LogFunc(("failed, returning %d\n", rc));
442 }
443 return rc;
444}
445
446/** Free a kernel space bounce buffer for user space memory. */
447static int vboxadd_hgcm_free_buffer(hgcm_bounce_buffer *pBuf, bool copy)
448{
449 int rc = 0;
450 AssertPtrReturn(pBuf, -EINVAL);
451 if (copy && copy_to_user(pBuf->pUser, pBuf->pKernel, pBuf->cb) != 0)
452 rc = -EFAULT;
453 kfree(pBuf->pKernel); /* We want to do this whatever the outcome. */
454 kfree(pBuf);
455 if (rc < 0)
456 LogFunc(("failed, returning %d\n", rc));
457 return rc;
458}
459
460/** Lock down R3 memory as needed for the HGCM call. Copied from
461 * HGCMInternal.cpp and SysHlp.cpp */
462static int vboxadd_buffer_hgcm_parms(void **ppvCtx, VBoxGuestHGCMCallInfo *pCallInfo)
463{
464 uint32_t cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter);
465 int rc = 0;
466 unsigned iParm;
467 HGCMFunctionParameter *pParm;
468 memset (ppvCtx, 0, sizeof(void *) * pCallInfo->cParms);
469 if (cbParms)
470 {
471 /* Lock user buffers. */
472 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
473
474 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
475 {
476 switch (pParm->type)
477 {
478 case VMMDevHGCMParmType_LinAddr_Locked_In:
479 pParm->type = VMMDevHGCMParmType_LinAddr_In;
480 break;
481 case VMMDevHGCMParmType_LinAddr_Locked_Out:
482 pParm->type = VMMDevHGCMParmType_LinAddr_Out;
483 break;
484 case VMMDevHGCMParmType_LinAddr_Locked:
485 pParm->type = VMMDevHGCMParmType_LinAddr;
486 break;
487
488 case VMMDevHGCMParmType_LinAddr_In:
489 case VMMDevHGCMParmType_LinAddr_Out:
490 case VMMDevHGCMParmType_LinAddr:
491 {
492 void *pv = (void *) pParm->u.Pointer.u.linearAddr;
493 uint32_t u32Size = pParm->u.Pointer.size;
494 hgcm_bounce_buffer *MemObj = NULL;
495 rc = vboxadd_hgcm_alloc_buffer(&MemObj, pv, u32Size,
496 pParm->type != VMMDevHGCMParmType_LinAddr_Out /* copy */);
497 if (rc >= 0)
498 {
499 ppvCtx[iParm] = MemObj;
500 pParm->u.Pointer.u.linearAddr = (uintptr_t)MemObj->pKernel;
501 }
502 else
503 ppvCtx[iParm] = NULL;
504 break;
505 }
506 default:
507 /* make gcc happy */
508 break;
509 }
510 if (rc < 0)
511 break;
512 }
513 }
514 return rc;
515}
516
517/** Unlock R3 memory after the HGCM call. Copied from HGCMInternal.cpp and
518 * SysHlp.cpp */
519static int vboxadd_unbuffer_hgcm_parms(void **ppvCtx, VBoxGuestHGCMCallInfo *pCallInfo)
520{
521 int rc = 0;
522 unsigned iParm;
523 /* Unlock user buffers. */
524 HGCMFunctionParameter *pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
525
526 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
527 {
528 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
529 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
530 || pParm->type == VMMDevHGCMParmType_LinAddr)
531 {
532 if (ppvCtx[iParm] != NULL)
533 {
534 hgcm_bounce_buffer *MemObj = (hgcm_bounce_buffer *)ppvCtx[iParm];
535 int rc2 = vboxadd_hgcm_free_buffer(MemObj,
536 pParm->type != VMMDevHGCMParmType_LinAddr_In /* copy */);
537 if (rc >= 0 && rc2 < 0)
538 rc = rc2; /* Report the first error. */
539 }
540 }
541 else
542 {
543 if (ppvCtx[iParm] != NULL)
544 {
545 AssertFailed();
546 rc = -EOVERFLOW; /* Something unlikely to turn up elsewhere so
547 * we can see where it's coming from. */
548 }
549 }
550 }
551 return rc;
552}
553
554/**
555 * IOCTL handler. Make an HGCM call.
556 *
557 * @returns 0 on success, or a Linux kernel errno value
558 * @param userspace_info userspace pointer to the hgcm connection information
559 * (VBoxGuestHGCMConnectInfo structure). This will be
560 * updated on success.
561 * @param u32Size the size of the userspace structure
562 */
563static int vboxadd_hgcm_call(unsigned long userspace_info, uint32_t u32Size)
564{
565 VBoxGuestHGCMCallInfo *pInfo = NULL;
566 void *apvCtx[VBOX_HGCM_MAX_PARMS];
567 unsigned haveParms = 0;
568 int rc = 0;
569
570 pInfo = kmalloc(u32Size, GFP_KERNEL);
571 if (pInfo == NULL)
572 rc = -ENOMEM;
573 if ( rc >= 0
574 && 0 != copy_from_user ((void *)pInfo, (void *)userspace_info, u32Size))
575 {
576 LogRelFunc (("can not get info from user space\n"));
577 rc = -EFAULT;
578 }
579 if ( rc >= 0
580 && sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) != u32Size)
581 {
582 LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
583 sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter),
584 u32Size));
585 rc = -EINVAL;
586 }
587 if (rc >= 0)
588 {
589 haveParms = 1;
590 rc = vboxadd_buffer_hgcm_parms(apvCtx, pInfo);
591 }
592 if (rc >= 0)
593 {
594 int vrc;
595 vrc = vboxadd_cmc_call(vboxDev,
596 VBOXGUEST_IOCTL_HGCM_CALL(u32Size), pInfo);
597 rc = -RTErrConvertToErrno(vrc);
598 if ( rc >= 0
599 && copy_to_user ((void *)userspace_info, (void *)pInfo,
600 u32Size))
601 {
602 LogRelFunc (("failed to return the information to user space\n"));
603 rc = -EFAULT;
604 }
605 }
606 if (haveParms)
607 {
608 int rc2 = vboxadd_unbuffer_hgcm_parms(apvCtx, pInfo);
609 if (rc >= 0 && rc2 < 0)
610 rc = rc2;
611 }
612 if (pInfo != NULL)
613 kfree(pInfo);
614 return rc;
615}
616
617/**
618 * IOCTL handler. Make an HGCM call with timeout.
619 *
620 * @returns 0 on success, or a Linux kernel errno value
621 * @param userspace_info userspace pointer to the hgcm connection information
622 * (VBoxGuestHGCMConnectInfo structure). This will be
623 * updated on success.
624 * @param u32Size the size of the userspace structure
625 */
626static int vboxadd_hgcm_call_timed(unsigned long userspace_info,
627 uint32_t u32Size)
628{
629 VBoxGuestHGCMCallInfoTimed *pInfo = NULL;
630 void *apvCtx[VBOX_HGCM_MAX_PARMS];
631 unsigned haveParms = 0;
632 int rc = 0;
633
634 pInfo = kmalloc(u32Size, GFP_KERNEL);
635 if (pInfo == NULL)
636 rc = -ENOMEM;
637 if ( rc >= 0
638 && 0 != copy_from_user ((void *)pInfo, (void *)userspace_info, u32Size))
639 {
640 LogRelFunc (("can not get info from user space\n"));
641 rc = -EFAULT;
642 }
643 if ( rc >= 0
644 && sizeof(*pInfo) + pInfo->info.cParms * sizeof(HGCMFunctionParameter) != u32Size)
645 {
646 LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
647 sizeof(*pInfo) + pInfo->info.cParms * sizeof(HGCMFunctionParameter),
648 u32Size));
649 rc = -EINVAL;
650 }
651 if (rc >= 0)
652 {
653 haveParms = 1;
654 rc = vboxadd_buffer_hgcm_parms(apvCtx, &pInfo->info);
655 }
656 if (rc >= 0)
657 {
658 int vrc;
659 pInfo->fInterruptible = true; /* User space may not do uninterruptible waits */
660 vrc = vboxadd_cmc_call(vboxDev,
661 VBOXGUEST_IOCTL_HGCM_CALL_TIMED(u32Size), pInfo);
662 rc = -RTErrConvertToErrno(vrc);
663 if ( rc >= 0
664 && copy_to_user ((void *)userspace_info, (void *)pInfo, u32Size))
665 {
666 LogRelFunc (("failed to return the information to user space\n"));
667 rc = -EFAULT;
668 }
669 }
670 if (haveParms)
671 {
672 int rc2 = vboxadd_unbuffer_hgcm_parms(apvCtx, &pInfo->info);
673 if (rc >= 0 && rc2 < 0)
674 rc = rc2;
675 }
676 if (pInfo != NULL)
677 kfree(pInfo);
678 return rc;
679}
680
681/**
682 * IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
683 * we know how to handle.
684 *
685 * @returns iprt status code
686 * @param pInfo kernel space pointer to the filter mask change info
687 */
688static int vboxadd_control_filter_mask(VBoxGuestFilterMaskInfo *pInfo)
689{
690 VMMDevCtlGuestFilterMask *pReq = NULL;
691 int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
692
693 LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
694 if (RT_FAILURE(rc))
695 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
696 else
697 {
698 pReq->u32OrMask = pInfo->u32OrMask;
699 pReq->u32NotMask = pInfo->u32NotMask;
700 rc = VbglGRPerform(&pReq->header);
701 }
702 if (RT_FAILURE(rc))
703 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: VbglGRPerform failed, rc=%Rrc!\n", rc));
704 else if (RT_FAILURE(pReq->header.rc))
705 {
706 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
707 rc = pReq->header.rc;
708 }
709 if (pReq)
710 VbglGRFree(&pReq->header);
711 return rc;
712}
713
714/**
715 * IOCTL handler for vboxadd
716 */
717static int vboxadd_ioctl(struct inode *inode, struct file *filp,
718 unsigned int cmd, unsigned long arg)
719{
720 int rc = 0;
721
722 /* Deal with variable size ioctls first. */
723 if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0))
724 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
725 {
726 char *pszMessage;
727
728 IOCTL_LOG_ENTRY(arg);
729 pszMessage = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
730 if (NULL == pszMessage)
731 {
732 LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
733 _IOC_SIZE(cmd)));
734 rc = -ENOMEM;
735 }
736 if ( (0 == rc)
737 && copy_from_user(pszMessage, (void*)arg, _IOC_SIZE(cmd)))
738 {
739 LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
740 rc = -EFAULT;
741 }
742 if (0 == rc)
743 {
744 Log(("%.*s", _IOC_SIZE(cmd), pszMessage));
745 }
746 if (NULL != pszMessage)
747 {
748 kfree(pszMessage);
749 }
750 IOCTL_LOG_EXIT(arg);
751 }
752 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
753 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
754 {
755 VMMDevRequestHeader reqHeader;
756 VMMDevRequestHeader *reqFull = NULL;
757 size_t cbRequestSize;
758 size_t cbVanillaRequestSize;
759
760 IOCTL_VMM_ENTRY(arg);
761 if (copy_from_user(&reqHeader, (void*)arg, sizeof(reqHeader)))
762 {
763 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
764 rc = -EFAULT;
765 }
766 if (0 == rc)
767 {
768 /* get the request size */
769 cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
770 if (!cbVanillaRequestSize)
771 {
772 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
773 reqHeader.requestType));
774 rc = -EINVAL;
775 }
776 }
777 if (0 == rc)
778 {
779 cbRequestSize = reqHeader.size;
780 if (cbRequestSize < cbVanillaRequestSize)
781 {
782 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
783 cbRequestSize,
784 cbVanillaRequestSize,
785 reqHeader.requestType));
786 rc = -EINVAL;
787 }
788 }
789 if (0 == rc)
790 {
791 /* request storage for the full request */
792 rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
793 if (RT_FAILURE(rc))
794 {
795 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
796 rc = -EFAULT;
797 }
798 }
799 if (0 == rc)
800 {
801 /* now get the full request */
802 if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
803 {
804 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
805 rc = -EFAULT;
806 }
807 }
808
809 /* now issue the request */
810 if (0 == rc)
811 {
812 int rrc = VbglGRPerform(reqFull);
813
814 /* asynchronous processing? */
815 if (rrc == VINF_HGCM_ASYNC_EXECUTE)
816 {
817 VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
818 wait_event_interruptible (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
819 rrc = reqFull->rc;
820 }
821
822 /* failed? */
823 if (RT_FAILURE(rrc) || RT_FAILURE(reqFull->rc))
824 {
825 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
826 rc = RT_FAILURE(rrc) ? -RTErrConvertToErrno(rrc)
827 : -RTErrConvertToErrno(reqFull->rc);
828 }
829 else
830 {
831 /* success, copy the result data to user space */
832 if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
833 {
834 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
835 rc = -EFAULT;
836 }
837 }
838 }
839 if (NULL != reqFull)
840 VbglGRFree(reqFull);
841 IOCTL_VMM_EXIT(arg);
842 }
843 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
844 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
845 {
846 /* Do the HGCM call using the Vbgl bits */
847 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
848 rc = vboxadd_hgcm_call(arg, _IOC_SIZE(cmd));
849 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
850 }
851 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
852 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
853 {
854 /* Do the HGCM call using the Vbgl bits */
855 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
856 rc = vboxadd_hgcm_call_timed(arg, _IOC_SIZE(cmd));
857 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
858 }
859 else
860 {
861 switch (cmd)
862 {
863 case VBOXGUEST_IOCTL_WAITEVENT:
864 IOCTL_ENTRY("VBOXGUEST_IOCTL_WAITEVENT", arg);
865 rc = vboxadd_wait_event((void *) arg);
866 IOCTL_EXIT("VBOXGUEST_IOCTL_WAITEVENT", arg);
867 break;
868 case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
869 IOCTL_ENTRY("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
870 ++vboxDev->u32GuestInterruptions;
871 IOCTL_EXIT("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
872 break;
873 case VBOXGUEST_IOCTL_HGCM_CONNECT:
874 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
875 rc = vboxadd_hgcm_connect(filp, arg);
876 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
877 break;
878 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
879 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
880 vboxadd_hgcm_disconnect(filp, arg);
881 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
882 break;
883 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
884 {
885 VBoxGuestFilterMaskInfo info;
886 IOCTL_ENTRY("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
887 if (copy_from_user((void*)&info, (void*)arg, sizeof(info)))
888 {
889 LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
890 rc = -EFAULT;
891 break;
892 }
893 rc = -RTErrConvertToErrno(vboxadd_control_filter_mask(&info));
894 IOCTL_EXIT("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
895 break;
896 }
897 default:
898 LogRelFunc(("unknown command: %x\n", cmd));
899 rc = -EINVAL;
900 break;
901 }
902 }
903 return rc;
904}
905
906/**
907 * IOCTL handler for vboxuser
908 */
909static int vboxuser_ioctl(struct inode *inode, struct file *filp,
910 unsigned int cmd, unsigned long arg)
911{
912 int rc = 0;
913
914 /* Deal with variable size ioctls first. */
915 if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
916 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
917 {
918 /* Do the HGCM call using the Vbgl bits */
919 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
920 rc = vboxadd_hgcm_call(arg, _IOC_SIZE(cmd));
921 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
922 }
923 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
924 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
925 {
926 /* Do the HGCM call using the Vbgl bits */
927 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
928 rc = vboxadd_hgcm_call_timed(arg, _IOC_SIZE(cmd));
929 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
930 }
931 else
932 {
933 switch (cmd)
934 {
935 case VBOXGUEST_IOCTL_HGCM_CONNECT:
936 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
937 rc = vboxadd_hgcm_connect(filp, arg);
938 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
939 break;
940 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
941 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
942 vboxadd_hgcm_disconnect(filp, arg);
943 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
944 break;
945 default:
946 LogRelFunc(("unknown command: %x\n", cmd));
947 rc = -EINVAL;
948 break;
949 }
950 }
951 return rc;
952}
953
954/**
955 * Poll function. This returns "ready to read" if the guest is in absolute
956 * mouse pointer mode and the pointer position has changed since the last
957 * poll.
958 */
959unsigned int
960vboxadd_poll (struct file *file, poll_table *wait)
961{
962 int result = 0;
963 poll_wait(file, &vboxDev->eventq, wait);
964 if (vboxDev->u32Events & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
965 result = (POLLIN | POLLRDNORM);
966 vboxDev->u32Events &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
967 return result;
968}
969
970/** Asynchronous notification activation method. */
971static int
972vboxadd_fasync(int fd, struct file *file, int mode)
973{
974 return fasync_helper(fd, file, mode, &vboxDev->async_queue);
975}
976
977/**
978 * Dummy read function - we only supply this because we implement poll and
979 * fasync.
980 */
981static ssize_t
982vboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
983{
984 if (0 == count || *loff != 0)
985 {
986 return -EINVAL;
987 }
988 buf[0] = 0;
989 return 1;
990}
991
992/**
993 * File close handler for vboxadd. Clean up any HGCM connections associated
994 * with the open file which might still be open.
995 */
996static int vboxadd_release(struct inode *inode, struct file * filp)
997{
998 vboxadd_unregister_all_hgcm_connections(filp);
999 /* Deactivate our asynchronous queue. */
1000 vboxadd_fasync(-1, filp, 0);
1001 return 0;
1002}
1003
1004/**
1005 * File close handler for vboxuser. Clean up any HGCM connections associated
1006 * with the open file which might still be open.
1007 */
1008static int vboxuser_release(struct inode *inode, struct file * filp)
1009{
1010 vboxadd_unregister_all_hgcm_connections(filp);
1011 return 0;
1012}
1013
1014/** file operations for the vboxadd device */
1015static struct file_operations vboxadd_fops =
1016{
1017 .owner = THIS_MODULE,
1018 .open = vboxadd_open,
1019 .ioctl = vboxadd_ioctl,
1020 .poll = vboxadd_poll,
1021 .fasync = vboxadd_fasync,
1022 .read = vboxadd_read,
1023 .release = vboxadd_release,
1024 .llseek = no_llseek
1025};
1026
1027/** Miscellaneous device allocation for vboxadd */
1028static struct miscdevice gMiscVBoxAdd =
1029{
1030 minor: MISC_DYNAMIC_MINOR,
1031 name: VBOXADD_NAME,
1032 fops: &vboxadd_fops
1033};
1034
1035/** file operations for the vboxuser device */
1036static struct file_operations vboxuser_fops =
1037{
1038 .owner = THIS_MODULE,
1039 .open = vboxadd_open,
1040 .ioctl = vboxuser_ioctl,
1041 .release = vboxuser_release,
1042 .llseek = no_llseek
1043};
1044
1045/** Miscellaneous device allocation for vboxuser */
1046static struct miscdevice gMiscVBoxUser =
1047{
1048 minor: MISC_DYNAMIC_MINOR,
1049 name: VBOXUSER_NAME,
1050 fops: &vboxuser_fops
1051};
1052
1053#ifndef IRQ_RETVAL
1054/* interrupt handlers in 2.4 kernels don't return anything */
1055# define irqreturn_t void
1056# define IRQ_RETVAL(n)
1057#endif
1058
1059/**
1060 * vboxadd_irq_handler
1061 *
1062 * Interrupt handler
1063 *
1064 * @returns scsi error code
1065 * @param irq Irq number
1066 * @param dev_id Irq handler parameter
1067 * @param regs Regs
1068 *
1069 */
1070#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1071static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
1072#else
1073static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
1074#endif
1075{
1076 int fIRQTaken = 0;
1077 int rcVBox;
1078
1079#ifdef IRQ_DEBUG
1080 Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
1081 vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
1082#endif
1083
1084 /* check if IRQ was asserted by VBox */
1085 if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
1086 {
1087#ifdef IRQ_DEBUG
1088 Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
1089 vboxDev->irqAckRequest->events));
1090#endif
1091
1092 /* make a copy of the event mask */
1093 rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
1094 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(vboxDev->irqAckRequest->header.rc))
1095 {
1096 if (RT_LIKELY (vboxDev->irqAckRequest->events))
1097 {
1098 vboxDev->u32Events |= vboxDev->irqAckRequest->events;
1099 if ( vboxDev->irqAckRequest->events
1100 & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
1101 kill_fasync(&vboxDev->async_queue, SIGIO, POLL_IN);
1102 wake_up (&vboxDev->eventq);
1103 }
1104 }
1105 else
1106 {
1107 /* impossible... */
1108 LogRelFunc(("IRQ was not acknowledged! rc = %Rrc, header.rc = %Rrc\n",
1109 rcVBox, vboxDev->irqAckRequest->header.rc));
1110 BUG ();
1111 }
1112
1113 /* it was ours! */
1114 fIRQTaken = 1;
1115 }
1116#ifdef IRQ_DEBUG
1117 else
1118 {
1119 /* we might be attached to a shared interrupt together with another device. */
1120 Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
1121 vboxDev->pVMMDevMemory,
1122 vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
1123 vboxDev->u32Events));
1124 }
1125#endif
1126 /* it was ours */
1127 return IRQ_RETVAL(fIRQTaken);
1128}
1129
1130/**
1131 * Helper function to reserve a fixed kernel address space window
1132 * and tell the VMM that it can safely put its hypervisor there.
1133 * This function might fail which is not a critical error.
1134 */
1135static int vboxadd_reserve_hypervisor(void)
1136{
1137 VMMDevReqHypervisorInfo *req = NULL;
1138 int rcVBox;
1139
1140 /* allocate request structure */
1141 rcVBox = VbglGRAlloc(
1142 (VMMDevRequestHeader**)&req,
1143 sizeof(VMMDevReqHypervisorInfo),
1144 VMMDevReq_GetHypervisorInfo
1145 );
1146 if (RT_FAILURE(rcVBox))
1147 {
1148 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
1149 goto bail_out;
1150 }
1151 /* query the hypervisor information */
1152 rcVBox = VbglGRPerform(&req->header);
1153 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1154 {
1155 /* are we supposed to make a reservation? */
1156 if (req->hypervisorSize)
1157 {
1158 /** @todo repeat this several times until we get an address the host likes */
1159
1160 void *hypervisorArea;
1161 /* reserve another 4MB because the start needs to be 4MB aligned */
1162 uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
1163 /* perform a fictive IO space mapping */
1164 hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
1165 if (hypervisorArea)
1166 {
1167 /* communicate result to VMM, align at 4MB */
1168 req->hypervisorStart = (VMMDEVHYPPTR32)(uintptr_t)RT_ALIGN_P(hypervisorArea, 0x400000);
1169 req->header.requestType = VMMDevReq_SetHypervisorInfo;
1170 req->header.rc = VERR_GENERAL_FAILURE;
1171 rcVBox = VbglGRPerform(&req->header);
1172 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1173 {
1174 /* store mapping for future unmapping */
1175 vboxDev->hypervisorStart = hypervisorArea;
1176 vboxDev->hypervisorSize = hypervisorSize;
1177 }
1178 else
1179 {
1180 LogRelFunc(("failed to set hypervisor region! rc = %Rrc, header.rc = %Rrc\n",
1181 rcVBox, req->header.rc));
1182 goto bail_out;
1183 }
1184 }
1185 else
1186 {
1187 LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
1188 goto bail_out;
1189 }
1190 }
1191 }
1192 else
1193 {
1194 LogRelFunc(("failed to query hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
1195 rcVBox, req->header.rc));
1196 goto bail_out;
1197 }
1198 /* successful return */
1199 VbglGRFree(&req->header);
1200 return 0;
1201
1202bail_out:
1203 /* error return */
1204 if (req)
1205 VbglGRFree(&req->header);
1206 return 1;
1207}
1208
1209/**
1210 * Helper function to free the hypervisor address window
1211 *
1212 */
1213static int vboxadd_free_hypervisor(void)
1214{
1215 VMMDevReqHypervisorInfo *req = NULL;
1216 int rcVBox;
1217
1218 /* allocate request structure */
1219 rcVBox = VbglGRAlloc(
1220 (VMMDevRequestHeader**)&req,
1221 sizeof(VMMDevReqHypervisorInfo),
1222 VMMDevReq_SetHypervisorInfo
1223 );
1224 if (RT_FAILURE(rcVBox))
1225 {
1226 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
1227 goto bail_out;
1228 }
1229 /* reset the hypervisor information */
1230 req->hypervisorStart = 0;
1231 req->hypervisorSize = 0;
1232 rcVBox = VbglGRPerform(&req->header);
1233 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1234 {
1235 /* now we can free the associated IO space mapping */
1236 iounmap(vboxDev->hypervisorStart);
1237 vboxDev->hypervisorStart = 0;
1238 }
1239 else
1240 {
1241 LogRelFunc(("failed to reset hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
1242 rcVBox, req->header.rc));
1243 goto bail_out;
1244 }
1245 return 0;
1246
1247 bail_out:
1248 if (req)
1249 VbglGRFree(&req->header);
1250 return 1;
1251}
1252
1253/**
1254 * Helper to free resources
1255 *
1256 */
1257static void free_resources(void)
1258{
1259 if (vboxDev)
1260 {
1261 {
1262 /* Unregister notifications when the host absolute pointer
1263 * position changes. */
1264 VBoxGuestFilterMaskInfo info;
1265 info.u32OrMask = 0;
1266 info.u32NotMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1267 vboxadd_control_filter_mask(&info);
1268 }
1269 /* Detach from IRQ before cleaning up! */
1270 if (vboxDev->irq)
1271 free_irq(vboxDev->irq, vboxDev);
1272 if (vboxDev->hypervisorStart)
1273 vboxadd_free_hypervisor();
1274 if (vboxDev->irqAckRequest)
1275 {
1276 VbglGRFree(&vboxDev->irqAckRequest->header);
1277 VbglTerminate();
1278 }
1279 if (vboxDev->pVMMDevMemory)
1280 iounmap(vboxDev->pVMMDevMemory);
1281 if (vboxDev->vmmdevmem)
1282 release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
1283 kfree(vboxDev);
1284 vboxDev = NULL;
1285 }
1286}
1287
1288#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1289#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
1290#define PCI_DEV_PUT(x) pci_dev_put(x)
1291#else
1292#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
1293#define PCI_DEV_PUT(x) do {} while(0)
1294#endif
1295
1296/**
1297 * Module initialization
1298 *
1299 */
1300static __init int init(void)
1301{
1302 int rc = 0, rcVBox = VINF_SUCCESS;
1303 bool fHaveVBoxAdd = false, fHaveVBoxUser = false, fHaveGuestLib = false;
1304 struct pci_dev *pcidev = NULL;
1305
1306 rcVBox = vboxadd_cmc_init();
1307 if (RT_FAILURE(rcVBox))
1308 {
1309 printk (KERN_ERR "vboxadd: could not init cmc, VBox error code %d.\n", rcVBox);
1310 rc = -RTErrConvertToErrno(rcVBox);
1311 }
1312
1313 /* Detect PCI device */
1314 if (!rc)
1315 {
1316 pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
1317 if (!pcidev)
1318 {
1319 printk(KERN_ERR "vboxadd: VirtualBox Guest PCI device not found.\n");
1320 rc = -ENODEV;
1321 }
1322 }
1323
1324 if (!rc)
1325 {
1326 rc = pci_enable_device (pcidev);
1327 if (rc)
1328 LogRel(("vboxadd: could not enable device: %d\n", rc));
1329 }
1330 if (!rc)
1331 LogRel(("Starting VirtualBox version %s Guest Additions\n",
1332 VBOX_VERSION_STRING));
1333
1334 /* Register vboxadd */
1335 if (!rc && vbox_major > 0) /* Register as a character device in this case */
1336 {
1337 rc = register_chrdev(vbox_major, VBOXADD_NAME, &vboxadd_fops);
1338 if (rc) /* As we pass a non-zero major, rc should be zero on success. */
1339 LogRel(("vboxadd: register_chrdev failed: vbox_major: %d, err = %d\n",
1340 vbox_major, rc));
1341 }
1342 else if (!rc) /* Register as a miscellaneous device otherwise */
1343 {
1344 rc = misc_register(&gMiscVBoxAdd);
1345 if (rc)
1346 LogRel(("vboxadd: misc_register failed for %s (rc=%d)\n",
1347 VBOXADD_NAME, rc));
1348 }
1349 if (!rc)
1350 fHaveVBoxAdd = true;
1351
1352 /* Register our user session device */
1353 if (!rc)
1354 {
1355 rc = misc_register(&gMiscVBoxUser);
1356 if (rc)
1357 LogRel(("vboxadd: misc_register failed for %s (rc=%d)\n",
1358 VBOXUSER_NAME, rc));
1359 }
1360 if (!rc)
1361 fHaveVBoxUser = true;
1362
1363 /* allocate and initialize device extension */
1364 if (!rc)
1365 {
1366 vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
1367 if (vboxDev)
1368 memset(vboxDev, 0, sizeof(*vboxDev));
1369 else
1370 {
1371 LogRel(("vboxadd: could not allocate private device structure\n"));
1372 rc = -ENOMEM;
1373 }
1374 }
1375
1376 if (!rc)
1377 {
1378 /* get the IO port region */
1379 vboxDev->io_port = pci_resource_start(pcidev, 0);
1380
1381 /* get the memory region */
1382 vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
1383 vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
1384
1385 /* all resources found? */
1386 if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
1387 {
1388 LogRel(("vboxadd: did not find expected hardware resources\n"));
1389 rc = -ENXIO;
1390 }
1391 }
1392
1393 /* request ownership of adapter memory */
1394 if (!rc && !request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1395 VBOXADD_NAME))
1396 {
1397 LogRel(("vboxadd: failed to obtain adapter memory\n"));
1398 rc = -EBUSY;
1399 }
1400
1401 /* map adapter memory into kernel address space and check version */
1402 if (!rc)
1403 {
1404 vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
1405 vboxDev->vmmdevmem_size);
1406 if (!vboxDev->pVMMDevMemory)
1407 {
1408 LogRel(("vboxadd: ioremap failed\n"));
1409 rc = -ENOMEM;
1410 }
1411 }
1412
1413 if (!rc && (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION))
1414 {
1415 LogRel(("vboxadd: invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
1416 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
1417 rc = -ENXIO;
1418 }
1419
1420 /* initialize ring 0 guest library */
1421 if (!rc)
1422 {
1423 rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
1424 if (RT_FAILURE(rcVBox))
1425 {
1426 LogRel(("vboxadd: could not initialize VBGL subsystem: %Rrc\n",
1427 rcVBox));
1428 rc = -RTErrConvertToErrno(rcVBox);
1429 }
1430 }
1431 if (!rc)
1432 fHaveGuestLib = true;
1433
1434 /* report guest information to host, this must be done as the very first request */
1435 if (!rc)
1436 {
1437 VMMDevReportGuestInfo *infoReq = NULL;
1438
1439 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
1440 sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
1441 if (RT_FAILURE(rcVBox))
1442 {
1443 LogRel(("vboxadd: could not allocate request structure: %Rrc\n", rcVBox));
1444 rc = -RTErrConvertToErrno(rcVBox);
1445 }
1446 /* report guest version to host, the VMMDev requires that to be done
1447 * before any other VMMDev operations. */
1448 if (infoReq)
1449 {
1450 infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
1451#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
1452 infoReq->guestInfo.osType = VBOXOSTYPE_Linux26;
1453#else
1454 infoReq->guestInfo.osType = VBOXOSTYPE_Linux24;
1455#endif
1456 rcVBox = VbglGRPerform(&infoReq->header);
1457 }
1458 if ( infoReq
1459 && ( RT_FAILURE(rcVBox)
1460 || RT_FAILURE(infoReq->header.rc)))
1461 {
1462 LogRel(("vboxadd: error reporting guest information to host: %Rrc, header: %Rrc\n",
1463 rcVBox, infoReq->header.rc));
1464 rc = RT_FAILURE(rcVBox) ? -RTErrConvertToErrno(rcVBox)
1465 : -RTErrConvertToErrno(infoReq->header.rc);
1466 }
1467 if (infoReq)
1468 VbglGRFree(&infoReq->header);
1469 }
1470
1471 /* Unset the graphics capability until/unless X is loaded. */
1472 /** @todo check the error code once we bump the additions version.
1473 For now we ignore it for compatibility with older hosts. */
1474 if (!rc)
1475 {
1476 VMMDevReqGuestCapabilities2 *vmmreqGuestCaps;
1477
1478 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vmmreqGuestCaps,
1479 sizeof(VMMDevReqGuestCapabilities2),
1480 VMMDevReq_SetGuestCapabilities);
1481 if (RT_FAILURE(rcVBox))
1482 {
1483 LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
1484 rcVBox));
1485 rc = -RTErrConvertToErrno(rcVBox);
1486 }
1487 else
1488 {
1489 vmmreqGuestCaps->u32OrMask = 0;
1490 vmmreqGuestCaps->u32NotMask = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
1491 rcVBox = VbglGRPerform(&vmmreqGuestCaps->header);
1492 if (RT_FAILURE(rcVBox))
1493 {
1494 LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
1495 rcVBox));
1496 rc = -RTErrConvertToErrno(rcVBox);
1497 }
1498 VbglGRFree(&vmmreqGuestCaps->header);
1499 }
1500 }
1501
1502 /* perform hypervisor address space reservation */
1503 if (!rc && vboxadd_reserve_hypervisor())
1504 {
1505 /* we just ignore the error, no address window reservation, non fatal */
1506 }
1507
1508 /* allocate a VMM request structure for use in the ISR */
1509 if (!rc)
1510 {
1511 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
1512 sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
1513 if (RT_FAILURE(rcVBox))
1514 {
1515 LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
1516 rcVBox));
1517 rc = -RTErrConvertToErrno(rcVBox);
1518 }
1519 }
1520
1521 /* get ISR */
1522 if (!rc)
1523 {
1524 rc = request_irq(pcidev->irq, vboxadd_irq_handler,
1525#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1526 IRQF_SHARED,
1527#else
1528 SA_SHIRQ,
1529#endif
1530 VBOXADD_NAME, vboxDev);
1531 if (rc)
1532 LogRel(("vboxadd: could not request IRQ %d, err: %d\n", pcidev->irq, rc));
1533 else
1534 vboxDev->irq = pcidev->irq;
1535 }
1536
1537 if (!rc)
1538 {
1539 VBoxGuestFilterMaskInfo info;
1540
1541 init_waitqueue_head (&vboxDev->eventq);
1542 /* Register for notification when the host absolute pointer position
1543 * changes. */
1544 info.u32OrMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1545 info.u32NotMask = 0;
1546 rcVBox = vboxadd_control_filter_mask(&info);
1547 if (RT_FAILURE(rcVBox))
1548 {
1549 LogRel(("vboxadd: failed to register for VMMDEV_EVENT_MOUSE_POSITION_CHANGED events: %Rrc\n",
1550 rcVBox));
1551 rc = -RTErrConvertToErrno(rcVBox);
1552 }
1553 }
1554
1555 if (!rc)
1556 {
1557 /* some useful information for the user but don't show this on the console */
1558 LogRel(("VirtualBox device settings: major %d, IRQ %d, "
1559 "I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
1560 "hypervisor window at 0x%p (size 0x%x)\n",
1561 vbox_major, vboxDev->irq, vboxDev->io_port,
1562 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1563 vboxDev->hypervisorStart, vboxDev->hypervisorSize));
1564 printk(KERN_DEBUG "vboxadd: Successfully loaded version "
1565 VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")\n");
1566 }
1567 else /* Clean up on failure */
1568 {
1569 if (fHaveGuestLib)
1570 VbglTerminate();
1571 if (vboxDev)
1572 free_resources();
1573 if (fHaveVBoxUser)
1574 misc_deregister(&gMiscVBoxUser);
1575 if (fHaveVBoxAdd && vbox_major > 0)
1576 unregister_chrdev(vbox_major, VBOXADD_NAME);
1577 else if (fHaveVBoxAdd)
1578 misc_deregister(&gMiscVBoxAdd);
1579 }
1580
1581 /* We always release this. Presumably because we no longer need to do
1582 * anything with the device structure. */
1583 if (pcidev)
1584 PCI_DEV_PUT(pcidev);
1585
1586 return rc;
1587}
1588
1589/**
1590 * Module termination
1591 *
1592 */
1593static __exit void fini(void)
1594{
1595 misc_deregister(&gMiscVBoxUser);
1596 if (vbox_major > 0)
1597 unregister_chrdev(vbox_major, VBOXADD_NAME);
1598 else
1599 misc_deregister(&gMiscVBoxAdd);
1600 free_resources();
1601 vboxadd_cmc_fini ();
1602}
1603
1604module_init(init);
1605module_exit(fini);
1606
1607/* PCI hotplug structure */
1608static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
1609{
1610 {
1611 .vendor = VMMDEV_VENDORID,
1612 .device = VMMDEV_DEVICEID
1613 },
1614 {
1615 /* empty entry */
1616 }
1617};
1618MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
1619
1620
1621
1622/*
1623 * Local Variables:
1624 * c-mode: bsd
1625 * indent-tabs-mode: nil
1626 * c-plusplus: evil
1627 * End:
1628 */
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