vboxmod.c revision b357df727b216b85d4517efecf466a7b14c2e80c
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * vboxadd -- VirtualBox Guest Additions for Linux
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Copyright (C) 2006-2007 Sun Microsystems, Inc.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * This file is part of VirtualBox Open Source Edition (OSE), as
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * available from http://www.virtualbox.org. This file is free software;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * you can redistribute it and/or modify it under the terms of the GNU
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * General Public License (GPL) as published by the Free Software
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Foundation, in version 2 as it comes in the "COPYING" file of the
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Clara, CA 95054 USA or visit http://www.sun.com if you need
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * additional information or have any questions.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/* #define IRQ_DEBUG */
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering/* #define IOCTL_DEBUG */
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Log(("IOCTL_ENTRY: %s, 0x%x\n", (name), (arg))); \
4349cd7c1d153c4ffa23cf1cff1644e0afa9bcf0Lennart Poettering Log(("IOCTL_EXIT: %s, 0x%x\n", (name), (arg))); \
4e731273edfe852a3eee2949cd20f49fd5b4f6d7Lennart Poettering# define IOCTL_ENTRY(name, arg) do { } while(0)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering# define IOCTL_EXIT(name, arg) do { } while(0)
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Log(("IOCTL_ENTRY: Log, 0x%x\n", (arg))); \
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering Log(("IOCTL_EXIT: Log, 0x%x\n", (arg))); \
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering# define IOCTL_LOG_ENTRY(arg) do { } while(0)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering# define IOCTL_LOG_EXIT(arg) do { } while(0)
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek Log(("IOCTL_ENTRY: VMMDevReq, 0x%x\n", (arg))); \
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek Log(("IOCTL_EXIT: VMMDevReq, 0x%x\n", (arg))); \
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart PoetteringMODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
b7def684941808600c344f0be7a2b9fcdda97e0fLennart PoetteringMODULE_VERSION(VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")");
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/* This is called by our assert macros to find out whether we want
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering to insert a breakpoint after the assertion. In kernel modules we
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering do not of course. */
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen return false;
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-SzmekEXPORT_SYMBOL(RTAssertDoBreakpoint);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/** device extension structure (we only support one device instance) */
64347fc2b983f33e7efb0fd2bb44e133fb9f30f4Tom Gundersen/** our file node major id (set dynamically) */
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poetteringstatic unsigned int vbox_major = CONFIG_VBOXADD_MAJOR;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poetteringstatic unsigned int vbox_major = 0;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal SchmidtDECLVBGL (void) vboxadd_cmc_close (void *opaque)
b3208b662948b51ff34e7b7752e28ec7a48708aeZbigniew Jędrzejewski-SzmekEXPORT_SYMBOL (vboxadd_cmc_open);
b3208b662948b51ff34e7b7752e28ec7a48708aeZbigniew Jędrzejewski-SzmekEXPORT_SYMBOL (vboxadd_cmc_close);
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen * Structure for keeping track of HGCM connections owned by user space processes, so that
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen * we can close the connection if a process does not clean up properly (for example if it
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen * was terminated too abruptly).
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt/* We just define a fixed number of these so far. This can be changed if it ever becomes
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt a problem. */
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersenstatic struct {
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen /** Open file structure that this connection handle is associated with */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /** HGCM connection ID */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering} hgcm_connections[MAX_HGCM_CONNECTIONS] = { { 0 } };
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek * Register an HGCM connection as being connected with a given file descriptor, so that it
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek * will be closed automatically when that file descriptor is.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * @returns 0 on success or Linux kernel error number
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen * @param clientID the client ID of the HGCM connection
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen * @param filep the file structure that the connection is to be associated with
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmekstatic int vboxadd_register_hgcm_connection(uint32_t client_id, struct file *filp)
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen bool found = false;
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich Assert(hgcm_connections[i].client_id != client_id);
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich if (ASMAtomicCmpXchgU32(&hgcm_connections[i].client_id, client_id, 0)) {
336b5c615e9c101476784b32df1b86aaeac96431Zbigniew Jędrzejewski-Szmek hgcm_connections[i].filp = filp;
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich return found ? 0 : -ENFILE; /* Any ideas for a better error code? */
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * Unregister an HGCM connection associated with a given file descriptor without closing
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * the connection.
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * @returns 0 on success or Linux kernel error number
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * @param clientID the client ID of the HGCM connection
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrichstatic int vboxadd_unregister_hgcm_connection_no_close(uint32_t client_id)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak bool found = false;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak Assert(hgcm_connections[i].client_id != client_id);
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * Unregister all HGCM connections associated with a given file descriptor, closing
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * the connections in the process. This should be called when a file descriptor is
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @returns 0 on success or Linux kernel error number
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @param clientID the client ID of the HGCM connection
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_unregister_all_hgcm_connections(struct file *filp)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak infoDisconnect.u32ClientID = hgcm_connections[i].client_id;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * File open handler
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_open(struct inode *inode, struct file *filp)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak /* no checks required */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * File close handler. Clean up any HGCM connections associated with the open file
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * which might still be open.
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_release(struct inode *inode, struct file * filp)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poetteringvboxadd_wait_for_event (VBoxGuestWaitEventInfo *info)
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering uint32_t cInterruptions = vboxDev->u32GuestInterruptions;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_OK;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering if (RT_INDEFINITE_WAIT != info->u32TimeoutIn) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering timeleft = wait_event_interruptible_timeout
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek || (vboxDev->u32GuestInterruptions != cInterruptions),
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek msecs_to_jiffies (info->u32TimeoutIn)
94192cdaf652c9717f15274504ed315126c07a93Zbigniew Jędrzejewski-Szmek if (vboxDev->u32GuestInterruptions != cInterruptions) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (wait_event_interruptible(vboxDev->eventq,
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering || (vboxDev->u32GuestInterruptions != cInterruptions)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32EventFlagsOut = vboxDev->u32Events & in_mask;
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek * IOCtl handler - wait for an event from the host.
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek * @returns Linux kernel return code
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek * @param ptr User space pointer to a structure describing the event
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_from_user (&info, ptr, sizeof (info))) {
b7def684941808600c344f0be7a2b9fcdda97e0fLennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not get event info\n"));
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen if (copy_to_user (ptr, &info, sizeof (info))) {
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not put out_mask\n"));
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * succeeds, it will be associated with the file structure used to open it, so that it will be
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * automatically shut down again if the file descriptor is closed.
0d3d3be1e225d51ebf46fb40a89419eb6a7d334eFranck Bui * @returns 0 on success, or a Linux kernel errno value
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering * @param filp the file structure with which the application opened the driver
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * @param userspace_info userspace pointer to the hgcm connection information
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * (VBoxGuestHGCMConnectInfo structure)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @retval userspace_info userspace pointer to the hgcm connection information
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_hgcm_connect(struct file *filp, unsigned long userspace_info)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (0 != copy_from_user ((void *)&info, (void *)userspace_info, sizeof (info))) {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: can not get connection info\n"));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering rcVBox = vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_CONNECT, &info);
64e70e4b86d3f732d3513189312f6220d1d5cfbcThomas Bächler if (RT_FAILURE(rcVBox) || (RT_FAILURE(info.result))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_HGCM_CONNECT: hgcm connection failed. internal ioctl result %Vrc, hgcm result %Vrc\n", rcVBox, info.result));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering rc = RT_FAILURE(rcVBox) ? -RTErrConvertToErrno(rcVBox)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering /* Register that the connection is associated with this file pointer. */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("Connected, client ID %u\n", info.u32ClientID));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = vboxadd_register_hgcm_connection(info.u32ClientID, filp);
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_HGCM_CONNECT: failed to register the HGCM connection\n"));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_to_user ((void *)userspace_info, (void *)&info,
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek LogRelFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: failed to return the connection structure\n"));
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen /* Unregister again, as we didn't get as far as informing userspace. */
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek vboxadd_unregister_hgcm_connection_no_close(info.u32ClientID);
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek /* And disconnect the hgcm connection again, as we told userspace it failed. */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering infoDisconnect.u32ClientID = info.u32ClientID;
0d3d3be1e225d51ebf46fb40a89419eb6a7d334eFranck Bui vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * IOCTL handler. Disconnect a specific HGCM connection.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * @returns 0 on success, or a Linux kernel errno value
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering * @param filp the file structure with which the application opened the driver
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * @param userspace_info userspace pointer to the hgcm connection information
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * (VBoxGuestHGCMConnectInfo structure)
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * @retval userspace_info userspace pointer to the hgcm connection information
b7def684941808600c344f0be7a2b9fcdda97e0fLennart Poetteringstatic int vboxadd_hgcm_disconnect(struct file *filp, unsigned long userspace_info)
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek VBoxGuestHGCMDisconnectInfo info;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (0 != copy_from_user ((void *)&info, (void *)userspace_info, sizeof (info))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: can not get info\n"));
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt LogRelFunc(("client ID %u\n", info.u32ClientID));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_to_user ((void *)userspace_info, (void *)&info, sizeof(info))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: failed to return the connection structure\n"));
700e07ffd53083114e91bb4ba646ed26d0463f67Harald Hoyer * IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * we know how to handle.
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @returns iprt status code
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @param pInfo kernel space pointer to the filter mask change info
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_control_filter_mask(VBoxGuestFilterMaskInfo *pInfo)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: VbglGRPerform failed, rc=%Rrc!\n", rc));
b7def684941808600c344f0be7a2b9fcdda97e0fLennart Poettering Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poetteringstatic int vboxadd_ioctl(struct inode *inode, struct file *filp,
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* Deal with variable size ioctls first. */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0))
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering pszMessage = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek && copy_from_user(pszMessage, (void*)arg, _IOC_SIZE(cmd))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_from_user(&reqHeader, (void*)arg, sizeof(reqHeader)))
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* get the request size */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (cbRequestSize < cbVanillaRequestSize)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering /* request storage for the full request */
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* now get the full request */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger /* now issue the request */
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger /* asynchronous processing? */
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek wait_event_interruptible (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek if (VBOX_FAILURE(rrc) || VBOX_FAILURE(reqFull->rc))
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = VBOX_FAILURE(rrc) ? -RTErrConvertToErrno(rrc)
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering /* success, copy the result data to user space */
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger else if ( ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger /* This IOCTL allows the guest to make an HGCM call from user space. The
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger OS-independant part of the Guest Additions already contain code for making an
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger HGCM call from the guest, but this code assumes that the call is made from the
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger kernel's address space. So before calling it, we have to copy all parameters
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger to the HGCM call from user space to kernel space and reconstruct the structures
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger passed to the call (which include pointers to other memory) inside the kernel's
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger address space. */
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_WAITEVENT", arg);
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger if (copy_from_user((void*)&info, (void*)arg, sizeof(info)))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
104bc12fbc23c3ca852d9d389805c615cd590d01nmartensen rc = -RTErrConvertToErrno(vboxadd_control_filter_mask(&info));
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering LogRelFunc(("unknown command: %x\n", cmd));
059cb3858acd038ff2cef10a3a99119bf71a8fc6Lennart Poetteringvboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
f88dc3edeb9c49622fcc773cb6153238fe9efbe2Tobias Hunger *(uint32_t *) buf = vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering *(uint32_t *) (buf + 4) = vboxDev->u32Events;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering/** strategy handlers (file operations) */
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger/* interrupt handlers in 2.4 kernels don't return anything */
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * vboxadd_irq_handler
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * Interrupt handler
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @returns scsi error code
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @param irq Irq number
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @param dev_id Irq handler parameter
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @param regs Regs
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poetteringstatic irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmekstatic irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
07719a21b6425d378b36bb8d7f47ad5ec5296d28Lennart Poettering Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* check if IRQ was asserted by VBox */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* make a copy of the event mask */
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(vboxDev->irqAckRequest->header.rc))
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering if (RT_LIKELY (vboxDev->irqAckRequest->events))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger vboxDev->u32Events |= vboxDev->irqAckRequest->events;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* impossible... */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering LogRelFunc(("IRQ was not acknowledged! rc = %Vrc, header.rc = %Vrc\n",
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering rcVBox, vboxDev->irqAckRequest->header.rc));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* it was ours! */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* we might be attached to a shared interrupt together with another device. */
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* it was ours */
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering * Helper function to reserve a fixed kernel address space window
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering * and tell the VMM that it can safely put its hypervisor there.
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering * This function might fail which is not a critical error.
126cc76074b763c7de9edec848fb86b22e8a78efZbigniew Jędrzejewski-Szmekstatic int vboxadd_reserve_hypervisor(void)
int rcVBox;
sizeof(VMMDevReqHypervisorInfo),
goto bail_out;
void *hypervisorArea;
if (hypervisorArea)
goto bail_out;
goto bail_out;
goto bail_out;
if (req)
static int vboxadd_free_hypervisor(void)
int rcVBox;
sizeof(VMMDevReqHypervisorInfo),
goto bail_out;
goto bail_out;
if (req)
static void free_resources(void)
if (vboxDev)
#define PCI_DEV_PUT(x)
int err;
int rcVBox;
if (vboxadd_cmc_init ())
return -ENODEV;
if (!pcidev)
return -ENODEV;
if (err)
return -ENODEV;
if (vbox_major > 0)
return -ENODEV;
if (!vbox_major)
if (err)
return -ENODEV;
if (!vboxDev)
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
sizeof(VMMDevReqGuestCapabilities2),
goto fail;
goto fail;
if (vboxadd_reserve_hypervisor())
goto fail;
if (err)
goto fail;
fail:
return err;
vboxadd_cmc_fini ();