VirtualBox

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

Last change on this file since 18576 was 18361, checked in by vboxsync, 16 years ago

Additions/linux/vboxadd: added additional functionality to /dev/vboxuser

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette