VirtualBox

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

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

likely isn't available in all kernels (like 2.4.18), so stick to what we know is around (IPRT).

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