VirtualBox

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

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

Guest Additions (Linux kernel module): logging change

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