VirtualBox

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

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

Additions/linux/vboxadd: use our own error conversion function to avoid assertions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.7 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)
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 */
942static int vboxuser_ioctl(struct inode *inode, struct file *filp,
943 unsigned int cmd, unsigned long arg)
944{
945 int rc = 0;
946
947 /* Deal with variable size ioctls first. */
948 if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
949 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
950 {
951 /* Do the HGCM call using the Vbgl bits */
952 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
953 rc = vboxadd_hgcm_call(arg, _IOC_SIZE(cmd));
954 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
955 }
956 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
957 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
958 {
959 /* Do the HGCM call using the Vbgl bits */
960 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
961 rc = vboxadd_hgcm_call_timed(arg, _IOC_SIZE(cmd));
962 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
963 }
964 else
965 {
966 switch (cmd)
967 {
968 case VBOXGUEST_IOCTL_HGCM_CONNECT:
969 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
970 rc = vboxadd_hgcm_connect(filp, arg);
971 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
972 break;
973 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
974 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
975 vboxadd_hgcm_disconnect(filp, arg);
976 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
977 break;
978 default:
979 LogRelFunc(("unknown command: %x\n", cmd));
980 rc = -EINVAL;
981 break;
982 }
983 }
984 return rc;
985}
986
987/**
988 * Poll function. This returns "ready to read" if the guest is in absolute
989 * mouse pointer mode and the pointer position has changed since the last
990 * poll.
991 */
992unsigned int
993vboxadd_poll (struct file *file, poll_table *wait)
994{
995 int result = 0;
996 poll_wait(file, &vboxDev->eventq, wait);
997 if (vboxDev->u32Events & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
998 result = (POLLIN | POLLRDNORM);
999 vboxDev->u32Events &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1000 return result;
1001}
1002
1003/** Asynchronous notification activation method. */
1004static int
1005vboxadd_fasync(int fd, struct file *file, int mode)
1006{
1007 return fasync_helper(fd, file, mode, &vboxDev->async_queue);
1008}
1009
1010/**
1011 * Dummy read function - we only supply this because we implement poll and
1012 * fasync.
1013 */
1014static ssize_t
1015vboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
1016{
1017 if (0 == count || *loff != 0)
1018 {
1019 return -EINVAL;
1020 }
1021 buf[0] = 0;
1022 return 1;
1023}
1024
1025/**
1026 * File close handler for vboxadd. Clean up any HGCM connections associated
1027 * with the open file which might still be open.
1028 */
1029static int vboxadd_release(struct inode *inode, struct file * filp)
1030{
1031 vboxadd_unregister_all_hgcm_connections(filp);
1032 /* Deactivate our asynchronous queue. */
1033 vboxadd_fasync(-1, filp, 0);
1034 return 0;
1035}
1036
1037/**
1038 * File close handler for vboxuser. Clean up any HGCM connections associated
1039 * with the open file which might still be open.
1040 */
1041static int vboxuser_release(struct inode *inode, struct file * filp)
1042{
1043 vboxadd_unregister_all_hgcm_connections(filp);
1044 return 0;
1045}
1046
1047/** file operations for the vboxadd device */
1048static struct file_operations vboxadd_fops =
1049{
1050 .owner = THIS_MODULE,
1051 .open = vboxadd_open,
1052 .ioctl = vboxadd_ioctl,
1053 .poll = vboxadd_poll,
1054 .fasync = vboxadd_fasync,
1055 .read = vboxadd_read,
1056 .release = vboxadd_release,
1057 .llseek = no_llseek
1058};
1059
1060/** Miscellaneous device allocation for vboxadd */
1061static struct miscdevice gMiscVBoxAdd =
1062{
1063 minor: MISC_DYNAMIC_MINOR,
1064 name: VBOXADD_NAME,
1065 fops: &vboxadd_fops
1066};
1067
1068/** file operations for the vboxuser device */
1069static struct file_operations vboxuser_fops =
1070{
1071 .owner = THIS_MODULE,
1072 .open = vboxadd_open,
1073 .ioctl = vboxuser_ioctl,
1074 .release = vboxuser_release,
1075 .llseek = no_llseek
1076};
1077
1078/** Miscellaneous device allocation for vboxuser */
1079static struct miscdevice gMiscVBoxUser =
1080{
1081 minor: MISC_DYNAMIC_MINOR,
1082 name: VBOXUSER_NAME,
1083 fops: &vboxuser_fops
1084};
1085
1086#ifndef IRQ_RETVAL
1087/* interrupt handlers in 2.4 kernels don't return anything */
1088# define irqreturn_t void
1089# define IRQ_RETVAL(n)
1090#endif
1091
1092/**
1093 * vboxadd_irq_handler
1094 *
1095 * Interrupt handler
1096 *
1097 * @returns scsi error code
1098 * @param irq Irq number
1099 * @param dev_id Irq handler parameter
1100 * @param regs Regs
1101 *
1102 */
1103#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
1104static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
1105#else
1106static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
1107#endif
1108{
1109 int fIRQTaken = 0;
1110 int rcVBox;
1111
1112#ifdef IRQ_DEBUG
1113 Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
1114 vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
1115#endif
1116
1117 /* check if IRQ was asserted by VBox */
1118 if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
1119 {
1120#ifdef IRQ_DEBUG
1121 Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
1122 vboxDev->irqAckRequest->events));
1123#endif
1124
1125 /* make a copy of the event mask */
1126 rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
1127 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(vboxDev->irqAckRequest->header.rc))
1128 {
1129 if (RT_LIKELY (vboxDev->irqAckRequest->events))
1130 {
1131 vboxDev->u32Events |= vboxDev->irqAckRequest->events;
1132 if ( vboxDev->irqAckRequest->events
1133 & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
1134 kill_fasync(&vboxDev->async_queue, SIGIO, POLL_IN);
1135 wake_up (&vboxDev->eventq);
1136 }
1137 }
1138 else
1139 {
1140 /* impossible... */
1141 LogRelFunc(("IRQ was not acknowledged! rc = %Rrc, header.rc = %Rrc\n",
1142 rcVBox, vboxDev->irqAckRequest->header.rc));
1143 BUG ();
1144 }
1145
1146 /* it was ours! */
1147 fIRQTaken = 1;
1148 }
1149#ifdef IRQ_DEBUG
1150 else
1151 {
1152 /* we might be attached to a shared interrupt together with another device. */
1153 Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
1154 vboxDev->pVMMDevMemory,
1155 vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
1156 vboxDev->u32Events));
1157 }
1158#endif
1159 /* it was ours */
1160 return IRQ_RETVAL(fIRQTaken);
1161}
1162
1163/**
1164 * Helper function to reserve a fixed kernel address space window
1165 * and tell the VMM that it can safely put its hypervisor there.
1166 * This function might fail which is not a critical error.
1167 */
1168static int vboxadd_reserve_hypervisor(void)
1169{
1170 VMMDevReqHypervisorInfo *req = NULL;
1171 int rcVBox;
1172
1173 /* allocate request structure */
1174 rcVBox = VbglGRAlloc(
1175 (VMMDevRequestHeader**)&req,
1176 sizeof(VMMDevReqHypervisorInfo),
1177 VMMDevReq_GetHypervisorInfo
1178 );
1179 if (RT_FAILURE(rcVBox))
1180 {
1181 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
1182 goto bail_out;
1183 }
1184 /* query the hypervisor information */
1185 rcVBox = VbglGRPerform(&req->header);
1186 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1187 {
1188 /* are we supposed to make a reservation? */
1189 if (req->hypervisorSize)
1190 {
1191 /** @todo repeat this several times until we get an address the host likes */
1192
1193 void *hypervisorArea;
1194 /* reserve another 4MB because the start needs to be 4MB aligned */
1195 uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
1196 /* perform a fictive IO space mapping */
1197 hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
1198 if (hypervisorArea)
1199 {
1200 /* communicate result to VMM, align at 4MB */
1201 req->hypervisorStart = (VMMDEVHYPPTR32)(uintptr_t)RT_ALIGN_P(hypervisorArea, 0x400000);
1202 req->header.requestType = VMMDevReq_SetHypervisorInfo;
1203 req->header.rc = VERR_GENERAL_FAILURE;
1204 rcVBox = VbglGRPerform(&req->header);
1205 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1206 {
1207 /* store mapping for future unmapping */
1208 vboxDev->hypervisorStart = hypervisorArea;
1209 vboxDev->hypervisorSize = hypervisorSize;
1210 }
1211 else
1212 {
1213 LogRelFunc(("failed to set hypervisor region! rc = %Rrc, header.rc = %Rrc\n",
1214 rcVBox, req->header.rc));
1215 goto bail_out;
1216 }
1217 }
1218 else
1219 {
1220 LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
1221 goto bail_out;
1222 }
1223 }
1224 }
1225 else
1226 {
1227 LogRelFunc(("failed to query hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
1228 rcVBox, req->header.rc));
1229 goto bail_out;
1230 }
1231 /* successful return */
1232 VbglGRFree(&req->header);
1233 return 0;
1234
1235bail_out:
1236 /* error return */
1237 if (req)
1238 VbglGRFree(&req->header);
1239 return 1;
1240}
1241
1242/**
1243 * Helper function to free the hypervisor address window
1244 *
1245 */
1246static int vboxadd_free_hypervisor(void)
1247{
1248 VMMDevReqHypervisorInfo *req = NULL;
1249 int rcVBox;
1250
1251 /* allocate request structure */
1252 rcVBox = VbglGRAlloc(
1253 (VMMDevRequestHeader**)&req,
1254 sizeof(VMMDevReqHypervisorInfo),
1255 VMMDevReq_SetHypervisorInfo
1256 );
1257 if (RT_FAILURE(rcVBox))
1258 {
1259 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
1260 goto bail_out;
1261 }
1262 /* reset the hypervisor information */
1263 req->hypervisorStart = 0;
1264 req->hypervisorSize = 0;
1265 rcVBox = VbglGRPerform(&req->header);
1266 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1267 {
1268 /* now we can free the associated IO space mapping */
1269 iounmap(vboxDev->hypervisorStart);
1270 vboxDev->hypervisorStart = 0;
1271 }
1272 else
1273 {
1274 LogRelFunc(("failed to reset hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
1275 rcVBox, req->header.rc));
1276 goto bail_out;
1277 }
1278 return 0;
1279
1280 bail_out:
1281 if (req)
1282 VbglGRFree(&req->header);
1283 return 1;
1284}
1285
1286/**
1287 * Helper to free resources
1288 *
1289 */
1290static void free_resources(void)
1291{
1292 if (vboxDev)
1293 {
1294 {
1295 /* Unregister notifications when the host absolute pointer
1296 * position changes. */
1297 VBoxGuestFilterMaskInfo info;
1298 info.u32OrMask = 0;
1299 info.u32NotMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1300 vboxadd_control_filter_mask(&info);
1301 }
1302 /* Detach from IRQ before cleaning up! */
1303 if (vboxDev->irq)
1304 free_irq(vboxDev->irq, vboxDev);
1305 if (vboxDev->hypervisorStart)
1306 vboxadd_free_hypervisor();
1307 if (vboxDev->irqAckRequest)
1308 {
1309 VbglGRFree(&vboxDev->irqAckRequest->header);
1310 VbglTerminate();
1311 }
1312 if (vboxDev->pVMMDevMemory)
1313 iounmap(vboxDev->pVMMDevMemory);
1314 if (vboxDev->vmmdevmem)
1315 release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
1316 kfree(vboxDev);
1317 vboxDev = NULL;
1318 }
1319}
1320
1321#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1322#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
1323#define PCI_DEV_PUT(x) pci_dev_put(x)
1324#else
1325#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
1326#define PCI_DEV_PUT(x) do {} while(0)
1327#endif
1328
1329/**
1330 * Module initialization
1331 *
1332 */
1333static __init int init(void)
1334{
1335 int rc = 0, rcVBox = VINF_SUCCESS;
1336 bool fHaveVBoxAdd = false, fHaveVBoxUser = false, fHaveGuestLib = false;
1337 struct pci_dev *pcidev = NULL;
1338
1339 rcVBox = vboxadd_cmc_init();
1340 if (RT_FAILURE(rcVBox))
1341 {
1342 printk (KERN_ERR "vboxadd: could not init cmc, VBox error code %d.\n", rcVBox);
1343 rc = -RTErrConvertToErrno(rcVBox);
1344 }
1345
1346 /* Detect PCI device */
1347 if (!rc)
1348 {
1349 pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
1350 if (!pcidev)
1351 {
1352 printk(KERN_ERR "vboxadd: VirtualBox Guest PCI device not found.\n");
1353 rc = -ENODEV;
1354 }
1355 }
1356
1357 if (!rc)
1358 {
1359 rc = pci_enable_device (pcidev);
1360 if (rc)
1361 LogRel(("vboxadd: could not enable device: %d\n", rc));
1362 }
1363 if (!rc)
1364 LogRel(("Starting VirtualBox version %s Guest Additions\n",
1365 VBOX_VERSION_STRING));
1366
1367 /* Register vboxadd */
1368 if (!rc && vbox_major > 0) /* Register as a character device in this case */
1369 {
1370 rc = register_chrdev(vbox_major, VBOXADD_NAME, &vboxadd_fops);
1371 if (rc) /* As we pass a non-zero major, rc should be zero on success. */
1372 LogRel(("vboxadd: register_chrdev failed: vbox_major: %d, err = %d\n",
1373 vbox_major, rc));
1374 }
1375 else if (!rc) /* Register as a miscellaneous device otherwise */
1376 {
1377 rc = misc_register(&gMiscVBoxAdd);
1378 if (rc)
1379 LogRel(("vboxadd: misc_register failed for %s (rc=%d)\n",
1380 VBOXADD_NAME, rc));
1381 }
1382 if (!rc)
1383 fHaveVBoxAdd = true;
1384
1385 /* Register our user session device */
1386 if (!rc)
1387 {
1388 rc = misc_register(&gMiscVBoxUser);
1389 if (rc)
1390 LogRel(("vboxadd: misc_register failed for %s (rc=%d)\n",
1391 VBOXUSER_NAME, rc));
1392 }
1393 if (!rc)
1394 fHaveVBoxUser = true;
1395
1396 /* allocate and initialize device extension */
1397 if (!rc)
1398 {
1399 vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
1400 if (vboxDev)
1401 memset(vboxDev, 0, sizeof(*vboxDev));
1402 else
1403 {
1404 LogRel(("vboxadd: could not allocate private device structure\n"));
1405 rc = -ENOMEM;
1406 }
1407 }
1408
1409 if (!rc)
1410 {
1411 /* get the IO port region */
1412 vboxDev->io_port = pci_resource_start(pcidev, 0);
1413
1414 /* get the memory region */
1415 vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
1416 vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
1417
1418 /* all resources found? */
1419 if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
1420 {
1421 LogRel(("vboxadd: did not find expected hardware resources\n"));
1422 rc = -ENXIO;
1423 }
1424 }
1425
1426 /* request ownership of adapter memory */
1427 if (!rc && !request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1428 VBOXADD_NAME))
1429 {
1430 LogRel(("vboxadd: failed to obtain adapter memory\n"));
1431 rc = -EBUSY;
1432 }
1433
1434 /* map adapter memory into kernel address space and check version */
1435 if (!rc)
1436 {
1437 vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
1438 vboxDev->vmmdevmem_size);
1439 if (!vboxDev->pVMMDevMemory)
1440 {
1441 LogRel(("vboxadd: ioremap failed\n"));
1442 rc = -ENOMEM;
1443 }
1444 }
1445
1446 if (!rc && (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION))
1447 {
1448 LogRel(("vboxadd: invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
1449 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
1450 rc = -ENXIO;
1451 }
1452
1453 /* initialize ring 0 guest library */
1454 if (!rc)
1455 {
1456 rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
1457 if (RT_FAILURE(rcVBox))
1458 {
1459 LogRel(("vboxadd: could not initialize VBGL subsystem: %Rrc\n",
1460 rcVBox));
1461 rc = -RTErrConvertToErrno(rcVBox);
1462 }
1463 }
1464 if (!rc)
1465 fHaveGuestLib = true;
1466
1467 /* report guest information to host, this must be done as the very first request */
1468 if (!rc)
1469 {
1470 VMMDevReportGuestInfo *infoReq = NULL;
1471
1472 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
1473 sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
1474 if (RT_FAILURE(rcVBox))
1475 {
1476 LogRel(("vboxadd: could not allocate request structure: %Rrc\n", rcVBox));
1477 rc = -RTErrConvertToErrno(rcVBox);
1478 }
1479 /* report guest version to host, the VMMDev requires that to be done
1480 * before any other VMMDev operations. */
1481 if (infoReq)
1482 {
1483 infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
1484#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
1485 infoReq->guestInfo.osType = VBOXOSTYPE_Linux26;
1486#else
1487 infoReq->guestInfo.osType = VBOXOSTYPE_Linux24;
1488#endif
1489 rcVBox = VbglGRPerform(&infoReq->header);
1490 }
1491 if ( infoReq
1492 && ( RT_FAILURE(rcVBox)
1493 || RT_FAILURE(infoReq->header.rc)))
1494 {
1495 LogRel(("vboxadd: error reporting guest information to host: %Rrc, header: %Rrc\n",
1496 rcVBox, infoReq->header.rc));
1497 rc = RT_FAILURE(rcVBox) ? -RTErrConvertToErrno(rcVBox)
1498 : -RTErrConvertToErrno(infoReq->header.rc);
1499 }
1500 if (infoReq)
1501 VbglGRFree(&infoReq->header);
1502 }
1503
1504 /* Unset the graphics capability until/unless X is loaded. */
1505 /** @todo check the error code once we bump the additions version.
1506 For now we ignore it for compatibility with older hosts. */
1507 if (!rc)
1508 {
1509 VMMDevReqGuestCapabilities2 *vmmreqGuestCaps;
1510
1511 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vmmreqGuestCaps,
1512 sizeof(VMMDevReqGuestCapabilities2),
1513 VMMDevReq_SetGuestCapabilities);
1514 if (RT_FAILURE(rcVBox))
1515 {
1516 LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
1517 rcVBox));
1518 rc = -RTErrConvertToErrno(rcVBox);
1519 }
1520 else
1521 {
1522 vmmreqGuestCaps->u32OrMask = 0;
1523 vmmreqGuestCaps->u32NotMask = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
1524 rcVBox = VbglGRPerform(&vmmreqGuestCaps->header);
1525 if (RT_FAILURE(rcVBox))
1526 {
1527 LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
1528 rcVBox));
1529 rc = -RTErrConvertToErrno(rcVBox);
1530 }
1531 VbglGRFree(&vmmreqGuestCaps->header);
1532 }
1533 }
1534
1535 /* perform hypervisor address space reservation */
1536 if (!rc && vboxadd_reserve_hypervisor())
1537 {
1538 /* we just ignore the error, no address window reservation, non fatal */
1539 }
1540
1541 /* allocate a VMM request structure for use in the ISR */
1542 if (!rc)
1543 {
1544 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
1545 sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
1546 if (RT_FAILURE(rcVBox))
1547 {
1548 LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
1549 rcVBox));
1550 rc = -RTErrConvertToErrno(rcVBox);
1551 }
1552 }
1553
1554 /* get ISR */
1555 if (!rc)
1556 {
1557 rc = request_irq(pcidev->irq, vboxadd_irq_handler,
1558#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1559 IRQF_SHARED,
1560#else
1561 SA_SHIRQ,
1562#endif
1563 VBOXADD_NAME, vboxDev);
1564 if (rc)
1565 LogRel(("vboxadd: could not request IRQ %d, err: %d\n", pcidev->irq, rc));
1566 else
1567 vboxDev->irq = pcidev->irq;
1568 }
1569
1570 if (!rc)
1571 {
1572 VBoxGuestFilterMaskInfo info;
1573
1574 init_waitqueue_head (&vboxDev->eventq);
1575 /* Register for notification when the host absolute pointer position
1576 * changes. */
1577 info.u32OrMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1578 info.u32NotMask = 0;
1579 rcVBox = vboxadd_control_filter_mask(&info);
1580 if (RT_FAILURE(rcVBox))
1581 {
1582 LogRel(("vboxadd: failed to register for VMMDEV_EVENT_MOUSE_POSITION_CHANGED events: %Rrc\n",
1583 rcVBox));
1584 rc = -RTErrConvertToErrno(rcVBox);
1585 }
1586 }
1587
1588 if (!rc)
1589 {
1590 /* some useful information for the user but don't show this on the console */
1591 LogRel(("VirtualBox device settings: major %d, IRQ %d, "
1592 "I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
1593 "hypervisor window at 0x%p (size 0x%x)\n",
1594 vbox_major, vboxDev->irq, vboxDev->io_port,
1595 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1596 vboxDev->hypervisorStart, vboxDev->hypervisorSize));
1597 printk(KERN_DEBUG "vboxadd: Successfully loaded version "
1598 VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")\n");
1599 }
1600 else /* Clean up on failure */
1601 {
1602 if (fHaveGuestLib)
1603 VbglTerminate();
1604 if (vboxDev)
1605 free_resources();
1606 if (fHaveVBoxUser)
1607 misc_deregister(&gMiscVBoxUser);
1608 if (fHaveVBoxAdd && vbox_major > 0)
1609 unregister_chrdev(vbox_major, VBOXADD_NAME);
1610 else if (fHaveVBoxAdd)
1611 misc_deregister(&gMiscVBoxAdd);
1612 }
1613
1614 /* We always release this. Presumably because we no longer need to do
1615 * anything with the device structure. */
1616 if (pcidev)
1617 PCI_DEV_PUT(pcidev);
1618
1619 return rc;
1620}
1621
1622/**
1623 * Module termination
1624 *
1625 */
1626static __exit void fini(void)
1627{
1628 misc_deregister(&gMiscVBoxUser);
1629 if (vbox_major > 0)
1630 unregister_chrdev(vbox_major, VBOXADD_NAME);
1631 else
1632 misc_deregister(&gMiscVBoxAdd);
1633 free_resources();
1634 vboxadd_cmc_fini ();
1635}
1636
1637module_init(init);
1638module_exit(fini);
1639
1640/* PCI hotplug structure */
1641static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
1642{
1643 {
1644 .vendor = VMMDEV_VENDORID,
1645 .device = VMMDEV_DEVICEID
1646 },
1647 {
1648 /* empty entry */
1649 }
1650};
1651MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
1652
1653
1654
1655/*
1656 * Local Variables:
1657 * c-mode: bsd
1658 * indent-tabs-mode: nil
1659 * c-plusplus: evil
1660 * End:
1661 */
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