VirtualBox

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

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

vbox version visible in additions modules

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