Index: /trunk/src/VBox/Additions/linux/module/vboxmod.c
===================================================================
--- /trunk/src/VBox/Additions/linux/module/vboxmod.c	(revision 1618)
+++ /trunk/src/VBox/Additions/linux/module/vboxmod.c	(revision 1619)
@@ -244,4 +244,163 @@
             VbglGRFree(reqFull);
             break;
+        }
+
+        case IOCTL_VBOXGUEST_HGCM_CALL:
+        {
+            VBoxGuestHGCMCallInfo callHeader, *hgcmR3, *hgcmR0;
+            uint8_t *pu8PointerData;
+            size_t cbPointerData = 0, offPointerData = 0;
+            int i, rc;
+
+            compiler_assert(_IOC_SIZE(IOCTL_VBOXGUEST_HGCM_CALL) == sizeof(VBoxGuestHGCMCallInfo));
+            if (copy_from_user(&callHeader, (void*)arg, _IOC_SIZE(cmd)))
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_from_user failed!\n");
+                return -EFAULT;
+            }
+            hgcmR3 = kmalloc(sizeof(*hgcmR3) + callHeader.cParms * sizeof(HGCMFunctionParameter),
+                               GFP_KERNEL);
+            if (!hgcmR3)
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: cannot allocate memory!\n");
+                return -ENOMEM;
+            }
+            if (copy_from_user(hgcmR3, (void*)arg,
+                               sizeof(*hgcmR3) +   callHeader.cParms
+                                                 * sizeof(HGCMFunctionParameter)))
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_from_user failed!\n");
+                kfree(hgcmR3);
+                return -EFAULT;
+            }
+            hgcmR0 = kmalloc(sizeof(*hgcmR0) + callHeader.cParms * sizeof(HGCMFunctionParameter),
+                               GFP_KERNEL);
+            if (!hgcmR0)
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: cannot allocate memory!\n");
+                kfree(hgcmR3);
+                return -ENOMEM;
+            }
+            hgcmR0->u32ClientID = callHeader.u32ClientID;
+            hgcmR0->u32Function = callHeader.u32Function;
+            hgcmR0->cParms = callHeader.cParms;
+            /* Calculate the total size of pointer space.  Will normally be for a single pointer */
+            for (i = 0; i < callHeader.cParms; ++i)
+            {
+                switch (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type)
+                {
+                case VMMDevHGCMParmType_32bit:
+                case VMMDevHGCMParmType_64bit:
+                    break;
+                case VMMDevHGCMParmType_LinAddr:
+                case VMMDevHGCMParmType_LinAddr_In:
+                case VMMDevHGCMParmType_LinAddr_Out:
+                    cbPointerData += VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size;
+                    break;
+                default:
+                    elog("IOCTL_VBOXGUEST_HGCM_CALL: unsupported or unknown parameter type\n");
+                    kfree(hgcmR3);
+                    kfree(hgcmR0);
+                    return -EINVAL;
+                }
+            }
+            pu8PointerData = kmalloc (cbPointerData, GFP_KERNEL);
+            /* Reconstruct the pointer parameter data in kernel space */
+            if (pu8PointerData == NULL)
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: out of memory allocating %d bytes for pointer data\n",
+                       cbPointerData);
+                kfree(hgcmR3);
+                kfree(hgcmR0);
+                return -ENOMEM;
+            }
+            for (i = 0; i < callHeader.cParms; ++i)
+            {
+                VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].type
+                    = VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type;
+                if (   (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type == VMMDevHGCMParmType_LinAddr)
+                    || (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type
+                            == VMMDevHGCMParmType_LinAddr_In))
+                {
+                    /* We are sending data to the host or sending and reading. */
+                    if (copy_from_user(&pu8PointerData[offPointerData],
+                                       VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.u.linearAddr,
+                                       VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size))
+                    {
+                        elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_from_user failed!\n");
+                        rc = -EFAULT;
+                        goto hgcm_exit;
+                    }
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.u.linearAddr
+                        = &pu8PointerData[offPointerData];
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.size
+                        = VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size;
+                    offPointerData += VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size;
+                }
+                else if (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type
+                             == VMMDevHGCMParmType_LinAddr_Out)
+                {
+                    /* We are reading data from the host */
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.u.linearAddr
+                        = &pu8PointerData[offPointerData];
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.size
+                        = VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size;
+                    offPointerData += VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size;
+                }
+                else
+                {
+                    /* If it is not a pointer, then it is a 32bit or 64bit value */
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.value64
+                        = VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.value64;
+                }
+            }
+            /* Internal VBoxGuest IOCTL interface */
+            rc = vboxadd_cmc_call(vboxDev, IOCTL_VBOXGUEST_HGCM_CALL, hgcmR0);
+            if (rc != VINF_SUCCESS)
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: internal ioctl call failed, rc=%d\n", rc);
+                /** @todo We need a function to convert VBox error codes back to Linux. */
+                rc = -EINVAL;
+                goto hgcm_exit;
+            }
+            for (i = 0; i < callHeader.cParms; ++i)
+            {
+                if (   (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type == VMMDevHGCMParmType_LinAddr)
+                    || (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type
+                            == VMMDevHGCMParmType_LinAddr_Out))
+                {
+                    /* We are sending data to the host or sending and reading. */
+                    if (copy_to_user(VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.u.linearAddr,
+                                     VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.u.linearAddr,
+                                     VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.size))
+                    {
+                        elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_to_user failed!\n");
+                        rc = -EFAULT;
+                        goto hgcm_exit;
+                    }
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.Pointer.size
+                        = VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.Pointer.size;
+                }
+                else if (VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].type
+                             != VMMDevHGCMParmType_LinAddr_Out)
+                {
+                    /* If it is not a pointer, then it is a 32bit or 64bit value */
+                    VBOXGUEST_HGCM_CALL_PARMS(hgcmR3)[i].u.value64
+                        = VBOXGUEST_HGCM_CALL_PARMS(hgcmR0)[i].u.value64;
+                }
+            }
+            hgcmR3->result = hgcmR0->result;
+            if (copy_to_user((void*)arg, hgcmR3,
+                             sizeof(*hgcmR3) + callHeader.cParms * sizeof(HGCMFunctionParameter)))
+            {
+                elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_to_user failed!\n");
+                rc = -EFAULT;
+                goto hgcm_exit;
+            }
+        hgcm_exit:
+            kfree(hgcmR3);
+            kfree(hgcmR0);
+            kfree(pu8PointerData);
+            return rc;
         }
 
Index: /trunk/src/VBox/Additions/linux/module/vboxmod.h
===================================================================
--- /trunk/src/VBox/Additions/linux/module/vboxmod.h	(revision 1618)
+++ /trunk/src/VBox/Additions/linux/module/vboxmod.h	(revision 1619)
@@ -67,4 +67,14 @@
 if (n >= vboxadd_verbosity) printk (KERN_DEBUG "vboxadd: " __VA_ARGS__)
 
+#define compiler_assert(val) \
+do { \
+switch(0) { \
+case 0: \
+case (val): \
+default: \
+break; \
+} \
+} while(0);
+
 extern int vboxadd_cmc_init (void);
 extern void vboxadd_cmc_fini (void);
