VirtualBox

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

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

Guest Additions (Linux): fixed VBOXGUEST_IOCTL_WAITEVENT ioctl in kernel module

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