VirtualBox

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

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

-s

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.6 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/** Jump buffer structure for hcgm guest-host data copies. */
368typedef struct hgcm_jump_buffer
369{
370 /** Kernel memory address. */
371 void *pKernel;
372 /** User memory address. */
373 void *pUser;
374 /** Buffer size. */
375 size_t cb;
376} hgcm_jump_buffer;
377
378/** Create a jump buffer in kernel space for user space memory. */
379static int vboxadd_hgcm_alloc_buffer(hgcm_jump_buffer **ppBuf, void *pUser,
380 size_t cb)
381{
382 hgcm_jump_buffer *pBuf = NULL;
383 void *pKernel = NULL;
384 int rc = 0;
385 AssertPtrReturn(ppBuf, -EINVAL);
386 AssertPtrReturn(pUser, -EINVAL);
387 pBuf = kmalloc(sizeof(*pBuf), GFP_KERNEL);
388 if (pBuf == NULL)
389 rc = -ENOMEM;
390 if (rc >= 0) {
391 pKernel = kmalloc(cb, GFP_KERNEL);
392 if (pKernel == NULL)
393 rc = -ENOMEM;
394 }
395 if ( rc >= 0
396 && copy_from_user(pKernel, pUser, cb) != 0)
397 rc = -EFAULT;
398 if (rc >= 0) {
399 pBuf->pKernel = pKernel;
400 pBuf->pUser = pUser;
401 pBuf->cb = cb;
402 *ppBuf = pBuf;
403 }
404 else {
405 kfree(pBuf);
406 kfree(pKernel);
407 LogFunc(("failed, returning %d\n", rc));
408 }
409 return rc;
410}
411
412/** Free a kernel space jump buffer for user space memory. */
413static int vboxadd_hgcm_free_buffer(hgcm_jump_buffer *pBuf)
414{
415 int rc = 0;
416 AssertPtrReturn(pBuf, -EINVAL);
417 if (copy_to_user(pBuf->pUser, pBuf->pKernel, pBuf->cb) != 0)
418 rc = -EFAULT;
419 kfree(pBuf->pKernel); /* We want to do this whatever the outcome. */
420 kfree(pBuf);
421 if (rc < 0)
422 LogFunc(("failed, returning %d\n", rc));
423 return rc;
424}
425
426/** Lock down R3 memory as needed for the HGCM call. Copied from
427 * HGCMInternal.cpp and SysHlp.cpp */
428static int vboxadd_buffer_hgcm_parms(void **ppvCtx, VBoxGuestHGCMCallInfo *pCallInfo)
429{
430 uint32_t cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter);
431 int rc = 0;
432 unsigned iParm;
433 HGCMFunctionParameter *pParm;
434 memset (ppvCtx, 0, sizeof(void *) * pCallInfo->cParms);
435 if (cbParms)
436 {
437 /* Lock user buffers. */
438 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
439
440 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
441 {
442 switch (pParm->type)
443 {
444 case VMMDevHGCMParmType_LinAddr_Locked_In:
445 pParm->type = VMMDevHGCMParmType_LinAddr_In;
446 break;
447 case VMMDevHGCMParmType_LinAddr_Locked_Out:
448 pParm->type = VMMDevHGCMParmType_LinAddr_Out;
449 break;
450 case VMMDevHGCMParmType_LinAddr_Locked:
451 pParm->type = VMMDevHGCMParmType_LinAddr;
452 break;
453
454 case VMMDevHGCMParmType_LinAddr_In:
455 case VMMDevHGCMParmType_LinAddr_Out:
456 case VMMDevHGCMParmType_LinAddr:
457 {
458 void *pv = (void *) pParm->u.Pointer.u.linearAddr;
459 uint32_t u32Size = pParm->u.Pointer.size;
460 hgcm_jump_buffer *MemObj = NULL;
461 rc = vboxadd_hgcm_alloc_buffer(&MemObj, pv, u32Size);
462 if (rc >= 0) {
463 ppvCtx[iParm] = MemObj;
464 pParm->u.Pointer.u.linearAddr = (uintptr_t)MemObj->pKernel;
465 } else
466 ppvCtx[iParm] = NULL;
467 break;
468 }
469 default:
470 /* make gcc happy */
471 break;
472 }
473 if (rc < 0)
474 break;
475 }
476 }
477 return rc;
478}
479
480/** Unlock R3 memory after the HGCM call. Copied from HGCMInternal.cpp and
481 * SysHlp.cpp */
482static void vboxadd_unbuffer_hgcm_parms(void **ppvCtx, VBoxGuestHGCMCallInfo *pCallInfo)
483{
484 unsigned iParm;
485 /* Unlock user buffers. */
486 HGCMFunctionParameter *pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
487
488 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
489 {
490 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
491 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
492 || pParm->type == VMMDevHGCMParmType_LinAddr)
493 {
494 if (ppvCtx[iParm] != NULL)
495 {
496 hgcm_jump_buffer *MemObj = (hgcm_jump_buffer *)ppvCtx[iParm];
497#ifdef VBOX_STRICT
498 int rc = vboxadd_hgcm_free_buffer(MemObj);
499 Assert(rc >= 0); /* vboxadd_hgcm_unbuffer_user logs this. */
500#else
501 vboxadd_hgcm_free_buffer(MemObj);
502#endif
503 }
504 }
505 else
506 Assert(!ppvCtx[iParm]);
507 }
508}
509
510/**
511 * IOCTL handler. Make an HGCM call.
512 *
513 * @returns 0 on success, or a Linux kernel errno value
514 * @param userspace_info userspace pointer to the hgcm connection information
515 * (VBoxGuestHGCMConnectInfo structure). This will be
516 * updated on success.
517 * @param u32Size the size of the userspace structure
518 */
519static int vboxadd_hgcm_call(unsigned long userspace_info, uint32_t u32Size)
520{
521 VBoxGuestHGCMCallInfo *pInfo = NULL;
522 void *apvCtx[VBOX_HGCM_MAX_PARMS];
523 unsigned haveParms = 0;
524 int rc = 0;
525
526 pInfo = kmalloc(u32Size, GFP_KERNEL);
527 if (pInfo == NULL)
528 rc = -ENOMEM;
529 if (rc >= 0 &&
530 0 != copy_from_user ((void *)pInfo, (void *)userspace_info, u32Size)) {
531 LogRelFunc (("can not get info from user space\n"));
532 rc = -EFAULT;
533 }
534 if (rc >= 0 &&
535 sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) != u32Size) {
536 LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
537 sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter),
538 u32Size));
539 rc = -EINVAL;
540 }
541 if (rc >= 0) {
542 haveParms = 1;
543 rc = vboxadd_buffer_hgcm_parms(apvCtx, pInfo);
544 }
545 if (rc >= 0) {
546 int vrc;
547 LogRelFunc(("client ID %u\n", pInfo->u32ClientID));
548 vrc = vboxadd_cmc_call(vboxDev,
549 VBOXGUEST_IOCTL_HGCM_CALL(u32Size), pInfo);
550 rc = -RTErrConvertToErrno(vrc);
551 if ( rc >= 0
552 && copy_to_user ((void *)userspace_info, (void *)pInfo,
553 u32Size)) {
554 LogRelFunc (("failed to return the information to user space\n"));
555 rc = -EFAULT;
556 }
557 }
558 if (haveParms)
559 vboxadd_unbuffer_hgcm_parms(apvCtx, pInfo);
560 if (pInfo != NULL)
561 kfree(pInfo);
562 return rc;
563}
564
565/**
566 * IOCTL handler. Make an HGCM call with timeout.
567 *
568 * @returns 0 on success, or a Linux kernel errno value
569 * @param userspace_info userspace pointer to the hgcm connection information
570 * (VBoxGuestHGCMConnectInfo structure). This will be
571 * updated on success.
572 * @param u32Size the size of the userspace structure
573 */
574static int vboxadd_hgcm_call_timed(unsigned long userspace_info,
575 uint32_t u32Size)
576{
577 VBoxGuestHGCMCallInfoTimed *pInfo = NULL;
578 void *apvCtx[VBOX_HGCM_MAX_PARMS];
579 unsigned haveParms = 0;
580 int rc = 0;
581
582 pInfo = kmalloc(u32Size, GFP_KERNEL);
583 if (pInfo == NULL)
584 rc = -ENOMEM;
585 if (rc >= 0 &&
586 0 != copy_from_user ((void *)pInfo, (void *)userspace_info, u32Size)) {
587 LogRelFunc (("can not get info from user space\n"));
588 rc = -EFAULT;
589 }
590 if (rc >= 0 &&
591 sizeof(*pInfo) + pInfo->info.cParms * sizeof(HGCMFunctionParameter) != u32Size) {
592 LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
593 sizeof(*pInfo) + pInfo->info.cParms * sizeof(HGCMFunctionParameter),
594 u32Size));
595 rc = -EINVAL;
596 }
597 if (rc >= 0) {
598 haveParms = 1;
599 rc = vboxadd_buffer_hgcm_parms(apvCtx, &pInfo->info);
600 }
601 if (rc >= 0) {
602 int vrc;
603 LogRelFunc(("client ID %u\n", pInfo->info.u32ClientID));
604 pInfo->fInterruptible = true; /* User space may not do uninterruptible waits */
605 vrc = vboxadd_cmc_call(vboxDev,
606 VBOXGUEST_IOCTL_HGCM_CALL_TIMED(u32Size), pInfo);
607 rc = -RTErrConvertToErrno(vrc);
608 if ( rc >= 0
609 && copy_to_user ((void *)userspace_info, (void *)pInfo,
610 u32Size)) {
611 LogRelFunc (("failed to return the information to user space\n"));
612 rc = -EFAULT;
613 }
614 }
615 if (haveParms)
616 vboxadd_unbuffer_hgcm_parms(apvCtx, &pInfo->info);
617 if (pInfo != NULL)
618 kfree(pInfo);
619 return rc;
620}
621
622/**
623 * IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
624 * we know how to handle.
625 *
626 * @returns iprt status code
627 * @param pInfo kernel space pointer to the filter mask change info
628 */
629static int vboxadd_control_filter_mask(VBoxGuestFilterMaskInfo *pInfo)
630{
631 VMMDevCtlGuestFilterMask *pReq = NULL;
632 int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
633
634 LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
635 if (RT_FAILURE(rc))
636 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
637 else
638 {
639 pReq->u32OrMask = pInfo->u32OrMask;
640 pReq->u32NotMask = pInfo->u32NotMask;
641 rc = VbglGRPerform(&pReq->header);
642 }
643 if (RT_FAILURE(rc))
644 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: VbglGRPerform failed, rc=%Rrc!\n", rc));
645 else if (RT_FAILURE(pReq->header.rc))
646 {
647 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
648 rc = pReq->header.rc;
649 }
650 if (pReq)
651 VbglGRFree(&pReq->header);
652 return rc;
653}
654
655/**
656 * IOCTL handler
657 *
658 */
659static int vboxadd_ioctl(struct inode *inode, struct file *filp,
660 unsigned int cmd, unsigned long arg)
661{
662 int rc = 0;
663
664 /* Deal with variable size ioctls first. */
665 if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0))
666 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
667 char *pszMessage;
668
669 IOCTL_LOG_ENTRY(arg);
670 pszMessage = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
671 if (NULL == pszMessage) {
672 LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
673 _IOC_SIZE(cmd)));
674 rc = -ENOMEM;
675 }
676 if ( (0 == rc)
677 && copy_from_user(pszMessage, (void*)arg, _IOC_SIZE(cmd))) {
678 LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
679 rc = -EFAULT;
680 }
681 if (0 == rc) {
682 Log(("%.*s", _IOC_SIZE(cmd), pszMessage));
683 }
684 if (NULL != pszMessage) {
685 kfree(pszMessage);
686 }
687 IOCTL_LOG_EXIT(arg);
688 }
689 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
690 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
691 VMMDevRequestHeader reqHeader;
692 VMMDevRequestHeader *reqFull = NULL;
693 size_t cbRequestSize;
694 size_t cbVanillaRequestSize;
695
696 IOCTL_VMM_ENTRY(arg);
697 if (copy_from_user(&reqHeader, (void*)arg, sizeof(reqHeader)))
698 {
699 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
700 rc = -EFAULT;
701 }
702 if (0 == rc)
703 {
704 /* get the request size */
705 cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
706 if (!cbVanillaRequestSize)
707 {
708 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
709 reqHeader.requestType));
710 rc = -EINVAL;
711 }
712 }
713 if (0 == rc)
714 {
715 cbRequestSize = reqHeader.size;
716 if (cbRequestSize < cbVanillaRequestSize)
717 {
718 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
719 cbRequestSize,
720 cbVanillaRequestSize,
721 reqHeader.requestType));
722 rc = -EINVAL;
723 }
724 }
725 if (0 == rc)
726 {
727 /* request storage for the full request */
728 rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
729 if (RT_FAILURE(rc))
730 {
731 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
732 rc = -EFAULT;
733 }
734 }
735 if (0 == rc)
736 {
737 /* now get the full request */
738 if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
739 {
740 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
741 rc = -EFAULT;
742 }
743 }
744
745 /* now issue the request */
746 if (0 == rc)
747 {
748 int rrc = VbglGRPerform(reqFull);
749
750 /* asynchronous processing? */
751 if (rrc == VINF_HGCM_ASYNC_EXECUTE)
752 {
753 VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
754 wait_event_interruptible (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
755 rrc = reqFull->rc;
756 }
757
758 /* failed? */
759 if (RT_FAILURE(rrc) || RT_FAILURE(reqFull->rc))
760 {
761 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
762 rc = RT_FAILURE(rrc) ? -RTErrConvertToErrno(rrc)
763 : -RTErrConvertToErrno(reqFull->rc);
764 }
765 else
766 {
767 /* success, copy the result data to user space */
768 if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
769 {
770 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
771 rc = -EFAULT;
772 }
773 }
774 }
775 if (NULL != reqFull)
776 VbglGRFree(reqFull);
777 IOCTL_VMM_EXIT(arg);
778 }
779 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
780 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
781 {
782 /* Do the HGCM call using the Vbgl bits */
783 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
784 rc = vboxadd_hgcm_call(arg, _IOC_SIZE(cmd));
785 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
786 }
787 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
788 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
789 {
790 /* Do the HGCM call using the Vbgl bits */
791 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
792 rc = vboxadd_hgcm_call_timed(arg, _IOC_SIZE(cmd));
793 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
794 }
795 else
796 {
797 switch (cmd) {
798 case VBOXGUEST_IOCTL_WAITEVENT:
799 IOCTL_ENTRY("VBOXGUEST_IOCTL_WAITEVENT", arg);
800 rc = vboxadd_wait_event((void *) arg);
801 IOCTL_EXIT("VBOXGUEST_IOCTL_WAITEVENT", arg);
802 break;
803 case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
804 IOCTL_ENTRY("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
805 ++vboxDev->u32GuestInterruptions;
806 IOCTL_EXIT("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
807 break;
808 case VBOXGUEST_IOCTL_HGCM_CONNECT:
809 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
810 rc = vboxadd_hgcm_connect(filp, arg);
811 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
812 break;
813 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
814 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
815 vboxadd_hgcm_disconnect(filp, arg);
816 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
817 break;
818 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
819 {
820 VBoxGuestFilterMaskInfo info;
821 IOCTL_ENTRY("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
822 if (copy_from_user((void*)&info, (void*)arg, sizeof(info)))
823 {
824 LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
825 rc = -EFAULT;
826 break;
827 }
828 rc = -RTErrConvertToErrno(vboxadd_control_filter_mask(&info));
829 IOCTL_EXIT("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
830 break;
831 }
832 default:
833 LogRelFunc(("unknown command: %x\n", cmd));
834 rc = -EINVAL;
835 break;
836 }
837 }
838 return rc;
839}
840
841/**
842 * Poll function. This returns "ready to read" if the guest is in absolute
843 * mouse pointer mode and the pointer position has changed since the last
844 * poll.
845 */
846unsigned int
847vboxadd_poll (struct file *file, poll_table *wait)
848{
849 int result = 0;
850 poll_wait(file, &vboxDev->eventq, wait);
851 if (vboxDev->u32Events & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
852 result = (POLLIN | POLLRDNORM);
853 vboxDev->u32Events &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
854 return result;
855}
856
857/** Asynchronous notification activation method. */
858static int
859vboxadd_fasync(int fd, struct file *file, int mode)
860{
861 return fasync_helper(fd, file, mode, &vboxDev->async_queue);
862}
863
864/**
865 * Dummy read function - we only supply this because we implement poll and
866 * fasync.
867 */
868static ssize_t
869vboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
870{
871 if (0 == count || *loff != 0)
872 {
873 return -EINVAL;
874 }
875 buf[0] = 0;
876 return 1;
877}
878
879/**
880 * File close handler. Clean up any HGCM connections associated with the open file
881 * which might still be open.
882 */
883static int vboxadd_release(struct inode *inode, struct file * filp)
884{
885 vboxadd_unregister_all_hgcm_connections(filp);
886 /* Deactivate our asynchronous queue. */
887 vboxadd_fasync(-1, filp, 0);
888 return 0;
889}
890
891/** strategy handlers (file operations) */
892static struct file_operations vbox_fops =
893{
894 .owner = THIS_MODULE,
895 .open = vboxadd_open,
896 .ioctl = vboxadd_ioctl,
897 .poll = vboxadd_poll,
898 .fasync = vboxadd_fasync,
899 .read = vboxadd_read,
900 .release = vboxadd_release,
901 .llseek = no_llseek
902};
903
904static struct miscdevice gMiscDevice =
905{
906 minor: MISC_DYNAMIC_MINOR,
907 name: "vboxadd",
908 fops: &vbox_fops
909};
910
911#ifndef IRQ_RETVAL
912/* interrupt handlers in 2.4 kernels don't return anything */
913# define irqreturn_t void
914# define IRQ_RETVAL(n)
915#endif
916
917/**
918 * vboxadd_irq_handler
919 *
920 * Interrupt handler
921 *
922 * @returns scsi error code
923 * @param irq Irq number
924 * @param dev_id Irq handler parameter
925 * @param regs Regs
926 *
927 */
928#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
929static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
930#else
931static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
932#endif
933{
934 int fIRQTaken = 0;
935 int rcVBox;
936
937#ifdef IRQ_DEBUG
938 Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
939 vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
940#endif
941
942 /* check if IRQ was asserted by VBox */
943 if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
944 {
945#ifdef IRQ_DEBUG
946 Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
947 vboxDev->irqAckRequest->events));
948#endif
949
950 /* make a copy of the event mask */
951 rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
952 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(vboxDev->irqAckRequest->header.rc))
953 {
954 if (RT_LIKELY (vboxDev->irqAckRequest->events))
955 {
956 vboxDev->u32Events |= vboxDev->irqAckRequest->events;
957 if ( vboxDev->irqAckRequest->events
958 & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
959 kill_fasync(&vboxDev->async_queue, SIGIO, POLL_IN);
960 wake_up (&vboxDev->eventq);
961 }
962 }
963 else
964 {
965 /* impossible... */
966 LogRelFunc(("IRQ was not acknowledged! rc = %Rrc, header.rc = %Rrc\n",
967 rcVBox, vboxDev->irqAckRequest->header.rc));
968 BUG ();
969 }
970
971 /* it was ours! */
972 fIRQTaken = 1;
973 }
974#ifdef IRQ_DEBUG
975 else
976 {
977 /* we might be attached to a shared interrupt together with another device. */
978 Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
979 vboxDev->pVMMDevMemory,
980 vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
981 vboxDev->u32Events));
982 }
983#endif
984 /* it was ours */
985 return IRQ_RETVAL(fIRQTaken);
986}
987
988/**
989 * Helper function to reserve a fixed kernel address space window
990 * and tell the VMM that it can safely put its hypervisor there.
991 * This function might fail which is not a critical error.
992 */
993static int vboxadd_reserve_hypervisor(void)
994{
995 VMMDevReqHypervisorInfo *req = NULL;
996 int rcVBox;
997
998 /* allocate request structure */
999 rcVBox = VbglGRAlloc(
1000 (VMMDevRequestHeader**)&req,
1001 sizeof(VMMDevReqHypervisorInfo),
1002 VMMDevReq_GetHypervisorInfo
1003 );
1004 if (RT_FAILURE(rcVBox))
1005 {
1006 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
1007 goto bail_out;
1008 }
1009 /* query the hypervisor information */
1010 rcVBox = VbglGRPerform(&req->header);
1011 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1012 {
1013 /* are we supposed to make a reservation? */
1014 if (req->hypervisorSize)
1015 {
1016 /** @todo repeat this several times until we get an address the host likes */
1017
1018 void *hypervisorArea;
1019 /* reserve another 4MB because the start needs to be 4MB aligned */
1020 uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
1021 /* perform a fictive IO space mapping */
1022 hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
1023 if (hypervisorArea)
1024 {
1025 /* communicate result to VMM, align at 4MB */
1026 req->hypervisorStart = (VMMDEVHYPPTR32)(uintptr_t)RT_ALIGN_P(hypervisorArea, 0x400000);
1027 req->header.requestType = VMMDevReq_SetHypervisorInfo;
1028 req->header.rc = VERR_GENERAL_FAILURE;
1029 rcVBox = VbglGRPerform(&req->header);
1030 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1031 {
1032 /* store mapping for future unmapping */
1033 vboxDev->hypervisorStart = hypervisorArea;
1034 vboxDev->hypervisorSize = hypervisorSize;
1035 }
1036 else
1037 {
1038 LogRelFunc(("failed to set hypervisor region! rc = %Rrc, header.rc = %Rrc\n",
1039 rcVBox, req->header.rc));
1040 goto bail_out;
1041 }
1042 }
1043 else
1044 {
1045 LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
1046 goto bail_out;
1047 }
1048 }
1049 }
1050 else
1051 {
1052 LogRelFunc(("failed to query hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
1053 rcVBox, req->header.rc));
1054 goto bail_out;
1055 }
1056 /* successful return */
1057 VbglGRFree(&req->header);
1058 return 0;
1059bail_out:
1060 /* error return */
1061 if (req)
1062 VbglGRFree(&req->header);
1063 return 1;
1064}
1065
1066/**
1067 * Helper function to free the hypervisor address window
1068 *
1069 */
1070static int vboxadd_free_hypervisor(void)
1071{
1072 VMMDevReqHypervisorInfo *req = NULL;
1073 int rcVBox;
1074
1075 /* allocate request structure */
1076 rcVBox = VbglGRAlloc(
1077 (VMMDevRequestHeader**)&req,
1078 sizeof(VMMDevReqHypervisorInfo),
1079 VMMDevReq_SetHypervisorInfo
1080 );
1081 if (RT_FAILURE(rcVBox))
1082 {
1083 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
1084 goto bail_out;
1085 }
1086 /* reset the hypervisor information */
1087 req->hypervisorStart = 0;
1088 req->hypervisorSize = 0;
1089 rcVBox = VbglGRPerform(&req->header);
1090 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
1091 {
1092 /* now we can free the associated IO space mapping */
1093 iounmap(vboxDev->hypervisorStart);
1094 vboxDev->hypervisorStart = 0;
1095 }
1096 else
1097 {
1098 LogRelFunc(("failed to reset hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
1099 rcVBox, req->header.rc));
1100 goto bail_out;
1101 }
1102 return 0;
1103
1104 bail_out:
1105 if (req)
1106 VbglGRFree(&req->header);
1107 return 1;
1108}
1109
1110/**
1111 * Helper to free resources
1112 *
1113 */
1114static void free_resources(void)
1115{
1116 if (vboxDev)
1117 {
1118 {
1119 /* Unregister notifications when the host absolute pointer
1120 * position changes. */
1121 VBoxGuestFilterMaskInfo info;
1122 info.u32OrMask = 0;
1123 info.u32NotMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1124 vboxadd_control_filter_mask(&info);
1125 }
1126 /* Detach from IRQ before cleaning up! */
1127 if (vboxDev->irq)
1128 free_irq(vboxDev->irq, vboxDev);
1129 if (vboxDev->hypervisorStart)
1130 vboxadd_free_hypervisor();
1131 if (vboxDev->irqAckRequest)
1132 {
1133 VbglGRFree(&vboxDev->irqAckRequest->header);
1134 VbglTerminate();
1135 }
1136 if (vboxDev->pVMMDevMemory)
1137 iounmap(vboxDev->pVMMDevMemory);
1138 if (vboxDev->vmmdevmem)
1139 release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
1140 kfree(vboxDev);
1141 vboxDev = NULL;
1142 }
1143}
1144
1145#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1146#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
1147#define PCI_DEV_PUT(x) pci_dev_put(x)
1148#else
1149#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
1150#define PCI_DEV_PUT(x)
1151#endif
1152
1153/**
1154 * Module initialization
1155 *
1156 */
1157static __init int init(void)
1158{
1159 int err;
1160 int rcVBox;
1161 struct pci_dev *pcidev = NULL;
1162 VMMDevReportGuestInfo *infoReq = NULL;
1163
1164 if (vboxadd_cmc_init ())
1165 {
1166 printk (KERN_ERR "vboxadd: could not init cmc.\n");
1167 return -ENODEV;
1168 }
1169
1170 /*
1171 * Detect PCI device
1172 */
1173 pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
1174 if (!pcidev)
1175 {
1176 printk(KERN_ERR "vboxadd: VirtualBox PCI device not found.\n");
1177 return -ENODEV;
1178 }
1179
1180 err = pci_enable_device (pcidev);
1181 if (err)
1182 {
1183 Log(("vboxadd: could not enable device: %d\n", err));
1184 PCI_DEV_PUT(pcidev);
1185 return -ENODEV;
1186 }
1187
1188 LogRel(("Starting VirtualBox version %s Guest Additions\n",
1189 VBOX_VERSION_STRING));
1190 /* register a character device */
1191 if (vbox_major > 0)
1192 {
1193 err = register_chrdev(vbox_major, "vboxadd", &vbox_fops);
1194 if (err < 0 || (vbox_major & err) || (!vbox_major && !err))
1195 {
1196 LogRelFunc(("register_chrdev failed: vbox_major: %d, err = %d\n",
1197 vbox_major, err));
1198 PCI_DEV_PUT(pcidev);
1199 return -ENODEV;
1200 }
1201 /* if no major code was set, take the return value */
1202 if (!vbox_major)
1203 vbox_major = err;
1204 }
1205 else
1206 {
1207 err = misc_register(&gMiscDevice);
1208 if (err)
1209 {
1210 LogRelFunc(("misc_register failed (rc=%d)\n", err));
1211 return -ENODEV;
1212 }
1213 }
1214
1215 /* allocate and initialize device extension */
1216 vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
1217 if (!vboxDev)
1218 {
1219 LogRelFunc(("cannot allocate device!\n"));
1220 err = -ENOMEM;
1221 goto fail;
1222 }
1223 memset(vboxDev, 0, sizeof(*vboxDev));
1224 snprintf(vboxDev->name, sizeof(vboxDev->name), "vboxadd");
1225
1226 /* get the IO port region */
1227 vboxDev->io_port = pci_resource_start(pcidev, 0);
1228
1229 /* get the memory region */
1230 vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
1231 vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
1232
1233 /* all resources found? */
1234 if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
1235 {
1236 LogRelFunc(("did not find expected hardware resources!\n"));
1237 err = -ENXIO;
1238 goto fail;
1239 }
1240
1241 /* request ownership of adapter memory */
1242 if (request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size, "vboxadd") == 0)
1243 {
1244 LogRelFunc(("failed to request adapter memory!\n"));
1245 err = -ENXIO;
1246 goto fail;
1247 }
1248
1249 /* map adapter memory into kernel address space and check version */
1250 vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
1251 vboxDev->vmmdevmem_size);
1252 if (!vboxDev->pVMMDevMemory)
1253 {
1254 LogRelFunc(("ioremap failed\n"));
1255 err = -ENOMEM;
1256 goto fail;
1257 }
1258
1259 if (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
1260 {
1261 LogRelFunc(("invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
1262 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
1263 err = -ENXIO;
1264 goto fail;
1265 }
1266
1267 /* initialize VBGL subsystem */
1268 rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
1269 if (RT_FAILURE(rcVBox))
1270 {
1271 LogRelFunc(("could not initialize VBGL subsystem! rc = %Rrc\n", rcVBox));
1272 err = -ENXIO;
1273 goto fail;
1274 }
1275
1276 /* report guest information to host, this must be done as the very first request */
1277 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
1278 sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
1279 if (RT_FAILURE(rcVBox))
1280 {
1281 LogRelFunc(("could not allocate request structure! rc = %Rrc\n", rcVBox));
1282 err = -ENOMEM;
1283 goto fail;
1284 }
1285
1286 /* report guest version to host, the VMMDev requires that to be done first */
1287 infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
1288#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
1289 infoReq->guestInfo.osType = VBOXOSTYPE_Linux26;
1290#else
1291 infoReq->guestInfo.osType = VBOXOSTYPE_Linux24;
1292#endif
1293 rcVBox = VbglGRPerform(&infoReq->header);
1294 if (RT_FAILURE(rcVBox) || RT_FAILURE(infoReq->header.rc))
1295 {
1296 LogRelFunc(("error reporting guest info to host! rc = %Rrc, header.rc = %Rrc\n",
1297 rcVBox, infoReq->header.rc));
1298 VbglGRFree(&infoReq->header);
1299 err = -ENXIO;
1300 goto fail;
1301 }
1302 VbglGRFree(&infoReq->header);
1303
1304 /* Unset the graphics capability until/unless X is loaded. */
1305 /** @todo check the error code once we bump the additions version.
1306 For now we ignore it for compatibility with older hosts. */
1307 {
1308 VMMDevReqGuestCapabilities2 *vmmreqGuestCaps;
1309
1310
1311 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vmmreqGuestCaps,
1312 sizeof(VMMDevReqGuestCapabilities2),
1313 VMMDevReq_SetGuestCapabilities);
1314 if (RT_FAILURE(rcVBox))
1315 {
1316 LogRelFunc(("could not allocate request structure! rc = %Rrc\n", rcVBox));
1317 err = -ENOMEM;
1318 goto fail;
1319 }
1320 vmmreqGuestCaps->u32OrMask = 0;
1321 vmmreqGuestCaps->u32NotMask = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
1322 rcVBox = VbglGRPerform(&vmmreqGuestCaps->header);
1323 VbglGRFree(&vmmreqGuestCaps->header);
1324 if (RT_FAILURE(rcVBox))
1325 {
1326 err = -ENXIO;
1327 goto fail;
1328 }
1329 }
1330
1331 /* perform hypervisor address space reservation */
1332 if (vboxadd_reserve_hypervisor())
1333 {
1334 /* we just ignore the error, no address window reservation, non fatal */
1335 }
1336
1337 /* allocate a VMM request structure for use in the ISR */
1338 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
1339 sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
1340 if (RT_FAILURE(rcVBox))
1341 {
1342 LogRelFunc(("could not allocate request structure! rc = %Rrc\n", rcVBox));
1343 err = -ENOMEM;
1344 goto fail;
1345 }
1346
1347 /* get ISR */
1348 err = request_irq(pcidev->irq, vboxadd_irq_handler,
1349#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1350 IRQF_SHARED,
1351#else
1352 SA_SHIRQ,
1353#endif
1354 "vboxadd", vboxDev);
1355 if (err)
1356 {
1357 LogRelFunc(("could not request IRQ %d, err: %d\n", pcidev->irq, err));
1358 goto fail;
1359 }
1360 vboxDev->irq = pcidev->irq;
1361
1362 init_waitqueue_head (&vboxDev->eventq);
1363
1364 {
1365 /* Register for notification when the host absolute pointer position
1366 * changes. */
1367 VBoxGuestFilterMaskInfo info;
1368 info.u32OrMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1369 info.u32NotMask = 0;
1370 rcVBox = vboxadd_control_filter_mask(&info);
1371 if (!RT_SUCCESS(rcVBox))
1372 {
1373 LogRelFunc(("failed to register for VMMDEV_EVENT_MOUSE_POSITION_CHANGED events\n"));
1374 err = -RTErrConvertToErrno(rcVBox);
1375 goto fail;
1376 }
1377 }
1378
1379 /* some useful information for the user but don't show this on the console */
1380 LogRel(("VirtualBox device settings: major %d, IRQ %d, "
1381 "I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
1382 "hypervisor window at 0x%p (size 0x%x)\n",
1383 vbox_major, vboxDev->irq, vboxDev->io_port,
1384 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1385 vboxDev->hypervisorStart, vboxDev->hypervisorSize));
1386 printk(KERN_DEBUG "vboxadd: Successfully loaded version "
1387 VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")\n");
1388
1389 /* successful return */
1390 PCI_DEV_PUT(pcidev);
1391 return 0;
1392
1393fail:
1394 PCI_DEV_PUT(pcidev);
1395 free_resources();
1396 if (vbox_major > 0)
1397 unregister_chrdev(vbox_major, "vboxadd");
1398 else
1399 misc_deregister(&gMiscDevice);
1400 return err;
1401}
1402
1403/**
1404 * Module termination
1405 *
1406 */
1407static __exit void fini(void)
1408{
1409 if (vbox_major > 0)
1410 unregister_chrdev(vbox_major, "vboxadd");
1411 else
1412 misc_deregister(&gMiscDevice);
1413 free_resources();
1414 vboxadd_cmc_fini ();
1415}
1416
1417module_init(init);
1418module_exit(fini);
1419
1420/* PCI hotplug structure */
1421static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
1422{
1423 {
1424 .vendor = VMMDEV_VENDORID,
1425 .device = VMMDEV_DEVICEID
1426 },
1427 {
1428 /* empty entry */
1429 }
1430};
1431MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
1432
1433
1434
1435/*
1436 * Local Variables:
1437 * c-mode: bsd
1438 * indent-tabs-mode: nil
1439 * c-plusplus: evil
1440 * End:
1441 */
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