VirtualBox

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

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

Guest Additions (Linux): replaced compiler_assert by AssertCompiler in the kernel module

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