lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <31f56fac-b607-c129-8fc5-8fa938ea2974@lwfinger.net>
Date:   Mon, 27 Nov 2017 13:46:57 -0600
From:   Larry Finger <Larry.Finger@...inger.net>
To:     Hans de Goede <hdegoede@...hat.com>, Arnd Bergmann <arnd@...db.de>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Cc:     Michael Thayer <michael.thayer@...cle.com>,
        "Knut St . Osmundsen" <knut.osmundsen@...cle.com>,
        Christoph Hellwig <hch@...radead.org>,
        linux-kernel@...r.kernel.org
Subject: Re: [PATCH resend v2 2/3] virt: Add vboxguest VMMDEV communication
 code

On 11/26/2017 09:12 AM, Hans de Goede wrote:
> This commits adds a header describing the hardware interface for the
> Virtual Box Guest PCI device used in Virtual Box virtual machines and
> utility functions for talking to the Virtual Box hypervisor over this
> interface.
> 
> These utility functions will used both by the vboxguest driver for the
> PCI device which offers the /dev/vboxguest ioctl API and by the vboxfs
> driver which offers folder sharing support.
> 
> Signed-off-by: Hans de Goede <hdegoede@...hat.com>

Reviewed-by: Larry Finger <Larry.Finger.net>

This patch has only minor defects. Please see the inline comments.

> ---
> Changes in v2:
> -Change all uapi headers to kernel coding style: Drop struct and enum typedefs
>   make type and struct-member names all lowercase, enum values all uppercase.
> -Remove unused struct type declarations from some headers (shaving of another
>   1000 lines)
> -Remove or fixup doxygen style comments
> -Get rid of CHECK macros, use a function taking in_ and out_size args instead
> -Some other small codyingstyle fixes
> -Split into multiple patches
> ---
>   MAINTAINERS                              |   2 +
>   drivers/virt/vboxguest/vboxguest_utils.c | 811 +++++++++++++++++++++++++++++++
>   drivers/virt/vboxguest/vmmdev.h          | 460 ++++++++++++++++++
>   include/linux/vbox_utils.h               |  92 ++++
>   4 files changed, 1365 insertions(+)
>   create mode 100644 drivers/virt/vboxguest/vboxguest_utils.c
>   create mode 100644 drivers/virt/vboxguest/vmmdev.h
>   create mode 100644 include/linux/vbox_utils.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index fe3dc0e9b901..01b30c12c267 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -14554,7 +14554,9 @@ M:	Hans de Goede <hdegoede@...hat.com>
>   M:	Arnd Bergmann <arnd@...db.de>
>   M:	Greg Kroah-Hartman <gregkh@...uxfoundation.org>
>   S:	Maintained
> +F:	include/linux/vbox_utils.h
>   F:	include/uapi/linux/vbox*.h
> +F:	drivers/virt/vboxguest/
>   
>   VIRTUAL SERIO DEVICE DRIVER
>   M:	Stephen Chandler Paul <thatslyude@...il.com>
> diff --git a/drivers/virt/vboxguest/vboxguest_utils.c b/drivers/virt/vboxguest/vboxguest_utils.c
> new file mode 100644
> index 000000000000..5e1737d0a4fb
> --- /dev/null
> +++ b/drivers/virt/vboxguest/vboxguest_utils.c
> @@ -0,0 +1,811 @@
> +/*
> + * vboxguest vmm-req and hgcm-call code, VBoxGuestR0LibHGCMInternal.cpp,
> + * VBoxGuestR0LibGenericRequest.cpp and RTErrConvertToErrno.cpp in vbox svn.
> + *
> + * Copyright (C) 2006-2016 Oracle Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * The contents of this file may alternatively be used under the terms
> + * of the Common Development and Distribution License Version 1.0
> + * (CDDL) only, in which case the provisions of the CDDL are applicable
> + * instead of those of the GPL.
> + *
> + * You may elect to license modified versions of this file under the
> + * terms and conditions of either the GPL or the CDDL or both.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/sizes.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/vmalloc.h>
> +#include <linux/vbox_err.h>
> +#include <linux/vbox_utils.h>
> +#include "vboxguest_core.h"
> +
> +/* Get the pointer to the first parameter of a HGCM call request. */
> +#define VMMDEV_HGCM_CALL_PARMS(a) \
> +	((struct vmmdev_hgcm_function_parameter *)( \
> +		(u8 *)(a) + sizeof(struct vmmdev_hgcm_call)))
> +
> +/* The max parameter buffer size for a user request. */
> +#define VBG_MAX_HGCM_USER_PARM		(24 * SZ_1M)
> +/* The max parameter buffer size for a kernel request. */
> +#define VBG_MAX_HGCM_KERNEL_PARM	(16 * SZ_1M)
> +
> +#define VBG_DEBUG_PORT			0x504
> +
> +/* This protects vbg_log_buf and serializes VBG_DEBUG_PORT accesses */
> +static DEFINE_SPINLOCK(vbg_log_lock);
> +static char vbg_log_buf[128];
> +
> +#define VBG_LOG(name, pr_func) \
> +void name(const char *fmt, ...)						\
> +{									\
> +	unsigned long flags;						\
> +	va_list args;							\
> +	int i, count;							\
> +									\
> +	va_start(args, fmt);						\
> +	spin_lock_irqsave(&vbg_log_lock, flags);			\
> +									\
> +	count = vscnprintf(vbg_log_buf, sizeof(vbg_log_buf), fmt, args);\
> +	for (i = 0; i < count; i++)					\
> +		outb(vbg_log_buf[i], VBG_DEBUG_PORT);			\
> +									\
> +	pr_func("%s", vbg_log_buf);					\
> +									\
> +	spin_unlock_irqrestore(&vbg_log_lock, flags);			\
> +	va_end(args);							\
> +}									\
> +EXPORT_SYMBOL(name)
> +
> +VBG_LOG(vbg_info, pr_info);
> +VBG_LOG(vbg_warn, pr_warn);
> +VBG_LOG(vbg_err, pr_err);
> +#if defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG)
> +VBG_LOG(vbg_debug, pr_debug);
> +#endif
> +
> +void *vbg_req_alloc(size_t len, enum vmmdev_request_type req_type)
> +{
> +	struct vmmdev_request_header *req;
> +
> +	req = kmalloc(len, GFP_KERNEL | __GFP_DMA32);
> +	if (!req)
> +		return NULL;
> +
> +	memset(req, 0xaa, len);
> +
> +	req->size = len;
> +	req->version = VMMDEV_REQUEST_HEADER_VERSION;
> +	req->request_type = req_type;
> +	req->rc = VERR_GENERAL_FAILURE;
> +	req->reserved1 = 0;
> +	req->reserved2 = 0;
> +
> +	return req;
> +}
> +
> +/* Note this function returns a VBox status code, not a negative errno!! */
> +int vbg_req_perform(struct vbg_dev *gdev, void *req)
> +{
> +	unsigned long phys_req = virt_to_phys(req);
> +
> +	outl(phys_req, gdev->io_port + VMMDEV_PORT_OFF_REQUEST);
> +	/*
> +	 * The host changes the request as a result of the outl, make sure
> +	 * the outl and any reads of the req happen in the correct order.
> +	 */
> +	mb();
> +
> +	return ((struct vmmdev_request_header *)req)->rc;
> +}
> +
> +static bool hgcm_req_done(struct vbg_dev *gdev,
> +			  struct vmmdev_hgcmreq_header *header)
> +{
> +	unsigned long flags;
> +	bool done;
> +
> +	spin_lock_irqsave(&gdev->event_spinlock, flags);
> +	done = header->flags & VMMDEV_HGCM_REQ_DONE;
> +	spin_unlock_irqrestore(&gdev->event_spinlock, flags);
> +
> +	return done;
> +}
> +
> +int vbg_hgcm_connect(struct vbg_dev *gdev,
> +		     struct vmmdev_hgcm_service_location *loc,
> +		     u32 *client_id, int *vbox_status)
> +{
> +	struct vmmdev_hgcm_connect *hgcm_connect = NULL;
> +	int rc;
> +
> +	hgcm_connect = vbg_req_alloc(sizeof(*hgcm_connect),
> +				     VMMDEVREQ_HGCM_CONNECT);
> +	if (!hgcm_connect)
> +		return -ENOMEM;
> +
> +	hgcm_connect->header.flags = 0;
> +	memcpy(&hgcm_connect->loc, loc, sizeof(*loc));
> +	hgcm_connect->client_id = 0;
> +
> +	rc = vbg_req_perform(gdev, hgcm_connect);
> +
> +	if (rc == VINF_HGCM_ASYNC_EXECUTE)
> +		wait_event(gdev->hgcm_wq,
> +			   hgcm_req_done(gdev, &hgcm_connect->header));
> +
> +	if (rc >= 0) {
> +		*client_id = hgcm_connect->client_id;
> +		rc = hgcm_connect->header.result;
> +	}
> +
> +	kfree(hgcm_connect);
> +
> +	*vbox_status = rc;
> +	return 0;
> +}
> +EXPORT_SYMBOL(vbg_hgcm_connect);
> +
> +int vbg_hgcm_disconnect(struct vbg_dev *gdev, u32 client_id, int *vbox_status)
> +{
> +	struct vmmdev_hgcm_disconnect *hgcm_disconnect = NULL;
> +	int rc;
> +
> +	hgcm_disconnect = vbg_req_alloc(sizeof(*hgcm_disconnect),
> +					VMMDEVREQ_HGCM_DISCONNECT);
> +	if (!hgcm_disconnect)
> +		return -ENOMEM;
> +
> +	hgcm_disconnect->header.flags = 0;
> +	hgcm_disconnect->client_id = client_id;
> +
> +	rc = vbg_req_perform(gdev, hgcm_disconnect);
> +
> +	if (rc == VINF_HGCM_ASYNC_EXECUTE)
> +		wait_event(gdev->hgcm_wq,
> +			   hgcm_req_done(gdev, &hgcm_disconnect->header));
> +
> +	if (rc >= 0)
> +		rc = hgcm_disconnect->header.result;
> +
> +	kfree(hgcm_disconnect);
> +
> +	*vbox_status = rc;
> +	return 0;
> +}
> +EXPORT_SYMBOL(vbg_hgcm_disconnect);
> +
> +static u32 hgcm_call_buf_size_in_pages(void *buf, u32 len)
> +{
> +	u32 size = PAGE_ALIGN(len + ((unsigned long)buf & ~PAGE_MASK));
> +
> +	return size >> PAGE_SHIFT;
> +}
> +
> +static void hgcm_call_add_pagelist_size(void *buf, u32 len, size_t *extra)
> +{
> +	u32 page_count;
> +
> +	page_count = hgcm_call_buf_size_in_pages(buf, len);
> +	*extra += offsetof(struct vmmdev_hgcm_pagelist, pages[page_count]);
> +}
> +
> +static int hgcm_call_preprocess_linaddr(
> +	const struct vmmdev_hgcm_function_parameter *src_parm,
> +	void **bounce_buf_ret, size_t *extra)
> +{
> +	void *buf, *bounce_buf;
> +	bool copy_in;
> +	u32 len;
> +	int ret;
> +
> +	buf = (void *)src_parm->u.pointer.u.linear_addr;
> +	len = src_parm->u.pointer.size;
> +	copy_in = src_parm->type != VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT;
> +
> +	if (len > VBG_MAX_HGCM_USER_PARM)
> +		return -E2BIG;
> +
> +	bounce_buf = kvmalloc(len, GFP_KERNEL);
> +	if (!bounce_buf)
> +		return -ENOMEM;
> +
> +	if (copy_in) {
> +		ret = copy_from_user(bounce_buf, (void __user *)buf, len);
> +		if (ret)
> +			return -EFAULT;
> +	} else {
> +		memset(bounce_buf, 0, len);
> +	}
> +
> +	*bounce_buf_ret = bounce_buf;
> +	hgcm_call_add_pagelist_size(bounce_buf, len, extra);
> +	return 0;
> +}
> +
> +/**
> + * Preprocesses the HGCM call, validate parameters, alloc bounce buffers and
> + * figure out how much extra storage we need for page lists.
> + * Return: 0 or negative errno value.
> + * @src_parm:         Pointer to source function call parameters
> + * @parm_count:       Number of function call parameters.
> + * @bounce_bufs_ret:  Where to return the allocated bouncebuffer array
> + * @extra:            Where to return the extra request space needed for
> + *                    physical page lists.
> + */
> +static int hgcm_call_preprocess(
> +	const struct vmmdev_hgcm_function_parameter *src_parm,
> +	u32 parm_count, void ***bounce_bufs_ret, size_t *extra)
> +{
> +	void *buf, **bounce_bufs = NULL;
> +	u32 i, len;
> +	int ret;
> +
> +	for (i = 0; i < parm_count; i++, src_parm++) {
> +		switch (src_parm->type) {
> +		case VMMDEV_HGCM_PARM_TYPE_32BIT:
> +		case VMMDEV_HGCM_PARM_TYPE_64BIT:
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
> +			if (!bounce_bufs) {
> +				bounce_bufs = kcalloc(parm_count,
> +						      sizeof(void *),
> +						      GFP_KERNEL);
> +				if (!bounce_bufs)
> +					return -ENOMEM;
> +
> +				*bounce_bufs_ret = bounce_bufs;
> +			}
> +
> +			ret = hgcm_call_preprocess_linaddr(src_parm,
> +							   &bounce_bufs[i],
> +							   extra);
> +			if (ret)
> +				return ret;
> +
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
> +			buf = (void *)src_parm->u.pointer.u.linear_addr;
> +			len = src_parm->u.pointer.size;
> +			if (WARN_ON(len > VBG_MAX_HGCM_KERNEL_PARM))
> +				return -E2BIG;
> +
> +			hgcm_call_add_pagelist_size(buf, len, extra);
> +			break;
> +
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * Translates linear address types to page list direction flags.
> + *
> + * Return: page list flags.
> + * @type:  The type.
> + */
> +static u32 hgcm_call_linear_addr_type_to_pagelist_flags(
> +	enum vmmdev_hgcm_function_parameter_type type)
> +{
> +	switch (type) {
> +	default:
> +		WARN_ON(1);

Do you intend a fall through here? If so, please add a comment to that effect.

> +	case VMMDEV_HGCM_PARM_TYPE_LINADDR:
> +	case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL:
> +		return VMMDEV_HGCM_F_PARM_DIRECTION_BOTH;
> +
> +	case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
> +	case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN:
> +		return VMMDEV_HGCM_F_PARM_DIRECTION_TO_HOST;
> +
> +	case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
> +	case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
> +		return VMMDEV_HGCM_F_PARM_DIRECTION_FROM_HOST;
> +	}
> +}
> +
> +static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
> +	struct vmmdev_hgcm_function_parameter *dst_parm, void *buf, u32 len,
> +	enum vmmdev_hgcm_function_parameter_type type, u32 *off_extra)
> +{
> +	struct vmmdev_hgcm_pagelist *dst_pg_lst;
> +	struct page *page;
> +	bool is_vmalloc;
> +	u32 i, page_count;
> +
> +	dst_parm->type = type;
> +
> +	if (len == 0) {
> +		dst_parm->u.pointer.size = 0;
> +		dst_parm->u.pointer.u.linear_addr = 0;
> +		return;
> +	}
> +
> +	dst_pg_lst = (void *)call + *off_extra;
> +	page_count = hgcm_call_buf_size_in_pages(buf, len);
> +	is_vmalloc = is_vmalloc_addr(buf);
> +
> +	dst_parm->type = VMMDEV_HGCM_PARM_TYPE_PAGELIST;
> +	dst_parm->u.page_list.size = len;
> +	dst_parm->u.page_list.offset = *off_extra;
> +	dst_pg_lst->flags = hgcm_call_linear_addr_type_to_pagelist_flags(type);
> +	dst_pg_lst->offset_first_page = (unsigned long)buf & ~PAGE_MASK;
> +	dst_pg_lst->page_count = page_count;
> +
> +	for (i = 0; i < page_count; i++) {
> +		if (is_vmalloc)
> +			page = vmalloc_to_page(buf);
> +		else
> +			page = virt_to_page(buf);
> +
> +		dst_pg_lst->pages[i] = page_to_phys(page);
> +		buf += PAGE_SIZE;
> +	}
> +
> +	*off_extra += offsetof(struct vmmdev_hgcm_pagelist, pages[page_count]);
> +}
> +
> +/**
> + * Initializes the call request that we're sending to the host.
> + * @call:            The call to initialize.
> + * @client_id:       The client ID of the caller.
> + * @function:        The function number of the function to call.
> + * @src_parm:        Pointer to source function call parameters.
> + * @parm_count:      Number of function call parameters.
> + * @bounce_bufs:     The bouncebuffer array.
> + */
> +static void hgcm_call_init_call(
> +	struct vmmdev_hgcm_call *call, u32 client_id, u32 function,
> +	const struct vmmdev_hgcm_function_parameter *src_parm,
> +	u32 parm_count, void **bounce_bufs)
> +{
> +	struct vmmdev_hgcm_function_parameter *dst_parm =
> +		VMMDEV_HGCM_CALL_PARMS(call);
> +	u32 i, off_extra = (uintptr_t)(dst_parm + parm_count) - (uintptr_t)call;
> +	void *buf;
> +
> +	call->header.flags = 0;
> +	call->header.result = VINF_SUCCESS;
> +	call->client_id = client_id;
> +	call->function = function;
> +	call->parm_count = parm_count;
> +
> +	for (i = 0; i < parm_count; i++, src_parm++, dst_parm++) {
> +		switch (src_parm->type) {
> +		case VMMDEV_HGCM_PARM_TYPE_32BIT:
> +		case VMMDEV_HGCM_PARM_TYPE_64BIT:
> +			*dst_parm = *src_parm;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
> +			hgcm_call_init_linaddr(call, dst_parm, bounce_bufs[i],
> +					       src_parm->u.pointer.size,
> +					       src_parm->type, &off_extra);
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
> +			buf = (void *)src_parm->u.pointer.u.linear_addr;
> +			hgcm_call_init_linaddr(call, dst_parm, buf,
> +					       src_parm->u.pointer.size,
> +					       src_parm->type, &off_extra);
> +			break;
> +
> +		default:
> +			WARN_ON(1);
> +			dst_parm->type = VMMDEV_HGCM_PARM_TYPE_INVALID;
> +		}
> +	}
> +}
> +
> +/**
> + * Tries to cancel a pending HGCM call.
> + *
> + * Return: VBox status code
> + */
> +static int hgcm_cancel_call(struct vbg_dev *gdev, struct vmmdev_hgcm_call *call)
> +{
> +	int rc;
> +
> +	/*
> +	 * We use a pre-allocated request for cancellations, which is
> +	 * protected by cancel_req_mutex. This means that all cancellations
> +	 * get serialized, this should be fine since they should be rare.
> +	 */
> +	mutex_lock(&gdev->cancel_req_mutex);
> +	gdev->cancel_req->phys_req_to_cancel = virt_to_phys(call);
> +	rc = vbg_req_perform(gdev, gdev->cancel_req);
> +	mutex_unlock(&gdev->cancel_req_mutex);
> +
> +	if (rc == VERR_NOT_IMPLEMENTED) {
> +		call->header.flags |= VMMDEV_HGCM_REQ_CANCELLED;
> +		call->header.header.request_type = VMMDEVREQ_HGCM_CANCEL;
> +
> +		rc = vbg_req_perform(gdev, call);
> +		if (rc == VERR_INVALID_PARAMETER)
> +			rc = VERR_NOT_FOUND;
> +	}
> +
> +	if (rc >= 0)
> +		call->header.flags |= VMMDEV_HGCM_REQ_CANCELLED;
> +
> +	return rc;
> +}
> +
> +/**
> + * Performs the call and completion wait.
> + * Return: 0 or negative errno value.
> + * @gdev:        The VBoxGuest device extension.
> + * @call:        The call to execute.
> + * @timeout_ms:  Timeout in ms.
> + * @leak_it:     Where to return the leak it / free it, indicator.
> + *               Cancellation fun.
> + */
> +static int vbg_hgcm_do_call(struct vbg_dev *gdev, struct vmmdev_hgcm_call *call,
> +			    u32 timeout_ms, bool *leak_it)
> +{
> +	int rc, cancel_rc, ret;
> +	long timeout;
> +
> +	*leak_it = false;
> +
> +	rc = vbg_req_perform(gdev, call);
> +
> +	/*
> +	 * If the call failed, then pretend success. Upper layers will
> +	 * interpret the result code in the packet.
> +	 */
> +	if (rc < 0) {
> +		call->header.result = rc;
> +		return 0;
> +	}
> +
> +	if (rc != VINF_HGCM_ASYNC_EXECUTE)
> +		return 0;
> +
> +	/* Host decided to process the request asynchronously, wait for it */
> +	if (timeout_ms == U32_MAX)
> +		timeout = MAX_SCHEDULE_TIMEOUT;
> +	else
> +		timeout = msecs_to_jiffies(timeout_ms);
> +
> +	timeout = wait_event_interruptible_timeout(
> +					gdev->hgcm_wq,
> +					hgcm_req_done(gdev, &call->header),
> +					timeout);
> +
> +	/* timeout > 0 means hgcm_req_done has returned true, so success */
> +	if (timeout > 0)
> +		return 0;
> +
> +	if (timeout == 0)
> +		ret = -ETIMEDOUT;
> +	else
> +		ret = -EINTR;
> +
> +	/* Cancel the request */
> +	cancel_rc = hgcm_cancel_call(gdev, call);
> +	if (cancel_rc >= 0)
> +		return ret;
> +
> +	/*
> +	 * Failed to cancel, this should mean that the cancel has lost the
> +	 * race with normal completion, wait while the host completes it.
> +	 */
> +	if (cancel_rc == VERR_NOT_FOUND || cancel_rc == VERR_SEM_DESTROYED)
> +		timeout = msecs_to_jiffies(500);
> +	else
> +		timeout = msecs_to_jiffies(2000);
> +
> +	timeout = wait_event_timeout(gdev->hgcm_wq,
> +				     hgcm_req_done(gdev, &call->header),
> +				     timeout);
> +
> +	if (WARN_ON(timeout == 0)) {
> +		/* We really should never get here */
> +		vbg_err("%s: Call timedout and cancellation failed, leaking the request\n",
> +			__func__);
> +		*leak_it = true;
> +		return ret;
> +	}
> +
> +	/* The call has completed normally after all */
> +	return 0;
> +}
> +
> +/**
> + * Copies the result of the call back to the caller info structure and user
> + * buffers.
> + * Return: 0 or negative errno value.
> + * @call:            HGCM call request.
> + * @dst_parm:        Pointer to function call parameters destination.
> + * @parm_count:      Number of function call parameters.
> + * @bounce_bufs:     The bouncebuffer array.
> + */
> +static int hgcm_call_copy_back_result(
> +	const struct vmmdev_hgcm_call *call,
> +	struct vmmdev_hgcm_function_parameter *dst_parm,
> +	u32 parm_count, void **bounce_bufs)
> +{
> +	const struct vmmdev_hgcm_function_parameter *src_parm =
> +		VMMDEV_HGCM_CALL_PARMS(call);
> +	void __user *p;
> +	int ret;
> +	u32 i;
> +
> +	/* Copy back parameters. */
> +	for (i = 0; i < parm_count; i++, src_parm++, dst_parm++) {
> +		switch (dst_parm->type) {
> +		case VMMDEV_HGCM_PARM_TYPE_32BIT:
> +		case VMMDEV_HGCM_PARM_TYPE_64BIT:
> +			*dst_parm = *src_parm;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_PAGELIST:
> +			dst_parm->u.page_list.size = src_parm->u.page_list.size;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT:
> +			dst_parm->u.pointer.size = src_parm->u.pointer.size;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
> +			dst_parm->u.pointer.size = src_parm->u.pointer.size;
> +
> +			p = (void __user *)dst_parm->u.pointer.u.linear_addr;
> +			ret = copy_to_user(p, bounce_bufs[i],
> +					   min(src_parm->u.pointer.size,
> +					       dst_parm->u.pointer.size));
> +			if (ret)
> +				return -EFAULT;
> +			break;
> +
> +		default:
> +			WARN_ON(1);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int vbg_hgcm_call(struct vbg_dev *gdev, u32 client_id, u32 function,
> +		  u32 timeout_ms, struct vmmdev_hgcm_function_parameter *parms,
> +		  u32 parm_count, int *vbox_status)
> +{
> +	struct vmmdev_hgcm_call *call;
> +	void **bounce_bufs = NULL;
> +	bool leak_it;
> +	size_t size;
> +	int i, ret;
> +
> +	size = sizeof(struct vmmdev_hgcm_call) +
> +		   parm_count * sizeof(struct vmmdev_hgcm_function_parameter);
> +	/*
> +	 * Validate and buffer the parameters for the call. This also increases
> +	 * call_size with the amount of extra space needed for page lists.
> +	 */
> +	ret = hgcm_call_preprocess(parms, parm_count, &bounce_bufs, &size);
> +	if (ret) {
> +		/* Even on error bounce bufs may still have been allocated */
> +		goto free_bounce_bufs;
> +	}
> +
> +	call = vbg_req_alloc(size, VMMDEVREQ_HGCM_CALL);
> +	if (!call) {
> +		ret = -ENOMEM;
> +		goto free_bounce_bufs;
> +	}
> +
> +	hgcm_call_init_call(call, client_id, function, parms, parm_count,
> +			    bounce_bufs);
> +
> +	ret = vbg_hgcm_do_call(gdev, call, timeout_ms, &leak_it);
> +	if (ret == 0) {
> +		*vbox_status = call->header.result;
> +		ret = hgcm_call_copy_back_result(call, parms, parm_count,
> +						 bounce_bufs);
> +	}
> +
> +	if (!leak_it)
> +		kfree(call);
> +
> +free_bounce_bufs:
> +	if (bounce_bufs) {
> +		for (i = 0; i < parm_count; i++)
> +			kvfree(bounce_bufs[i]);
> +		kfree(bounce_bufs);
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(vbg_hgcm_call);
> +
> +#ifdef CONFIG_COMPAT
> +int vbg_hgcm_call32(
> +	struct vbg_dev *gdev, u32 client_id, u32 function, u32 timeout_ms,
> +	struct vmmdev_hgcm_function_parameter32 *parm32, u32 parm_count,
> +	int *vbox_status)
> +{
> +	struct vmmdev_hgcm_function_parameter *parm64 = NULL;
> +	u32 i, size;
> +	int ret = 0;
> +
> +	/* KISS allocate a temporary request and convert the parameters. */
> +	size = parm_count * sizeof(struct vmmdev_hgcm_function_parameter);
> +	parm64 = kzalloc(size, GFP_KERNEL);
> +	if (!parm64)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < parm_count; i++) {
> +		switch (parm32[i].type) {
> +		case VMMDEV_HGCM_PARM_TYPE_32BIT:
> +			parm64[i].type = VMMDEV_HGCM_PARM_TYPE_32BIT;
> +			parm64[i].u.value32 = parm32[i].u.value32;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_64BIT:
> +			parm64[i].type = VMMDEV_HGCM_PARM_TYPE_64BIT;
> +			parm64[i].u.value64 = parm32[i].u.value64;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
> +			parm64[i].type = parm32[i].type;
> +			parm64[i].u.pointer.size = parm32[i].u.pointer.size;
> +			parm64[i].u.pointer.u.linear_addr =
> +			    parm32[i].u.pointer.u.linear_addr;
> +			break;
> +
> +		default:
> +			ret = -EINVAL;
> +		}
> +		if (ret < 0)
> +			goto out_free;
> +	}
> +
> +	ret = vbg_hgcm_call(gdev, client_id, function, timeout_ms,
> +			    parm64, parm_count, vbox_status);
> +	if (ret < 0)
> +		goto out_free;
> +
> +	/* Copy back. */
> +	for (i = 0; i < parm_count; i++, parm32++, parm64++) {
> +		switch (parm64[i].type) {
> +		case VMMDEV_HGCM_PARM_TYPE_32BIT:
> +			parm32[i].u.value32 = parm64[i].u.value32;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_64BIT:
> +			parm32[i].u.value64 = parm64[i].u.value64;
> +			break;
> +
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_OUT:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR:
> +		case VMMDEV_HGCM_PARM_TYPE_LINADDR_IN:
> +			parm32[i].u.pointer.size = parm64[i].u.pointer.size;
> +			break;
> +
> +		default:
> +			WARN_ON(1);
> +			ret = -EINVAL;
> +		}
> +	}
> +
> +out_free:
> +	kfree(parm64);
> +	return ret;
> +}
> +#endif
> +
> +static const int vbg_status_code_to_errno_table[] = {
> +	[-VERR_ACCESS_DENIED]                            = -EPERM,
> +	[-VERR_FILE_NOT_FOUND]                           = -ENOENT,
> +	[-VERR_PROCESS_NOT_FOUND]                        = -ESRCH,
> +	[-VERR_INTERRUPTED]                              = -EINTR,
> +	[-VERR_DEV_IO_ERROR]                             = -EIO,
> +	[-VERR_TOO_MUCH_DATA]                            = -E2BIG,
> +	[-VERR_BAD_EXE_FORMAT]                           = -ENOEXEC,
> +	[-VERR_INVALID_HANDLE]                           = -EBADF,
> +	[-VERR_TRY_AGAIN]                                = -EAGAIN,
> +	[-VERR_NO_MEMORY]                                = -ENOMEM,
> +	[-VERR_INVALID_POINTER]                          = -EFAULT,
> +	[-VERR_RESOURCE_BUSY]                            = -EBUSY,
> +	[-VERR_ALREADY_EXISTS]                           = -EEXIST,
> +	[-VERR_NOT_SAME_DEVICE]                          = -EXDEV,
> +	[-VERR_NOT_A_DIRECTORY]                          = -ENOTDIR,
> +	[-VERR_PATH_NOT_FOUND]                           = -ENOTDIR,
> +	[-VERR_IS_A_DIRECTORY]                           = -EISDIR,
> +	[-VERR_INVALID_PARAMETER]                        = -EINVAL,
> +	[-VERR_TOO_MANY_OPEN_FILES]                      = -ENFILE,
> +	[-VERR_INVALID_FUNCTION]                         = -ENOTTY,
> +	[-VERR_SHARING_VIOLATION]                        = -ETXTBSY,
> +	[-VERR_FILE_TOO_BIG]                             = -EFBIG,
> +	[-VERR_DISK_FULL]                                = -ENOSPC,
> +	[-VERR_SEEK_ON_DEVICE]                           = -ESPIPE,
> +	[-VERR_WRITE_PROTECT]                            = -EROFS,
> +	[-VERR_BROKEN_PIPE]                              = -EPIPE,
> +	[-VERR_DEADLOCK]                                 = -EDEADLK,
> +	[-VERR_FILENAME_TOO_LONG]                        = -ENAMETOOLONG,
> +	[-VERR_FILE_LOCK_FAILED]                         = -ENOLCK,
> +	[-VERR_NOT_IMPLEMENTED]                          = -ENOSYS,
> +	[-VERR_NOT_SUPPORTED]                            = -ENOSYS,
> +	[-VERR_DIR_NOT_EMPTY]                            = -ENOTEMPTY,
> +	[-VERR_TOO_MANY_SYMLINKS]                        = -ELOOP,
> +	[-VERR_NO_DATA]                                  = -ENODATA,
> +	[-VERR_NET_NO_NETWORK]                           = -ENONET,
> +	[-VERR_NET_NOT_UNIQUE_NAME]                      = -ENOTUNIQ,
> +	[-VERR_NO_TRANSLATION]                           = -EILSEQ,
> +	[-VERR_NET_NOT_SOCKET]                           = -ENOTSOCK,
> +	[-VERR_NET_DEST_ADDRESS_REQUIRED]                = -EDESTADDRREQ,
> +	[-VERR_NET_MSG_SIZE]                             = -EMSGSIZE,
> +	[-VERR_NET_PROTOCOL_TYPE]                        = -EPROTOTYPE,
> +	[-VERR_NET_PROTOCOL_NOT_AVAILABLE]               = -ENOPROTOOPT,
> +	[-VERR_NET_PROTOCOL_NOT_SUPPORTED]               = -EPROTONOSUPPORT,
> +	[-VERR_NET_SOCKET_TYPE_NOT_SUPPORTED]            = -ESOCKTNOSUPPORT,
> +	[-VERR_NET_OPERATION_NOT_SUPPORTED]              = -EOPNOTSUPP,
> +	[-VERR_NET_PROTOCOL_FAMILY_NOT_SUPPORTED]        = -EPFNOSUPPORT,
> +	[-VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED]         = -EAFNOSUPPORT,
> +	[-VERR_NET_ADDRESS_IN_USE]                       = -EADDRINUSE,
> +	[-VERR_NET_ADDRESS_NOT_AVAILABLE]                = -EADDRNOTAVAIL,
> +	[-VERR_NET_DOWN]                                 = -ENETDOWN,
> +	[-VERR_NET_UNREACHABLE]                          = -ENETUNREACH,
> +	[-VERR_NET_CONNECTION_RESET]                     = -ENETRESET,
> +	[-VERR_NET_CONNECTION_ABORTED]                   = -ECONNABORTED,
> +	[-VERR_NET_CONNECTION_RESET_BY_PEER]             = -ECONNRESET,
> +	[-VERR_NET_NO_BUFFER_SPACE]                      = -ENOBUFS,
> +	[-VERR_NET_ALREADY_CONNECTED]                    = -EISCONN,
> +	[-VERR_NET_NOT_CONNECTED]                        = -ENOTCONN,
> +	[-VERR_NET_SHUTDOWN]                             = -ESHUTDOWN,
> +	[-VERR_NET_TOO_MANY_REFERENCES]                  = -ETOOMANYREFS,
> +	[-VERR_TIMEOUT]                                  = -ETIMEDOUT,
> +	[-VERR_NET_CONNECTION_REFUSED]                   = -ECONNREFUSED,
> +	[-VERR_NET_HOST_DOWN]                            = -EHOSTDOWN,
> +	[-VERR_NET_HOST_UNREACHABLE]                     = -EHOSTUNREACH,
> +	[-VERR_NET_ALREADY_IN_PROGRESS]                  = -EALREADY,
> +	[-VERR_NET_IN_PROGRESS]                          = -EINPROGRESS,
> +	[-VERR_MEDIA_NOT_PRESENT]                        = -ENOMEDIUM,
> +	[-VERR_MEDIA_NOT_RECOGNIZED]                     = -EMEDIUMTYPE,
> +};
> +
> +int vbg_status_code_to_errno(int rc)
> +{
> +	if (rc >= 0)
> +		return 0;
> +
> +	rc = -rc;
> +	if (rc >= ARRAY_SIZE(vbg_status_code_to_errno_table) ||
> +	    vbg_status_code_to_errno_table[rc] == 0) {
> +		vbg_warn("%s: Unhandled err %d\n", __func__, -rc);
> +		return -EPROTO;
> +	}
> +
> +	return vbg_status_code_to_errno_table[rc];
> +}
> +EXPORT_SYMBOL(vbg_status_code_to_errno);
> diff --git a/drivers/virt/vboxguest/vmmdev.h b/drivers/virt/vboxguest/vmmdev.h
> new file mode 100644
> index 000000000000..0802a669b72b
> --- /dev/null
> +++ b/drivers/virt/vboxguest/vmmdev.h
> @@ -0,0 +1,460 @@
> +/*
> + * Virtual Device for Guest <-> VMM/Host communication interface
> + *
> + * Copyright (C) 2006-2016 Oracle Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * The contents of this file may alternatively be used under the terms
> + * of the Common Development and Distribution License Version 1.0
> + * (CDDL) only, in which case the provisions of the CDDL are applicable
> + * instead of those of the GPL.
> + *
> + * You may elect to license modified versions of this file under the
> + * terms and conditions of either the GPL or the CDDL or both.
> + */
> +
> +#ifndef __VBOX_VMMDEV_H__
> +#define __VBOX_VMMDEV_H__
> +
> +#include <asm/bitsperlong.h>
> +#include <linux/sizes.h>
> +#include <linux/types.h>
> +#include <linux/vbox_vmmdev_types.h>
> +
> +/* Port for generic request interface (relative offset). */
> +#define VMMDEV_PORT_OFF_REQUEST                             0
> +
> +/** Layout of VMMDEV RAM region that contains information for guest. */
> +struct vmmdev_memory {
> +	/** The size of this structure. */
> +	u32 size;
> +	/** The structure version. (VMMDEV_MEMORY_VERSION) */
> +	u32 version;
> +
> +	union {
> +		struct {
> +			/** Flag telling that VMMDev has events pending. */
> +			u8 have_events;
> +			/** Explicit padding, MBZ. */
> +			u8 padding[3];
> +		} V1_04;
> +
> +		struct {
> +			/** Pending events flags, set by host. */
> +			u32 host_events;
> +			/** Mask of events the guest wants, set by guest. */
> +			u32 guest_event_mask;
> +		} V1_03;
> +	} V;
> +
> +	/* struct vbva_memory, not used */
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_memory, 8 + 8);
> +
> +/** Version of vmmdev_memory structure (vmmdev_memory::version). */
> +#define VMMDEV_MEMORY_VERSION   (1)
> +
> +/* Host mouse capabilities has been changed. */
> +#define VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED             BIT(0)
> +/* HGCM event. */
> +#define VMMDEV_EVENT_HGCM                                   BIT(1)
> +/* A display change request has been issued. */
> +#define VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST                 BIT(2)
> +/* Credentials are available for judgement. */
> +#define VMMDEV_EVENT_JUDGE_CREDENTIALS                      BIT(3)
> +/* The guest has been restored. */
> +#define VMMDEV_EVENT_RESTORED                               BIT(4)
> +/* Seamless mode state changed. */
> +#define VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST           BIT(5)
> +/* Memory balloon size changed. */
> +#define VMMDEV_EVENT_BALLOON_CHANGE_REQUEST                 BIT(6)
> +/* Statistics interval changed. */
> +#define VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST     BIT(7)
> +/* VRDP status changed. */
> +#define VMMDEV_EVENT_VRDP                                   BIT(8)
> +/* New mouse position data available. */
> +#define VMMDEV_EVENT_MOUSE_POSITION_CHANGED                 BIT(9)
> +/* CPU hotplug event occurred. */
> +#define VMMDEV_EVENT_CPU_HOTPLUG                            BIT(10)
> +/* The mask of valid events, for sanity checking. */
> +#define VMMDEV_EVENT_VALID_EVENT_MASK                       0x000007ffU
> +
> +/*
> + * Additions are allowed to work only if additions_major == vmmdev_current &&
> + * additions_minor <= vmmdev_current. Additions version is reported to host
> + * (VMMDev) by VMMDEVREQ_REPORT_GUEST_INFO.
> + */
> +#define VMMDEV_VERSION                      0x00010004
> +#define VMMDEV_VERSION_MAJOR                (VMMDEV_VERSION >> 16)
> +#define VMMDEV_VERSION_MINOR                (VMMDEV_VERSION & 0xffff)
> +
> +/* Maximum request packet size. */
> +#define VMMDEV_MAX_VMMDEVREQ_SIZE           1048576
> +
> +/* Version of vmmdev_request_header structure. */
> +#define VMMDEV_REQUEST_HEADER_VERSION       0x10001
> +
> +/** struct vmmdev_request_header - Generic VMMDev request header. */
> +struct vmmdev_request_header {
> +	/** IN: Size of the structure in bytes (including body). */
> +	u32 size;
> +	/** IN: Version of the structure.  */
> +	u32 version;
> +	/** IN: Type of the request. */
> +	enum vmmdev_request_type request_type;
> +	/** OUT: Return code. */
> +	s32 rc;
> +	/** Reserved field no.1. MBZ. */
> +	u32 reserved1;
> +	/** Reserved field no.2. MBZ. */
> +	u32 reserved2;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_request_header, 24);
> +
> +/**
> + * struct vmmdev_mouse_status - Mouse status request structure.
> + *
> + * Used by VMMDEVREQ_GET_MOUSE_STATUS and VMMDEVREQ_SET_MOUSE_STATUS.
> + */
> +struct vmmdev_mouse_status {
> +	/** header */
> +	struct vmmdev_request_header header;
> +	/** Mouse feature mask. See VMMDEV_MOUSE_*. */
> +	u32 mouse_features;
> +	/** Mouse x position. */
> +	s32 pointer_pos_x;
> +	/** Mouse y position. */
> +	s32 pointer_pos_y;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_mouse_status, 24 + 12);
> +
> +/* The guest can (== wants to) handle absolute coordinates.  */
> +#define VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE                     BIT(0)
> +/*
> + * The host can (== wants to) send absolute coordinates.
> + * (Input not captured.)
> + */
> +#define VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE                    BIT(1)
> +/*
> + * The guest can *NOT* switch to software cursor and therefore depends on the
> + * host cursor.
> + *
> + * When guest additions are installed and the host has promised to display the
> + * cursor itself, the guest installs a hardware mouse driver. Don't ask the
> + * guest to switch to a software cursor then.
> + */
> +#define VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR                BIT(2)
> +/* The host does NOT provide support for drawing the cursor itself. */
> +#define VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER                  BIT(3)
> +/* The guest can read VMMDev events to find out about pointer movement */
> +#define VMMDEV_MOUSE_NEW_PROTOCOL                           BIT(4)
> +/*
> + * If the guest changes the status of the VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR
> + * bit, the host will honour this.
> + */
> +#define VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR        BIT(5)
> +/*
> + * The host supplies an absolute pointing device.  The Guest Additions may
> + * wish to use this to decide whether to install their own driver.
> + */
> +#define VMMDEV_MOUSE_HOST_HAS_ABS_DEV                       BIT(6)
> +
> +/* The minimum value our pointing device can return. */
> +#define VMMDEV_MOUSE_RANGE_MIN 0
> +/* The maximum value our pointing device can return. */
> +#define VMMDEV_MOUSE_RANGE_MAX 0xFFFF
> +
> +/**
> + * struct vmmdev_host_version - VirtualBox host version request structure.
> + *
> + * VBG uses this to detect the precense of new features in the interface.
> + */
> +struct vmmdev_host_version {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** Major version. */
> +	u16 major;
> +	/** Minor version. */
> +	u16 minor;
> +	/** Build number. */
> +	u32 build;
> +	/** SVN revision. */
> +	u32 revision;
> +	/** Feature mask. */
> +	u32 features;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_host_version, 24 + 16);
> +
> +/* Physical page lists are supported by HGCM. */
> +#define VMMDEV_HVF_HGCM_PHYS_PAGE_LIST  BIT(0)
> +
> +/**
> + * struct vmmdev_mask - Structure to set / clear bits in a mask used for
> + * VMMDEVREQ_SET_GUEST_CAPABILITIES and VMMDEVREQ_CTL_GUEST_FILTER_MASK.
> + */
> +struct vmmdev_mask {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** Mask of bits to be set. */
> +	u32 or_mask;
> +	/** Mask of bits to be cleared. */
> +	u32 not_mask;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_mask, 24 + 8);
> +
> +/* The guest supports seamless display rendering. */
> +#define VMMDEV_GUEST_SUPPORTS_SEAMLESS                      BIT(0)
> +/* The guest supports mapping guest to host windows. */
> +#define VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING     BIT(1)
> +/*
> + * The guest graphical additions are active.
> + * Used for fast activation and deactivation of certain graphical operations
> + * (e.g. resizing & seamless). The legacy VMMDEVREQ_REPORT_GUEST_CAPABILITIES
> + * request sets this automatically, but VMMDEVREQ_SET_GUEST_CAPABILITIES does
> + * not.
> + */
> +#define VMMDEV_GUEST_SUPPORTS_GRAPHICS                      BIT(2)
> +
> +/** struct vmmdev_hypervisorinfo - Hypervisor info structure. */
> +struct vmmdev_hypervisorinfo {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/**
> +	 * Guest virtual address of proposed hypervisor start.
> +	 * Not used by VMMDEVREQ_GET_HYPERVISOR_INFO.
> +	 */
> +	u32 hypervisor_start;
> +	/** Hypervisor size in bytes. */
> +	u32 hypervisor_size;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_hypervisorinfo, 24 + 8);
> +
> +/** struct vmmdev_events - Pending events structure. */
> +struct vmmdev_events {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** OUT: Pending event mask. */
> +	u32 events;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_events, 24 + 4);
> +
> +#define VMMDEV_OSTYPE_LINUX26		0x53000
> +#define VMMDEV_OSTYPE_X64		BIT(8)
> +
> +/** struct vmmdev_guestinfo - Guest information report. */
> +struct vmmdev_guest_info {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/**
> +	 * The VMMDev interface version expected by additions.
> +	 * *Deprecated*, do not use anymore! Will be removed.
> +	 */
> +	u32 interface_version;
> +	/** Guest OS type. */
> +	u32 os_type;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_guest_info, 24 + 8);
> +
> +/** struct vmmdev_guestinfo2 - Guest information report, version 2. */
> +struct vmmdev_guest_info2 {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** Major version. */
> +	u16 additions_major;
> +	/** Minor version. */
> +	u16 additions_minor;
> +	/** Build number. */
> +	u32 additions_build;
> +	/** SVN revision. */
> +	u32 additions_revision;
> +	/** Feature mask, currently unused. */
> +	u32 additions_features;
> +	/**
> +	 * The intentional meaning of this field was:
> +	 * Some additional information, for example 'Beta 1' or something like
> +	 * that.
> +	 *
> +	 * The way it was implemented was implemented: VBG_VERSION_STRING.
> +	 *
> +	 * This means the first three members are duplicated in this field (if
> +	 * the guest build config is sane). So, the user must check this and
> +	 * chop it off before usage. There is, because of the Main code's blind
> +	 * trust in the field's content, no way back.
> +	 */
> +	char name[128];
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_guest_info2, 24 + 144);
> +
> +enum vmmdev_guest_facility_type {
> +	VBOXGUEST_FACILITY_TYPE_UNKNOWN          = 0,
> +	VBOXGUEST_FACILITY_TYPE_VBOXGUEST_DRIVER = 20,
> +	/* VBoxGINA / VBoxCredProv / pam_vbox. */
> +	VBOXGUEST_FACILITY_TYPE_AUTO_LOGON       = 90,
> +	VBOXGUEST_FACILITY_TYPE_VBOX_SERVICE     = 100,
> +	/* VBoxTray (Windows), VBoxClient (Linux, Unix). */
> +	VBOXGUEST_FACILITY_TYPE_VBOX_TRAY_CLIENT = 101,
> +	VBOXGUEST_FACILITY_TYPE_SEAMLESS         = 1000,
> +	VBOXGUEST_FACILITY_TYPE_GRAPHICS         = 1100,
> +	VBOXGUEST_FACILITY_TYPE_ALL              = 0x7ffffffe,
> +	/* Ensure the enum is a 32 bit data-type */
> +	VBOXGUEST_FACILITY_TYPE_SIZEHACK         = 0x7fffffff
> +};
> +
> +enum vmmdev_guest_facility_status {
> +	VBOXGUEST_FACILITY_STATUS_INACTIVE    = 0,
> +	VBOXGUEST_FACILITY_STATUS_PAUSED      = 1,
> +	VBOXGUEST_FACILITY_STATUS_PRE_INIT    = 20,
> +	VBOXGUEST_FACILITY_STATUS_INIT        = 30,
> +	VBOXGUEST_FACILITY_STATUS_ACTIVE      = 50,
> +	VBOXGUEST_FACILITY_STATUS_TERMINATING = 100,
> +	VBOXGUEST_FACILITY_STATUS_TERMINATED  = 101,
> +	VBOXGUEST_FACILITY_STATUS_FAILED      = 800,
> +	VBOXGUEST_FACILITY_STATUS_UNKNOWN     = 999,
> +	/* Ensure the enum is a 32 bit data-type */
> +	VBOXGUEST_FACILITY_STATUS_SIZEHACK    = 0x7fffffff
> +};
> +
> +/** struct vmmdev_guest_status - Guest Additions status structure. */
> +struct vmmdev_guest_status {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** Facility the status is indicated for. */
> +	enum vmmdev_guest_facility_type facility;
> +	/** Current guest status. */
> +	enum vmmdev_guest_facility_status status;
> +	/** Flags, not used at the moment. */
> +	u32 flags;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_guest_status, 24 + 12);
> +
> +#define VMMDEV_MEMORY_BALLOON_CHUNK_SIZE             (1048576)
> +#define VMMDEV_MEMORY_BALLOON_CHUNK_PAGES            (1048576 / 4096)
> +
> +/** struct vmmdev_memballoon_info - Memory-balloon info structure. */
> +struct vmmdev_memballoon_info {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** Balloon size in megabytes. */
> +	u32 balloon_chunks;
> +	/** Guest ram size in megabytes. */
> +	u32 phys_mem_chunks;
> +	/**
> +	 * Setting this to VMMDEV_EVENT_BALLOON_CHANGE_REQUEST indicates that
> +	 * the request is a response to that event.
> +	 * (Don't confuse this with VMMDEVREQ_ACKNOWLEDGE_EVENTS.)
> +	 */
> +	u32 event_ack;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_memballoon_info, 24 + 12);
> +
> +/** struct vmmdev_memballoon_change - Change the size of the balloon. */
> +struct vmmdev_memballoon_change {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** The number of pages in the array. */
> +	u32 pages;
> +	/** true = inflate, false = deflate.  */
> +	u32 inflate;
> +	/** Physical address (u64) of each page. */
> +	u64 phys_page[VMMDEV_MEMORY_BALLOON_CHUNK_PAGES];
> +};
> +
> +/** struct vmmdev_write_core_dump - Write Core Dump request data. */
> +struct vmmdev_write_core_dump {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** Flags (reserved, MBZ). */
> +	u32 flags;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_write_core_dump, 24 + 4);
> +
> +/** struct vmmdev_heartbeat - Heart beat check state structure. */
> +struct vmmdev_heartbeat {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** OUT: Guest heartbeat interval in nanosec. */
> +	u64 interval_ns;
> +	/** Heartbeat check flag. */
> +	u8 enabled;
> +	/** Explicit padding, MBZ. */
> +	u8 padding[3];
> +} __packed;
> +VMMDEV_ASSERT_SIZE(vmmdev_heartbeat, 24 + 12);
> +
> +#define VMMDEV_HGCM_REQ_DONE      BIT(0)
> +#define VMMDEV_HGCM_REQ_CANCELLED BIT(1)
> +
> +/** struct vmmdev_hgcmreq_header - vmmdev HGCM requests header. */
> +struct vmmdev_hgcmreq_header {
> +	/** Request header. */
> +	struct vmmdev_request_header header;
> +
> +	/** HGCM flags. */
> +	u32 flags;
> +
> +	/** Result code. */
> +	s32 result;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_hgcmreq_header, 24 + 8);
> +
> +/** struct vmmdev_hgcm_connect - HGCM connect request structure. */
> +struct vmmdev_hgcm_connect {
> +	/** HGCM request header. */
> +	struct vmmdev_hgcmreq_header header;
> +
> +	/** IN: Description of service to connect to. */
> +	struct vmmdev_hgcm_service_location loc;
> +
> +	/** OUT: Client identifier assigned by local instance of HGCM. */
> +	u32 client_id;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_hgcm_connect, 32 + 132 + 4);
> +
> +/** struct vmmdev_hgcm_disconnect - HGCM disconnect request structure. */
> +struct vmmdev_hgcm_disconnect {
> +	/** HGCM request header. */
> +	struct vmmdev_hgcmreq_header header;
> +
> +	/** IN: Client identifier. */
> +	u32 client_id;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_hgcm_disconnect, 32 + 4);
> +
> +#define VMMDEV_HGCM_MAX_PARMS 32
> +
> +/** struct vmmdev_hgcm_call - HGCM call request structure. */
> +struct vmmdev_hgcm_call {
> +	/* request header */
> +	struct vmmdev_hgcmreq_header header;
> +
> +	/** IN: Client identifier. */
> +	u32 client_id;
> +	/** IN: Service function number. */
> +	u32 function;
> +	/** IN: Number of parameters. */
> +	u32 parm_count;
> +	/** Parameters follow in form: HGCMFunctionParameter32|64 parms[X]; */
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_hgcm_call, 32 + 12);
> +
> +/**
> + * struct vmmdev_hgcm_cancel2 - HGCM cancel request structure, version 2.
> + *
> + * After the request header.rc will be:
> + *
> + * VINF_SUCCESS when cancelled.
> + * VERR_NOT_FOUND if the specified request cannot be found.
> + * VERR_INVALID_PARAMETER if the address is invalid valid.
> + */
> +struct vmmdev_hgcm_cancel2 {
> +	/** Header. */
> +	struct vmmdev_request_header header;
> +	/** The physical address of the request to cancel. */
> +	u32 phys_req_to_cancel;
> +};
> +VMMDEV_ASSERT_SIZE(vmmdev_hgcm_cancel2, 24 + 4);
> +
> +#endif
> diff --git a/include/linux/vbox_utils.h b/include/linux/vbox_utils.h
> new file mode 100644
> index 000000000000..a0a2b84c8c2e
> --- /dev/null
> +++ b/include/linux/vbox_utils.h
> @@ -0,0 +1,92 @@
> +/*
> + * Copyright (C) 2006-2016 Oracle Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * The contents of this file may alternatively be used under the terms
> + * of the Common Development and Distribution License Version 1.0
> + * (CDDL) only, in which case the provisions of the CDDL are applicable
> + * instead of those of the GPL.
> + *
> + * You may elect to license modified versions of this file under the
> + * terms and conditions of either the GPL or the CDDL or both.
> + */
> +
> +#ifndef __VBOX_UTILS_H__
> +#define __VBOX_UTILS_H__
> +
> +#include <linux/printk.h>
> +#include <linux/vbox_vmmdev_types.h>
> +
> +struct vbg_dev;
> +
> +/**
> + * vboxguest logging functions, these log both to the backdoor and call
> + * the equivalent kernel pr_foo function.
> + */
> +__printf(1, 2) void vbg_info(const char *fmt, ...);
> +__printf(1, 2) void vbg_warn(const char *fmt, ...);
> +__printf(1, 2) void vbg_err(const char *fmt, ...);
> +
> +/* Only use backdoor logging for non-dynamic debug builds */
> +#if defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG)
> +__printf(1, 2) void vbg_debug(const char *fmt, ...);
> +#else
> +#define vbg_debug pr_debug
> +#endif
> +
> +/**
> + * Allocate memory for generic request and initialize the request header.
> + *
> + * Return: the allocated memory
> + * @len:		Size of memory block required for the request.
> + * @req_type:		The generic request type.
> + */
> +void *vbg_req_alloc(size_t len, enum vmmdev_request_type req_type);
> +
> +/**
> + * Perform a generic request.
> + *
> + * Return: VBox status code
> + * @gdev:		The Guest extension device.
> + * @req:		Pointer to the request structure.
> + */
> +int vbg_req_perform(struct vbg_dev *gdev, void *req);
> +
> +int vbg_hgcm_connect(struct vbg_dev *gdev,
> +		     struct vmmdev_hgcm_service_location *loc,
> +		     u32 *client_id, int *vbox_status);
> +
> +int vbg_hgcm_disconnect(struct vbg_dev *gdev, u32 client_id, int *vbox_status);
> +
> +int vbg_hgcm_call(struct vbg_dev *gdev, u32 client_id, u32 function,
> +		  u32 timeout_ms, struct vmmdev_hgcm_function_parameter *parms,
> +		  u32 parm_count, int *vbox_status);
> +
> +int vbg_hgcm_call32(
> +	struct vbg_dev *gdev, u32 client_id, u32 function, u32 timeout_ms,
> +	struct vmmdev_hgcm_function_parameter32 *parm32, u32 parm_count,
> +	int *vbox_status);
> +
> +/**
> + * Convert a VirtualBox status code to a standard Linux kernel return value.
> + * Return: 0 or negative errno value.
> + * @rc:			VirtualBox status code to convert.
> + */
> +int vbg_status_code_to_errno(int rc);
> +
> +/**
> + * Helper for the vboxsf driver to get a reference to the guest device.
> + * Return: a pointer to the gdev; or a ERR_PTR value on error.
> + */
> +struct vbg_dev *vbg_get_gdev(void);
> +
> +/**
> + * Helper for the vboxsf driver to put a guest device reference.
> + * @gdev:		Reference returned by vbg_get_gdev to put.
> + */
> +void vbg_put_gdev(struct vbg_dev *gdev);
> +
> +#endif
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ