VirtualBox

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

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

vboxmod.c: review comment.

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