VirtualBox

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

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

Linux additions: print VBox version and module interface version during module initialization; print information with DEBUG level not INFO level (thus prevent output to text console)

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