VirtualBox

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

Last change on this file since 4745 was 4745, checked in by vboxsync, 18 years ago

Linux Additions smoke test fix

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