VirtualBox

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

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

vboxmod.c: vboxadd_lock_hgcm_parms must negate the RTErrConvertToErrno result.

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