VirtualBox

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

Last change on this file since 7438 was 7438, checked in by vboxsync, 17 years ago

Additions/Linux: turn off the graphics capability when the additions first load

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.9 KB
Line 
1/** @file
2 *
3 * vboxadd -- VirtualBox Guest Additions for Linux
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "the-linux-kernel.h"
19#include "version-generated.h"
20
21/* #define IRQ_DEBUG */
22// #define IOCTL_DEBUG
23#ifdef IOCTL_DEBUG
24# define IOCTL_ENTRY(name, arg) \
25do { \
26 Log(("IOCTL_ENTRY: %s, 0x%x\n", (name), (arg))); \
27} while(0)
28# define IOCTL_EXIT(name, arg) \
29do { \
30 Log(("IOCTL_EXIT: %s, 0x%x\n", (name), (arg))); \
31} while(0)
32#else
33# define IOCTL_ENTRY(name, arg) do { } while(0)
34# define IOCTL_EXIT(name, arg) do { } while(0)
35#endif
36#ifdef IOCTL_LOG_DEBUG
37# define IOCTL_LOG_ENTRY(arg) \
38do { \
39 Log(("IOCTL_ENTRY: Log, 0x%x\n", (arg))); \
40} while(0)
41# define IOCTL_LOG_EXIT(arg) \
42do { \
43 Log(("IOCTL_EXIT: Log, 0x%x\n", (arg))); \
44} while(0)
45#else
46# define IOCTL_LOG_ENTRY(arg) do { } while(0)
47# define IOCTL_LOG_EXIT(arg) do { } while(0)
48#endif
49#ifdef IOCTL_VMM_DEBUG
50# define IOCTL_VMM_ENTRY(arg) \
51do { \
52 Log(("IOCTL_ENTRY: VMMDevReq, 0x%x\n", (arg))); \
53} while(0)
54# define IOCTL_VMM_EXIT(arg) \
55do { \
56 Log(("IOCTL_EXIT: VMMDevReq, 0x%x\n", (arg))); \
57} while(0)
58#else
59# define IOCTL_VMM_ENTRY(arg) do { } while(0)
60# define IOCTL_VMM_EXIT(arg) do { } while(0)
61#endif
62
63#include "vboxmod.h"
64#include "waitcompat.h"
65
66#include <VBox/log.h>
67#include <VBox/VBoxDev.h>
68#include <iprt/asm.h>
69#include <iprt/assert.h>
70
71#define xstr(s) str(s)
72#define str(s) #s
73
74MODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
75MODULE_AUTHOR("innotek GmbH");
76MODULE_LICENSE("GPL");
77#ifdef MODULE_VERSION
78MODULE_VERSION(VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")");
79#endif
80
81/* This is called by our assert macros to find out whether we want
82 to insert a breakpoint after the assertion. In kernel modules we
83 do not of course. */
84RTDECL(bool) RTAssertDoBreakpoint(void)
85{
86 return false;
87}
88EXPORT_SYMBOL(RTAssertDoBreakpoint);
89
90/** device extension structure (we only support one device instance) */
91static VBoxDevice *vboxDev = NULL;
92/** our file node major id (set dynamically) */
93#ifdef CONFIG_VBOXADD_MAJOR
94static unsigned int vbox_major = CONFIG_VBOXADD_MAJOR;
95#else
96static unsigned int vbox_major = 0;
97#endif
98
99DECLVBGL (void *) vboxadd_cmc_open (void)
100{
101 return vboxDev;
102}
103
104DECLVBGL (void) vboxadd_cmc_close (void *opaque)
105{
106 (void) opaque;
107}
108
109EXPORT_SYMBOL (vboxadd_cmc_open);
110EXPORT_SYMBOL (vboxadd_cmc_close);
111
112#define MAX_HGCM_CONNECTIONS 1024
113
114/**
115 * Structure for keeping track of HGCM connections owned by user space processes, so that
116 * we can close the connection if a process does not clean up properly (for example if it
117 * was terminated too abruptly).
118 */
119/* We just define a fixed number of these so far. This can be changed if it ever becomes
120 a problem. */
121static struct {
122 /** Open file structure that this connection handle is associated with */
123 struct file *filp;
124 /** HGCM connection ID */
125 uint32_t client_id;
126} hgcm_connections[MAX_HGCM_CONNECTIONS] = { { 0 } };
127
128/**
129 * Register an HGCM connection as being connected with a given file descriptor, so that it
130 * will be closed automatically when that file descriptor is.
131 *
132 * @returns 0 on success or Linux kernel error number
133 * @param clientID the client ID of the HGCM connection
134 * @param filep the file structure that the connection is to be associated with
135 */
136static int vboxadd_register_hgcm_connection(uint32_t client_id, struct file *filp)
137{
138 int i;
139 bool found = false;
140
141 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
142 Assert(hgcm_connections[i].client_id != client_id);
143 }
144 for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
145 if (ASMAtomicCmpXchgU32(&hgcm_connections[i].client_id, client_id, 0)) {
146 hgcm_connections[i].filp = filp;
147 found = true;
148 }
149 }
150 return found ? 0 : -ENFILE; /* Any ideas for a better error code? */
151}
152
153/**
154 * Unregister an HGCM connection associated with a given file descriptor without closing
155 * the connection.
156 *
157 * @returns 0 on success or Linux kernel error number
158 * @param clientID the client ID of the HGCM connection
159 */
160static int vboxadd_unregister_hgcm_connection_no_close(uint32_t client_id)
161{
162 int i;
163 bool found = false;
164
165 for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
166 if (hgcm_connections[i].client_id == client_id) {
167 hgcm_connections[i].filp = NULL;
168 hgcm_connections[i].client_id = 0;
169 found = true;
170 }
171 }
172 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
173 Assert(hgcm_connections[i].client_id != client_id);
174 }
175 return found ? 0 : -ENOENT;
176}
177
178/**
179 * Unregister all HGCM connections associated with a given file descriptor, closing
180 * the connections in the process. This should be called when a file descriptor is
181 * closed.
182 *
183 * @returns 0 on success or Linux kernel error number
184 * @param clientID the client ID of the HGCM connection
185 */
186static int vboxadd_unregister_all_hgcm_connections(struct file *filp)
187{
188 int i;
189
190 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
191 if (hgcm_connections[i].filp == filp) {
192 VBoxGuestHGCMDisconnectInfo infoDisconnect;
193 infoDisconnect.u32ClientID = hgcm_connections[i].client_id;
194 vboxadd_cmc_call(vboxDev, IOCTL_VBOXGUEST_HGCM_DISCONNECT,
195 &infoDisconnect);
196 hgcm_connections[i].filp = NULL;
197 hgcm_connections[i].client_id = 0;
198 }
199 }
200 return 0;
201}
202
203
204/**
205 * File open handler
206 *
207 */
208static int vboxadd_open(struct inode *inode, struct file *filp)
209{
210 /* no checks required */
211 return 0;
212}
213
214/**
215 * File close handler. Clean up any HGCM connections associated with the open file
216 * which might still be open.
217 */
218static int vboxadd_release(struct inode *inode, struct file * filp)
219{
220 vboxadd_unregister_all_hgcm_connections(filp);
221 return 0;
222}
223
224static void
225vboxadd_wait_for_event (VBoxGuestWaitEventInfo *info)
226{
227 long timeleft;
228 uint32_t cInterruptions = vboxDev->u32GuestInterruptions;
229 uint32_t in_mask = info->u32EventMaskIn;
230
231 info->u32Result = VBOXGUEST_WAITEVENT_OK;
232 if (RT_INDEFINITE_WAIT != info->u32TimeoutIn) {
233 timeleft = wait_event_interruptible_timeout
234 (vboxDev->eventq,
235 (vboxDev->u32Events & in_mask)
236 || (vboxDev->u32GuestInterruptions != cInterruptions),
237 msecs_to_jiffies (info->u32TimeoutIn)
238 );
239 if (vboxDev->u32GuestInterruptions != cInterruptions) {
240 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
241 }
242 if (timeleft < 0) {
243 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
244 }
245 if (timeleft == 0) {
246 info->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
247 }
248 }
249 else {
250 if (wait_event_interruptible(vboxDev->eventq,
251 (vboxDev->u32Events & in_mask)
252 || (vboxDev->u32GuestInterruptions != cInterruptions)
253 )
254 ) {
255 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
256 }
257 }
258 info->u32EventFlagsOut = vboxDev->u32Events & in_mask;
259 vboxDev->u32Events &= ~in_mask;
260}
261
262/**
263 * IOCtl handler - wait for an event from the host.
264 *
265 * @returns Linux kernel return code
266 * @param ptr User space pointer to a structure describing the event
267 */
268static int vboxadd_wait_event(void *ptr)
269{
270 int rc = 0;
271 VBoxGuestWaitEventInfo info;
272
273 if (copy_from_user (&info, ptr, sizeof (info))) {
274 LogRelFunc (("IOCTL_VBOXGUEST_WAITEVENT: can not get event info\n"));
275 rc = -EFAULT;
276 }
277
278 if (0 == rc) {
279 vboxadd_wait_for_event (&info);
280
281 if (copy_to_user (ptr, &info, sizeof (info))) {
282 LogRelFunc (("IOCTL_VBOXGUEST_WAITEVENT: can not put out_mask\n"));
283 rc = -EFAULT;
284 }
285 }
286 return 0;
287}
288
289/**
290 * IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
291 * succeeds, it will be associated with the file structure used to open it, so that it will be
292 * automatically shut down again if the file descriptor is closed.
293 *
294 * @returns 0 on success, or a Linux kernel errno value
295 * @param filp the file structure with which the application opened the driver
296 * @param userspace_info userspace pointer to the hgcm connection information
297 * (VBoxGuestHGCMConnectInfo structure)
298 * @retval userspace_info userspace pointer to the hgcm connection information
299 */
300static int vboxadd_hgcm_connect(struct file *filp, unsigned long userspace_info)
301{
302 VBoxGuestHGCMConnectInfo info;
303 VBoxGuestHGCMDisconnectInfo infoDisconnect;
304 int rc = 0, rcVBox;
305
306 if (0 != copy_from_user ((void *)&info, (void *)userspace_info, sizeof (info))) {
307 LogRelFunc (("IOCTL_VBOXGUEST_HGCM_CONNECT: can not get connection info\n"));
308 return -EFAULT;
309 }
310 rcVBox = vboxadd_cmc_call(vboxDev, IOCTL_VBOXGUEST_HGCM_CONNECT, &info);
311 if (RT_FAILURE(rcVBox) || (RT_FAILURE(info.result))) {
312 LogRelFunc(("IOCTL_VBOXGUEST_HGCM_CONNECT: hgcm connection failed. internal ioctl result %Vrc, hgcm result %Vrc\n", rcVBox, info.result));
313 rc = RT_FAILURE(rcVBox) ? -RTErrConvertToErrno(rcVBox)
314 : -RTErrConvertToErrno(info.result);
315 } else {
316 /* Register that the connection is associated with this file pointer. */
317 LogRelFunc(("Connected, client ID %u\n", info.u32ClientID));
318 rc = vboxadd_register_hgcm_connection(info.u32ClientID, filp);
319 if (0 != rc) {
320 LogRelFunc(("IOCTL_VBOXGUEST_HGCM_CONNECT: failed to register the HGCM connection\n"));
321 } else {
322 if (copy_to_user ((void *)userspace_info, (void *)&info,
323 sizeof(info))) {
324 LogRelFunc (("IOCTL_VBOXGUEST_HGCM_CONNECT: failed to return the connection structure\n"));
325 rc = -EFAULT;
326 } else {
327 return 0;
328 }
329 /* Unregister again, as we didn't get as far as informing userspace. */
330 vboxadd_unregister_hgcm_connection_no_close(info.u32ClientID);
331 }
332 /* And disconnect the hgcm connection again, as we told userspace it failed. */
333 infoDisconnect.u32ClientID = info.u32ClientID;
334 vboxadd_cmc_call(vboxDev, IOCTL_VBOXGUEST_HGCM_DISCONNECT,
335 &infoDisconnect);
336 }
337 return rc;
338}
339
340/**
341 * IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
342 * we know how to handle.
343 *
344 * @returns iprt status code
345 * @param pInfo kernel space pointer to the filter mask change info
346 */
347static int vboxadd_control_filter_mask(VBoxGuestFilterMaskInfo *pInfo)
348{
349 VMMDevCtlGuestFilterMask *pReq = NULL;
350 int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
351
352 LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
353 if (RT_FAILURE(rc))
354 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
355 else
356 {
357 pReq->u32OrMask = pInfo->u32OrMask;
358 pReq->u32NotMask = pInfo->u32NotMask;
359 rc = VbglGRPerform(&pReq->header);
360 }
361 if (RT_FAILURE(rc))
362 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: VbglGRPerform failed, rc=%Rrc!\n", rc));
363 else if (RT_FAILURE(pReq->header.rc))
364 {
365 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
366 rc = pReq->header.rc;
367 }
368 if (pReq)
369 VbglGRFree(&pReq->header);
370 return rc;
371}
372
373/**
374 * IOCTL handler
375 *
376 */
377static int vboxadd_ioctl(struct inode *inode, struct file *filp,
378 unsigned int cmd, unsigned long arg)
379{
380 int rc = 0;
381
382 /* Deal with variable size ioctls first. */
383 if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0))
384 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
385 char *pszMessage;
386
387 IOCTL_LOG_ENTRY(arg);
388 pszMessage = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
389 if (NULL == pszMessage) {
390 LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
391 _IOC_SIZE(cmd)));
392 rc = -ENOMEM;
393 }
394 if ( (0 == rc)
395 && copy_from_user(pszMessage, (void*)arg, _IOC_SIZE(cmd))) {
396 LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
397 rc = -EFAULT;
398 }
399 if (0 == rc) {
400 Log(("%.*s", _IOC_SIZE(cmd), pszMessage));
401 }
402 if (NULL != pszMessage) {
403 kfree(pszMessage);
404 }
405 IOCTL_LOG_EXIT(arg);
406 }
407 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
408 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
409 VMMDevRequestHeader reqHeader;
410 VMMDevRequestHeader *reqFull = NULL;
411 size_t cbRequestSize;
412 size_t cbVanillaRequestSize;
413
414 IOCTL_VMM_ENTRY(arg);
415 if (copy_from_user(&reqHeader, (void*)arg, sizeof(reqHeader)))
416 {
417 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: copy_from_user failed for vmm request!\n"));
418 rc = -EFAULT;
419 }
420 if (0 == rc)
421 {
422 /* get the request size */
423 cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
424 if (!cbVanillaRequestSize)
425 {
426 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: invalid request type: %d\n",
427 reqHeader.requestType));
428 rc = -EINVAL;
429 }
430 }
431 if (0 == rc)
432 {
433 cbRequestSize = reqHeader.size;
434 if (cbRequestSize < cbVanillaRequestSize)
435 {
436 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
437 cbRequestSize,
438 cbVanillaRequestSize,
439 reqHeader.requestType));
440 rc = -EINVAL;
441 }
442 }
443 if (0 == rc)
444 {
445 /* request storage for the full request */
446 rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
447 if (VBOX_FAILURE(rc))
448 {
449 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
450 rc = -EFAULT;
451 }
452 }
453 if (0 == rc)
454 {
455 /* now get the full request */
456 if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
457 {
458 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: failed to fetch full request from user space!\n"));
459 rc = -EFAULT;
460 }
461 }
462
463 /* now issue the request */
464 if (0 == rc)
465 {
466 int rrc = VbglGRPerform(reqFull);
467
468 /* asynchronous processing? */
469 if (rrc == VINF_HGCM_ASYNC_EXECUTE)
470 {
471 VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
472 wait_event_interruptible (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
473 rrc = reqFull->rc;
474 }
475
476 /* failed? */
477 if (VBOX_FAILURE(rrc) || VBOX_FAILURE(reqFull->rc))
478 {
479 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: request execution failed!\n"));
480 rc = VBOX_FAILURE(rrc) ? -RTErrConvertToErrno(rrc)
481 : -RTErrConvertToErrno(reqFull->rc);
482 }
483 else
484 {
485 /* success, copy the result data to user space */
486 if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
487 {
488 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: error copying request result to user space!\n"));
489 rc = -EFAULT;
490 }
491 }
492 }
493 if (NULL != reqFull)
494 VbglGRFree(reqFull);
495 IOCTL_VMM_EXIT(arg);
496 }
497 else if ( ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
498 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
499 || (cmd == IOCTL_VBOXGUEST_HGCM_CALL))
500 {
501 /* This IOCTL allows the guest to make an HGCM call from user space. The
502 OS-independant part of the Guest Additions already contain code for making an
503 HGCM call from the guest, but this code assumes that the call is made from the
504 kernel's address space. So before calling it, we have to copy all parameters
505 to the HGCM call from user space to kernel space and reconstruct the structures
506 passed to the call (which include pointers to other memory) inside the kernel's
507 address space. */
508 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
509 rc = vbox_ioctl_hgcm_call(arg, vboxDev);
510 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
511 }
512 else
513 {
514 switch (cmd) {
515 case IOCTL_VBOXGUEST_WAITEVENT:
516 IOCTL_ENTRY("IOCTL_VBOXGUEST_WAITEVENT", arg);
517 rc = vboxadd_wait_event((void *) arg);
518 IOCTL_EXIT("IOCTL_VBOXGUEST_WAITEVENT", arg);
519 break;
520 case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
521 IOCTL_ENTRY("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
522 ++vboxDev->u32GuestInterruptions;
523 IOCTL_EXIT("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
524 break;
525 case IOCTL_VBOXGUEST_HGCM_CONNECT:
526 IOCTL_ENTRY("IOCTL_VBOXGUEST_HGCM_CONNECT", arg);
527 rc = vboxadd_hgcm_connect(filp, arg);
528 IOCTL_EXIT("IOCTL_VBOXGUEST_HGCM_CONNECT", arg);
529 break;
530 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
531 {
532 VBoxGuestFilterMaskInfo info;
533 IOCTL_ENTRY("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
534 if (copy_from_user((void*)&info, (void*)arg, sizeof(info)))
535 {
536 LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
537 rc = -EFAULT;
538 break;
539 }
540 rc = -RTErrConvertToErrno(vboxadd_control_filter_mask(&info));
541 IOCTL_EXIT("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
542 break;
543 }
544 default:
545 LogRelFunc(("unknown command: %x\n", cmd));
546 rc = -EINVAL;
547 break;
548 }
549 }
550 return rc;
551}
552
553#ifdef DEBUG
554static ssize_t
555vboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
556{
557 if (count != 8 || *loff != 0)
558 {
559 return -EINVAL;
560 }
561 *(uint32_t *) buf = vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents;
562 *(uint32_t *) (buf + 4) = vboxDev->u32Events;
563 *loff += 8;
564 return 8;
565}
566#endif
567
568/** strategy handlers (file operations) */
569static struct file_operations vbox_fops =
570{
571 .owner = THIS_MODULE,
572 .open = vboxadd_open,
573 .release = vboxadd_release,
574 .ioctl = vboxadd_ioctl,
575#ifdef DEBUG
576 .read = vboxadd_read,
577#endif
578 .llseek = no_llseek
579};
580
581#ifndef IRQ_RETVAL
582/* interrupt handlers in 2.4 kernels don't return anything */
583# define irqreturn_t void
584# define IRQ_RETVAL(n)
585#endif
586
587/**
588 * vboxadd_irq_handler
589 *
590 * Interrupt handler
591 *
592 * @returns scsi error code
593 * @param irq Irq number
594 * @param dev_id Irq handler parameter
595 * @param regs Regs
596 *
597 */
598#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
599static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
600#else
601static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
602#endif
603{
604 int fIRQTaken = 0;
605 int rcVBox;
606
607#ifdef IRQ_DEBUG
608 Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
609 vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
610#endif
611
612 /* check if IRQ was asserted by VBox */
613 if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
614 {
615#ifdef IRQ_DEBUG
616 Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
617 vboxDev->irqAckRequest->events));
618#endif
619
620 /* make a copy of the event mask */
621 rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
622 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(vboxDev->irqAckRequest->header.rc))
623 {
624 if (RT_LIKELY (vboxDev->irqAckRequest->events))
625 {
626 vboxDev->u32Events |= vboxDev->irqAckRequest->events;
627 wake_up (&vboxDev->eventq);
628 }
629 }
630 else
631 {
632 /* impossible... */
633 LogRelFunc(("IRQ was not acknowledged! rc = %Vrc, header.rc = %Vrc\n",
634 rcVBox, vboxDev->irqAckRequest->header.rc));
635 BUG ();
636 }
637
638 /* it was ours! */
639 fIRQTaken = 1;
640 }
641#ifdef IRQ_DEBUG
642 else
643 {
644 Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
645 vboxDev->pVMMDevMemory,
646 vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
647 vboxDev->u32Events));
648 }
649#endif
650 /* it was ours */
651 return IRQ_RETVAL(fIRQTaken);
652}
653
654/**
655 * Helper function to reserve a fixed kernel address space window
656 * and tell the VMM that it can safely put its hypervisor there.
657 * This function might fail which is not a critical error.
658 */
659static int vboxadd_reserve_hypervisor(void)
660{
661 VMMDevReqHypervisorInfo *req = NULL;
662 int rcVBox;
663
664 /* allocate request structure */
665 rcVBox = VbglGRAlloc(
666 (VMMDevRequestHeader**)&req,
667 sizeof(VMMDevReqHypervisorInfo),
668 VMMDevReq_GetHypervisorInfo
669 );
670 if (VBOX_FAILURE(rcVBox))
671 {
672 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Vrc\n", rcVBox));
673 goto bail_out;
674 }
675 /* query the hypervisor information */
676 rcVBox = VbglGRPerform(&req->header);
677 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
678 {
679 /* are we supposed to make a reservation? */
680 if (req->hypervisorSize)
681 {
682 /** @todo repeat this several times until we get an address the host likes */
683
684 void *hypervisorArea;
685 /* reserve another 4MB because the start needs to be 4MB aligned */
686 uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
687 /* perform a fictive IO space mapping */
688 hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
689 if (hypervisorArea)
690 {
691 /* communicate result to VMM, align at 4MB */
692 req->hypervisorStart = (vmmDevHypPtr)RT_ALIGN_P(hypervisorArea, 0x400000);
693 req->header.requestType = VMMDevReq_SetHypervisorInfo;
694 req->header.rc = VERR_GENERAL_FAILURE;
695 rcVBox = VbglGRPerform(&req->header);
696 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
697 {
698 /* store mapping for future unmapping */
699 vboxDev->hypervisorStart = hypervisorArea;
700 vboxDev->hypervisorSize = hypervisorSize;
701 }
702 else
703 {
704 LogRelFunc(("failed to set hypervisor region! rc = %Vrc, header.rc = %Vrc\n",
705 rcVBox, req->header.rc));
706 goto bail_out;
707 }
708 }
709 else
710 {
711 LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
712 goto bail_out;
713 }
714 }
715 }
716 else
717 {
718 LogRelFunc(("failed to query hypervisor info! rc = %Vrc, header.rc = %Vrc\n",
719 rcVBox, req->header.rc));
720 goto bail_out;
721 }
722 /* successful return */
723 VbglGRFree(&req->header);
724 return 0;
725bail_out:
726 /* error return */
727 if (req)
728 VbglGRFree(&req->header);
729 return 1;
730}
731
732/**
733 * Helper function to free the hypervisor address window
734 *
735 */
736static int vboxadd_free_hypervisor(void)
737{
738 VMMDevReqHypervisorInfo *req = NULL;
739 int rcVBox;
740
741 /* allocate request structure */
742 rcVBox = VbglGRAlloc(
743 (VMMDevRequestHeader**)&req,
744 sizeof(VMMDevReqHypervisorInfo),
745 VMMDevReq_SetHypervisorInfo
746 );
747 if (VBOX_FAILURE(rcVBox))
748 {
749 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Vrc\n", rcVBox));
750 goto bail_out;
751 }
752 /* reset the hypervisor information */
753 req->hypervisorStart = 0;
754 req->hypervisorSize = 0;
755 rcVBox = VbglGRPerform(&req->header);
756 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
757 {
758 /* now we can free the associated IO space mapping */
759 iounmap(vboxDev->hypervisorStart);
760 vboxDev->hypervisorStart = 0;
761 }
762 else
763 {
764 LogRelFunc(("failed to reset hypervisor info! rc = %Vrc, header.rc = %Vrc\n",
765 rcVBox, req->header.rc));
766 goto bail_out;
767 }
768 return 0;
769
770 bail_out:
771 if (req)
772 VbglGRFree(&req->header);
773 return 1;
774}
775
776/**
777 * Helper to free resources
778 *
779 */
780static void free_resources(void)
781{
782 if (vboxDev)
783 {
784 if (vboxDev->hypervisorStart)
785 {
786 vboxadd_free_hypervisor();
787 }
788 if (vboxDev->irqAckRequest)
789 {
790 VbglGRFree(&vboxDev->irqAckRequest->header);
791 VbglTerminate();
792 }
793 if (vboxDev->pVMMDevMemory)
794 iounmap(vboxDev->pVMMDevMemory);
795 if (vboxDev->vmmdevmem)
796 release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
797 if (vboxDev->irq)
798 free_irq(vboxDev->irq, vboxDev);
799 kfree(vboxDev);
800 vboxDev = NULL;
801 }
802}
803
804#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
805#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
806#define PCI_DEV_PUT(x) pci_dev_put(x)
807#else
808#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
809#define PCI_DEV_PUT(x)
810#endif
811
812/**
813 * Module initialization
814 *
815 */
816static __init int init(void)
817{
818 int err;
819 int rcVBox;
820 struct pci_dev *pcidev = NULL;
821 VMMDevReportGuestInfo *infoReq = NULL;
822
823 if (vboxadd_cmc_init ())
824 {
825 printk (KERN_ERR "vboxadd: could not init cmc.\n");
826 return -ENODEV;
827 }
828
829 /*
830 * Detect PCI device
831 */
832 pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
833 if (!pcidev)
834 {
835 printk(KERN_ERR "vboxadd: VirtualBox PCI device not found.\n");
836 return -ENODEV;
837 }
838
839 err = pci_enable_device (pcidev);
840 if (err)
841 {
842 Log(("vboxadd: could not enable device: %d\n", err));
843 PCI_DEV_PUT(pcidev);
844 return -ENODEV;
845 }
846
847 LogRel(("Starting VirtualBox version %s Guest Additions\n",
848 VBOX_VERSION_STRING));
849 /* register a character device */
850 err = register_chrdev(vbox_major, "vboxadd", &vbox_fops);
851 if (err < 0 || ((vbox_major & err) || (!vbox_major && !err)))
852 {
853 LogRelFunc(("register_chrdev failed: vbox_major: %d, err = %d\n",
854 vbox_major, err));
855 PCI_DEV_PUT(pcidev);
856 return -ENODEV;
857 }
858 /* if no major code was set, take the return value */
859 if (!vbox_major)
860 vbox_major = err;
861
862 /* allocate and initialize device extension */
863 vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
864 if (!vboxDev)
865 {
866 LogRelFunc(("cannot allocate device!\n"));
867 err = -ENOMEM;
868 goto fail;
869 }
870 memset(vboxDev, 0, sizeof(*vboxDev));
871 snprintf(vboxDev->name, sizeof(vboxDev->name), "vboxadd");
872
873 /* get the IO port region */
874 vboxDev->io_port = pci_resource_start(pcidev, 0);
875
876 /* get the memory region */
877 vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
878 vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
879
880 /* all resources found? */
881 if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
882 {
883 LogRelFunc(("did not find expected hardware resources!\n"));
884 goto fail;
885 }
886
887 /* request ownership of adapter memory */
888 if (request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size, "vboxadd") == 0)
889 {
890 LogRelFunc(("failed to request adapter memory!\n"));
891 goto fail;
892 }
893
894 /* map adapter memory into kernel address space and check version */
895 vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
896 vboxDev->vmmdevmem_size);
897 if (!vboxDev->pVMMDevMemory)
898 {
899 LogRelFunc(("ioremap failed\n"));
900 goto fail;
901 }
902
903 if (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
904 {
905 LogRelFunc(("invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
906 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
907 goto fail;
908 }
909
910 /* initialize VBGL subsystem */
911 rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
912 if (VBOX_FAILURE(rcVBox))
913 {
914 LogRelFunc(("could not initialize VBGL subsystem! rc = %Vrc\n", rcVBox));
915 goto fail;
916 }
917
918 /* report guest information to host, this must be done as the very first request */
919 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
920 sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
921 if (VBOX_FAILURE(rcVBox))
922 {
923 LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
924 goto fail;
925 }
926
927 /* report guest version to host, the VMMDev requires that to be done first */
928 infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
929#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
930 infoReq->guestInfo.osType = VBOXOSTYPE_Linux26;
931#else
932 infoReq->guestInfo.osType = VBOXOSTYPE_Linux24;
933#endif
934 rcVBox = VbglGRPerform(&infoReq->header);
935 if (VBOX_FAILURE(rcVBox) || VBOX_FAILURE(infoReq->header.rc))
936 {
937 LogRelFunc(("error reporting guest info to host! rc = %Vrc, header.rc = %Vrc\n",
938 rcVBox, infoReq->header.rc));
939 VbglGRFree(&infoReq->header);
940 goto fail;
941 }
942 VbglGRFree(&infoReq->header);
943
944 /* Unset the graphics capability until/unless X is loaded. */
945 /** @todo check the error code once we bump the additions version.
946 For now we ignore it for compatibility with older hosts. */
947 {
948 VMMDevReqGuestCapabilities2 *vmmreqGuestCaps;
949
950
951 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vmmreqGuestCaps,
952 sizeof(VMMDevReqGuestCapabilities2),
953 VMMDevReq_SetGuestCapabilities);
954 if (VBOX_FAILURE(rcVBox))
955 {
956 LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
957 goto fail;
958 }
959 vmmreqGuestCaps->u32OrMask = 0;
960 vmmreqGuestCaps->u32NotMask = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
961 rcVBox = VbglGRPerform(&vmmreqGuestCaps->header);
962 VbglGRFree(&vmmreqGuestCaps->header);
963 if (RT_FAILURE(rcVBox))
964 goto fail;
965 }
966
967 /* perform hypervisor address space reservation */
968 if (vboxadd_reserve_hypervisor())
969 {
970 /* we just ignore the error, no address window reservation, non fatal */
971 }
972
973 /* allocate a VMM request structure for use in the ISR */
974 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
975 sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
976 if (VBOX_FAILURE(rcVBox))
977 {
978 LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
979 goto fail;
980 }
981
982 /* get ISR */
983 err = request_irq(pcidev->irq, vboxadd_irq_handler,
984#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
985 IRQF_SHARED,
986#else
987 SA_SHIRQ,
988#endif
989 "vboxadd", vboxDev);
990 if (err)
991 {
992 LogRelFunc(("could not request IRQ %d, err: %d\n", pcidev->irq, err));
993 goto fail;
994 }
995 vboxDev->irq = pcidev->irq;
996
997 init_waitqueue_head (&vboxDev->eventq);
998
999 /* some useful information for the user but don't show this on the console */
1000 LogRel(("VirtualBox device settings: major %d, IRQ %d, "
1001 "I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
1002 "hypervisor window at 0x%p (size 0x%x)\n",
1003 vbox_major, vboxDev->irq, vboxDev->io_port,
1004 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1005 vboxDev->hypervisorStart, vboxDev->hypervisorSize));
1006 Log(("Successfully loaded VirtualBox device version "
1007 VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")\n"));
1008
1009 /* successful return */
1010 PCI_DEV_PUT(pcidev);
1011 return 0;
1012
1013fail:
1014 PCI_DEV_PUT(pcidev);
1015 free_resources();
1016 unregister_chrdev(vbox_major, "vboxadd");
1017 return err;
1018}
1019
1020/**
1021 * Module termination
1022 *
1023 */
1024static __exit void fini(void)
1025{
1026 unregister_chrdev(vbox_major, "vboxadd");
1027 free_resources();
1028 vboxadd_cmc_fini ();
1029}
1030
1031module_init(init);
1032module_exit(fini);
1033
1034/* PCI hotplug structure */
1035static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
1036{
1037 {
1038 .vendor = VMMDEV_VENDORID,
1039 .device = VMMDEV_DEVICEID
1040 },
1041 {
1042 /* empty entry */
1043 }
1044};
1045MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
1046
1047int __gxx_personality_v0 = 0xdeadbeef;
1048
1049/*
1050 * Local Variables:
1051 * c-mode: bsd
1052 * indent-tabs-mode: nil
1053 * c-plusplus: evil
1054 * End:
1055 */
Note: See TracBrowser for help on using the repository browser.

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