VirtualBox

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

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

Additions/Linux: removed some debug logging

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