VirtualBox

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

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

Additions (Linux): compiler assertions 2 - no, it was my fault

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 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 vboxadd_unregister_all_hgcm_connections(filp);
239 return 0;
240}
241
242static void
243vboxadd_wait_for_event (VBoxGuestWaitEventInfo * info)
244{
245 long timeleft;
246 uint32_t cInterruptions = vboxDev->u32GuestInterruptions;
247 uint32_t in_mask = info->u32EventMaskIn;
248
249 info->u32Result = VBOXGUEST_WAITEVENT_OK;
250 timeleft = vbox_wait_event_interruptible_timeout
251 (vboxDev->eventq,
252 (vboxDev->u32Events & in_mask)
253 || (vboxDev->u32GuestInterruptions != cInterruptions),
254 msecs_to_jiffies (info->u32TimeoutIn));
255 if (vboxDev->u32GuestInterruptions != cInterruptions) {
256 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
257 }
258 if (timeleft < 0) {
259 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
260 }
261 if (timeleft == 0) {
262 info->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
263 }
264 info->u32EventFlagsOut = vboxDev->u32Events & in_mask;
265 vboxDev->u32Events &= ~in_mask;
266}
267
268/**
269 * IOCtl handler - wait for an event from the host.
270 *
271 * @returns Linux kernel return code
272 * @param ptr User space pointer to a structure describing the event
273 */
274static int vboxadd_wait_event(void *ptr)
275{
276 int rc = 0;
277 VBoxGuestWaitEventInfo info;
278
279 if (copy_from_user (&info, ptr, sizeof (info))) {
280 LogRelFunc (("IOCTL_VBOXGUEST_WAITEVENT: can not get event info\n"));
281 rc = -EFAULT;
282 }
283
284 if (0 == rc) {
285 vboxadd_wait_for_event (&info);
286
287 if (copy_to_user (ptr, &info, sizeof (info))) {
288 LogRelFunc (("IOCTL_VBOXGUEST_WAITEVENT: can not put out_mask\n"));
289 rc = -EFAULT;
290 }
291 }
292 return 0;
293}
294
295/**
296 * IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
297 * succeeds, it will be associated with the file structure used to open it, so that it will be
298 * automatically shut down again if the file descriptor is closed.
299 *
300 * @returns 0 on success, or a Linux kernel errno value
301 * @param filp the file structure with which the application opened the driver
302 * @param userspace_info userspace pointer to the hgcm connection information
303 * (VBoxGuestHGCMConnectInfo structure)
304 * @retval userspace_info userspace pointer to the hgcm connection information
305 */
306static int vboxadd_hgcm_connect(struct file *filp, unsigned long userspace_info)
307{
308 VBoxGuestHGCMConnectInfo info;
309 VBoxGuestHGCMDisconnectInfo infoDisconnect;
310 int rc = 0, rcVBox;
311
312 if (0 != copy_from_user ((void *)&info, (void *)userspace_info, sizeof (info))) {
313 LogRelFunc (("IOCTL_VBOXGUEST_HGCM_CONNECT: can not get connection info\n"));
314 return -EFAULT;
315 }
316 rcVBox = vboxadd_cmc_call(vboxDev, IOCTL_VBOXGUEST_HGCM_CONNECT, &info);
317 if (RT_FAILURE(rcVBox) || (RT_FAILURE(info.result))) {
318 LogRelFunc(("IOCTL_VBOXGUEST_HGCM_CONNECT: hgcm connection failed. internal ioctl result %Vrc, hgcm result %Vrc\n", rcVBox, info.result));
319 rc = RT_FAILURE(rcVBox) ? -RTErrConvertToErrno(rcVBox)
320 : -RTErrConvertToErrno(info.result);
321 } else {
322 /* Register that the connection is associated with this file pointer. */
323 LogRelFunc(("Connected, client ID %u\n", info.u32ClientID));
324 rc = vboxadd_register_hgcm_connection(info.u32ClientID, filp);
325 if (0 != rc) {
326 LogRelFunc(("IOCTL_VBOXGUEST_HGCM_CONNECT: failed to register the HGCM connection\n"));
327 } else {
328 if (copy_to_user ((void *)userspace_info, (void *)&info,
329 sizeof(info))) {
330 LogRelFunc (("IOCTL_VBOXGUEST_HGCM_CONNECT: failed to return the connection structure\n"));
331 rc = -EFAULT;
332 } else {
333 return 0;
334 }
335 /* Unregister again, as we didn't get as far as informing userspace. */
336 vboxadd_unregister_hgcm_connection_no_close(info.u32ClientID);
337 }
338 /* And disconnect the hgcm connection again, as we told userspace it failed. */
339 infoDisconnect.u32ClientID = info.u32ClientID;
340 vboxadd_cmc_call(vboxDev, IOCTL_VBOXGUEST_HGCM_DISCONNECT,
341 &infoDisconnect);
342 }
343 return rc;
344}
345
346/**
347 * IOCTL handler
348 *
349 */
350static int vboxadd_ioctl(struct inode *inode, struct file *filp,
351 unsigned int cmd, unsigned long arg)
352{
353 int rc = 0;
354
355 switch (cmd) {
356 case IOCTL_VBOXGUEST_WAITEVENT:
357 rc = vboxadd_wait_event((void *) arg);
358 break;
359
360 case VBOXGUEST_IOCTL_WAITEVENT_INTERRUPT_ALL:
361 ++vboxDev->u32GuestInterruptions;
362 break;
363
364 case IOCTL_VBOXGUEST_VMMREQUEST: {
365 VMMDevRequestHeader reqHeader;
366 VMMDevRequestHeader *reqFull = NULL;
367 size_t cbRequestSize;
368 size_t cbVanillaRequestSize;
369 int rc;
370
371 compiler_assert(sizeof(VMMDevRequestHeader) == _IOC_SIZE(IOCTL_VBOXGUEST_VMMREQUEST));
372 if (copy_from_user(&reqHeader, (void*)arg, _IOC_SIZE(cmd)))
373 {
374 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: copy_from_user failed for vmm request!\n"));
375 return -EFAULT;
376 }
377 /* get the request size */
378 cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
379 if (!cbVanillaRequestSize)
380 {
381 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: invalid request type: %d\n",
382 reqHeader.requestType));
383 return -EINVAL;
384 }
385
386 cbRequestSize = reqHeader.size;
387 if (cbRequestSize < cbVanillaRequestSize)
388 {
389 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
390 cbRequestSize,
391 cbVanillaRequestSize,
392 reqHeader.requestType));
393 return -EINVAL;
394 }
395 /* request storage for the full request */
396 rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
397 if (VBOX_FAILURE(rc))
398 {
399 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
400 return -EFAULT;
401 }
402 /* now get the full request */
403 if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
404 {
405 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: failed to fetch full request from user space!\n"));
406 VbglGRFree(reqFull);
407 return -EFAULT;
408 }
409
410 /* now issue the request */
411 rc = VbglGRPerform(reqFull);
412
413 /* asynchronous processing? */
414 if (rc == VINF_HGCM_ASYNC_EXECUTE)
415 {
416 VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
417 wait_event (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
418 rc = reqFull->rc;
419 }
420
421 /* failed? */
422 if (VBOX_FAILURE(rc) || VBOX_FAILURE(reqFull->rc))
423 {
424 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: request execution failed!\n"));
425 VbglGRFree(reqFull);
426 return VBOX_FAILURE(rc) ? -RTErrConvertToErrno(rc)
427 : -RTErrConvertToErrno(reqFull->rc);
428 }
429 else
430 {
431 /* success, copy the result data to user space */
432 if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
433 {
434 LogRelFunc(("IOCTL_VBOXGUEST_VMMREQUEST: error copying request result to user space!\n"));
435 VbglGRFree(reqFull);
436 return -EFAULT;
437 }
438 }
439 VbglGRFree(reqFull);
440 break;
441 }
442
443 case IOCTL_VBOXGUEST_HGCM_CALL:
444 /* This IOCTL allows the guest to make an HGCM call from user space. The
445 OS-independant part of the Guest Additions already contain code for making an
446 HGCM call from the guest, but this code assumes that the call is made from the
447 kernel's address space. So before calling it, we have to copy all parameters
448 to the HGCM call from user space to kernel space and reconstruct the structures
449 passed to the call (which include pointers to other memory) inside the kernel's
450 address space. */
451 rc = vbox_ioctl_hgcm_call(arg, vboxDev);
452 break;
453
454 case IOCTL_VBOXGUEST_HGCM_CONNECT:
455 rc = vboxadd_hgcm_connect(filp, arg);
456 break;
457
458 default:
459 LogRelFunc(("unknown command: %x\n", cmd));
460 rc = -EINVAL;
461 break;
462 }
463 return rc;
464}
465
466#ifdef DEBUG
467static ssize_t
468vboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
469{
470 if (count != 8 || *loff != 0)
471 {
472 return -EINVAL;
473 }
474 *(uint32_t *) buf = vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents;
475 *(uint32_t *) (buf + 4) = vboxDev->u32Events;
476 *loff += 8;
477 return 8;
478}
479#endif
480
481/** strategy handlers (file operations) */
482static struct file_operations vbox_fops =
483{
484 .owner = THIS_MODULE,
485 .open = vboxadd_open,
486 .release = vboxadd_release,
487 .ioctl = vboxadd_ioctl,
488#ifdef DEBUG
489 .read = vboxadd_read,
490#endif
491 .llseek = no_llseek
492};
493
494#ifndef IRQ_RETVAL
495/* interrupt handlers in 2.4 kernels don't return anything */
496# define irqreturn_t void
497# define IRQ_RETVAL(n)
498#endif
499
500/**
501 * vboxadd_irq_handler
502 *
503 * Interrupt handler
504 *
505 * @returns scsi error code
506 * @param irq Irq number
507 * @param dev_id Irq handler parameter
508 * @param regs Regs
509 *
510 */
511#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
512static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
513#else
514static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
515#endif
516{
517 int fIRQTaken = 0;
518 int rcVBox;
519
520#ifdef IRQ_DEBUG
521 printk ("%s: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
522 __func__, vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->fHaveEvents);
523#endif
524
525 /* check if IRQ was asserted by VBox */
526 if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
527 {
528#ifdef IRQ_DEBUG
529 printk(KERN_INFO "vboxadd: got IRQ with event mask 0x%x\n",
530 vboxDev->pVMMDevMemory->u32HostEvents);
531#endif
532
533 /* make a copy of the event mask */
534 rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
535 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(vboxDev->irqAckRequest->header.rc))
536 {
537 if (RT_LIKELY (vboxDev->irqAckRequest->events))
538 {
539 vboxDev->u32Events |= vboxDev->irqAckRequest->events;
540 wake_up (&vboxDev->eventq);
541 }
542 }
543 else
544 {
545 /* impossible... */
546 LogRelFunc(("IRQ was not acknowledged! rc = %Vrc, header.rc = %Vrc\n",
547 rcVBox, vboxDev->irqAckRequest->header.rc));
548 BUG ();
549 }
550
551 /* it was ours! */
552 fIRQTaken = 1;
553 }
554#ifdef IRQ_DEBUG
555 else
556 {
557 printk ("vboxadd: stale IRQ mem=%p events=%d devevents=%#x\n",
558 vboxDev->pVMMDevMemory,
559 vboxDev->pVMMDevMemory->fHaveEvents,
560 vboxDev->u32Events);
561 }
562#endif
563 /* it was ours */
564 return IRQ_RETVAL(fIRQTaken);
565}
566
567/**
568 * Helper function to reserve a fixed kernel address space window
569 * and tell the VMM that it can safely put its hypervisor there.
570 * This function might fail which is not a critical error.
571 */
572static int vboxadd_reserve_hypervisor(void)
573{
574 VMMDevReqHypervisorInfo *req = NULL;
575 int rcVBox;
576
577 /* allocate request structure */
578 rcVBox = VbglGRAlloc(
579 (VMMDevRequestHeader**)&req,
580 sizeof(VMMDevReqHypervisorInfo),
581 VMMDevReq_GetHypervisorInfo
582 );
583 if (VBOX_FAILURE(rcVBox))
584 {
585 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Vrc\n", rcVBox));
586 goto bail_out;
587 }
588 /* query the hypervisor information */
589 rcVBox = VbglGRPerform(&req->header);
590 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
591 {
592 /* are we supposed to make a reservation? */
593 if (req->hypervisorSize)
594 {
595 /** @todo repeat this several times until we get an address the host likes */
596
597 void *hypervisorArea;
598 /* reserve another 4MB because the start needs to be 4MB aligned */
599 uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
600 /* perform a fictive IO space mapping */
601 hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
602 if (hypervisorArea)
603 {
604 /* communicate result to VMM, align at 4MB */
605 req->hypervisorStart = (vmmDevHypPtr)RT_ALIGN_P(hypervisorArea, 0x400000);
606 req->header.requestType = VMMDevReq_SetHypervisorInfo;
607 req->header.rc = VERR_GENERAL_FAILURE;
608 rcVBox = VbglGRPerform(&req->header);
609 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
610 {
611 /* store mapping for future unmapping */
612 vboxDev->hypervisorStart = hypervisorArea;
613 vboxDev->hypervisorSize = hypervisorSize;
614 }
615 else
616 {
617 LogRelFunc(("failed to set hypervisor region! rc = %Vrc, header.rc = %Vrc\n",
618 rcVBox, req->header.rc));
619 goto bail_out;
620 }
621 }
622 else
623 {
624 LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
625 goto bail_out;
626 }
627 }
628 }
629 else
630 {
631 LogRelFunc(("failed to query hypervisor info! rc = %Vrc, header.rc = %Vrc\n",
632 rcVBox, req->header.rc));
633 goto bail_out;
634 }
635 /* successful return */
636 VbglGRFree(&req->header);
637 return 0;
638bail_out:
639 /* error return */
640 if (req)
641 VbglGRFree(&req->header);
642 return 1;
643}
644
645/**
646 * Helper function to free the hypervisor address window
647 *
648 */
649static int vboxadd_free_hypervisor(void)
650{
651 VMMDevReqHypervisorInfo *req = NULL;
652 int rcVBox;
653
654 /* allocate request structure */
655 rcVBox = VbglGRAlloc(
656 (VMMDevRequestHeader**)&req,
657 sizeof(VMMDevReqHypervisorInfo),
658 VMMDevReq_SetHypervisorInfo
659 );
660 if (VBOX_FAILURE(rcVBox))
661 {
662 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Vrc\n", rcVBox));
663 goto bail_out;
664 }
665 /* reset the hypervisor information */
666 req->hypervisorStart = 0;
667 req->hypervisorSize = 0;
668 rcVBox = VbglGRPerform(&req->header);
669 if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
670 {
671 /* now we can free the associated IO space mapping */
672 iounmap(vboxDev->hypervisorStart);
673 vboxDev->hypervisorStart = 0;
674 }
675 else
676 {
677 LogRelFunc(("failed to reset hypervisor info! rc = %Vrc, header.rc = %Vrc\n",
678 rcVBox, req->header.rc));
679 goto bail_out;
680 }
681 return 0;
682
683 bail_out:
684 if (req)
685 VbglGRFree(&req->header);
686 return 1;
687}
688
689/**
690 * Helper to free resources
691 *
692 */
693static void free_resources(void)
694{
695 if (vboxDev)
696 {
697 if (vboxDev->hypervisorStart)
698 {
699 vboxadd_free_hypervisor();
700 }
701 if (vboxDev->irqAckRequest)
702 {
703 VbglGRFree(&vboxDev->irqAckRequest->header);
704 VbglTerminate();
705 }
706 if (vboxDev->pVMMDevMemory)
707 iounmap(vboxDev->pVMMDevMemory);
708 if (vboxDev->vmmdevmem)
709 release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
710 if (vboxDev->irq)
711 free_irq(vboxDev->irq, vboxDev);
712 kfree(vboxDev);
713 vboxDev = NULL;
714 }
715}
716
717#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
718#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
719#define PCI_DEV_PUT(x) pci_dev_put(x)
720#else
721#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
722#define PCI_DEV_PUT(x)
723#endif
724
725/**
726 * Module initialization
727 *
728 */
729static __init int init(void)
730{
731 int err;
732 int rcVBox;
733 struct pci_dev *pcidev = NULL;
734 VMMDevReportGuestInfo *infoReq = NULL;
735
736 printk(KERN_INFO "vboxadd: initializing version %s\n", VBOX_VERSION_STRING);
737
738 if (vboxadd_cmc_init ())
739 {
740 printk (KERN_ERR "vboxadd: could not init cmc.\n");
741 return -ENODEV;
742 }
743
744 /*
745 * Detect PCI device
746 */
747 pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
748 if (!pcidev)
749 {
750 printk(KERN_ERR "vboxadd: VirtualBox PCI device not found.\n");
751 return -ENODEV;
752 }
753
754 err = pci_enable_device (pcidev);
755 if (err)
756 {
757 printk (KERN_ERR "vboxadd: could not enable device: %d\n", err);
758 PCI_DEV_PUT(pcidev);
759 return -ENODEV;
760 }
761
762 LogRel(("Starting VirtualBox version %s Guest Additions\n",
763 VBOX_VERSION_STRING));
764 /* register a character device */
765 err = register_chrdev(vbox_major, "vboxadd", &vbox_fops);
766 if (err < 0 || ((vbox_major & err) || (!vbox_major && !err)))
767 {
768 printk(KERN_ERR "vboxadd: register_chrdev failed: vbox_major: %d, err = %d\n",
769 vbox_major, err);
770 LogRelFunc(("register_chrdev failed: vbox_major: %d, err = %d\n",
771 vbox_major, err));
772 PCI_DEV_PUT(pcidev);
773 return -ENODEV;
774 }
775 /* if no major code was set, take the return value */
776 if (!vbox_major)
777 vbox_major = err;
778
779 /* allocate and initialize device extension */
780 vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
781 if (!vboxDev)
782 {
783 printk(KERN_ERR "vboxadd: cannot allocate device!\n");
784 LogRelFunc(("cannot allocate device!\n"));
785 err = -ENOMEM;
786 goto fail;
787 }
788 memset(vboxDev, 0, sizeof(*vboxDev));
789 snprintf(vboxDev->name, sizeof(vboxDev->name), "vboxadd");
790
791 /* get the IO port region */
792 vboxDev->io_port = pci_resource_start(pcidev, 0);
793
794 /* get the memory region */
795 vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
796 vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
797
798 /* all resources found? */
799 if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
800 {
801 printk(KERN_ERR "vboxadd: did not find expected hardware resources!\n");
802 LogRelFunc(("did not find expected hardware resources!\n"));
803 goto fail;
804 }
805
806 /* request ownership of adapter memory */
807 if (request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size, "vboxadd") == 0)
808 {
809 printk(KERN_ERR "vboxadd: failed to request adapter memory!\n");
810 LogRelFunc(("failed to request adapter memory!\n"));
811 goto fail;
812 }
813
814 /* map adapter memory into kernel address space and check version */
815 vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
816 vboxDev->vmmdevmem_size);
817 if (!vboxDev->pVMMDevMemory)
818 {
819 printk (KERN_ERR "vboxadd: ioremap failed\n");
820 LogRelFunc(("ioremap failed\n"));
821 goto fail;
822 }
823
824 if (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
825 {
826 printk(KERN_ERR
827 "vboxadd: invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
828 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION);
829 LogRelFunc(("invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
830 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
831 goto fail;
832 }
833
834 /* initialize VBGL subsystem */
835 rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
836 if (VBOX_FAILURE(rcVBox))
837 {
838 printk(KERN_ERR "vboxadd: could not initialize VBGL subsystem! rc = %d\n", rcVBox);
839 LogRelFunc(("could not initialize VBGL subsystem! rc = %Vrc\n", rcVBox));
840 goto fail;
841 }
842
843 /* report guest information to host, this must be done as the very first request */
844 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
845 sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
846 if (VBOX_FAILURE(rcVBox))
847 {
848 printk(KERN_ERR "vboxadd: could not allocate request structure! rc = %d\n", rcVBox);
849 LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
850 goto fail;
851 }
852
853 /* report guest version to host, the VMMDev requires that to be done first */
854 infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
855#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
856 infoReq->guestInfo.osType = OSTypeLinux26;
857#else
858 infoReq->guestInfo.osType = OSTypeLinux24;
859#endif
860 rcVBox = VbglGRPerform(&infoReq->header);
861 if (VBOX_FAILURE(rcVBox) || VBOX_FAILURE(infoReq->header.rc))
862 {
863 printk(KERN_ERR
864 "vboxadd: error reporting guest info to host! rc = %d, header.rc = %d\n",
865 rcVBox, infoReq->header.rc);
866 LogRelFunc(("error reporting guest info to host! rc = %Vrc, header.rc = %Vrc\n",
867 rcVBox, infoReq->header.rc));
868 VbglGRFree(&infoReq->header);
869 goto fail;
870 }
871 VbglGRFree(&infoReq->header);
872
873 /* perform hypervisor address space reservation */
874 if (vboxadd_reserve_hypervisor())
875 {
876 /* we just ignore the error, no address window reservation, non fatal */
877 }
878
879 /* allocate a VMM request structure for use in the ISR */
880 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
881 sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
882 if (VBOX_FAILURE(rcVBox))
883 {
884 printk(KERN_ERR "vboxadd: could not allocate request structure! rc = %d\n", rcVBox);
885 LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
886 goto fail;
887 }
888
889 /* get ISR */
890 err = request_irq(pcidev->irq, vboxadd_irq_handler,
891#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
892 IRQF_SHARED,
893#else
894 SA_SHIRQ,
895#endif
896 "vboxadd", vboxDev);
897 if (err)
898 {
899 printk(KERN_ERR "vboxadd: Could not request IRQ %d, err: %d\n", pcidev->irq, err);
900 LogRelFunc(("could not request IRQ %d, err: %d\n", pcidev->irq, err));
901 goto fail;
902 }
903 vboxDev->irq = pcidev->irq;
904
905 init_waitqueue_head (&vboxDev->eventq);
906
907 /* some useful information for the user */
908 printk(KERN_INFO
909 "vboxadd: major code: %d, using irq %d, "
910 "io port 0x%x, memory at 0x%x (size %d bytes), "
911 "hypervisor window at 0x%p (size 0x%x bytes)\n",
912 vbox_major, vboxDev->irq, vboxDev->io_port,
913 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
914 vboxDev->hypervisorStart, vboxDev->hypervisorSize);
915 LogRelFunc(("major code: %d, using irq %d, "
916 "io port 0x%x, memory at 0x%x (size %d bytes), "
917 "hypervisor window at 0x%p (size 0x%x bytes)\n",
918 vbox_major, vboxDev->irq, vboxDev->io_port,
919 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
920 vboxDev->hypervisorStart, vboxDev->hypervisorSize));
921
922 /* successful return */
923 PCI_DEV_PUT(pcidev);
924 return 0;
925
926fail:
927 PCI_DEV_PUT(pcidev);
928 free_resources();
929 unregister_chrdev(vbox_major, "vboxadd");
930 return err;
931}
932
933/**
934 * Module termination
935 *
936 */
937static __exit void fini(void)
938{
939 printk(KERN_DEBUG "vboxadd: unloading...\n");
940 LogRelFunc(("unloading...\n"));
941
942 unregister_chrdev(vbox_major, "vboxadd");
943 free_resources();
944 vboxadd_cmc_fini ();
945 printk(KERN_DEBUG "vboxadd: unloaded\n");
946 LogRelFunc(("unloaded\n"));
947}
948
949module_init(init);
950module_exit(fini);
951
952/* PCI hotplug structure */
953static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
954{
955 {
956 .vendor = VMMDEV_VENDORID,
957 .device = VMMDEV_DEVICEID
958 },
959 {
960 /* empty entry */
961 }
962};
963MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
964
965int __gxx_personality_v0 = 0xdeadbeef;
966
967/*
968 * Local Variables:
969 * c-mode: bsd
970 * indent-tabs-mode: nil
971 * c-plusplus: evil
972 * End:
973 */
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