VirtualBox

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

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

Linux kernel module put_user fix. Code is unused but would not compile on certain compilers.

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