VirtualBox

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

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

Fixes to the Linux additions - use and export functions from the runtime

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