[PATCH] staging: vboxvideo: Add vboxvideo to drivers/staging

Michael Thayer michael.thayer at oracle.com
Fri Jun 9 12:33:46 UTC 2017


09.06.2017 11:58, Hans de Goede wrote:
> This commit adds the vboxvideo drm/kms driver for the virtual graphics
> card used in Virtual Box virtual machines to drivers/staging.
> 
> Why drivers/staging? This driver is already being patched into the kernel
> by several distros, thus it is good to get this driver upstream soon, so
> that work on the driver can be easily shared.
> 
> At the same time we want to take our time to get this driver properly
> cleaned up before submitting it as a normal driver under drivers/gpu/drm,
> putting this driver in staging for now allows both.
> 
> Note this driver has already been significantly cleaned up, when I started
> working on this the files under /usr/src/vboxguest/vboxvideo as installed
> by Virtual Box 5.1.18 Guest Additions had a total linecount of 52681
> lines. The version in this commit has 7275 lines.
> 
> Of those 7275 lines 3980 lines are in an osindependent directory which
> contains portable code which is shared with other guest platforms such as
> C-structure definitions for the virtual graphics card protocol and helper
> functions for using these structures to communicate with the card. Since
> these files are shared they are in the standard Virtual Box upstream code
> style and not in the kernel coding style. All files outside of the
> osindependent directory fully adhere to the kernel coding style.
> 
> Cc: vbox-dev at virtualbox.org
> Cc: Michael Thayer <michael.thayer at oracle.com>
> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
Signed-off-by: Michael Thayer <michael.thayer at oracle.com>

> ---
>   .config                                            |    1 +
>   drivers/staging/Kconfig                            |    2 +
>   drivers/staging/Makefile                           |    1 +
>   drivers/staging/vboxvideo/Kconfig                  |   11 +
>   drivers/staging/vboxvideo/Makefile                 |    7 +
>   drivers/staging/vboxvideo/TODO                     |    7 +
>   .../staging/vboxvideo/osindependent/HGSMIBase.c    |  371 ++++
>   .../staging/vboxvideo/osindependent/HGSMIBase.h    |   52 +
>   .../staging/vboxvideo/osindependent/HGSMIChSetup.h |   76 +
>   .../vboxvideo/osindependent/HGSMIChannels.h        |   65 +
>   .../staging/vboxvideo/osindependent/HGSMIDefs.h    |  123 ++
>   .../staging/vboxvideo/osindependent/Modesetting.c  |  391 ++++
>   drivers/staging/vboxvideo/osindependent/VBVABase.c |  395 ++++
>   .../staging/vboxvideo/osindependent/VBoxVideo.h    | 2105 ++++++++++++++++++++
>   .../vboxvideo/osindependent/VBoxVideoGuest.h       |  180 ++
>   .../vboxvideo/osindependent/VBoxVideoIPRT.h        |  137 ++
>   .../staging/vboxvideo/osindependent/VBoxVideoVBE.h |   85 +
>   drivers/staging/vboxvideo/vbox_drv.c               |  287 +++
>   drivers/staging/vboxvideo/vbox_drv.h               |  287 +++
>   drivers/staging/vboxvideo/vbox_fb.c                |  444 +++++
>   drivers/staging/vboxvideo/vbox_hgsmi.c             |  114 ++
>   drivers/staging/vboxvideo/vbox_irq.c               |  207 ++
>   drivers/staging/vboxvideo/vbox_main.c              |  512 +++++
>   drivers/staging/vboxvideo/vbox_mode.c              |  864 ++++++++
>   drivers/staging/vboxvideo/vbox_prime.c             |   74 +
>   drivers/staging/vboxvideo/vbox_ttm.c               |  477 +++++
>   26 files changed, 7275 insertions(+)
>   create mode 100644 drivers/staging/vboxvideo/Kconfig
>   create mode 100644 drivers/staging/vboxvideo/Makefile
>   create mode 100644 drivers/staging/vboxvideo/TODO
>   create mode 100644 drivers/staging/vboxvideo/osindependent/HGSMIBase.c
>   create mode 100644 drivers/staging/vboxvideo/osindependent/HGSMIBase.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/HGSMIChSetup.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/HGSMIChannels.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/HGSMIDefs.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/Modesetting.c
>   create mode 100644 drivers/staging/vboxvideo/osindependent/VBVABase.c
>   create mode 100644 drivers/staging/vboxvideo/osindependent/VBoxVideo.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/VBoxVideoGuest.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/VBoxVideoIPRT.h
>   create mode 100644 drivers/staging/vboxvideo/osindependent/VBoxVideoVBE.h
>   create mode 100644 drivers/staging/vboxvideo/vbox_drv.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_drv.h
>   create mode 100644 drivers/staging/vboxvideo/vbox_fb.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_hgsmi.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_irq.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_main.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_mode.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_prime.c
>   create mode 100644 drivers/staging/vboxvideo/vbox_ttm.c
> 
> diff --git a/.config b/.config
> index a0f011992252..2ff5041c7b53 100644
> --- a/.config
> +++ b/.config
> @@ -6575,6 +6575,7 @@ CONFIG_LIRC_ZILOG=m
>   CONFIG_TYPEC_TCPM=m
>   CONFIG_TYPEC_TCPCI=m
>   CONFIG_TYPEC_FUSB302=m
> +CONFIG_DRM_VBOXVIDEO=m
>   CONFIG_X86_PLATFORM_DEVICES=y
>   CONFIG_ACER_WMI=m
>   CONFIG_ACERHDF=m
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index 268d4e6ef48a..ef28a1cb64ae 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -110,4 +110,6 @@ source "drivers/staging/ccree/Kconfig"
>   
>   source "drivers/staging/typec/Kconfig"
>   
> +source "drivers/staging/vboxvideo/Kconfig"
> +
>   endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index b93e6f5f0f6e..2918580bdb9e 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -44,3 +44,4 @@ obj-$(CONFIG_KS7010)		+= ks7010/
>   obj-$(CONFIG_GREYBUS)		+= greybus/
>   obj-$(CONFIG_BCM2835_VCHIQ)	+= vc04_services/
>   obj-$(CONFIG_CRYPTO_DEV_CCREE)	+= ccree/
> +obj-$(CONFIG_DRM_VBOXVIDEO)	+= vboxvideo/
> diff --git a/drivers/staging/vboxvideo/Kconfig b/drivers/staging/vboxvideo/Kconfig
> new file mode 100644
> index 000000000000..a19168d69e99
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/Kconfig
> @@ -0,0 +1,11 @@
> +config DRM_VBOXVIDEO
> +	tristate "Virtual Box Graphics Card"
> +	depends on DRM && X86 && PCI
> +	select DRM_KMS_HELPER
> +	help
> +	  This is a KMS driver for the virtual Graphics Card used in
> +	  Virtual Box virtual machines.
> +
> +	  Although it is possible to builtin this module, it is advised
> +	  to build this driver as a module. Select M to built this driver as
> +	  a module and add support for these devices via drm/kms interfaces.
> diff --git a/drivers/staging/vboxvideo/Makefile b/drivers/staging/vboxvideo/Makefile
> new file mode 100644
> index 000000000000..88deaf66a0a6
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/Makefile
> @@ -0,0 +1,7 @@
> +ccflags-y := -Iinclude/drm -I$(src)/osindependent
> +
> +vboxvideo-y :=  osindependent/HGSMIBase.o osindependent/Modesetting.o \
> +		osindependent/VBVABase.o vbox_drv.o vbox_fb.o vbox_hgsmi.o \
> +		vbox_irq.o vbox_main.o vbox_mode.o vbox_prime.o vbox_ttm.o
> +
> +obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo.o
> diff --git a/drivers/staging/vboxvideo/TODO b/drivers/staging/vboxvideo/TODO
> new file mode 100644
> index 000000000000..df7bd0188918
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/TODO
> @@ -0,0 +1,7 @@
> +TODO:
> +-Get a review from the drm-maintainers on dri-devel done on this driver
> +-Fill this TODO with the results of that review
> +
> +Please send any patches to Greg Kroah-Hartman <gregkh at linuxfoundation.org>,
> +Hans de Goede <hdegoede at redhat.com> and
> +Michael Thayer <michael.thayer at oracle.com>.
> diff --git a/drivers/staging/vboxvideo/osindependent/HGSMIBase.c b/drivers/staging/vboxvideo/osindependent/HGSMIBase.c
> new file mode 100644
> index 000000000000..3cdf961b1d71
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/HGSMIBase.c
> @@ -0,0 +1,371 @@
> +/* $Id: HGSMIBase.cpp 67145 2017-05-30 15:11:29Z vboxsync $ */
> +/** @file
> + * VirtualBox Video driver, common code - HGSMI guest-to-host communication.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <VBoxVideoGuest.h>
> +#include <VBoxVideoVBE.h>
> +#include <VBoxVideoIPRT.h>
> +
> +/** Detect whether HGSMI is supported by the host. */
> +DECLHIDDEN(bool) VBoxHGSMIIsSupported(void)
> +{
> +    uint16_t DispiId;
> +
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
> +
> +    DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +
> +    return (DispiId == VBE_DISPI_ID_HGSMI);
> +}
> +
> +
> +/**
> + * Inform the host of the location of the host flags in VRAM via an HGSMI
> + * command.
> + * @returns  IPRT status value.
> + * @returns  VERR_NOT_IMPLEMENTED  if the host does not support the command.
> + * @returns  VERR_NO_MEMORY        if a heap allocation fails.
> + * @param    pCtx                  the context of the guest heap to use.
> + * @param    offLocation           the offset chosen for the flags withing guest
> + *                                 VRAM.
> + */
> +DECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                             HGSMIOFFSET offLocation)
> +{
> +    HGSMIBUFFERLOCATION *p;
> +    int rc = VINF_SUCCESS;
> +
> +    /* Allocate the IO buffer. */
> +    p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx,
> +                                              sizeof(HGSMIBUFFERLOCATION),
> +                                              HGSMI_CH_HGSMI,
> +                                              HGSMI_CC_HOST_FLAGS_LOCATION);
> +    if (p)
> +    {
> +        /* Prepare data to be sent to the host. */
> +        p->offLocation = offLocation;
> +        p->cbLocation  = sizeof(HGSMIHOSTFLAGS);
> +        rc = VBoxHGSMIBufferSubmit(pCtx, p);
> +        /* Free the IO buffer. */
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    return rc;
> +}
> +
> +
> +/**
> + * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
> + * @returns  IPRT status value.
> + * @returns  VERR_NOT_IMPLEMENTED  if the host does not support the command.
> + * @returns  VERR_NO_MEMORY        if a heap allocation fails.
> + * @param    pCtx                  the context of the guest heap to use.
> + * @param    fCaps                 the capabilities to report, see VBVACAPS.
> + */
> +DECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                      uint32_t fCaps)
> +{
> +    VBVACAPS *pCaps;
> +    int rc = VINF_SUCCESS;
> +
> +    /* Allocate the IO buffer. */
> +    pCaps = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx,
> +                                       sizeof(VBVACAPS), HGSMI_CH_VBVA,
> +                                       VBVA_INFO_CAPS);
> +
> +    if (pCaps)
> +    {
> +        /* Prepare data to be sent to the host. */
> +        pCaps->rc    = VERR_NOT_IMPLEMENTED;
> +        pCaps->fCaps = fCaps;
> +        rc = VBoxHGSMIBufferSubmit(pCtx, pCaps);
> +        if (RT_SUCCESS(rc))
> +        {
> +            AssertRC(pCaps->rc);
> +            rc = pCaps->rc;
> +        }
> +        /* Free the IO buffer. */
> +        VBoxHGSMIBufferFree(pCtx, pCaps);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    return rc;
> +}
> +
> +
> +/**
> + * Get the information needed to map the basic communication structures in
> + * device memory into our address space.  All pointer parameters are optional.
> + *
> + * @param  cbVRAM               how much video RAM is allocated to the device
> + * @param  poffVRAMBaseMapping  where to save the offset from the start of the
> + *                              device VRAM of the whole area to map
> + * @param  pcbMapping           where to save the mapping size
> + * @param  poffGuestHeapMemory  where to save the offset into the mapped area
> + *                              of the guest heap backing memory
> + * @param  pcbGuestHeapMemory   where to save the size of the guest heap
> + *                              backing memory
> + * @param  poffHostFlags        where to save the offset into the mapped area
> + *                              of the host flags
> + */
> +DECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM,
> +                                             uint32_t *poffVRAMBaseMapping,
> +                                             uint32_t *pcbMapping,
> +                                             uint32_t *poffGuestHeapMemory,
> +                                             uint32_t *pcbGuestHeapMemory,
> +                                             uint32_t *poffHostFlags)
> +{
> +    AssertPtrNullReturnVoid(poffVRAMBaseMapping);
> +    AssertPtrNullReturnVoid(pcbMapping);
> +    AssertPtrNullReturnVoid(poffGuestHeapMemory);
> +    AssertPtrNullReturnVoid(pcbGuestHeapMemory);
> +    AssertPtrNullReturnVoid(poffHostFlags);
> +    if (poffVRAMBaseMapping)
> +        *poffVRAMBaseMapping = cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE;
> +    if (pcbMapping)
> +        *pcbMapping = VBVA_ADAPTER_INFORMATION_SIZE;
> +    if (poffGuestHeapMemory)
> +        *poffGuestHeapMemory = 0;
> +    if (pcbGuestHeapMemory)
> +        *pcbGuestHeapMemory =   VBVA_ADAPTER_INFORMATION_SIZE
> +                              - sizeof(HGSMIHOSTFLAGS);
> +    if (poffHostFlags)
> +        *poffHostFlags =   VBVA_ADAPTER_INFORMATION_SIZE
> +                         - sizeof(HGSMIHOSTFLAGS);
> +}
> +
> +
> +/** Sanity test on first call.  We do not worry about concurrency issues. */
> +static int testQueryConf(PHGSMIGUESTCOMMANDCONTEXT pCtx)
> +{
> +    static bool cOnce = false;
> +    uint32_t ulValue = 0;
> +    int rc;
> +
> +    if (cOnce)
> +        return VINF_SUCCESS;
> +    cOnce = true;
> +    rc = VBoxQueryConfHGSMI(pCtx, UINT32_MAX, &ulValue);
> +    if (RT_SUCCESS(rc) && ulValue == UINT32_MAX)
> +        return VINF_SUCCESS;
> +    cOnce = false;
> +    if (RT_FAILURE(rc))
> +        return rc;
> +    return VERR_INTERNAL_ERROR;
> +}
> +
> +
> +/**
> + * Query the host for an HGSMI configuration parameter via an HGSMI command.
> + * @returns iprt status value
> + * @param  pCtx      the context containing the heap used
> + * @param  u32Index  the index of the parameter to query,
> + *                   @see VBVACONF32::u32Index
> + * @param  u32DefValue defaut value
> + * @param  pulValue  where to store the value of the parameter on success
> + */
> +DECLHIDDEN(int) VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                      uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue)
> +{
> +    int rc = VINF_SUCCESS;
> +    VBVACONF32 *p;
> +    // LogFunc(("u32Index = %d\n", u32Index));
> +
> +    rc = testQueryConf(pCtx);
> +    if (RT_FAILURE(rc))
> +        return rc;
> +    /* Allocate the IO buffer. */
> +    p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx,
> +                                     sizeof(VBVACONF32), HGSMI_CH_VBVA,
> +                                     VBVA_QUERY_CONF32);
> +    if (p)
> +    {
> +        /* Prepare data to be sent to the host. */
> +        p->u32Index = u32Index;
> +        p->u32Value = u32DefValue;
> +        rc = VBoxHGSMIBufferSubmit(pCtx, p);
> +        if (RT_SUCCESS(rc))
> +        {
> +            *pulValue = p->u32Value;
> +            // LogFunc(("u32Value = %d\n", p->u32Value));
> +        }
> +        /* Free the IO buffer. */
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    // LogFunc(("rc = %d\n", rc));
> +    return rc;
> +}
> +
> +DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                   uint32_t u32Index, uint32_t *pulValue)
> +{
> +    return VBoxQueryConfHGSMIDef(pCtx, u32Index, UINT32_MAX, pulValue);
> +}
> +
> +/**
> + * Pass the host a new mouse pointer shape via an HGSMI command.
> + *
> + * @returns  success or failure
> + * @param  pCtx      the context containing the heap to be used
> + * @param  fFlags    cursor flags, @see VMMDevReqMousePointer::fFlags
> + * @param  cHotX     horizontal position of the hot spot
> + * @param  cHotY     vertical position of the hot spot
> + * @param  cWidth    width in pixels of the cursor
> + * @param  cHeight   height in pixels of the cursor
> + * @param  pPixels   pixel data, @see VMMDevReqMousePointer for the format
> + * @param  cbLength  size in bytes of the pixel data
> + */
> +DECLHIDDEN(int)  VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                             uint32_t fFlags,
> +                                             uint32_t cHotX,
> +                                             uint32_t cHotY,
> +                                             uint32_t cWidth,
> +                                             uint32_t cHeight,
> +                                             uint8_t *pPixels,
> +                                             uint32_t cbLength)
> +{
> +    VBVAMOUSEPOINTERSHAPE *p;
> +    uint32_t cbData = 0;
> +    int rc = VINF_SUCCESS;
> +
> +    if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
> +    {
> +        /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
> +        cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
> +                 + cWidth * 4 * cHeight;
> +        /* If shape is supplied, then always create the pointer visible.
> +         * See comments in 'vboxUpdatePointerShape'
> +         */
> +        fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
> +    }
> +    // LogFlowFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight));
> +    if (cbData > cbLength)
> +    {
> +        // LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n",
> +        //          cbData, cbLength));
> +        return VERR_INVALID_PARAMETER;
> +    }
> +    /* Allocate the IO buffer. */
> +    p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx,
> +                                                  sizeof(VBVAMOUSEPOINTERSHAPE)
> +                                                + cbData,
> +                                                HGSMI_CH_VBVA,
> +                                                VBVA_MOUSE_POINTER_SHAPE);
> +    if (p)
> +    {
> +        /* Prepare data to be sent to the host. */
> +        /* Will be updated by the host. */
> +        p->i32Result = VINF_SUCCESS;
> +        /* We have our custom flags in the field */
> +        p->fu32Flags = fFlags;
> +        p->u32HotX   = cHotX;
> +        p->u32HotY   = cHotY;
> +        p->u32Width  = cWidth;
> +        p->u32Height = cHeight;
> +        if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
> +            /* Copy the actual pointer data. */
> +            memcpy (p->au8Data, pPixels, cbData);
> +        rc = VBoxHGSMIBufferSubmit(pCtx, p);
> +        if (RT_SUCCESS(rc))
> +            rc = p->i32Result;
> +        /* Free the IO buffer. */
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    // LogFlowFunc(("rc %d\n", rc));
> +    return rc;
> +}
> +
> +
> +/**
> + * Report the guest cursor position.  The host may wish to use this information
> + * to re-position its own cursor (though this is currently unlikely).  The
> + * current host cursor position is returned.
> + * @param  pCtx             The context containing the heap used.
> + * @param  fReportPosition  Are we reporting a position?
> + * @param  x                Guest cursor X position.
> + * @param  y                Guest cursor Y position.
> + * @param  pxHost           Host cursor X position is stored here.  Optional.
> + * @param  pyHost           Host cursor Y position is stored here.  Optional.
> + * @returns  iprt status code.
> + * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
> + */
> +DECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y,
> +                                        uint32_t *pxHost, uint32_t *pyHost)
> +{
> +    int rc = VINF_SUCCESS;
> +    VBVACURSORPOSITION *p;
> +    // Log(("%s: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));
> +
> +    /* Allocate the IO buffer. */
> +    p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACURSORPOSITION), HGSMI_CH_VBVA, VBVA_CURSOR_POSITION);
> +    if (p)
> +    {
> +        /* Prepare data to be sent to the host. */
> +        p->fReportPosition = fReportPosition ? 1 : 0;
> +        p->x = x;
> +        p->y = y;
> +        rc = VBoxHGSMIBufferSubmit(pCtx, p);
> +        if (RT_SUCCESS(rc))
> +        {
> +            if (pxHost)
> +                *pxHost = p->x;
> +            if (pyHost)
> +                *pyHost = p->y;
> +            // Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)p->x, (unsigned)p->y));
> +        }
> +        /* Free the IO buffer. */
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    // LogFunc(("rc = %d\n", rc));
> +    return rc;
> +}
> +
> +
> +/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
> + * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
> + * host information which is needed by the guest.
> + *
> + * Reading will not cause a switch to the host.
> + *
> + * Have to take into account:
> + *  * synchronization: host must write to the memory only from EMT,
> + *    large structures must be read under flag, which tells the host
> + *    that the guest is currently reading the memory (OWNER flag?).
> + *  * guest writes: may be allocate a page for the host info and make
> + *    the page readonly for the guest.
> + *  * the information should be available only for additions drivers.
> + *  * VMMDev additions driver will inform the host which version of the info it expects,
> + *    host must support all versions.
> + *
> + */
> diff --git a/drivers/staging/vboxvideo/osindependent/HGSMIBase.h b/drivers/staging/vboxvideo/osindependent/HGSMIBase.h
> new file mode 100644
> index 000000000000..aafe0f95601f
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/HGSMIBase.h
> @@ -0,0 +1,52 @@
> +/** @file
> + * VBox Host Guest Shared Memory Interface (HGSMI) buffer management.
> + */
> +
> +/*
> + * Copyright (C) 2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef ___VBox_Graphics_HGSMIBase_h___
> +#define ___VBox_Graphics_HGSMIBase_h___
> +
> +#include <VBoxVideoIPRT.h>
> +#include <HGSMIChannels.h>
> +#include <HGSMIChSetup.h>
> +#include <HGSMIDefs.h>
> +#include <linux/genalloc.h>
> +
> +typedef struct gen_pool *PHGSMIGUESTCOMMANDCONTEXT;
> +
> +void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
> +			 u8 channel, u16 channel_info);
> +void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf);
> +int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf);
> +
> +/*
> + * Translate CamelCase names used in osindependent code to standard
> + * kernel style names.
> + */
> +#define VBoxHGSMIBufferAlloc(ctx, size, ch, ch_info) \
> +	hgsmi_buffer_alloc(ctx, size, ch, ch_info)
> +#define VBoxHGSMIBufferFree(ctx, buf)	hgsmi_buffer_free(ctx, buf)
> +#define VBoxHGSMIBufferSubmit(ctx, buf)	hgsmi_buffer_submit(ctx, buf)
> +
> +#endif
> diff --git a/drivers/staging/vboxvideo/osindependent/HGSMIChSetup.h b/drivers/staging/vboxvideo/osindependent/HGSMIChSetup.h
> new file mode 100644
> index 000000000000..c9de45603240
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/HGSMIChSetup.h
> @@ -0,0 +1,76 @@
> +/** @file
> + * VBox Host Guest Shared Memory Interface (HGSMI), sHost/Guest shared part.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef ___VBox_Graphics_HGSMIChSetup_h
> +#define ___VBox_Graphics_HGSMIChSetup_h
> +
> +/* HGSMI setup and configuration channel commands and data structures. */
> +#define HGSMI_CC_HOST_FLAGS_LOCATION 0 /* Tell the host the location of HGSMIHOSTFLAGS structure,
> +                                        * where the host can write information about pending
> +                                        * buffers, etc, and which can be quickly polled by
> +                                        * the guest without a need to port IO.
> +                                        */
> +
> +typedef struct HGSMIBUFFERLOCATION
> +{
> +    HGSMIOFFSET offLocation;
> +    HGSMISIZE   cbLocation;
> +} HGSMIBUFFERLOCATION;
> +AssertCompileSize(HGSMIBUFFERLOCATION, 8);
> +
> +/* HGSMI setup and configuration data structures. */
> +/* host->guest commands pending, should be accessed under FIFO lock only */
> +#define HGSMIHOSTFLAGS_COMMANDS_PENDING    UINT32_C(0x1)
> +/* IRQ is fired, should be accessed under VGAState::lock only  */
> +#define HGSMIHOSTFLAGS_IRQ                 UINT32_C(0x2)
> +#ifdef VBOX_WITH_WDDM
> +/* one or more guest commands is completed, should be accessed under FIFO lock only */
> +# define HGSMIHOSTFLAGS_GCOMMAND_COMPLETED UINT32_C(0x4)
> +/* watchdog timer interrupt flag (used for debugging), should be accessed under VGAState::lock only */
> +# define HGSMIHOSTFLAGS_WATCHDOG           UINT32_C(0x8)
> +#endif
> +/* vsync interrupt flag, should be accessed under VGAState::lock only */
> +#define HGSMIHOSTFLAGS_VSYNC               UINT32_C(0x10)
> +/** monitor hotplug flag, should be accessed under VGAState::lock only */
> +#define HGSMIHOSTFLAGS_HOTPLUG             UINT32_C(0x20)
> +/** Cursor capability state change flag, should be accessed under
> + * VGAState::lock only.  @see VBVACONF32. */
> +#define HGSMIHOSTFLAGS_CURSOR_CAPABILITIES UINT32_C(0x40)
> +
> +typedef struct HGSMIHOSTFLAGS
> +{
> +    /* host flags can be accessed and modified in multiple threads concurrently,
> +     * e.g. CrOpenGL HGCM and GUI threads when to completing HGSMI 3D and Video Accel respectively,
> +     * EMT thread when dealing with HGSMI command processing, etc.
> +     * Besides settings/cleaning flags atomically, some each flag has its own special sync restrictions,
> +     * see commants for flags definitions above */
> +    volatile uint32_t u32HostFlags;
> +    uint32_t au32Reserved[3];
> +} HGSMIHOSTFLAGS;
> +AssertCompileSize(HGSMIHOSTFLAGS, 16);
> +
> +#endif
> +
> diff --git a/drivers/staging/vboxvideo/osindependent/HGSMIChannels.h b/drivers/staging/vboxvideo/osindependent/HGSMIChannels.h
> new file mode 100644
> index 000000000000..04c2c1c9ba9c
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/HGSMIChannels.h
> @@ -0,0 +1,65 @@
> +/** @file
> + *
> + * VBox Host Guest Shared Memory Interface (HGSMI).
> + * Host/Guest shared part.
> + * Channel identifiers.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +
> +#ifndef __HGSMIChannels_h__
> +#define __HGSMIChannels_h__
> +
> +
> +/* Each channel has an 8 bit identifier. There are a number of predefined
> + * (hardcoded) channels.
> + *
> + * HGSMI_CH_HGSMI channel can be used to map a string channel identifier
> + * to a free 16 bit numerical value. values are allocated in range
> + * [HGSMI_CH_STRING_FIRST;HGSMI_CH_STRING_LAST].
> + *
> + */
> +
> +
> +/* Predefined channel identifiers. Used internally by VBOX to simplify the channel setup. */
> +#define HGSMI_CH_RESERVED     (0x00) /* A reserved channel value. */
> +
> +#define HGSMI_CH_HGSMI        (0x01) /* HGCMI: setup and configuration channel. */
> +
> +#define HGSMI_CH_VBVA         (0x02) /* Graphics: VBVA. */
> +#define HGSMI_CH_SEAMLESS     (0x03) /* Graphics: Seamless with a single guest region. */
> +#define HGSMI_CH_SEAMLESS2    (0x04) /* Graphics: Seamless with separate host windows. */
> +#define HGSMI_CH_OPENGL       (0x05) /* Graphics: OpenGL HW acceleration. */
> +
> +
> +/* Dynamically allocated channel identifiers. */
> +#define HGSMI_CH_STRING_FIRST (0x20) /* The first channel index to be used for string mappings (inclusive). */
> +#define HGSMI_CH_STRING_LAST  (0xff) /* The last channel index for string mappings (inclusive). */
> +
> +
> +/* Check whether the channel identifier is allocated for a dynamic channel. */
> +#define HGSMI_IS_DYNAMIC_CHANNEL(_channel) (((uint8_t)(_channel) & 0xE0) != 0)
> +
> +
> +#endif /* !__HGSMIChannels_h__*/
> diff --git a/drivers/staging/vboxvideo/osindependent/HGSMIDefs.h b/drivers/staging/vboxvideo/osindependent/HGSMIDefs.h
> new file mode 100644
> index 000000000000..99cfdc165237
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/HGSMIDefs.h
> @@ -0,0 +1,123 @@
> +/** @file
> + *
> + * VBox Host Guest Shared Memory Interface (HGSMI).
> + * Host/Guest shared part: types and defines.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +
> +#ifndef ___VBox_Graphics_HGSMIDefs_h
> +#define ___VBox_Graphics_HGSMIDefs_h
> +
> +#include <VBoxVideoIPRT.h>
> +
> +/* HGSMI uses 32 bit offsets and sizes. */
> +typedef uint32_t HGSMISIZE;
> +typedef uint32_t HGSMIOFFSET;
> +
> +#define HGSMIOFFSET_VOID ((HGSMIOFFSET)~0)
> +
> +/* Describes a shared memory area buffer.
> + * Used for calculations with offsets and for buffers verification.
> + */
> +typedef struct HGSMIAREA
> +{
> +    uint8_t     *pu8Base; /* The starting address of the area. Corresponds to offset 'offBase'. */
> +    HGSMIOFFSET  offBase; /* The starting offset of the area. */
> +    HGSMIOFFSET  offLast; /* The last valid offset:
> +                           * offBase + cbArea - 1 - (sizeof(header) + sizeof(tail)).
> +                           */
> +    HGSMISIZE    cbArea;  /* Size of the area. */
> +} HGSMIAREA;
> +
> +
> +/* The buffer description flags. */
> +#define HGSMI_BUFFER_HEADER_F_SEQ_MASK     0x03 /* Buffer sequence type mask. */
> +#define HGSMI_BUFFER_HEADER_F_SEQ_SINGLE   0x00 /* Single buffer, not a part of a sequence. */
> +#define HGSMI_BUFFER_HEADER_F_SEQ_START    0x01 /* The first buffer in a sequence. */
> +#define HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE 0x02 /* A middle buffer in a sequence. */
> +#define HGSMI_BUFFER_HEADER_F_SEQ_END      0x03 /* The last buffer in a sequence. */
> +
> +
> +#pragma pack(1)
> +/* 16 bytes buffer header. */
> +typedef struct HGSMIBUFFERHEADER
> +{
> +    uint32_t    u32DataSize;            /* Size of data that follows the header. */
> +
> +    uint8_t     u8Flags;                /* The buffer description: HGSMI_BUFFER_HEADER_F_* */
> +
> +    uint8_t     u8Channel;              /* The channel the data must be routed to. */
> +    uint16_t    u16ChannelInfo;         /* Opaque to the HGSMI, used by the channel. */
> +
> +    union {
> +        uint8_t au8Union[8];            /* Opaque placeholder to make the union 8 bytes. */
> +
> +        struct
> +        {                               /* HGSMI_BUFFER_HEADER_F_SEQ_SINGLE */
> +            uint32_t u32Reserved1;      /* A reserved field, initialize to 0. */
> +            uint32_t u32Reserved2;      /* A reserved field, initialize to 0. */
> +        } Buffer;
> +
> +        struct
> +        {                               /* HGSMI_BUFFER_HEADER_F_SEQ_START */
> +            uint32_t u32SequenceNumber; /* The sequence number, the same for all buffers in the sequence. */
> +            uint32_t u32SequenceSize;   /* The total size of the sequence. */
> +        } SequenceStart;
> +
> +        struct
> +        {                               /* HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE and HGSMI_BUFFER_HEADER_F_SEQ_END */
> +            uint32_t u32SequenceNumber; /* The sequence number, the same for all buffers in the sequence. */
> +            uint32_t u32SequenceOffset; /* Data offset in the entire sequence. */
> +        } SequenceContinue;
> +    } u;
> +} HGSMIBUFFERHEADER;
> +
> +/* 8 bytes buffer tail. */
> +typedef struct HGSMIBUFFERTAIL
> +{
> +    uint32_t    u32Reserved;        /* Reserved, must be initialized to 0. */
> +    uint32_t    u32Checksum;        /* Verifyer for the buffer header and offset and for first 4 bytes of the tail. */
> +} HGSMIBUFFERTAIL;
> +#pragma pack()
> +
> +AssertCompileSize(HGSMIBUFFERHEADER, 16);
> +AssertCompileSize(HGSMIBUFFERTAIL, 8);
> +
> +/* The size of the array of channels. Array indexes are uint8_t. Note: the value must not be changed. */
> +#define HGSMI_NUMBER_OF_CHANNELS 0x100
> +
> +typedef struct HGSMIENV
> +{
> +    /* Environment context pointer. */
> +    void *pvEnv;
> +
> +    /* Allocate system memory. */
> +    DECLCALLBACKMEMBER(void *, pfnAlloc)(void *pvEnv, HGSMISIZE cb);
> +
> +    /* Free system memory. */
> +    DECLCALLBACKMEMBER(void, pfnFree)(void *pvEnv, void *pv);
> +} HGSMIENV;
> +
> +#endif /* !___VBox_Graphics_HGSMIDefs_h */
> diff --git a/drivers/staging/vboxvideo/osindependent/Modesetting.c b/drivers/staging/vboxvideo/osindependent/Modesetting.c
> new file mode 100644
> index 000000000000..9a7c0553b6a8
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/Modesetting.c
> @@ -0,0 +1,391 @@
> +/* $Id: Modesetting.cpp 66544 2017-04-12 17:02:30Z vboxsync $ */
> +/** @file
> + * VirtualBox Video driver, common code - HGSMI initialisation and helper
> + * functions.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <VBoxVideoGuest.h>
> +#include <VBoxVideoVBE.h>
> +
> +#ifndef VBOX_GUESTR3XF86MOD
> +# include <VBoxVideoIPRT.h>
> +#endif
> +
> +/**
> + * Gets the count of virtual monitors attached to the guest via an HGSMI
> + * command
> + *
> + * @returns the right count on success or 1 on failure.
> + * @param  pCtx  the context containing the heap to use
> + */
> +DECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx)
> +{
> +    /* Query the configured number of displays. */
> +    uint32_t cDisplays = 0;
> +    VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
> +    // LogFunc(("cDisplays = %d\n", cDisplays));
> +    if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
> +        /* Host reported some bad value. Continue in the 1 screen mode. */
> +        cDisplays = 1;
> +    return cDisplays;
> +}
> +
> +
> +/**
> + * Returns the size of the video RAM in bytes.
> + *
> + * @returns the size
> + */
> +DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void)
> +{
> +    /** @note A 32bit read on this port returns the VRAM size. */
> +    return VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
> +}
> +
> +
> +/**
> + * Check whether this hardware allows the display width to have non-multiple-
> + * of-eight values.
> + *
> + * @returns true if any width is allowed, false otherwise.
> + */
> +DECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void)
> +{
> +    unsigned DispiId;
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
> +    DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +    return (DispiId == VBE_DISPI_ID_ANYX);
> +}
> +
> +
> +/**
> + * Tell the host about how VRAM is divided up between each screen via an HGSMI
> + * command.  It is acceptable to specifiy identical data for each screen if
> + * they share a single framebuffer.
> + *
> + * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
> + *          @a pfnFill
> + * @todo  What was I thinking of with that callback function?  It
> + *        would be much simpler to just pass in a structure in normal
> + *        memory and copy it.
> + * @param  pCtx      the context containing the heap to use
> + * @param  u32Count  the number of screens we are activating
> + * @param  pfnFill   a callback which initialises the VBVAINFOVIEW structures
> + *                   for all screens
> + * @param  pvData    context data for @a pfnFill
> + */
> +DECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                      uint32_t u32Count,
> +                                      PFNHGSMIFILLVIEWINFO pfnFill,
> +                                      void *pvData)
> +{
> +    int rc;
> +    /* Issue the screen info command. */
> +    void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
> +                                   HGSMI_CH_VBVA, VBVA_INFO_VIEW);
> +    if (p)
> +    {
> +        VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
> +        rc = pfnFill(pvData, pInfo, u32Count);
> +        if (RT_SUCCESS(rc))
> +            VBoxHGSMIBufferSubmit (pCtx, p);
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    return rc;
> +}
> +
> +
> +/**
> + * Set a video mode using port registers.  This must be done for the first
> + * screen before every HGSMI modeset and also works when HGSM is not enabled.
> + * @param  cWidth      the mode width
> + * @param  cHeight     the mode height
> + * @param  cVirtWidth  the mode pitch
> + * @param  cBPP        the colour depth of the mode
> + * @param  fFlags      flags for the mode.  These will be or-ed with the
> + *                     default _ENABLED flag, so unless you are restoring
> + *                     a saved mode or have special requirements you can pass
> + *                     zero here.
> + * @param  cx          the horizontal panning offset
> + * @param  cy          the vertical panning offset
> + */
> +DECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
> +                                           uint16_t cVirtWidth, uint16_t cBPP,
> +                                           uint16_t fFlags, uint16_t cx,
> +                                           uint16_t cy)
> +{
> +    /* set the mode characteristics */
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cWidth);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cHeight);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                VBE_DISPI_INDEX_VIRT_WIDTH);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cVirtWidth);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cBPP);
> +    /* enable the mode */
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                VBE_DISPI_INDEX_ENABLE);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA,
> +                                fFlags | VBE_DISPI_ENABLED);
> +    /* Panning registers */
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                VBE_DISPI_INDEX_X_OFFSET);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cx);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                VBE_DISPI_INDEX_Y_OFFSET);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cy);
> +    /** @todo read from the port to see if the mode switch was successful */
> +}
> +
> +
> +/**
> + * Get the video mode for the first screen using the port registers.  All
> + * parameters are optional
> + * @returns  true if the VBE mode returned is active, false if we are in VGA
> + *           mode
> + * @note  If anyone else needs additional register values just extend the
> + *        function with additional parameters and fix any existing callers.
> + * @param  pcWidth      where to store the mode width
> + * @param  pcHeight     where to store the mode height
> + * @param  pcVirtWidth  where to store the mode pitch
> + * @param  pcBPP        where to store the colour depth of the mode
> + * @param  pfFlags      where to store the flags for the mode
> + */
> +DECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, uint16_t *pcHeight,
> +                                           uint16_t *pcVirtWidth, uint16_t *pcBPP,
> +                                           uint16_t *pfFlags)
> +{
> +    uint16_t fFlags;
> +
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                VBE_DISPI_INDEX_ENABLE);
> +    fFlags = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +    if (pcWidth)
> +    {
> +        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                    VBE_DISPI_INDEX_XRES);
> +        *pcWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +    }
> +    if (pcHeight)
> +    {
> +        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                    VBE_DISPI_INDEX_YRES);
> +        *pcHeight = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +    }
> +    if (pcVirtWidth)
> +    {
> +        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                    VBE_DISPI_INDEX_VIRT_WIDTH);
> +        *pcVirtWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +    }
> +    if (pcBPP)
> +    {
> +        VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                    VBE_DISPI_INDEX_BPP);
> +        *pcBPP = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
> +    }
> +    if (pfFlags)
> +        *pfFlags = fFlags;
> +    return RT_BOOL(fFlags & VBE_DISPI_ENABLED);
> +}
> +
> +
> +/**
> + * Disable our extended graphics mode and go back to VGA mode.
> + */
> +DECLHIDDEN(void) VBoxVideoDisableVBE(void)
> +{
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX,
> +                                VBE_DISPI_INDEX_ENABLE);
> +    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, 0);
> +}
> +
> +
> +/**
> + * Set a video mode via an HGSMI request.  The views must have been
> + * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
> + * set on the first display then it must be set first using registers.
> + * @param  pCtx      The context containing the heap to use.
> + * @param  cDisplay  the screen number
> + * @param  cOriginX  the horizontal displacement relative to the first screen
> + * @param  cOriginY  the vertical displacement relative to the first screen
> + * @param  offStart  the offset of the visible area of the framebuffer
> + *                   relative to the framebuffer start
> + * @param  cbPitch   the offset in bytes between the starts of two adjecent
> + *                   scan lines in video RAM
> + * @param  cWidth    the mode width
> + * @param  cHeight   the mode height
> + * @param  cBPP      the colour depth of the mode
> + * @param  fFlags    flags
> + */
> +DECLHIDDEN(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                             uint32_t cDisplay,
> +                                             int32_t  cOriginX,
> +                                             int32_t  cOriginY,
> +                                             uint32_t offStart,
> +                                             uint32_t cbPitch,
> +                                             uint32_t cWidth,
> +                                             uint32_t cHeight,
> +                                             uint16_t cBPP,
> +                                             uint16_t fFlags)
> +{
> +    /* Issue the screen info command. */
> +    void *p = VBoxHGSMIBufferAlloc(pCtx,
> +                                   sizeof (VBVAINFOSCREEN),
> +                                   HGSMI_CH_VBVA,
> +                                   VBVA_INFO_SCREEN);
> +    if (!p)
> +    {
> +        // LogFunc(("HGSMIHeapAlloc failed\n"));
> +    }
> +    else
> +    {
> +        VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
> +
> +        pScreen->u32ViewIndex    = cDisplay;
> +        pScreen->i32OriginX      = cOriginX;
> +        pScreen->i32OriginY      = cOriginY;
> +        pScreen->u32StartOffset  = offStart;
> +        pScreen->u32LineSize     = cbPitch;
> +        pScreen->u32Width        = cWidth;
> +        pScreen->u32Height       = cHeight;
> +        pScreen->u16BitsPerPixel = cBPP;
> +        pScreen->u16Flags        = fFlags;
> +
> +        VBoxHGSMIBufferSubmit(pCtx, p);
> +
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +}
> +
> +
> +/** Report the rectangle relative to which absolute pointer events should be
> + *  expressed.  This information remains valid until the next VBVA resize event
> + *  for any screen, at which time it is reset to the bounding rectangle of all
> + *  virtual screens.
> + * @param  pCtx      The context containing the heap to use.
> + * @param  cOriginX  Upper left X co-ordinate relative to the first screen.
> + * @param  cOriginY  Upper left Y co-ordinate relative to the first screen.
> + * @param  cWidth    Rectangle width.
> + * @param  cHeight   Rectangle height.
> + * @returns  iprt status code.
> + * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
> + */
> +DECLHIDDEN(int)      VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t  cOriginX, int32_t  cOriginY,
> +                                                 uint32_t cWidth, uint32_t cHeight)
> +{
> +    int rc = VINF_SUCCESS;
> +    VBVAREPORTINPUTMAPPING *p;
> +    // Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
> +    //      (unsigned)cWidth, (unsigned)cHeight));
> +
> +    /* Allocate the IO buffer. */
> +    p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
> +                                                       VBVA_REPORT_INPUT_MAPPING);
> +    if (p)
> +    {
> +        /* Prepare data to be sent to the host. */
> +        p->x  = cOriginX;
> +        p->y  = cOriginY;
> +        p->cx = cWidth;
> +        p->cy = cHeight;
> +        rc = VBoxHGSMIBufferSubmit(pCtx, p);
> +        /* Free the IO buffer. */
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    else
> +        rc = VERR_NO_MEMORY;
> +    // LogFunc(("rc = %d\n", rc));
> +    return rc;
> +}
> +
> +
> +/**
> + * Get most recent video mode hints.
> + * @param  pCtx      the context containing the heap to use
> + * @param  cScreens  the number of screens to query hints for, starting at 0.
> + * @param  paHints   array of VBVAMODEHINT structures for receiving the hints.
> + * @returns  iprt status code
> + * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
> + * @returns  VERR_NOT_SUPPORTED  Host does not support this command.
> + */
> +DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                      unsigned cScreens, VBVAMODEHINT *paHints)
> +{
> +    int rc;
> +    void *p;
> +
> +    AssertPtr(paHints);
> +    if (!VALID_PTR(paHints))
> +        return VERR_INVALID_POINTER;
> +
> +    p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAQUERYMODEHINTS)
> +                                       + cScreens * sizeof(VBVAMODEHINT),
> +                             HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
> +    if (!p)
> +    {
> +        // LogFunc(("HGSMIHeapAlloc failed\n"));
> +        return VERR_NO_MEMORY;
> +    }
> +    else
> +    {
> +        VBVAQUERYMODEHINTS *pQuery   = (VBVAQUERYMODEHINTS *)p;
> +
> +        pQuery->cHintsQueried        = cScreens;
> +        pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
> +        pQuery->rc                   = VERR_NOT_SUPPORTED;
> +
> +        VBoxHGSMIBufferSubmit(pCtx, p);
> +        rc = pQuery->rc;
> +        if (RT_SUCCESS(rc))
> +            memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS),
> +                   cScreens * sizeof(VBVAMODEHINT));
> +
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +    return rc;
> +}
> +
> +
> +/**
> + * Query the supported flags in VBVAINFOSCREEN::u16Flags.
> + *
> + * @returns The mask of VBVA_SCREEN_F_* flags or 0 if host does not support the request.
> + * @param  pCtx  the context containing the heap to use
> + */
> +DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx)
> +{
> +    uint32_t u32Flags = 0;
> +    int rc = VBoxQueryConfHGSMIDef(pCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, 0, &u32Flags);
> +    // LogFunc(("u32Flags = 0x%x rc %Rrc\n", u32Flags, rc));
> +    if (RT_FAILURE(rc))
> +        u32Flags = 0;
> +    return (uint16_t)u32Flags;
> +}
> diff --git a/drivers/staging/vboxvideo/osindependent/VBVABase.c b/drivers/staging/vboxvideo/osindependent/VBVABase.c
> new file mode 100644
> index 000000000000..392d4531ec3b
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/VBVABase.c
> @@ -0,0 +1,395 @@
> +/* $Id: VBVABase.cpp 66544 2017-04-12 17:02:30Z vboxsync $ */
> +/** @file
> + * VirtualBox Video driver, common code - VBVA initialisation and helper
> + * functions.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <VBoxVideoGuest.h>
> +#include <VBoxVideoIPRT.h>
> +
> +/*
> + * There is a hardware ring buffer in the graphics device video RAM, formerly
> + * in the VBox VMMDev PCI memory space.
> + * All graphics commands go there serialized by VBoxVBVABufferBeginUpdate.
> + * and vboxHwBufferEndUpdate.
> + *
> + * off32Free is writing position. off32Data is reading position.
> + * off32Free == off32Data means buffer is empty.
> + * There must be always gap between off32Data and off32Free when data
> + * are in the buffer.
> + * Guest only changes off32Free, host changes off32Data.
> + */
> +
> +/* Forward declarations of internal functions. */
> +static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx);
> +static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
> +                                    uint32_t cb, uint32_t offset);
> +static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
> +                              PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                              const void *p, uint32_t cb);
> +
> +
> +static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx,
> +                               PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                               int32_t cScreen, bool bEnable)
> +{
> +    bool bRc = false;
> +
> +#if 0  /* All callers check this */
> +    if (ppdev->bHGSMISupported)
> +#endif
> +    {
> +        void *p = VBoxHGSMIBufferAlloc(pHGSMICtx,
> +                                       sizeof (VBVAENABLE_EX),
> +                                       HGSMI_CH_VBVA,
> +                                       VBVA_ENABLE);
> +        if (!p)
> +        {
> +            // LogFunc(("HGSMIHeapAlloc failed\n"));
> +        }
> +        else
> +        {
> +            VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p;
> +
> +            pEnable->Base.u32Flags  = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE;
> +            pEnable->Base.u32Offset = pCtx->offVRAMBuffer;
> +            pEnable->Base.i32Result = VERR_NOT_SUPPORTED;
> +            if (cScreen >= 0)
> +            {
> +                pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET;
> +                pEnable->u32ScreenId    = cScreen;
> +            }
> +
> +            VBoxHGSMIBufferSubmit(pHGSMICtx, p);
> +
> +            if (bEnable)
> +            {
> +                bRc = RT_SUCCESS(pEnable->Base.i32Result);
> +            }
> +            else
> +            {
> +                bRc = true;
> +            }
> +
> +            VBoxHGSMIBufferFree(pHGSMICtx, p);
> +        }
> +    }
> +
> +    return bRc;
> +}
> +
> +/*
> + * Public hardware buffer methods.
> + */
> +DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
> +                                PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                                VBVABUFFER *pVBVA, int32_t cScreen)
> +{
> +    bool bRc = false;
> +
> +    // LogFlowFunc(("pVBVA %p\n", pVBVA));
> +
> +#if 0  /* All callers check this */
> +    if (ppdev->bHGSMISupported)
> +#endif
> +    {
> +        // LogFunc(("pVBVA %p vbva off 0x%x\n", pVBVA, pCtx->offVRAMBuffer));
> +
> +        pVBVA->hostFlags.u32HostEvents      = 0;
> +        pVBVA->hostFlags.u32SupportedOrders = 0;
> +        pVBVA->off32Data          = 0;
> +        pVBVA->off32Free          = 0;
> +        memset(pVBVA->aRecords, 0, sizeof (pVBVA->aRecords));
> +        pVBVA->indexRecordFirst   = 0;
> +        pVBVA->indexRecordFree    = 0;
> +        pVBVA->cbPartialWriteThreshold = 256;
> +        pVBVA->cbData             = pCtx->cbBuffer - sizeof (VBVABUFFER) + sizeof (pVBVA->au8Data);
> +
> +        pCtx->fHwBufferOverflow = false;
> +        pCtx->pRecord    = NULL;
> +        pCtx->pVBVA      = pVBVA;
> +
> +        bRc = vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, true);
> +    }
> +
> +    if (!bRc)
> +    {
> +        VBoxVBVADisable(pCtx, pHGSMICtx, cScreen);
> +    }
> +
> +    return bRc;
> +}
> +
> +DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
> +                                 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                                 int32_t cScreen)
> +{
> +    // LogFlowFunc(("\n"));
> +
> +    pCtx->fHwBufferOverflow = false;
> +    pCtx->pRecord           = NULL;
> +    pCtx->pVBVA             = NULL;
> +
> +    vboxVBVAInformHost(pCtx, pHGSMICtx, cScreen, false);
> +
> +    return;
> +}
> +
> +DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
> +                                           PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx)
> +{
> +    bool bRc = false;
> +
> +    // LogFunc(("flags = 0x%08X\n", pCtx->pVBVA? pCtx->pVBVA->u32HostEvents: -1));
> +
> +    if (   pCtx->pVBVA
> +        && (pCtx->pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
> +    {
> +        uint32_t indexRecordNext;
> +
> +        Assert(!pCtx->fHwBufferOverflow);
> +        Assert(pCtx->pRecord == NULL);
> +
> +        indexRecordNext = (pCtx->pVBVA->indexRecordFree + 1) % VBVA_MAX_RECORDS;
> +
> +        if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
> +        {
> +            /* All slots in the records queue are used. */
> +            vboxHwBufferFlush (pHGSMICtx);
> +        }
> +
> +        if (indexRecordNext == pCtx->pVBVA->indexRecordFirst)
> +        {
> +            /* Even after flush there is no place. Fail the request. */
> +            // LogFunc(("no space in the queue of records!!! first %d, last %d\n",
> +            //          pCtx->pVBVA->indexRecordFirst, pCtx->pVBVA->indexRecordFree));
> +        }
> +        else
> +        {
> +            /* Initialize the record. */
> +            VBVARECORD *pRecord = &pCtx->pVBVA->aRecords[pCtx->pVBVA->indexRecordFree];
> +
> +            pRecord->cbRecord = VBVA_F_RECORD_PARTIAL;
> +
> +            pCtx->pVBVA->indexRecordFree = indexRecordNext;
> +
> +            // LogFunc(("indexRecordNext = %d\n", indexRecordNext));
> +
> +            /* Remember which record we are using. */
> +            pCtx->pRecord = pRecord;
> +
> +            bRc = true;
> +        }
> +    }
> +
> +    return bRc;
> +}
> +
> +DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx)
> +{
> +    VBVARECORD *pRecord;
> +
> +    // LogFunc(("\n"));
> +
> +    Assert(pCtx->pVBVA);
> +
> +    pRecord = pCtx->pRecord;
> +    Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
> +
> +    /* Mark the record completed. */
> +    pRecord->cbRecord &= ~VBVA_F_RECORD_PARTIAL;
> +
> +    pCtx->fHwBufferOverflow = false;
> +    pCtx->pRecord = NULL;
> +
> +    return;
> +}
> +
> +/*
> + * Private operations.
> + */
> +static uint32_t vboxHwBufferAvail (const VBVABUFFER *pVBVA)
> +{
> +    int32_t i32Diff = pVBVA->off32Data - pVBVA->off32Free;
> +
> +    return i32Diff > 0? i32Diff: pVBVA->cbData + i32Diff;
> +}
> +
> +static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx)
> +{
> +    /* Issue the flush command. */
> +    void *p = VBoxHGSMIBufferAlloc(pCtx,
> +                                   sizeof (VBVAFLUSH),
> +                                   HGSMI_CH_VBVA,
> +                                   VBVA_FLUSH);
> +    if (!p)
> +    {
> +        // LogFunc(("HGSMIHeapAlloc failed\n"));
> +    }
> +    else
> +    {
> +        VBVAFLUSH *pFlush = (VBVAFLUSH *)p;
> +
> +        pFlush->u32Reserved = 0;
> +
> +        VBoxHGSMIBufferSubmit(pCtx, p);
> +
> +        VBoxHGSMIBufferFree(pCtx, p);
> +    }
> +
> +    return;
> +}
> +
> +static void vboxHwBufferPlaceDataAt(PVBVABUFFERCONTEXT pCtx, const void *p,
> +                                    uint32_t cb, uint32_t offset)
> +{
> +    VBVABUFFER *pVBVA = pCtx->pVBVA;
> +    uint32_t u32BytesTillBoundary = pVBVA->cbData - offset;
> +    uint8_t  *dst                 = &pVBVA->au8Data[offset];
> +    int32_t i32Diff               = cb - u32BytesTillBoundary;
> +
> +    if (i32Diff <= 0)
> +    {
> +        /* Chunk will not cross buffer boundary. */
> +        memcpy (dst, p, cb);
> +    }
> +    else
> +    {
> +        /* Chunk crosses buffer boundary. */
> +        memcpy (dst, p, u32BytesTillBoundary);
> +        memcpy (&pVBVA->au8Data[0], (uint8_t *)p + u32BytesTillBoundary, i32Diff);
> +    }
> +
> +    return;
> +}
> +
> +static bool vboxHwBufferWrite(PVBVABUFFERCONTEXT pCtx,
> +                              PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                              const void *p, uint32_t cb)
> +{
> +    VBVARECORD *pRecord;
> +    uint32_t cbHwBufferAvail;
> +
> +    uint32_t cbWritten = 0;
> +
> +    VBVABUFFER *pVBVA = pCtx->pVBVA;
> +    Assert(pVBVA);
> +
> +    if (!pVBVA || pCtx->fHwBufferOverflow)
> +    {
> +        return false;
> +    }
> +
> +    Assert(pVBVA->indexRecordFirst != pVBVA->indexRecordFree);
> +
> +    pRecord = pCtx->pRecord;
> +    Assert(pRecord && (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL));
> +
> +    // LogFunc(("%d\n", cb));
> +
> +    cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
> +
> +    while (cb > 0)
> +    {
> +        uint32_t cbChunk = cb;
> +
> +        // LogFunc(("pVBVA->off32Free %d, pRecord->cbRecord 0x%08X, cbHwBufferAvail %d, cb %d, cbWritten %d\n",
> +        //             pVBVA->off32Free, pRecord->cbRecord, cbHwBufferAvail, cb, cbWritten));
> +
> +        if (cbChunk >= cbHwBufferAvail)
> +        {
> +            // LogFunc(("1) avail %d, chunk %d\n", cbHwBufferAvail, cbChunk));
> +
> +            vboxHwBufferFlush (pHGSMICtx);
> +
> +            cbHwBufferAvail = vboxHwBufferAvail (pVBVA);
> +
> +            if (cbChunk >= cbHwBufferAvail)
> +            {
> +                // LogFunc(("no place for %d bytes. Only %d bytes available after flush. Going to partial writes.\n",
> +                //             cb, cbHwBufferAvail));
> +
> +                if (cbHwBufferAvail <= pVBVA->cbPartialWriteThreshold)
> +                {
> +                    // LogFunc(("Buffer overflow!!!\n"));
> +                    pCtx->fHwBufferOverflow = true;
> +                    Assert(false);
> +                    return false;
> +                }
> +
> +                cbChunk = cbHwBufferAvail - pVBVA->cbPartialWriteThreshold;
> +            }
> +        }
> +
> +        Assert(cbChunk <= cb);
> +        Assert(cbChunk <= vboxHwBufferAvail (pVBVA));
> +
> +        vboxHwBufferPlaceDataAt (pCtx, (uint8_t *)p + cbWritten, cbChunk, pVBVA->off32Free);
> +
> +        pVBVA->off32Free   = (pVBVA->off32Free + cbChunk) % pVBVA->cbData;
> +        pRecord->cbRecord += cbChunk;
> +        cbHwBufferAvail -= cbChunk;
> +
> +        cb        -= cbChunk;
> +        cbWritten += cbChunk;
> +    }
> +
> +    return true;
> +}
> +
> +/*
> + * Public writer to the hardware buffer.
> + */
> +DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
> +                               PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                               const void *pv, uint32_t cb)
> +{
> +    return vboxHwBufferWrite (pCtx, pHGSMICtx, pv, cb);
> +}
> +
> +DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code)
> +{
> +    VBVABUFFER *pVBVA = pCtx->pVBVA;
> +
> +    if (!pVBVA)
> +    {
> +        return false;
> +    }
> +
> +    if (pVBVA->hostFlags.u32SupportedOrders & (1 << code))
> +    {
> +        return true;
> +    }
> +
> +    return false;
> +}
> +
> +DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx,
> +                                            uint32_t offVRAMBuffer,
> +                                            uint32_t cbBuffer)
> +{
> +    pCtx->offVRAMBuffer = offVRAMBuffer;
> +    pCtx->cbBuffer      = cbBuffer;
> +}
> diff --git a/drivers/staging/vboxvideo/osindependent/VBoxVideo.h b/drivers/staging/vboxvideo/osindependent/VBoxVideo.h
> new file mode 100644
> index 000000000000..bfc9c5eea0c0
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/VBoxVideo.h
> @@ -0,0 +1,2105 @@
> +/** @file
> + * VirtualBox Video interface.
> + */
> +
> +/*
> + * Copyright (C) 2006-2016 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + */
> +
> +#ifndef ___VBox_Graphics_VBoxVideo_h
> +#define ___VBox_Graphics_VBoxVideo_h
> +
> +#include <VBoxVideoIPRT.h>
> +
> +/* this should be in sync with monitorCount <xsd:maxInclusive value="64"/> in src/VBox/Main/xml/VirtualBox-settings-common.xsd */
> +#define VBOX_VIDEO_MAX_SCREENS 64
> +
> +/*
> + * The last 4096 bytes of the guest VRAM contains the generic info for all
> + * DualView chunks: sizes and offsets of chunks. This is filled by miniport.
> + *
> + * Last 4096 bytes of each chunk contain chunk specific data: framebuffer info,
> + * etc. This is used exclusively by the corresponding instance of a display driver.
> + *
> + * The VRAM layout:
> + *     Last 4096 bytes - Adapter information area.
> + *     4096 bytes aligned miniport heap (value specified in the config rouded up).
> + *     Slack - what left after dividing the VRAM.
> + *     4096 bytes aligned framebuffers:
> + *       last 4096 bytes of each framebuffer is the display information area.
> + *
> + * The Virtual Graphics Adapter information in the guest VRAM is stored by the
> + * guest video driver using structures prepended by VBOXVIDEOINFOHDR.
> + *
> + * When the guest driver writes dword 0 to the VBE_DISPI_INDEX_VBOX_VIDEO
> + * the host starts to process the info. The first element at the start of
> + * the 4096 bytes region should be normally be a LINK that points to
> + * actual information chain. That way the guest driver can have some
> + * fixed layout of the information memory block and just rewrite
> + * the link to point to relevant memory chain.
> + *
> + * The processing stops at the END element.
> + *
> + * The host can access the memory only when the port IO is processed.
> + * All data that will be needed later must be copied from these 4096 bytes.
> + * But other VRAM can be used by host until the mode is disabled.
> + *
> + * The guest driver writes dword 0xffffffff to the VBE_DISPI_INDEX_VBOX_VIDEO
> + * to disable the mode.
> + *
> + * VBE_DISPI_INDEX_VBOX_VIDEO is used to read the configuration information
> + * from the host and issue commands to the host.
> + *
> + * The guest writes the VBE_DISPI_INDEX_VBOX_VIDEO index register, the the
> + * following operations with the VBE data register can be performed:
> + *
> + * Operation            Result
> + * write 16 bit value   NOP
> + * read 16 bit value    count of monitors
> + * write 32 bit value   sets the vbox command value and the command processed by the host
> + * read 32 bit value    result of the last vbox command is returned
> + */
> +
> +#define VBOX_VIDEO_PRIMARY_SCREEN 0
> +#define VBOX_VIDEO_NO_SCREEN ~0
> +
> +/**
> + * VBVA command header.
> + *
> + * @todo Where does this fit in?
> + */
> +typedef struct VBVACMDHDR
> +{
> +   /** Coordinates of affected rectangle. */
> +   int16_t x;
> +   int16_t y;
> +   uint16_t w;
> +   uint16_t h;
> +} VBVACMDHDR;
> +AssertCompileSize(VBVACMDHDR, 8);
> +
> +/** @name VBVA ring defines.
> + *
> + * The VBVA ring buffer is suitable for transferring large (< 2GB) amount of
> + * data. For example big bitmaps which do not fit to the buffer.
> + *
> + * Guest starts writing to the buffer by initializing a record entry in the
> + * aRecords queue. VBVA_F_RECORD_PARTIAL indicates that the record is being
> + * written. As data is written to the ring buffer, the guest increases off32End
> + * for the record.
> + *
> + * The host reads the aRecords on flushes and processes all completed records.
> + * When host encounters situation when only a partial record presents and
> + * cbRecord & ~VBVA_F_RECORD_PARTIAL >= VBVA_RING_BUFFER_SIZE -
> + * VBVA_RING_BUFFER_THRESHOLD, the host fetched all record data and updates
> + * off32Head. After that on each flush the host continues fetching the data
> + * until the record is completed.
> + *
> + */
> +#define VBVA_RING_BUFFER_SIZE        (_4M - _1K)
> +#define VBVA_RING_BUFFER_THRESHOLD   (4 * _1K)
> +
> +#define VBVA_MAX_RECORDS (64)
> +
> +#define VBVA_F_MODE_ENABLED         UINT32_C(0x00000001)
> +#define VBVA_F_MODE_VRDP            UINT32_C(0x00000002)
> +#define VBVA_F_MODE_VRDP_RESET      UINT32_C(0x00000004)
> +#define VBVA_F_MODE_VRDP_ORDER_MASK UINT32_C(0x00000008)
> +
> +#define VBVA_F_STATE_PROCESSING     UINT32_C(0x00010000)
> +
> +#define VBVA_F_RECORD_PARTIAL       UINT32_C(0x80000000)
> +
> +/**
> + * VBVA record.
> + */
> +typedef struct VBVARECORD
> +{
> +    /** The length of the record. Changed by guest. */
> +    uint32_t cbRecord;
> +} VBVARECORD;
> +AssertCompileSize(VBVARECORD, 4);
> +
> +/* The size of the information. */
> +/*
> + * The minimum HGSMI heap size is PAGE_SIZE (4096 bytes) and is a restriction of the
> + * runtime heapsimple API. Use minimum 2 pages here, because the info area also may
> + * contain other data (for example HGSMIHOSTFLAGS structure).
> + */
> +#ifndef VBOX_XPDM_MINIPORT
> +# define VBVA_ADAPTER_INFORMATION_SIZE (64*_1K)
> +#else
> +#define VBVA_ADAPTER_INFORMATION_SIZE  (16*_1K)
> +#define VBVA_DISPLAY_INFORMATION_SIZE  (64*_1K)
> +#endif
> +#define VBVA_MIN_BUFFER_SIZE           (64*_1K)
> +
> +
> +/* The value for port IO to let the adapter to interpret the adapter memory. */
> +#define VBOX_VIDEO_DISABLE_ADAPTER_MEMORY        0xFFFFFFFF
> +
> +/* The value for port IO to let the adapter to interpret the adapter memory. */
> +#define VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY      0x00000000
> +
> +/* The value for port IO to let the adapter to interpret the display memory.
> + * The display number is encoded in low 16 bits.
> + */
> +#define VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE 0x00010000
> +
> +
> +/* The end of the information. */
> +#define VBOX_VIDEO_INFO_TYPE_END          0
> +/* Instructs the host to fetch the next VBOXVIDEOINFOHDR at the given offset of VRAM. */
> +#define VBOX_VIDEO_INFO_TYPE_LINK         1
> +/* Information about a display memory position. */
> +#define VBOX_VIDEO_INFO_TYPE_DISPLAY      2
> +/* Information about a screen. */
> +#define VBOX_VIDEO_INFO_TYPE_SCREEN       3
> +/* Information about host notifications for the driver. */
> +#define VBOX_VIDEO_INFO_TYPE_HOST_EVENTS  4
> +/* Information about non-volatile guest VRAM heap. */
> +#define VBOX_VIDEO_INFO_TYPE_NV_HEAP      5
> +/* VBVA enable/disable. */
> +#define VBOX_VIDEO_INFO_TYPE_VBVA_STATUS  6
> +/* VBVA flush. */
> +#define VBOX_VIDEO_INFO_TYPE_VBVA_FLUSH   7
> +/* Query configuration value. */
> +#define VBOX_VIDEO_INFO_TYPE_QUERY_CONF32 8
> +
> +
> +#pragma pack(1)
> +typedef struct VBOXVIDEOINFOHDR
> +{
> +    uint8_t u8Type;
> +    uint8_t u8Reserved;
> +    uint16_t u16Length;
> +} VBOXVIDEOINFOHDR;
> +
> +
> +typedef struct VBOXVIDEOINFOLINK
> +{
> +    /* Relative offset in VRAM */
> +    int32_t i32Offset;
> +} VBOXVIDEOINFOLINK;
> +
> +
> +/* Resides in adapter info memory. Describes a display VRAM chunk. */
> +typedef struct VBOXVIDEOINFODISPLAY
> +{
> +    /* Index of the framebuffer assigned by guest. */
> +    uint32_t u32Index;
> +
> +    /* Absolute offset in VRAM of the framebuffer to be displayed on the monitor. */
> +    uint32_t u32Offset;
> +
> +    /* The size of the memory that can be used for the screen. */
> +    uint32_t u32FramebufferSize;
> +
> +    /* The size of the memory that is used for the Display information.
> +     * The information is at u32Offset + u32FramebufferSize
> +     */
> +    uint32_t u32InformationSize;
> +
> +} VBOXVIDEOINFODISPLAY;
> +
> +
> +/* Resides in display info area, describes the current video mode. */
> +#define VBOX_VIDEO_INFO_SCREEN_F_NONE   0x00
> +#define VBOX_VIDEO_INFO_SCREEN_F_ACTIVE 0x01
> +
> +typedef struct VBOXVIDEOINFOSCREEN
> +{
> +    /* Physical X origin relative to the primary screen. */
> +    int32_t xOrigin;
> +
> +    /* Physical Y origin relative to the primary screen. */
> +    int32_t yOrigin;
> +
> +    /* The scan line size in bytes. */
> +    uint32_t u32LineSize;
> +
> +    /* Width of the screen. */
> +    uint16_t u16Width;
> +
> +    /* Height of the screen. */
> +    uint16_t u16Height;
> +
> +    /* Color depth. */
> +    uint8_t bitsPerPixel;
> +
> +    /* VBOX_VIDEO_INFO_SCREEN_F_* */
> +    uint8_t u8Flags;
> +} VBOXVIDEOINFOSCREEN;
> +
> +/* The guest initializes the structure to 0. The positions of the structure in the
> + * display info area must not be changed, host will update the structure. Guest checks
> + * the events and modifies the structure as a response to host.
> + */
> +#define VBOX_VIDEO_INFO_HOST_EVENTS_F_NONE        0x00000000
> +#define VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET  0x00000080
> +
> +typedef struct VBOXVIDEOINFOHOSTEVENTS
> +{
> +    /* Host events. */
> +    uint32_t fu32Events;
> +} VBOXVIDEOINFOHOSTEVENTS;
> +
> +/* Resides in adapter info memory. Describes the non-volatile VRAM heap. */
> +typedef struct VBOXVIDEOINFONVHEAP
> +{
> +    /* Absolute offset in VRAM of the start of the heap. */
> +    uint32_t u32HeapOffset;
> +
> +    /* The size of the heap. */
> +    uint32_t u32HeapSize;
> +
> +} VBOXVIDEOINFONVHEAP;
> +
> +/* Display information area. */
> +typedef struct VBOXVIDEOINFOVBVASTATUS
> +{
> +    /* Absolute offset in VRAM of the start of the VBVA QUEUE. 0 to disable VBVA. */
> +    uint32_t u32QueueOffset;
> +
> +    /* The size of the VBVA QUEUE. 0 to disable VBVA. */
> +    uint32_t u32QueueSize;
> +
> +} VBOXVIDEOINFOVBVASTATUS;
> +
> +typedef struct VBOXVIDEOINFOVBVAFLUSH
> +{
> +    uint32_t u32DataStart;
> +
> +    uint32_t u32DataEnd;
> +
> +} VBOXVIDEOINFOVBVAFLUSH;
> +
> +#define VBOX_VIDEO_QCI32_MONITOR_COUNT       0
> +#define VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE 1
> +
> +typedef struct VBOXVIDEOINFOQUERYCONF32
> +{
> +    uint32_t u32Index;
> +
> +    uint32_t u32Value;
> +
> +} VBOXVIDEOINFOQUERYCONF32;
> +#pragma pack()
> +
> +#ifdef VBOX_WITH_VIDEOHWACCEL
> +#pragma pack(1)
> +
> +#define VBOXVHWA_VERSION_MAJ 0
> +#define VBOXVHWA_VERSION_MIN 0
> +#define VBOXVHWA_VERSION_BLD 6
> +#define VBOXVHWA_VERSION_RSV 0
> +
> +typedef enum
> +{
> +    VBOXVHWACMD_TYPE_SURF_CANCREATE = 1,
> +    VBOXVHWACMD_TYPE_SURF_CREATE,
> +    VBOXVHWACMD_TYPE_SURF_DESTROY,
> +    VBOXVHWACMD_TYPE_SURF_LOCK,
> +    VBOXVHWACMD_TYPE_SURF_UNLOCK,
> +    VBOXVHWACMD_TYPE_SURF_BLT,
> +    VBOXVHWACMD_TYPE_SURF_FLIP,
> +    VBOXVHWACMD_TYPE_SURF_OVERLAY_UPDATE,
> +    VBOXVHWACMD_TYPE_SURF_OVERLAY_SETPOSITION,
> +    VBOXVHWACMD_TYPE_SURF_COLORKEY_SET,
> +    VBOXVHWACMD_TYPE_QUERY_INFO1,
> +    VBOXVHWACMD_TYPE_QUERY_INFO2,
> +    VBOXVHWACMD_TYPE_ENABLE,
> +    VBOXVHWACMD_TYPE_DISABLE,
> +    VBOXVHWACMD_TYPE_HH_CONSTRUCT,
> +    VBOXVHWACMD_TYPE_HH_RESET
> +#ifdef VBOX_WITH_WDDM
> +    , VBOXVHWACMD_TYPE_SURF_GETINFO
> +    , VBOXVHWACMD_TYPE_SURF_COLORFILL
> +#endif
> +    , VBOXVHWACMD_TYPE_HH_DISABLE
> +    , VBOXVHWACMD_TYPE_HH_ENABLE
> +    , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN
> +    , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND
> +    , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM
> +    , VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM
> +} VBOXVHWACMD_TYPE;
> +
> +/* the command processing was asynch, set by the host to indicate asynch command completion
> + * must not be cleared once set, the command completion is performed by issuing a host->guest completion command
> + * while keeping this flag unchanged */
> +#define VBOXVHWACMD_FLAG_HG_ASYNCH               0x00010000
> +/* asynch completion is performed by issuing the event */
> +#define VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT         0x00000001
> +/* issue interrupt on asynch completion */
> +#define VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ           0x00000002
> +/* guest does not do any op on completion of this command, the host may copy the command and indicate that it does not need the command anymore
> + * by setting the VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED flag */
> +#define VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION  0x00000004
> +/* the host has copied the VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION command and returned it to the guest */
> +#define VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED      0x00020000
> +/* this is the host->host cmd, i.e. a configuration command posted by the host to the framebuffer */
> +#define VBOXVHWACMD_FLAG_HH_CMD                  0x10000000
> +
> +typedef struct VBOXVHWACMD
> +{
> +    VBOXVHWACMD_TYPE enmCmd; /* command type */
> +    volatile int32_t rc; /* command result */
> +    int32_t iDisplay; /* display index */
> +    volatile int32_t Flags; /* ored VBOXVHWACMD_FLAG_xxx values */
> +    uint64_t GuestVBVAReserved1; /* field internally used by the guest VBVA cmd handling, must NOT be modified by clients */
> +    uint64_t GuestVBVAReserved2; /* field internally used by the guest VBVA cmd handling, must NOT be modified by clients */
> +    volatile uint32_t cRefs;
> +    int32_t Reserved;
> +    union
> +    {
> +        struct VBOXVHWACMD *pNext;
> +        uint32_t             offNext;
> +        uint64_t Data; /* the body is 64-bit aligned */
> +    } u;
> +    char body[1];
> +} VBOXVHWACMD;
> +
> +#define VBOXVHWACMD_HEADSIZE() (RT_OFFSETOF(VBOXVHWACMD, body))
> +#define VBOXVHWACMD_SIZE_FROMBODYSIZE(_s) (VBOXVHWACMD_HEADSIZE() + (_s))
> +#define VBOXVHWACMD_SIZE(_tCmd) (VBOXVHWACMD_SIZE_FROMBODYSIZE(sizeof(_tCmd)))
> +typedef unsigned int VBOXVHWACMD_LENGTH;
> +typedef uint64_t VBOXVHWA_SURFHANDLE;
> +#define VBOXVHWA_SURFHANDLE_INVALID 0ULL
> +#define VBOXVHWACMD_BODY(_p, _t) ((_t*)(_p)->body)
> +#define VBOXVHWACMD_HEAD(_pb) ((VBOXVHWACMD*)((uint8_t *)(_pb) - RT_OFFSETOF(VBOXVHWACMD, body)))
> +
> +typedef struct VBOXVHWA_RECTL
> +{
> +    int32_t left;
> +    int32_t top;
> +    int32_t right;
> +    int32_t bottom;
> +} VBOXVHWA_RECTL;
> +
> +typedef struct VBOXVHWA_COLORKEY
> +{
> +    uint32_t low;
> +    uint32_t high;
> +} VBOXVHWA_COLORKEY;
> +
> +typedef struct VBOXVHWA_PIXELFORMAT
> +{
> +    uint32_t flags;
> +    uint32_t fourCC;
> +    union
> +    {
> +        uint32_t rgbBitCount;
> +        uint32_t yuvBitCount;
> +    } c;
> +
> +    union
> +    {
> +        uint32_t rgbRBitMask;
> +        uint32_t yuvYBitMask;
> +    } m1;
> +
> +    union
> +    {
> +        uint32_t rgbGBitMask;
> +        uint32_t yuvUBitMask;
> +    } m2;
> +
> +    union
> +    {
> +        uint32_t rgbBBitMask;
> +        uint32_t yuvVBitMask;
> +    } m3;
> +
> +    union
> +    {
> +        uint32_t rgbABitMask;
> +    } m4;
> +
> +    uint32_t Reserved;
> +} VBOXVHWA_PIXELFORMAT;
> +
> +typedef struct VBOXVHWA_SURFACEDESC
> +{
> +    uint32_t flags;
> +    uint32_t height;
> +    uint32_t width;
> +    uint32_t pitch;
> +    uint32_t sizeX;
> +    uint32_t sizeY;
> +    uint32_t cBackBuffers;
> +    uint32_t Reserved;
> +    VBOXVHWA_COLORKEY DstOverlayCK;
> +    VBOXVHWA_COLORKEY DstBltCK;
> +    VBOXVHWA_COLORKEY SrcOverlayCK;
> +    VBOXVHWA_COLORKEY SrcBltCK;
> +    VBOXVHWA_PIXELFORMAT PixelFormat;
> +    uint32_t surfCaps;
> +    uint32_t Reserved2;
> +    VBOXVHWA_SURFHANDLE hSurf;
> +    uint64_t offSurface;
> +} VBOXVHWA_SURFACEDESC;
> +
> +typedef struct VBOXVHWA_BLTFX
> +{
> +    uint32_t flags;
> +    uint32_t rop;
> +    uint32_t rotationOp;
> +    uint32_t rotation;
> +    uint32_t fillColor;
> +    uint32_t Reserved;
> +    VBOXVHWA_COLORKEY DstCK;
> +    VBOXVHWA_COLORKEY SrcCK;
> +} VBOXVHWA_BLTFX;
> +
> +typedef struct VBOXVHWA_OVERLAYFX
> +{
> +    uint32_t flags;
> +    uint32_t Reserved1;
> +    uint32_t fxFlags;
> +    uint32_t Reserved2;
> +    VBOXVHWA_COLORKEY DstCK;
> +    VBOXVHWA_COLORKEY SrcCK;
> +} VBOXVHWA_OVERLAYFX;
> +
> +#define VBOXVHWA_CAPS_BLT               0x00000040
> +#define VBOXVHWA_CAPS_BLTCOLORFILL      0x04000000
> +#define VBOXVHWA_CAPS_BLTFOURCC         0x00000100
> +#define VBOXVHWA_CAPS_BLTSTRETCH        0x00000200
> +#define VBOXVHWA_CAPS_BLTQUEUE          0x00000080
> +
> +#define VBOXVHWA_CAPS_OVERLAY           0x00000800
> +#define VBOXVHWA_CAPS_OVERLAYFOURCC     0x00002000
> +#define VBOXVHWA_CAPS_OVERLAYSTRETCH    0x00004000
> +#define VBOXVHWA_CAPS_OVERLAYCANTCLIP   0x00001000
> +
> +#define VBOXVHWA_CAPS_COLORKEY          0x00400000
> +#define VBOXVHWA_CAPS_COLORKEYHWASSIST  0x01000000
> +
> +#define VBOXVHWA_SCAPS_BACKBUFFER       0x00000004
> +#define VBOXVHWA_SCAPS_COMPLEX          0x00000008
> +#define VBOXVHWA_SCAPS_FLIP             0x00000010
> +#define VBOXVHWA_SCAPS_FRONTBUFFER      0x00000020
> +#define VBOXVHWA_SCAPS_OFFSCREENPLAIN   0x00000040
> +#define VBOXVHWA_SCAPS_OVERLAY          0x00000080
> +#define VBOXVHWA_SCAPS_PRIMARYSURFACE   0x00000200
> +#define VBOXVHWA_SCAPS_SYSTEMMEMORY     0x00000800
> +#define VBOXVHWA_SCAPS_VIDEOMEMORY      0x00004000
> +#define VBOXVHWA_SCAPS_VISIBLE          0x00008000
> +#define VBOXVHWA_SCAPS_LOCALVIDMEM      0x10000000
> +
> +#define VBOXVHWA_PF_PALETTEINDEXED8     0x00000020
> +#define VBOXVHWA_PF_RGB                 0x00000040
> +#define VBOXVHWA_PF_RGBTOYUV            0x00000100
> +#define VBOXVHWA_PF_YUV                 0x00000200
> +#define VBOXVHWA_PF_FOURCC              0x00000004
> +
> +#define VBOXVHWA_LOCK_DISCARDCONTENTS   0x00002000
> +
> +#define VBOXVHWA_CFG_ENABLED            0x00000001
> +
> +#define VBOXVHWA_SD_BACKBUFFERCOUNT     0x00000020
> +#define VBOXVHWA_SD_CAPS                0x00000001
> +#define VBOXVHWA_SD_CKDESTBLT           0x00004000
> +#define VBOXVHWA_SD_CKDESTOVERLAY       0x00002000
> +#define VBOXVHWA_SD_CKSRCBLT            0x00010000
> +#define VBOXVHWA_SD_CKSRCOVERLAY        0x00008000
> +#define VBOXVHWA_SD_HEIGHT              0x00000002
> +#define VBOXVHWA_SD_PITCH               0x00000008
> +#define VBOXVHWA_SD_PIXELFORMAT         0x00001000
> +/*#define VBOXVHWA_SD_REFRESHRATE       0x00040000*/
> +#define VBOXVHWA_SD_WIDTH               0x00000004
> +
> +#define VBOXVHWA_CKEYCAPS_DESTBLT                  0x00000001
> +#define VBOXVHWA_CKEYCAPS_DESTBLTCLRSPACE          0x00000002
> +#define VBOXVHWA_CKEYCAPS_DESTBLTCLRSPACEYUV       0x00000004
> +#define VBOXVHWA_CKEYCAPS_DESTBLTYUV               0x00000008
> +#define VBOXVHWA_CKEYCAPS_DESTOVERLAY              0x00000010
> +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYCLRSPACE      0x00000020
> +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYCLRSPACEYUV   0x00000040
> +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYONEACTIVE     0x00000080
> +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYYUV           0x00000100
> +#define VBOXVHWA_CKEYCAPS_SRCBLT                   0x00000200
> +#define VBOXVHWA_CKEYCAPS_SRCBLTCLRSPACE           0x00000400
> +#define VBOXVHWA_CKEYCAPS_SRCBLTCLRSPACEYUV        0x00000800
> +#define VBOXVHWA_CKEYCAPS_SRCBLTYUV                0x00001000
> +#define VBOXVHWA_CKEYCAPS_SRCOVERLAY               0x00002000
> +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYCLRSPACE       0x00004000
> +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYCLRSPACEYUV    0x00008000
> +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYONEACTIVE      0x00010000
> +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYYUV            0x00020000
> +#define VBOXVHWA_CKEYCAPS_NOCOSTOVERLAY            0x00040000
> +
> +#define VBOXVHWA_BLT_COLORFILL                      0x00000400
> +#define VBOXVHWA_BLT_DDFX                           0x00000800
> +#define VBOXVHWA_BLT_EXTENDED_FLAGS                 0x40000000
> +#define VBOXVHWA_BLT_EXTENDED_LINEAR_CONTENT        0x00000004
> +#define VBOXVHWA_BLT_EXTENDED_PRESENTATION_STRETCHFACTOR 0x00000010
> +#define VBOXVHWA_BLT_KEYDESTOVERRIDE                0x00004000
> +#define VBOXVHWA_BLT_KEYSRCOVERRIDE                 0x00010000
> +#define VBOXVHWA_BLT_LAST_PRESENTATION              0x20000000
> +#define VBOXVHWA_BLT_PRESENTATION                   0x10000000
> +#define VBOXVHWA_BLT_ROP                            0x00020000
> +
> +
> +#define VBOXVHWA_OVER_DDFX                          0x00080000
> +#define VBOXVHWA_OVER_HIDE                          0x00000200
> +#define VBOXVHWA_OVER_KEYDEST                       0x00000400
> +#define VBOXVHWA_OVER_KEYDESTOVERRIDE               0x00000800
> +#define VBOXVHWA_OVER_KEYSRC                        0x00001000
> +#define VBOXVHWA_OVER_KEYSRCOVERRIDE                0x00002000
> +#define VBOXVHWA_OVER_SHOW                          0x00004000
> +
> +#define VBOXVHWA_CKEY_COLORSPACE                    0x00000001
> +#define VBOXVHWA_CKEY_DESTBLT                       0x00000002
> +#define VBOXVHWA_CKEY_DESTOVERLAY                   0x00000004
> +#define VBOXVHWA_CKEY_SRCBLT                        0x00000008
> +#define VBOXVHWA_CKEY_SRCOVERLAY                    0x00000010
> +
> +#define VBOXVHWA_BLT_ARITHSTRETCHY                  0x00000001
> +#define VBOXVHWA_BLT_MIRRORLEFTRIGHT                0x00000002
> +#define VBOXVHWA_BLT_MIRRORUPDOWN                   0x00000004
> +
> +#define VBOXVHWA_OVERFX_ARITHSTRETCHY               0x00000001
> +#define VBOXVHWA_OVERFX_MIRRORLEFTRIGHT             0x00000002
> +#define VBOXVHWA_OVERFX_MIRRORUPDOWN                0x00000004
> +
> +#define VBOXVHWA_CAPS2_CANRENDERWINDOWED            0x00080000
> +#define VBOXVHWA_CAPS2_WIDESURFACES                 0x00001000
> +#define VBOXVHWA_CAPS2_COPYFOURCC                   0x00008000
> +/*#define VBOXVHWA_CAPS2_FLIPINTERVAL                 0x00200000*/
> +/*#define VBOXVHWA_CAPS2_FLIPNOVSYNC                  0x00400000*/
> +
> +
> +#define VBOXVHWA_OFFSET64_VOID        (UINT64_MAX)
> +
> +typedef struct VBOXVHWA_VERSION
> +{
> +    uint32_t maj;
> +    uint32_t min;
> +    uint32_t bld;
> +    uint32_t reserved;
> +} VBOXVHWA_VERSION;
> +
> +#define VBOXVHWA_VERSION_INIT(_pv) do { \
> +        (_pv)->maj = VBOXVHWA_VERSION_MAJ; \
> +        (_pv)->min = VBOXVHWA_VERSION_MIN; \
> +        (_pv)->bld = VBOXVHWA_VERSION_BLD; \
> +        (_pv)->reserved = VBOXVHWA_VERSION_RSV; \
> +        } while(0)
> +
> +typedef struct VBOXVHWACMD_QUERYINFO1
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_VERSION guestVersion;
> +        } in;
> +
> +        struct
> +        {
> +            uint32_t cfgFlags;
> +            uint32_t caps;
> +
> +            uint32_t caps2;
> +            uint32_t colorKeyCaps;
> +
> +            uint32_t stretchCaps;
> +            uint32_t surfaceCaps;
> +
> +            uint32_t numOverlays;
> +            uint32_t curOverlays;
> +
> +            uint32_t numFourCC;
> +            uint32_t reserved;
> +        } out;
> +    } u;
> +} VBOXVHWACMD_QUERYINFO1;
> +
> +typedef struct VBOXVHWACMD_QUERYINFO2
> +{
> +    uint32_t numFourCC;
> +    uint32_t FourCC[1];
> +} VBOXVHWACMD_QUERYINFO2;
> +
> +#define VBOXVHWAINFO2_SIZE(_cFourCC) RT_OFFSETOF(VBOXVHWACMD_QUERYINFO2, FourCC[_cFourCC])
> +
> +typedef struct VBOXVHWACMD_SURF_CANCREATE
> +{
> +    VBOXVHWA_SURFACEDESC SurfInfo;
> +    union
> +    {
> +        struct
> +        {
> +            uint32_t bIsDifferentPixelFormat;
> +            uint32_t Reserved;
> +        } in;
> +
> +        struct
> +        {
> +            int32_t ErrInfo;
> +        } out;
> +    } u;
> +} VBOXVHWACMD_SURF_CANCREATE;
> +
> +typedef struct VBOXVHWACMD_SURF_CREATE
> +{
> +    VBOXVHWA_SURFACEDESC SurfInfo;
> +} VBOXVHWACMD_SURF_CREATE;
> +
> +#ifdef VBOX_WITH_WDDM
> +typedef struct VBOXVHWACMD_SURF_GETINFO
> +{
> +    VBOXVHWA_SURFACEDESC SurfInfo;
> +} VBOXVHWACMD_SURF_GETINFO;
> +#endif
> +
> +typedef struct VBOXVHWACMD_SURF_DESTROY
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hSurf;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_DESTROY;
> +
> +typedef struct VBOXVHWACMD_SURF_LOCK
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hSurf;
> +            uint64_t offSurface;
> +            uint32_t flags;
> +            uint32_t rectValid;
> +            VBOXVHWA_RECTL rect;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_LOCK;
> +
> +typedef struct VBOXVHWACMD_SURF_UNLOCK
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hSurf;
> +            uint32_t xUpdatedMemValid;
> +            uint32_t reserved;
> +            VBOXVHWA_RECTL xUpdatedMemRect;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_UNLOCK;
> +
> +typedef struct VBOXVHWACMD_SURF_BLT
> +{
> +    uint64_t DstGuestSurfInfo;
> +    uint64_t SrcGuestSurfInfo;
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hDstSurf;
> +            uint64_t offDstSurface;
> +            VBOXVHWA_RECTL dstRect;
> +            VBOXVHWA_SURFHANDLE hSrcSurf;
> +            uint64_t offSrcSurface;
> +            VBOXVHWA_RECTL srcRect;
> +            uint32_t flags;
> +            uint32_t xUpdatedSrcMemValid;
> +            VBOXVHWA_BLTFX desc;
> +            VBOXVHWA_RECTL xUpdatedSrcMemRect;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_BLT;
> +
> +#ifdef VBOX_WITH_WDDM
> +typedef struct VBOXVHWACMD_SURF_COLORFILL
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hSurf;
> +            uint64_t offSurface;
> +            uint32_t u32Reserved;
> +            uint32_t cRects;
> +            VBOXVHWA_RECTL aRects[1];
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_COLORFILL;
> +#endif
> +
> +typedef struct VBOXVHWACMD_SURF_FLIP
> +{
> +    uint64_t TargGuestSurfInfo;
> +    uint64_t CurrGuestSurfInfo;
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hTargSurf;
> +            uint64_t offTargSurface;
> +            VBOXVHWA_SURFHANDLE hCurrSurf;
> +            uint64_t offCurrSurface;
> +            uint32_t flags;
> +            uint32_t xUpdatedTargMemValid;
> +            VBOXVHWA_RECTL xUpdatedTargMemRect;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_FLIP;
> +
> +typedef struct VBOXVHWACMD_SURF_COLORKEY_SET
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hSurf;
> +            uint64_t offSurface;
> +            VBOXVHWA_COLORKEY CKey;
> +            uint32_t flags;
> +            uint32_t reserved;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_COLORKEY_SET;
> +
> +#define VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_SRCMEMRECT 0x00000001
> +#define VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_DSTMEMRECT 0x00000002
> +
> +typedef struct VBOXVHWACMD_SURF_OVERLAY_UPDATE
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hDstSurf;
> +            uint64_t offDstSurface;
> +            VBOXVHWA_RECTL dstRect;
> +            VBOXVHWA_SURFHANDLE hSrcSurf;
> +            uint64_t offSrcSurface;
> +            VBOXVHWA_RECTL srcRect;
> +            uint32_t flags;
> +            uint32_t xFlags;
> +            VBOXVHWA_OVERLAYFX desc;
> +            VBOXVHWA_RECTL xUpdatedSrcMemRect;
> +            VBOXVHWA_RECTL xUpdatedDstMemRect;
> +        } in;
> +    } u;
> +}VBOXVHWACMD_SURF_OVERLAY_UPDATE;
> +
> +typedef struct VBOXVHWACMD_SURF_OVERLAY_SETPOSITION
> +{
> +    union
> +    {
> +        struct
> +        {
> +            VBOXVHWA_SURFHANDLE hDstSurf;
> +            uint64_t offDstSurface;
> +            VBOXVHWA_SURFHANDLE hSrcSurf;
> +            uint64_t offSrcSurface;
> +            uint32_t xPos;
> +            uint32_t yPos;
> +            uint32_t flags;
> +            uint32_t reserved;
> +        } in;
> +    } u;
> +} VBOXVHWACMD_SURF_OVERLAY_SETPOSITION;
> +
> +typedef struct VBOXVHWACMD_HH_CONSTRUCT
> +{
> +    void    *pVM;
> +    /* VRAM info for the backend to be able to properly translate VRAM offsets */
> +    void    *pvVRAM;
> +    uint32_t cbVRAM;
> +} VBOXVHWACMD_HH_CONSTRUCT;
> +
> +typedef struct VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM
> +{
> +    struct SSMHANDLE * pSSM;
> +} VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM;
> +
> +typedef struct VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM
> +{
> +    struct SSMHANDLE * pSSM;
> +} VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM;
> +
> +typedef DECLCALLBACK(void) FNVBOXVHWA_HH_CALLBACK(void*);
> +typedef FNVBOXVHWA_HH_CALLBACK *PFNVBOXVHWA_HH_CALLBACK;
> +
> +#define VBOXVHWA_HH_CALLBACK_SET(_pCmd, _pfn, _parg) \
> +    do { \
> +        (_pCmd)->GuestVBVAReserved1 = (uint64_t)(uintptr_t)(_pfn); \
> +        (_pCmd)->GuestVBVAReserved2 = (uint64_t)(uintptr_t)(_parg); \
> +    }while(0)
> +
> +#define VBOXVHWA_HH_CALLBACK_GET(_pCmd) ((PFNVBOXVHWA_HH_CALLBACK)(_pCmd)->GuestVBVAReserved1)
> +#define VBOXVHWA_HH_CALLBACK_GET_ARG(_pCmd) ((void*)(_pCmd)->GuestVBVAReserved2)
> +
> +#pragma pack()
> +#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
> +
> +/* All structures are without alignment. */
> +#pragma pack(1)
> +
> +typedef struct VBVAHOSTFLAGS
> +{
> +    uint32_t u32HostEvents;
> +    uint32_t u32SupportedOrders;
> +} VBVAHOSTFLAGS;
> +
> +typedef struct VBVABUFFER
> +{
> +    VBVAHOSTFLAGS hostFlags;
> +
> +    /* The offset where the data start in the buffer. */
> +    uint32_t off32Data;
> +    /* The offset where next data must be placed in the buffer. */
> +    uint32_t off32Free;
> +
> +    /* The queue of record descriptions. */
> +    VBVARECORD aRecords[VBVA_MAX_RECORDS];
> +    uint32_t indexRecordFirst;
> +    uint32_t indexRecordFree;
> +
> +    /* Space to leave free in the buffer when large partial records are transferred. */
> +    uint32_t cbPartialWriteThreshold;
> +
> +    uint32_t cbData;
> +    uint8_t  au8Data[1]; /* variable size for the rest of the VBVABUFFER area in VRAM. */
> +} VBVABUFFER;
> +
> +#define VBVA_MAX_RECORD_SIZE (128*_1M)
> +
> +/* guest->host commands */
> +#define VBVA_QUERY_CONF32 1
> +#define VBVA_SET_CONF32   2
> +#define VBVA_INFO_VIEW    3
> +#define VBVA_INFO_HEAP    4
> +#define VBVA_FLUSH        5
> +#define VBVA_INFO_SCREEN  6
> +#define VBVA_ENABLE       7
> +#define VBVA_MOUSE_POINTER_SHAPE 8
> +#ifdef VBOX_WITH_VIDEOHWACCEL
> +# define VBVA_VHWA_CMD    9
> +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */
> +#ifdef VBOX_WITH_VDMA
> +# define VBVA_VDMA_CTL   10 /* setup G<->H DMA channel info */
> +# define VBVA_VDMA_CMD    11 /* G->H DMA command             */
> +#endif
> +#define VBVA_INFO_CAPS   12 /* informs host about HGSMI caps. see VBVACAPS below */
> +#define VBVA_SCANLINE_CFG    13 /* configures scanline, see VBVASCANLINECFG below */
> +#define VBVA_SCANLINE_INFO   14 /* requests scanline info, see VBVASCANLINEINFO below */
> +#define VBVA_CMDVBVA_SUBMIT  16 /* inform host about VBVA Command submission */
> +#define VBVA_CMDVBVA_FLUSH   17 /* inform host about VBVA Command submission */
> +#define VBVA_CMDVBVA_CTL     18 /* G->H DMA command             */
> +#define VBVA_QUERY_MODE_HINTS 19 /* Query most recent mode hints sent. */
> +/** Report the guest virtual desktop position and size for mapping host and
> + * guest pointer positions. */
> +#define VBVA_REPORT_INPUT_MAPPING 20
> +/** Report the guest cursor position and query the host position. */
> +#define VBVA_CURSOR_POSITION 21
> +
> +/* host->guest commands */
> +#define VBVAHG_EVENT              1
> +#define VBVAHG_DISPLAY_CUSTOM     2
> +#ifdef VBOX_WITH_VDMA
> +#define VBVAHG_SHGSMI_COMPLETION  3
> +#endif
> +
> +#ifdef VBOX_WITH_VIDEOHWACCEL
> +#define VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE 1
> +#pragma pack(1)
> +typedef struct VBVAHOSTCMDVHWACMDCOMPLETE
> +{
> +    uint32_t offCmd;
> +}VBVAHOSTCMDVHWACMDCOMPLETE;
> +#pragma pack()
> +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */
> +
> +#pragma pack(1)
> +typedef enum
> +{
> +    VBVAHOSTCMD_OP_EVENT = 1,
> +    VBVAHOSTCMD_OP_CUSTOM
> +}VBVAHOSTCMD_OP_TYPE;
> +
> +typedef struct VBVAHOSTCMDEVENT
> +{
> +    uint64_t pEvent;
> +}VBVAHOSTCMDEVENT;
> +
> +
> +typedef struct VBVAHOSTCMD
> +{
> +    /* destination ID if >=0 specifies display index, otherwize the command is directed to the miniport */
> +    int32_t iDstID;
> +    int32_t customOpCode;
> +    union
> +    {
> +        struct VBVAHOSTCMD *pNext;
> +        uint32_t             offNext;
> +        uint64_t Data; /* the body is 64-bit aligned */
> +    } u;
> +    char body[1];
> +}VBVAHOSTCMD;
> +
> +#define VBVAHOSTCMD_SIZE(_size) (sizeof(VBVAHOSTCMD) + (_size))
> +#define VBVAHOSTCMD_BODY(_pCmd, _tBody) ((_tBody*)(_pCmd)->body)
> +#define VBVAHOSTCMD_HDR(_pBody) ((VBVAHOSTCMD*)(((uint8_t*)_pBody) - RT_OFFSETOF(VBVAHOSTCMD, body)))
> +#define VBVAHOSTCMD_HDRSIZE (RT_OFFSETOF(VBVAHOSTCMD, body))
> +
> +#pragma pack()
> +
> +/* VBVACONF32::u32Index */
> +#define VBOX_VBVA_CONF32_MONITOR_COUNT  0
> +#define VBOX_VBVA_CONF32_HOST_HEAP_SIZE 1
> +/** Returns VINF_SUCCESS if the host can report mode hints via VBVA.
> + * Set value to VERR_NOT_SUPPORTED before calling. */
> +#define VBOX_VBVA_CONF32_MODE_HINT_REPORTING  2
> +/** Returns VINF_SUCCESS if the host can report guest cursor enabled status via
> + * VBVA.  Set value to VERR_NOT_SUPPORTED before calling. */
> +#define VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING  3
> +/** Returns the currently available host cursor capabilities.  Available if
> + * VBVACONF32::VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING returns success.
> + * @see VMMDevReqMouseStatus::mouseFeatures. */
> +#define VBOX_VBVA_CONF32_CURSOR_CAPABILITIES  4
> +/** Returns the supported flags in VBVAINFOSCREEN::u8Flags. */
> +#define VBOX_VBVA_CONF32_SCREEN_FLAGS 5
> +/** Returns the max size of VBVA record. */
> +#define VBOX_VBVA_CONF32_MAX_RECORD_SIZE 6
> +
> +typedef struct VBVACONF32
> +{
> +    uint32_t u32Index;
> +    uint32_t u32Value;
> +} VBVACONF32;
> +
> +/** Reserved for historical reasons. */
> +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED0  RT_BIT(0)
> +/** Guest cursor capability: can the host show a hardware cursor at the host
> + * pointer location? */
> +#define VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE   RT_BIT(1)
> +/** Reserved for historical reasons. */
> +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED2  RT_BIT(2)
> +/** Reserved for historical reasons.  Must always be unset. */
> +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED3  RT_BIT(3)
> +/** Reserved for historical reasons. */
> +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED4  RT_BIT(4)
> +/** Reserved for historical reasons. */
> +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED5  RT_BIT(5)
> +
> +typedef struct VBVAINFOVIEW
> +{
> +    /* Index of the screen, assigned by the guest. */
> +    uint32_t u32ViewIndex;
> +
> +    /* The screen offset in VRAM, the framebuffer starts here. */
> +    uint32_t u32ViewOffset;
> +
> +    /* The size of the VRAM memory that can be used for the view. */
> +    uint32_t u32ViewSize;
> +
> +    /* The recommended maximum size of the VRAM memory for the screen. */
> +    uint32_t u32MaxScreenSize;
> +} VBVAINFOVIEW;
> +
> +typedef struct VBVAINFOHEAP
> +{
> +    /* Absolute offset in VRAM of the start of the heap. */
> +    uint32_t u32HeapOffset;
> +
> +    /* The size of the heap. */
> +    uint32_t u32HeapSize;
> +
> +} VBVAINFOHEAP;
> +
> +typedef struct VBVAFLUSH
> +{
> +    uint32_t u32Reserved;
> +
> +} VBVAFLUSH;
> +
> +typedef struct VBVACMDVBVASUBMIT
> +{
> +    uint32_t u32Reserved;
> +} VBVACMDVBVASUBMIT;
> +
> +/* flush is requested because due to guest command buffer overflow */
> +#define VBVACMDVBVAFLUSH_F_GUEST_BUFFER_OVERFLOW 1
> +
> +typedef struct VBVACMDVBVAFLUSH
> +{
> +    uint32_t u32Flags;
> +} VBVACMDVBVAFLUSH;
> +
> +
> +/* VBVAINFOSCREEN::u8Flags */
> +#define VBVA_SCREEN_F_NONE     0x0000
> +#define VBVA_SCREEN_F_ACTIVE   0x0001
> +/** The virtual monitor has been disabled by the guest and should be removed
> + * by the host and ignored for purposes of pointer position calculation. */
> +#define VBVA_SCREEN_F_DISABLED 0x0002
> +/** The virtual monitor has been blanked by the guest and should be blacked
> + * out by the host using width, height, etc values from the VBVAINFOSCREEN request. */
> +#define VBVA_SCREEN_F_BLANK    0x0004
> +/** The virtual monitor has been blanked by the guest and should be blacked
> + * out by the host using the previous mode values for width. height, etc. */
> +#define VBVA_SCREEN_F_BLANK2   0x0008
> +
> +typedef struct VBVAINFOSCREEN
> +{
> +    /* Which view contains the screen. */
> +    uint32_t u32ViewIndex;
> +
> +    /* Physical X origin relative to the primary screen. */
> +    int32_t i32OriginX;
> +
> +    /* Physical Y origin relative to the primary screen. */
> +    int32_t i32OriginY;
> +
> +    /* Offset of visible framebuffer relative to the framebuffer start. */
> +    uint32_t u32StartOffset;
> +
> +    /* The scan line size in bytes. */
> +    uint32_t u32LineSize;
> +
> +    /* Width of the screen. */
> +    uint32_t u32Width;
> +
> +    /* Height of the screen. */
> +    uint32_t u32Height;
> +
> +    /* Color depth. */
> +    uint16_t u16BitsPerPixel;
> +
> +    /* VBVA_SCREEN_F_* */
> +    uint16_t u16Flags;
> +} VBVAINFOSCREEN;
> +
> +
> +/* VBVAENABLE::u32Flags */
> +#define VBVA_F_NONE    0x00000000
> +#define VBVA_F_ENABLE  0x00000001
> +#define VBVA_F_DISABLE 0x00000002
> +/* extended VBVA to be used with WDDM */
> +#define VBVA_F_EXTENDED 0x00000004
> +/* vbva offset is absolute VRAM offset */
> +#define VBVA_F_ABSOFFSET 0x00000008
> +
> +typedef struct VBVAENABLE
> +{
> +    uint32_t u32Flags;
> +    uint32_t u32Offset;
> +    int32_t  i32Result;
> +} VBVAENABLE;
> +
> +typedef struct VBVAENABLE_EX
> +{
> +    VBVAENABLE Base;
> +    uint32_t u32ScreenId;
> +} VBVAENABLE_EX;
> +
> +
> +typedef struct VBVAMOUSEPOINTERSHAPE
> +{
> +    /* The host result. */
> +    int32_t i32Result;
> +
> +    /* VBOX_MOUSE_POINTER_* bit flags. */
> +    uint32_t fu32Flags;
> +
> +    /* X coordinate of the hot spot. */
> +    uint32_t u32HotX;
> +
> +    /* Y coordinate of the hot spot. */
> +    uint32_t u32HotY;
> +
> +    /* Width of the pointer in pixels. */
> +    uint32_t u32Width;
> +
> +    /* Height of the pointer in scanlines. */
> +    uint32_t u32Height;
> +
> +    /* Pointer data.
> +     *
> +     ****
> +     * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color) mask.
> +     *
> +     * For pointers without alpha channel the XOR mask pixels are 32 bit values: (lsb)BGR0(msb).
> +     * For pointers with alpha channel the XOR mask consists of (lsb)BGRA(msb) 32 bit values.
> +     *
> +     * Guest driver must create the AND mask for pointers with alpha channel, so if host does not
> +     * support alpha, the pointer could be displayed as a normal color pointer. The AND mask can
> +     * be constructed from alpha values. For example alpha value >= 0xf0 means bit 0 in the AND mask.
> +     *
> +     * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND mask,
> +     * therefore, is cbAnd = (width + 7) / 8 * height. The padding bits at the
> +     * end of any scanline are undefined.
> +     *
> +     * The XOR mask follows the AND mask on the next 4 bytes aligned offset:
> +     * uint8_t *pXor = pAnd + (cbAnd + 3) & ~3
> +     * Bytes in the gap between the AND and the XOR mask are undefined.
> +     * XOR mask scanlines have no gap between them and size of XOR mask is:
> +     * cXor = width * 4 * height.
> +     ****
> +     *
> +     * Preallocate 4 bytes for accessing actual data as p->au8Data.
> +     */
> +    uint8_t au8Data[4];
> +
> +} VBVAMOUSEPOINTERSHAPE;
> +
> +/** @name VBVAMOUSEPOINTERSHAPE::fu32Flags
> + * @note The VBOX_MOUSE_POINTER_* flags are used in the guest video driver,
> + *       values must be <= 0x8000 and must not be changed. (try make more sense
> + *       of this, please).
> + * @{
> + */
> +/** pointer is visible */
> +#define VBOX_MOUSE_POINTER_VISIBLE (0x0001)
> +/** pointer has alpha channel */
> +#define VBOX_MOUSE_POINTER_ALPHA   (0x0002)
> +/** pointerData contains new pointer shape */
> +#define VBOX_MOUSE_POINTER_SHAPE   (0x0004)
> +/** @} */
> +
> +/* the guest driver can handle asynch guest cmd completion by reading the command offset from io port */
> +#define VBVACAPS_COMPLETEGCMD_BY_IOREAD 0x00000001
> +/* the guest driver can handle video adapter IRQs */
> +#define VBVACAPS_IRQ                    0x00000002
> +/** The guest can read video mode hints sent via VBVA. */
> +#define VBVACAPS_VIDEO_MODE_HINTS       0x00000004
> +/** The guest can switch to a software cursor on demand. */
> +#define VBVACAPS_DISABLE_CURSOR_INTEGRATION 0x00000008
> +/** The guest does not depend on host handling the VBE registers. */
> +#define VBVACAPS_USE_VBVA_ONLY 0x00000010
> +typedef struct VBVACAPS
> +{
> +    int32_t rc;
> +    uint32_t fCaps;
> +} VBVACAPS;
> +
> +/* makes graphics device generate IRQ on VSYNC */
> +#define VBVASCANLINECFG_ENABLE_VSYNC_IRQ        0x00000001
> +/* guest driver may request the current scanline */
> +#define VBVASCANLINECFG_ENABLE_SCANLINE_INFO    0x00000002
> +/* request the current refresh period, returned in u32RefreshPeriodMs */
> +#define VBVASCANLINECFG_QUERY_REFRESH_PERIOD    0x00000004
> +/* set new refresh period specified in u32RefreshPeriodMs.
> + * if used with VBVASCANLINECFG_QUERY_REFRESH_PERIOD,
> + * u32RefreshPeriodMs is set to the previous refresh period on return */
> +#define VBVASCANLINECFG_SET_REFRESH_PERIOD      0x00000008
> +
> +typedef struct VBVASCANLINECFG
> +{
> +    int32_t rc;
> +    uint32_t fFlags;
> +    uint32_t u32RefreshPeriodMs;
> +    uint32_t u32Reserved;
> +} VBVASCANLINECFG;
> +
> +typedef struct VBVASCANLINEINFO
> +{
> +    int32_t rc;
> +    uint32_t u32ScreenId;
> +    uint32_t u32InVBlank;
> +    uint32_t u32ScanLine;
> +} VBVASCANLINEINFO;
> +
> +/** Query the most recent mode hints received from the host. */
> +typedef struct VBVAQUERYMODEHINTS
> +{
> +    /** The maximum number of screens to return hints for. */
> +    uint16_t cHintsQueried;
> +    /** The size of the mode hint structures directly following this one. */
> +    uint16_t cbHintStructureGuest;
> +    /** The return code for the operation.  Initialise to VERR_NOT_SUPPORTED. */
> +    int32_t  rc;
> +} VBVAQUERYMODEHINTS;
> +
> +/** Structure in which a mode hint is returned.  The guest allocates an array
> + *  of these immediately after the VBVAQUERYMODEHINTS structure.  To accomodate
> + *  future extensions, the VBVAQUERYMODEHINTS structure specifies the size of
> + *  the VBVAMODEHINT structures allocated by the guest, and the host only fills
> + *  out structure elements which fit into that size.  The host should fill any
> + *  unused members (e.g. dx, dy) or structure space on the end with ~0.  The
> + *  whole structure can legally be set to ~0 to skip a screen. */
> +typedef struct VBVAMODEHINT
> +{
> +    uint32_t magic;
> +    uint32_t cx;
> +    uint32_t cy;
> +    uint32_t cBPP;  /* Which has never been used... */
> +    uint32_t cDisplay;
> +    uint32_t dx;  /**< X offset into the virtual frame-buffer. */
> +    uint32_t dy;  /**< Y offset into the virtual frame-buffer. */
> +    uint32_t fEnabled;  /* Not fFlags.  Add new members for new flags. */
> +} VBVAMODEHINT;
> +
> +#define VBVAMODEHINT_MAGIC UINT32_C(0x0801add9)
> +
> +/** Report the rectangle relative to which absolute pointer events should be
> + *  expressed.  This information remains valid until the next VBVA resize event
> + *  for any screen, at which time it is reset to the bounding rectangle of all
> + *  virtual screens and must be re-set.
> + *  @see VBVA_REPORT_INPUT_MAPPING. */
> +typedef struct VBVAREPORTINPUTMAPPING
> +{
> +    int32_t x;    /**< Upper left X co-ordinate relative to the first screen. */
> +    int32_t y;    /**< Upper left Y co-ordinate relative to the first screen. */
> +    uint32_t cx;  /**< Rectangle width. */
> +    uint32_t cy;  /**< Rectangle height. */
> +} VBVAREPORTINPUTMAPPING;
> +
> +/** Report the guest cursor position and query the host one.  The host may wish
> + *  to use the guest information to re-position its own cursor (though this is
> + *  currently unlikely).
> + *  @see VBVA_CURSOR_POSITION */
> +typedef struct VBVACURSORPOSITION
> +{
> +    uint32_t fReportPosition;  /**< Are we reporting a position? */
> +    uint32_t x;                /**< Guest cursor X position */
> +    uint32_t y;                /**< Guest cursor Y position */
> +} VBVACURSORPOSITION;
> +
> +#pragma pack()
> +
> +typedef uint64_t VBOXVIDEOOFFSET;
> +
> +#define VBOXVIDEOOFFSET_VOID ((VBOXVIDEOOFFSET)~0)
> +
> +#pragma pack(1)
> +
> +/*
> + * VBOXSHGSMI made on top HGSMI and allows receiving notifications
> + * about G->H command completion
> + */
> +/* SHGSMI command header */
> +typedef struct VBOXSHGSMIHEADER
> +{
> +    uint64_t pvNext;    /*<- completion processing queue */
> +    uint32_t fFlags;    /*<- see VBOXSHGSMI_FLAG_XXX Flags */
> +    uint32_t cRefs;     /*<- command referece count */
> +    uint64_t u64Info1;  /*<- contents depends on the fFlags value */
> +    uint64_t u64Info2;  /*<- contents depends on the fFlags value */
> +} VBOXSHGSMIHEADER, *PVBOXSHGSMIHEADER;
> +
> +typedef enum
> +{
> +    VBOXVDMACMD_TYPE_UNDEFINED         = 0,
> +    VBOXVDMACMD_TYPE_DMA_PRESENT_BLT   = 1,
> +    VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER,
> +    VBOXVDMACMD_TYPE_DMA_BPB_FILL,
> +    VBOXVDMACMD_TYPE_DMA_PRESENT_SHADOW2PRIMARY,
> +    VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL,
> +    VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP,
> +    VBOXVDMACMD_TYPE_DMA_NOP,
> +    VBOXVDMACMD_TYPE_CHROMIUM_CMD, /* chromium cmd */
> +    VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER_VRAMSYS,
> +    VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ /* make the device notify child (monitor) state change IRQ */
> +} VBOXVDMACMD_TYPE;
> +
> +#pragma pack()
> +
> +/* the command processing was asynch, set by the host to indicate asynch command completion
> + * must not be cleared once set, the command completion is performed by issuing a host->guest completion command
> + * while keeping this flag unchanged */
> +#define VBOXSHGSMI_FLAG_HG_ASYNCH               0x00010000
> +#if 0
> +/* if set     - asynch completion is performed by issuing the event,
> + * if cleared - asynch completion is performed by calling a callback */
> +#define VBOXSHGSMI_FLAG_GH_ASYNCH_EVENT         0x00000001
> +#endif
> +/* issue interrupt on asynch completion, used for critical G->H commands,
> + * i.e. for completion of which guest is waiting. */
> +#define VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ           0x00000002
> +/* guest does not do any op on completion of this command,
> + * the host may copy the command and indicate that it does not need the command anymore
> + * by not setting VBOXSHGSMI_FLAG_HG_ASYNCH */
> +#define VBOXSHGSMI_FLAG_GH_ASYNCH_NOCOMPLETION  0x00000004
> +/* guest requires the command to be processed asynchronously,
> + * not setting VBOXSHGSMI_FLAG_HG_ASYNCH by the host in this case is treated as command failure */
> +#define VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE         0x00000008
> +/* force IRQ on cmd completion */
> +#define VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ_FORCE     0x00000010
> +/* an IRQ-level callback is associated with the command */
> +#define VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ  0x00000020
> +/* guest expects this command to be completed synchronously */
> +#define VBOXSHGSMI_FLAG_GH_SYNCH                0x00000040
> +
> +
> +DECLINLINE(uint8_t *) VBoxSHGSMIBufferData (const VBOXSHGSMIHEADER* pHeader)
> +{
> +    return (uint8_t *)pHeader + sizeof (VBOXSHGSMIHEADER);
> +}
> +
> +#define VBoxSHGSMIBufferHeaderSize() (sizeof (VBOXSHGSMIHEADER))
> +
> +DECLINLINE(PVBOXSHGSMIHEADER) VBoxSHGSMIBufferHeader (const void *pvData)
> +{
> +    return (PVBOXSHGSMIHEADER)((uint8_t *)pvData - sizeof (VBOXSHGSMIHEADER));
> +}
> +
> +#ifdef VBOX_WITH_VDMA
> +# pragma pack(1)
> +
> +/* VDMA - Video DMA */
> +
> +/* VDMA Control API */
> +/* VBOXVDMA_CTL::u32Flags */
> +typedef enum
> +{
> +    VBOXVDMA_CTL_TYPE_NONE = 0,
> +    VBOXVDMA_CTL_TYPE_ENABLE,
> +    VBOXVDMA_CTL_TYPE_DISABLE,
> +    VBOXVDMA_CTL_TYPE_FLUSH,
> +    VBOXVDMA_CTL_TYPE_WATCHDOG
> +} VBOXVDMA_CTL_TYPE;
> +
> +typedef struct VBOXVDMA_CTL
> +{
> +    VBOXVDMA_CTL_TYPE enmCtl;
> +    uint32_t u32Offset;
> +    int32_t  i32Result;
> +} VBOXVDMA_CTL, *PVBOXVDMA_CTL;
> +
> +typedef struct VBOXVDMA_RECTL
> +{
> +    int16_t left;
> +    int16_t top;
> +    uint16_t width;
> +    uint16_t height;
> +} VBOXVDMA_RECTL, *PVBOXVDMA_RECTL;
> +
> +typedef enum
> +{
> +    VBOXVDMA_PIXEL_FORMAT_UNKNOWN      =  0,
> +    VBOXVDMA_PIXEL_FORMAT_R8G8B8       = 20,
> +    VBOXVDMA_PIXEL_FORMAT_A8R8G8B8     = 21,
> +    VBOXVDMA_PIXEL_FORMAT_X8R8G8B8     = 22,
> +    VBOXVDMA_PIXEL_FORMAT_R5G6B5       = 23,
> +    VBOXVDMA_PIXEL_FORMAT_X1R5G5B5     = 24,
> +    VBOXVDMA_PIXEL_FORMAT_A1R5G5B5     = 25,
> +    VBOXVDMA_PIXEL_FORMAT_A4R4G4B4     = 26,
> +    VBOXVDMA_PIXEL_FORMAT_R3G3B2       = 27,
> +    VBOXVDMA_PIXEL_FORMAT_A8           = 28,
> +    VBOXVDMA_PIXEL_FORMAT_A8R3G3B2     = 29,
> +    VBOXVDMA_PIXEL_FORMAT_X4R4G4B4     = 30,
> +    VBOXVDMA_PIXEL_FORMAT_A2B10G10R10  = 31,
> +    VBOXVDMA_PIXEL_FORMAT_A8B8G8R8     = 32,
> +    VBOXVDMA_PIXEL_FORMAT_X8B8G8R8     = 33,
> +    VBOXVDMA_PIXEL_FORMAT_G16R16       = 34,
> +    VBOXVDMA_PIXEL_FORMAT_A2R10G10B10  = 35,
> +    VBOXVDMA_PIXEL_FORMAT_A16B16G16R16 = 36,
> +    VBOXVDMA_PIXEL_FORMAT_A8P8         = 40,
> +    VBOXVDMA_PIXEL_FORMAT_P8           = 41,
> +    VBOXVDMA_PIXEL_FORMAT_L8           = 50,
> +    VBOXVDMA_PIXEL_FORMAT_A8L8         = 51,
> +    VBOXVDMA_PIXEL_FORMAT_A4L4         = 52,
> +    VBOXVDMA_PIXEL_FORMAT_V8U8         = 60,
> +    VBOXVDMA_PIXEL_FORMAT_L6V5U5       = 61,
> +    VBOXVDMA_PIXEL_FORMAT_X8L8V8U8     = 62,
> +    VBOXVDMA_PIXEL_FORMAT_Q8W8V8U8     = 63,
> +    VBOXVDMA_PIXEL_FORMAT_V16U16       = 64,
> +    VBOXVDMA_PIXEL_FORMAT_W11V11U10    = 65,
> +    VBOXVDMA_PIXEL_FORMAT_A2W10V10U10  = 67
> +} VBOXVDMA_PIXEL_FORMAT;
> +
> +typedef struct VBOXVDMA_SURF_DESC
> +{
> +    uint32_t width;
> +    uint32_t height;
> +    VBOXVDMA_PIXEL_FORMAT format;
> +    uint32_t bpp;
> +    uint32_t pitch;
> +    uint32_t fFlags;
> +} VBOXVDMA_SURF_DESC, *PVBOXVDMA_SURF_DESC;
> +
> +/*typedef uint64_t VBOXVDMAPHADDRESS;*/
> +typedef uint64_t VBOXVDMASURFHANDLE;
> +
> +/* region specified as a rectangle, otherwize it is a size of memory pointed to by phys address */
> +#define VBOXVDMAOPERAND_FLAGS_RECTL       0x1
> +/* Surface handle is valid */
> +#define VBOXVDMAOPERAND_FLAGS_PRIMARY        0x2
> +/* address is offset in VRAM */
> +#define VBOXVDMAOPERAND_FLAGS_VRAMOFFSET  0x4
> +
> +
> +/* VBOXVDMACBUF_DR::phBuf specifies offset in VRAM */
> +#define VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET 0x00000001
> +/* command buffer follows the VBOXVDMACBUF_DR in VRAM, VBOXVDMACBUF_DR::phBuf is ignored */
> +#define VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR  0x00000002
> +
> +/*
> + * We can not submit the DMA command via VRAM since we do not have control over
> + * DMA command buffer [de]allocation, i.e. we only control the buffer contents.
> + * In other words the system may call one of our callbacks to fill a command buffer
> + * with the necessary commands and then discard the buffer w/o any notification.
> + *
> + * We have only DMA command buffer physical address at submission time.
> + *
> + * so the only way is to */
> +typedef struct VBOXVDMACBUF_DR
> +{
> +    uint16_t fFlags;
> +    uint16_t cbBuf;
> +    /* RT_SUCCESS()     - on success
> +     * VERR_INTERRUPTED - on preemption
> +     * VERR_xxx         - on error */
> +    int32_t  rc;
> +    union
> +    {
> +        uint64_t phBuf;
> +        VBOXVIDEOOFFSET offVramBuf;
> +    } Location;
> +    uint64_t aGuestData[7];
> +} VBOXVDMACBUF_DR, *PVBOXVDMACBUF_DR;
> +
> +#define VBOXVDMACBUF_DR_TAIL(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + sizeof (VBOXVDMACBUF_DR)) )
> +#define VBOXVDMACBUF_DR_FROM_TAIL(_pCmd) ( (VBOXVDMACBUF_DR*)(((uint8_t*)(_pCmd)) - sizeof (VBOXVDMACBUF_DR)) )
> +
> +typedef struct VBOXVDMACMD
> +{
> +    VBOXVDMACMD_TYPE enmType;
> +    uint32_t u32CmdSpecific;
> +} VBOXVDMACMD, *PVBOXVDMACMD;
> +
> +#define VBOXVDMACMD_HEADER_SIZE() sizeof (VBOXVDMACMD)
> +#define VBOXVDMACMD_SIZE_FROMBODYSIZE(_s) (VBOXVDMACMD_HEADER_SIZE() + (_s))
> +#define VBOXVDMACMD_SIZE(_t) (VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof (_t)))
> +#define VBOXVDMACMD_BODY(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + VBOXVDMACMD_HEADER_SIZE()) )
> +#define VBOXVDMACMD_BODY_SIZE(_s) ( (_s) - VBOXVDMACMD_HEADER_SIZE() )
> +#define VBOXVDMACMD_FROM_BODY(_pCmd) ( (VBOXVDMACMD*)(((uint8_t*)(_pCmd)) - VBOXVDMACMD_HEADER_SIZE()) )
> +#define VBOXVDMACMD_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)(uintptr_t)( VBOXVDMACMD_BODY(0, uint8_t) + RT_OFFSETOF(_t, _f) ) )
> +
> +typedef struct VBOXVDMACMD_DMA_PRESENT_BLT
> +{
> +    VBOXVIDEOOFFSET offSrc;
> +    VBOXVIDEOOFFSET offDst;
> +    VBOXVDMA_SURF_DESC srcDesc;
> +    VBOXVDMA_SURF_DESC dstDesc;
> +    VBOXVDMA_RECTL srcRectl;
> +    VBOXVDMA_RECTL dstRectl;
> +    uint32_t u32Reserved;
> +    uint32_t cDstSubRects;
> +    VBOXVDMA_RECTL aDstSubRects[1];
> +} VBOXVDMACMD_DMA_PRESENT_BLT, *PVBOXVDMACMD_DMA_PRESENT_BLT;
> +
> +typedef struct VBOXVDMACMD_DMA_PRESENT_SHADOW2PRIMARY
> +{
> +    VBOXVDMA_RECTL Rect;
> +} VBOXVDMACMD_DMA_PRESENT_SHADOW2PRIMARY, *PVBOXVDMACMD_DMA_PRESENT_SHADOW2PRIMARY;
> +
> +
> +#define VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET 0x00000001
> +#define VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET 0x00000002
> +
> +typedef struct VBOXVDMACMD_DMA_BPB_TRANSFER
> +{
> +    uint32_t cbTransferSize;
> +    uint32_t fFlags;
> +    union
> +    {
> +        uint64_t phBuf;
> +        VBOXVIDEOOFFSET offVramBuf;
> +    } Src;
> +    union
> +    {
> +        uint64_t phBuf;
> +        VBOXVIDEOOFFSET offVramBuf;
> +    } Dst;
> +} VBOXVDMACMD_DMA_BPB_TRANSFER, *PVBOXVDMACMD_DMA_BPB_TRANSFER;
> +
> +#define VBOXVDMACMD_SYSMEMEL_F_PAGELIST 0x00000001
> +
> +typedef struct VBOXVDMACMD_SYSMEMEL
> +{
> +    uint32_t cPages;
> +    uint32_t fFlags;
> +    uint64_t phBuf[1];
> +} VBOXVDMACMD_SYSMEMEL, *PVBOXVDMACMD_SYSMEMEL;
> +
> +#define VBOXVDMACMD_SYSMEMEL_NEXT(_pEl) (((_pEl)->fFlags & VBOXVDMACMD_SYSMEMEL_F_PAGELIST) ? \
> +        ((PVBOXVDMACMD_SYSMEMEL)(((uint8_t*)(_pEl))+RT_OFFSETOF(VBOXVDMACMD_SYSMEMEL, phBuf[(_pEl)->cPages]))) \
> +        : \
> +        ((_pEl)+1)
> +
> +#define VBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS_SYS2VRAM 0x00000001
> +
> +typedef struct VBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS
> +{
> +    uint32_t cTransferPages;
> +    uint32_t fFlags;
> +    VBOXVIDEOOFFSET offVramBuf;
> +    VBOXVDMACMD_SYSMEMEL FirstEl;
> +} VBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS, *PVBOXVDMACMD_DMA_BPB_TRANSFER_VRAMSYS;
> +
> +typedef struct VBOXVDMACMD_DMA_BPB_FILL
> +{
> +    VBOXVIDEOOFFSET offSurf;
> +    uint32_t cbFillSize;
> +    uint32_t u32FillPattern;
> +} VBOXVDMACMD_DMA_BPB_FILL, *PVBOXVDMACMD_DMA_BPB_FILL;
> +
> +#define VBOXVDMA_CHILD_STATUS_F_CONNECTED    0x01
> +#define VBOXVDMA_CHILD_STATUS_F_DISCONNECTED 0x02
> +#define VBOXVDMA_CHILD_STATUS_F_ROTATED      0x04
> +
> +typedef struct VBOXVDMA_CHILD_STATUS
> +{
> +    uint32_t iChild;
> +    uint8_t  fFlags;
> +    uint8_t  u8RotationAngle;
> +    uint16_t u16Reserved;
> +} VBOXVDMA_CHILD_STATUS, *PVBOXVDMA_CHILD_STATUS;
> +
> +/* apply the aInfos are applied to all targets, the iTarget is ignored */
> +#define VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL 0x00000001
> +
> +typedef struct VBOXVDMACMD_CHILD_STATUS_IRQ
> +{
> +    uint32_t cInfos;
> +    uint32_t fFlags;
> +    VBOXVDMA_CHILD_STATUS aInfos[1];
> +} VBOXVDMACMD_CHILD_STATUS_IRQ, *PVBOXVDMACMD_CHILD_STATUS_IRQ;
> +
> +# pragma pack()
> +#endif /* #ifdef VBOX_WITH_VDMA */
> +
> +#pragma pack(1)
> +typedef struct VBOXVDMACMD_CHROMIUM_BUFFER
> +{
> +    VBOXVIDEOOFFSET offBuffer;
> +    uint32_t cbBuffer;
> +    uint32_t u32GuestData;
> +    uint64_t u64GuestData;
> +} VBOXVDMACMD_CHROMIUM_BUFFER, *PVBOXVDMACMD_CHROMIUM_BUFFER;
> +
> +typedef struct VBOXVDMACMD_CHROMIUM_CMD
> +{
> +    uint32_t cBuffers;
> +    uint32_t u32Reserved;
> +    VBOXVDMACMD_CHROMIUM_BUFFER aBuffers[1];
> +} VBOXVDMACMD_CHROMIUM_CMD, *PVBOXVDMACMD_CHROMIUM_CMD;
> +
> +typedef enum
> +{
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_UNKNOWN = 0,
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP,
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN,
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END,
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB,
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRCONNECT,
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE_SIZEHACK = 0x7fffffff
> +} VBOXVDMACMD_CHROMIUM_CTL_TYPE;
> +
> +typedef struct VBOXVDMACMD_CHROMIUM_CTL
> +{
> +    VBOXVDMACMD_CHROMIUM_CTL_TYPE enmType;
> +    uint32_t cbCmd;
> +} VBOXVDMACMD_CHROMIUM_CTL, *PVBOXVDMACMD_CHROMIUM_CTL;
> +
> +
> +typedef struct PDMIDISPLAYVBVACALLBACKS *HCRHGSMICMDCOMPLETION;
> +typedef DECLCALLBACK(int) FNCRHGSMICMDCOMPLETION(HCRHGSMICMDCOMPLETION hCompletion, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc);
> +typedef FNCRHGSMICMDCOMPLETION *PFNCRHGSMICMDCOMPLETION;
> +
> +/* tells whether 3D backend has some 3D overlay data displayed */
> +typedef DECLCALLBACK(bool) FNCROGLHASDATA(void);
> +typedef FNCROGLHASDATA *PFNCROGLHASDATA;
> +
> +/* same as PFNCROGLHASDATA, but for specific screen */
> +typedef DECLCALLBACK(bool) FNCROGLHASDATAFORSCREEN(uint32_t i32ScreenID);
> +typedef FNCROGLHASDATAFORSCREEN *PFNCROGLHASDATAFORSCREEN;
> +
> +/* callbacks chrogl gives to main */
> +typedef struct CR_MAIN_INTERFACE
> +{
> +    PFNCROGLHASDATA pfnHasData;
> +    PFNCROGLHASDATAFORSCREEN pfnHasDataForScreen;
> +} CR_MAIN_INTERFACE;
> +
> +typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB
> +{
> +    VBOXVDMACMD_CHROMIUM_CTL Hdr;
> +    /*in*/
> +    HCRHGSMICMDCOMPLETION hCompletion;
> +    PFNCRHGSMICMDCOMPLETION pfnCompletion;
> +    /*out*/
> +    CR_MAIN_INTERFACE MainInterface;
> +} VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB, *PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB;
> +
> +typedef struct VBOXCRCON_SERVER *HVBOXCRCON_SERVER;
> +typedef struct PDMIDISPLAYVBVACALLBACKS* HVBOXCRCON_CLIENT;
> +
> +typedef struct VBOXCRCON_3DRGN_CLIENT* HVBOXCRCON_3DRGN_CLIENT;
> +typedef struct VBOXCRCON_3DRGN_ASYNCCLIENT* HVBOXCRCON_3DRGN_ASYNCCLIENT;
> +
> +/* server callbacks */
> +/* submit chromium cmd */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_SVR_CRCMD(HVBOXCRCON_SERVER hServer, PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd);
> +typedef FNVBOXCRCON_SVR_CRCMD *PFNVBOXCRCON_SVR_CRCMD;
> +
> +/* submit chromium control cmd */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_SVR_CRCTL(HVBOXCRCON_SERVER hServer, PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCmd);
> +typedef FNVBOXCRCON_SVR_CRCTL *PFNVBOXCRCON_SVR_CRCTL;
> +
> +/* request 3D data.
> + * The protocol is the following:
> + * 1. if there is no 3D data displayed on screen, returns VINF_EOF immediately w/o calling any PFNVBOXCRCON_3DRGN_XXX callbacks
> + * 2. otherwise calls PFNVBOXCRCON_3DRGN_ONSUBMIT, submits the "regions get" request to the CrOpenGL server to process it asynchronously and returns VINF_SUCCESS
> + * 2.a on "regions get" request processing calls PFNVBOXCRCON_3DRGN_BEGIN,
> + * 2.b then PFNVBOXCRCON_3DRGN_REPORT zero or more times for each 3D region,
> + * 2.c and then PFNVBOXCRCON_3DRGN_END
> + * 3. returns VERR_XXX code on failure
> + * */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_SVR_3DRGN_GET(HVBOXCRCON_SERVER hServer, HVBOXCRCON_3DRGN_CLIENT hRgnClient, uint32_t idScreen);
> +typedef FNVBOXCRCON_SVR_3DRGN_GET *PFNVBOXCRCON_SVR_3DRGN_GET;
> +
> +/* 3D Regions Client callbacks */
> +/* called from the PFNVBOXCRCON_SVR_3DRGN_GET callback in case server has 3D data and is going to process the request asynchronously,
> + * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_ONSUBMIT(HVBOXCRCON_3DRGN_CLIENT hRgnClient, uint32_t idScreen, HVBOXCRCON_3DRGN_ASYNCCLIENT *phRgnAsyncClient);
> +typedef FNVBOXCRCON_3DRGN_ONSUBMIT *PFNVBOXCRCON_3DRGN_ONSUBMIT;
> +
> +/* called from the "regions get" command processing thread, to indicate that the "regions get" is started.
> + * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_BEGIN(HVBOXCRCON_3DRGN_ASYNCCLIENT hRgnAsyncClient, uint32_t idScreen);
> +typedef FNVBOXCRCON_3DRGN_BEGIN *PFNVBOXCRCON_3DRGN_BEGIN;
> +
> +/* called from the "regions get" command processing thread, to report a 3D region.
> + * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_REPORT(HVBOXCRCON_3DRGN_ASYNCCLIENT hRgnAsyncClient, uint32_t idScreen, void *pvData, uint32_t cbStride, const RTRECT *pRect);
> +typedef FNVBOXCRCON_3DRGN_REPORT *PFNVBOXCRCON_3DRGN_REPORT;
> +
> +/* called from the "regions get" command processing thread, to indicate that the "regions get" is completed.
> + * see comments for PFNVBOXCRCON_SVR_3DRGN_GET above */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_3DRGN_END(HVBOXCRCON_3DRGN_ASYNCCLIENT hRgnAsyncClient, uint32_t idScreen);
> +typedef FNVBOXCRCON_3DRGN_END *PFNVBOXCRCON_3DRGN_END;
> +
> +
> +/* client callbacks */
> +/* complete chromium cmd */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_CLT_CRCTL_COMPLETE(HVBOXCRCON_CLIENT hClient, PVBOXVDMACMD_CHROMIUM_CTL pCtl, int rc);
> +typedef FNVBOXCRCON_CLT_CRCTL_COMPLETE *PFNVBOXCRCON_CLT_CRCTL_COMPLETE;
> +
> +/* complete chromium control cmd */
> +typedef DECLCALLBACK(int) FNVBOXCRCON_CLT_CRCMD_COMPLETE(HVBOXCRCON_CLIENT hClient, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc);
> +typedef FNVBOXCRCON_CLT_CRCMD_COMPLETE *PFNVBOXCRCON_CLT_CRCMD_COMPLETE;
> +
> +typedef struct VBOXCRCON_SERVER_CALLBACKS
> +{
> +    HVBOXCRCON_SERVER hServer;
> +    PFNVBOXCRCON_SVR_CRCMD pfnCrCmd;
> +    PFNVBOXCRCON_SVR_CRCTL pfnCrCtl;
> +    PFNVBOXCRCON_SVR_3DRGN_GET pfn3DRgnGet;
> +} VBOXCRCON_SERVER_CALLBACKS, *PVBOXCRCON_SERVER_CALLBACKS;
> +
> +typedef struct VBOXCRCON_CLIENT_CALLBACKS
> +{
> +    HVBOXCRCON_CLIENT hClient;
> +    PFNVBOXCRCON_CLT_CRCMD_COMPLETE pfnCrCmdComplete;
> +    PFNVBOXCRCON_CLT_CRCTL_COMPLETE pfnCrCtlComplete;
> +    PFNVBOXCRCON_3DRGN_ONSUBMIT pfn3DRgnOnSubmit;
> +    PFNVBOXCRCON_3DRGN_BEGIN pfn3DRgnBegin;
> +    PFNVBOXCRCON_3DRGN_REPORT pfn3DRgnReport;
> +    PFNVBOXCRCON_3DRGN_END pfn3DRgnEnd;
> +} VBOXCRCON_CLIENT_CALLBACKS, *PVBOXCRCON_CLIENT_CALLBACKS;
> +
> +/* issued by Main to establish connection between Main and CrOpenGL service */
> +typedef struct VBOXVDMACMD_CHROMIUM_CTL_CRCONNECT
> +{
> +    VBOXVDMACMD_CHROMIUM_CTL Hdr;
> +    /*input (filled by Client) :*/
> +    /*class VMMDev*/void *pVMMDev;
> +    VBOXCRCON_CLIENT_CALLBACKS ClientCallbacks;
> +    /*output (filled by Server) :*/
> +    VBOXCRCON_SERVER_CALLBACKS ServerCallbacks;
> +} VBOXVDMACMD_CHROMIUM_CTL_CRCONNECT, *PVBOXVDMACMD_CHROMIUM_CTL_CRCONNECT;
> +
> +/* ring command buffer dr */
> +#define VBOXCMDVBVA_STATE_SUBMITTED   1
> +#define VBOXCMDVBVA_STATE_CANCELLED   2
> +#define VBOXCMDVBVA_STATE_IN_PROGRESS 3
> +/* the "completed" state is signalled via the ring buffer values */
> +
> +/* CrHgsmi command */
> +#define VBOXCMDVBVA_OPTYPE_CRCMD                        1
> +/* blit command that does blitting of allocations identified by VRAM offset or host id
> + * for VRAM-offset ones the size and format are same as primary */
> +#define VBOXCMDVBVA_OPTYPE_BLT                          2
> +/* flip */
> +#define VBOXCMDVBVA_OPTYPE_FLIP                         3
> +/* ColorFill */
> +#define VBOXCMDVBVA_OPTYPE_CLRFILL                      4
> +/* allocation paging transfer request */
> +#define VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER              5
> +/* allocation paging fill request */
> +#define VBOXCMDVBVA_OPTYPE_PAGING_FILL                  6
> +/* same as VBOXCMDVBVA_OPTYPE_NOP, but contains VBOXCMDVBVA_HDR data */
> +#define VBOXCMDVBVA_OPTYPE_NOPCMD                       7
> +/* actual command is stored in guest system memory */
> +#define VBOXCMDVBVA_OPTYPE_SYSMEMCMD                    8
> +/* complex command - i.e. can contain multiple commands
> + * i.e. the VBOXCMDVBVA_OPTYPE_COMPLEXCMD VBOXCMDVBVA_HDR is followed
> + * by one or more VBOXCMDVBVA_HDR commands.
> + * Each command's size is specified in it's VBOXCMDVBVA_HDR's u32FenceID field */
> +#define VBOXCMDVBVA_OPTYPE_COMPLEXCMD                   9
> +
> +/* nop - is a one-bit command. The buffer size to skip is determined by VBVA buffer size */
> +#define VBOXCMDVBVA_OPTYPE_NOP                          0x80
> +
> +/* u8Flags flags */
> +/* transfer from RAM to Allocation */
> +#define VBOXCMDVBVA_OPF_PAGING_TRANSFER_IN                  0x80
> +
> +#define VBOXCMDVBVA_OPF_BLT_TYPE_SAMEDIM_A8R8G8B8           0
> +#define VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8           1
> +#define VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID         2
> +
> +#define VBOXCMDVBVA_OPF_BLT_TYPE_MASK                       3
> +
> +
> +#define VBOXCMDVBVA_OPF_CLRFILL_TYPE_GENERIC_A8R8G8B8       0
> +
> +#define VBOXCMDVBVA_OPF_CLRFILL_TYPE_MASK                   1
> +
> +
> +/* blit direction is from first operand to second */
> +#define VBOXCMDVBVA_OPF_BLT_DIR_IN_2                        0x10
> +/* operand 1 contains host id */
> +#define VBOXCMDVBVA_OPF_OPERAND1_ISID                       0x20
> +/* operand 2 contains host id */
> +#define VBOXCMDVBVA_OPF_OPERAND2_ISID                       0x40
> +/* primary hint id is src */
> +#define VBOXCMDVBVA_OPF_PRIMARY_HINT_SRC                    0x80
> +
> +/* trying to make the header as small as possible,
> + * we'd have pretty few op codes actually, so 8bit is quite enough,
> + * we will be able to extend it in any way. */
> +typedef struct VBOXCMDVBVA_HDR
> +{
> +    /* one VBOXCMDVBVA_OPTYPE_XXX, except NOP, see comments above */
> +    uint8_t u8OpCode;
> +    /* command-specific
> +     * VBOXCMDVBVA_OPTYPE_CRCMD                     - must be null
> +     * VBOXCMDVBVA_OPTYPE_BLT                       - OR-ed VBOXCMDVBVA_OPF_ALLOC_XXX flags
> +     * VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER           - must be null
> +     * VBOXCMDVBVA_OPTYPE_PAGING_FILL               - must be null
> +     * VBOXCMDVBVA_OPTYPE_NOPCMD                    - must be null
> +     * VBOXCMDVBVA_OPTYPE_NOP                       - not applicable (as the entire VBOXCMDVBVA_HDR is not valid) */
> +    uint8_t u8Flags;
> +    /* one of VBOXCMDVBVA_STATE_XXX*/
> +    volatile uint8_t u8State;
> +    union
> +    {
> +        /* result, 0 on success, otherwise contains the failure code TBD */
> +        int8_t i8Result;
> +        uint8_t u8PrimaryID;
> +    } u;
> +    union
> +    {
> +        /* complex command (VBOXCMDVBVA_OPTYPE_COMPLEXCMD) element data */
> +        struct
> +        {
> +            /* command length */
> +            uint16_t u16CbCmdHost;
> +            /* guest-specific data, host expects it to be NULL */
> +            uint16_t u16CbCmdGuest;
> +        } complexCmdEl;
> +        /* DXGK DDI fence ID */
> +        uint32_t u32FenceID;
> +    } u2;
> +} VBOXCMDVBVA_HDR;
> +
> +typedef uint32_t VBOXCMDVBVAOFFSET;
> +typedef uint64_t VBOXCMDVBVAPHADDR;
> +typedef uint32_t VBOXCMDVBVAPAGEIDX;
> +
> +typedef struct VBOXCMDVBVA_CRCMD_BUFFER
> +{
> +    uint32_t cbBuffer;
> +    VBOXCMDVBVAOFFSET offBuffer;
> +} VBOXCMDVBVA_CRCMD_BUFFER;
> +
> +typedef struct VBOXCMDVBVA_CRCMD_CMD
> +{
> +    uint32_t cBuffers;
> +    VBOXCMDVBVA_CRCMD_BUFFER aBuffers[1];
> +} VBOXCMDVBVA_CRCMD_CMD;
> +
> +typedef struct VBOXCMDVBVA_CRCMD
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    VBOXCMDVBVA_CRCMD_CMD Cmd;
> +} VBOXCMDVBVA_CRCMD;
> +
> +typedef struct VBOXCMDVBVA_ALLOCINFO
> +{
> +    union
> +    {
> +        VBOXCMDVBVAOFFSET offVRAM;
> +        uint32_t id;
> +    } u;
> +} VBOXCMDVBVA_ALLOCINFO;
> +
> +typedef struct VBOXCMDVBVA_ALLOCDESC
> +{
> +    VBOXCMDVBVA_ALLOCINFO Info;
> +    uint16_t u16Width;
> +    uint16_t u16Height;
> +} VBOXCMDVBVA_ALLOCDESC;
> +
> +typedef struct VBOXCMDVBVA_RECT
> +{
> +   /** Coordinates of affected rectangle. */
> +   int16_t xLeft;
> +   int16_t yTop;
> +   int16_t xRight;
> +   int16_t yBottom;
> +} VBOXCMDVBVA_RECT;
> +
> +typedef struct VBOXCMDVBVA_POINT
> +{
> +   int16_t x;
> +   int16_t y;
> +} VBOXCMDVBVA_POINT;
> +
> +typedef struct VBOXCMDVBVA_BLT_HDR
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    VBOXCMDVBVA_POINT Pos;
> +} VBOXCMDVBVA_BLT_HDR;
> +
> +typedef struct VBOXCMDVBVA_BLT_PRIMARY
> +{
> +    VBOXCMDVBVA_BLT_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCINFO alloc;
> +    /* the rects count is determined from the command size */
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_BLT_PRIMARY;
> +
> +typedef struct VBOXCMDVBVA_BLT_PRIMARY_GENERIC_A8R8G8B8
> +{
> +    VBOXCMDVBVA_BLT_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCDESC alloc;
> +    /* the rects count is determined from the command size */
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_BLT_PRIMARY_GENERIC_A8R8G8B8;
> +
> +typedef struct VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID
> +{
> +    VBOXCMDVBVA_BLT_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCINFO alloc;
> +    uint32_t id;
> +    /* the rects count is determined from the command size */
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID;
> +
> +typedef struct VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8
> +{
> +    VBOXCMDVBVA_BLT_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCDESC alloc1;
> +    VBOXCMDVBVA_ALLOCINFO info2;
> +    /* the rects count is determined from the command size */
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8;
> +
> +typedef struct VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8
> +{
> +    VBOXCMDVBVA_BLT_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCDESC alloc1;
> +    VBOXCMDVBVA_ALLOCDESC alloc2;
> +    /* the rects count is determined from the command size */
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8;
> +
> +#define VBOXCMDVBVA_SIZEOF_BLTSTRUCT_MAX (sizeof (VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8))
> +
> +typedef struct VBOXCMDVBVA_FLIP
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCINFO src;
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_FLIP;
> +
> +#define VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN (RT_OFFSETOF(VBOXCMDVBVA_FLIP, aRects))
> +
> +typedef struct VBOXCMDVBVA_CLRFILL_HDR
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    uint32_t u32Color;
> +} VBOXCMDVBVA_CLRFILL_HDR;
> +
> +typedef struct VBOXCMDVBVA_CLRFILL_PRIMARY
> +{
> +    VBOXCMDVBVA_CLRFILL_HDR Hdr;
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_CLRFILL_PRIMARY;
> +
> +typedef struct VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8
> +{
> +    VBOXCMDVBVA_CLRFILL_HDR Hdr;
> +    VBOXCMDVBVA_ALLOCDESC dst;
> +    VBOXCMDVBVA_RECT aRects[1];
> +} VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8;
> +
> +#define VBOXCMDVBVA_SIZEOF_CLRFILLSTRUCT_MAX (sizeof (VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8))
> +
> +#if 0
> +#define VBOXCMDVBVA_SYSMEMEL_CPAGES_MAX  0x1000
> +
> +typedef struct VBOXCMDVBVA_SYSMEMEL
> +{
> +    uint32_t cPagesAfterFirst  : 12;
> +    uint32_t iPage1            : 20;
> +    uint32_t iPage2;
> +} VBOXCMDVBVA_SYSMEMEL;
> +#endif
> +
> +typedef struct VBOXCMDVBVA_PAGING_TRANSFER_DATA
> +{
> +    /* for now can only contain offVRAM.
> +     * paging transfer can NOT be initiated for allocations having host 3D object (hostID) associated */
> +    VBOXCMDVBVA_ALLOCINFO Alloc;
> +    VBOXCMDVBVAPAGEIDX aPageNumbers[1];
> +} VBOXCMDVBVA_PAGING_TRANSFER_DATA;
> +
> +typedef struct VBOXCMDVBVA_PAGING_TRANSFER
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    VBOXCMDVBVA_PAGING_TRANSFER_DATA Data;
> +} VBOXCMDVBVA_PAGING_TRANSFER;
> +
> +typedef struct VBOXCMDVBVA_PAGING_FILL
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    uint32_t u32CbFill;
> +    uint32_t u32Pattern;
> +    /* paging transfer can NOT be initiated for allocations having host 3D object (hostID) associated */
> +    VBOXCMDVBVAOFFSET offVRAM;
> +} VBOXCMDVBVA_PAGING_FILL;
> +
> +typedef struct VBOXCMDVBVA_SYSMEMCMD
> +{
> +    VBOXCMDVBVA_HDR Hdr;
> +    VBOXCMDVBVAPHADDR phCmd;
> +} VBOXCMDVBVA_SYSMEMCMD;
> +
> +#define VBOXCMDVBVACTL_TYPE_ENABLE     1
> +#define VBOXCMDVBVACTL_TYPE_3DCTL      2
> +#define VBOXCMDVBVACTL_TYPE_RESIZE     3
> +
> +typedef struct VBOXCMDVBVA_CTL
> +{
> +    uint32_t u32Type;
> +    int32_t i32Result;
> +} VBOXCMDVBVA_CTL;
> +
> +typedef struct VBOXCMDVBVA_CTL_ENABLE
> +{
> +    VBOXCMDVBVA_CTL Hdr;
> +    VBVAENABLE Enable;
> +} VBOXCMDVBVA_CTL_ENABLE;
> +
> +#define VBOXCMDVBVA_SCREENMAP_SIZE(_elType) ((VBOX_VIDEO_MAX_SCREENS + sizeof (_elType) - 1) / sizeof (_elType))
> +#define VBOXCMDVBVA_SCREENMAP_DECL(_elType, _name) _elType _name[VBOXCMDVBVA_SCREENMAP_SIZE(_elType)]
> +
> +typedef struct VBOXCMDVBVA_RESIZE_ENTRY
> +{
> +    VBVAINFOSCREEN Screen;
> +    VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
> +} VBOXCMDVBVA_RESIZE_ENTRY;
> +
> +typedef struct VBOXCMDVBVA_RESIZE
> +{
> +    VBOXCMDVBVA_RESIZE_ENTRY aEntries[1];
> +} VBOXCMDVBVA_RESIZE;
> +
> +typedef struct VBOXCMDVBVA_CTL_RESIZE
> +{
> +    VBOXCMDVBVA_CTL Hdr;
> +    VBOXCMDVBVA_RESIZE Resize;
> +} VBOXCMDVBVA_CTL_RESIZE;
> +
> +#define VBOXCMDVBVA3DCTL_TYPE_CONNECT     1
> +#define VBOXCMDVBVA3DCTL_TYPE_DISCONNECT  2
> +#define VBOXCMDVBVA3DCTL_TYPE_CMD         3
> +
> +typedef struct VBOXCMDVBVA_3DCTL
> +{
> +    uint32_t u32Type;
> +    uint32_t u32CmdClientId;
> +} VBOXCMDVBVA_3DCTL;
> +
> +typedef struct VBOXCMDVBVA_3DCTL_CONNECT
> +{
> +    VBOXCMDVBVA_3DCTL Hdr;
> +    uint32_t u32MajorVersion;
> +    uint32_t u32MinorVersion;
> +    uint64_t u64Pid;
> +} VBOXCMDVBVA_3DCTL_CONNECT;
> +
> +typedef struct VBOXCMDVBVA_3DCTL_CMD
> +{
> +    VBOXCMDVBVA_3DCTL Hdr;
> +    VBOXCMDVBVA_HDR Cmd;
> +} VBOXCMDVBVA_3DCTL_CMD;
> +
> +typedef struct VBOXCMDVBVA_CTL_3DCTL_CMD
> +{
> +    VBOXCMDVBVA_CTL Hdr;
> +    VBOXCMDVBVA_3DCTL_CMD Cmd;
> +} VBOXCMDVBVA_CTL_3DCTL_CMD;
> +
> +typedef struct VBOXCMDVBVA_CTL_3DCTL_CONNECT
> +{
> +    VBOXCMDVBVA_CTL Hdr;
> +    VBOXCMDVBVA_3DCTL_CONNECT Connect;
> +} VBOXCMDVBVA_CTL_3DCTL_CONNECT;
> +
> +typedef struct VBOXCMDVBVA_CTL_3DCTL
> +{
> +    VBOXCMDVBVA_CTL Hdr;
> +    VBOXCMDVBVA_3DCTL Ctl;
> +} VBOXCMDVBVA_CTL_3DCTL;
> +
> +#pragma pack()
> +
> +
> +#ifdef VBOXVDMA_WITH_VBVA
> +# pragma pack(1)
> +
> +typedef struct VBOXVDMAVBVACMD
> +{
> +    HGSMIOFFSET offCmd;
> +} VBOXVDMAVBVACMD;
> +
> +#pragma pack()
> +#endif
> +
> +#endif
> diff --git a/drivers/staging/vboxvideo/osindependent/VBoxVideoGuest.h b/drivers/staging/vboxvideo/osindependent/VBoxVideoGuest.h
> new file mode 100644
> index 000000000000..eabdb73ff352
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/VBoxVideoGuest.h
> @@ -0,0 +1,180 @@
> +/** @file
> + * VBox Host Guest Shared Memory Interface (HGSMI).
> + * OS-independent guest structures.
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +
> +#ifndef ___VBox_Graphics_VBoxVideoGuest_h___
> +#define ___VBox_Graphics_VBoxVideoGuest_h___
> +
> +#include <HGSMIBase.h>
> +#include <VBoxVideo.h>
> +#include <VBoxVideoIPRT.h>
> +
> +RT_C_DECLS_BEGIN
> +
> +/**
> + * Structure grouping the context needed for sending graphics acceleration
> + * information to the host via VBVA.  Each screen has its own VBVA buffer.
> + */
> +typedef struct VBVABUFFERCONTEXT
> +{
> +    /** Offset of the buffer in the VRAM section for the screen */
> +    uint32_t    offVRAMBuffer;
> +    /** Length of the buffer in bytes */
> +    uint32_t    cbBuffer;
> +    /** This flag is set if we wrote to the buffer faster than the host could
> +     * read it. */
> +    bool        fHwBufferOverflow;
> +    /** The VBVA record that we are currently preparing for the host, NULL if
> +     * none. */
> +    struct VBVARECORD *pRecord;
> +    /** Pointer to the VBVA buffer mapped into the current address space.  Will
> +     * be NULL if VBVA is not enabled. */
> +    struct VBVABUFFER *pVBVA;
> +} VBVABUFFERCONTEXT, *PVBVABUFFERCONTEXT;
> +
> +/** @name Base HGSMI APIs
> + * @{ */
> +
> +DECLHIDDEN(bool)     VBoxHGSMIIsSupported(void);
> +DECLHIDDEN(void)     VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM,
> +                                                 uint32_t *poffVRAMBaseMapping,
> +                                                 uint32_t *pcbMapping,
> +                                                 uint32_t *poffGuestHeapMemory,
> +                                                 uint32_t *pcbGuestHeapMemory,
> +                                                 uint32_t *poffHostFlags);
> +DECLHIDDEN(int)      VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                                  HGSMIOFFSET offLocation);
> +DECLHIDDEN(int)      VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                           uint32_t fCaps);
> +DECLHIDDEN(void)     VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                                 uint32_t cbVRAM,
> +                                                 uint32_t offVRAMBaseMapping,
> +                                                 uint32_t *poffVRAMHostArea,
> +                                                 uint32_t *pcbHostArea);
> +DECLHIDDEN(int)      VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                              HGSMIOFFSET offVRAMFlagsLocation,
> +                                              uint32_t fCaps,
> +                                              uint32_t offVRAMHostArea,
> +                                              uint32_t cbHostArea);
> +DECLHIDDEN(int)      VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                    uint32_t u32Index, uint32_t *pulValue);
> +DECLHIDDEN(int)      VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                           uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue);
> +DECLHIDDEN(int)      VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                                 uint32_t fFlags,
> +                                                 uint32_t cHotX,
> +                                                 uint32_t cHotY,
> +                                                 uint32_t cWidth,
> +                                                 uint32_t cHeight,
> +                                                 uint8_t *pPixels,
> +                                                 uint32_t cbLength);
> +DECLHIDDEN(int)      VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y,
> +                                             uint32_t *pxHost, uint32_t *pyHost);
> +
> +/** @}  */
> +
> +/** @name VBVA APIs
> + * @{ */
> +DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx,
> +                                PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                                struct VBVABUFFER *pVBVA, int32_t cScreen);
> +DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx,
> +                                 PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                                 int32_t cScreen);
> +DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx,
> +                                           PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx);
> +DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx);
> +DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx,
> +                               PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx,
> +                               const void *pv, uint32_t cb);
> +DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code);
> +DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx,
> +                                            uint32_t offVRAMBuffer,
> +                                            uint32_t cbBuffer);
> +
> +/** @}  */
> +
> +/** @name Modesetting APIs
> + * @{ */
> +
> +DECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx);
> +DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void);
> +DECLHIDDEN(bool)     VBoxVideoAnyWidthAllowed(void);
> +DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx);
> +
> +struct VBVAINFOVIEW;
> +/**
> + * Callback funtion called from @a VBoxHGSMISendViewInfo to initialise
> + * the @a VBVAINFOVIEW structure for each screen.
> + *
> + * @returns  iprt status code
> + * @param  pvData  context data for the callback, passed to @a
> + *                 VBoxHGSMISendViewInfo along with the callback
> + * @param  pInfo   array of @a VBVAINFOVIEW structures to be filled in
> + * @todo  explicitly pass the array size
> + */
> +typedef DECLCALLBACK(int) FNHGSMIFILLVIEWINFO(void *pvData,
> +                                              struct VBVAINFOVIEW *pInfo,
> +                                              uint32_t cViews);
> +/** Pointer to a FNHGSMIFILLVIEWINFO callback */
> +typedef FNHGSMIFILLVIEWINFO *PFNHGSMIFILLVIEWINFO;
> +
> +DECLHIDDEN(int)      VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                           uint32_t u32Count,
> +                                           PFNHGSMIFILLVIEWINFO pfnFill,
> +                                           void *pvData);
> +DECLHIDDEN(void)     VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
> +                                               uint16_t cVirtWidth, uint16_t cBPP,
> +                                               uint16_t fFlags,
> +                                               uint16_t cx, uint16_t cy);
> +DECLHIDDEN(bool)     VBoxVideoGetModeRegisters(uint16_t *pcWidth,
> +                                               uint16_t *pcHeight,
> +                                               uint16_t *pcVirtWidth,
> +                                               uint16_t *pcBPP,
> +                                               uint16_t *pfFlags);
> +DECLHIDDEN(void)     VBoxVideoDisableVBE(void);
> +DECLHIDDEN(void)     VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                                 uint32_t cDisplay,
> +                                                 int32_t  cOriginX,
> +                                                 int32_t  cOriginY,
> +                                                 uint32_t offStart,
> +                                                 uint32_t cbPitch,
> +                                                 uint32_t cWidth,
> +                                                 uint32_t cHeight,
> +                                                 uint16_t cBPP,
> +                                                 uint16_t fFlags);
> +DECLHIDDEN(int)      VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t  cOriginX, int32_t  cOriginY,
> +                                                 uint32_t cWidth, uint32_t cHeight);
> +DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
> +                                      unsigned cScreens, VBVAMODEHINT *paHints);
> +
> +/** @}  */
> +
> +RT_C_DECLS_END
> +
> +#endif
> +
> diff --git a/drivers/staging/vboxvideo/osindependent/VBoxVideoIPRT.h b/drivers/staging/vboxvideo/osindependent/VBoxVideoIPRT.h
> new file mode 100644
> index 000000000000..de2a33cc3383
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/VBoxVideoIPRT.h
> @@ -0,0 +1,137 @@
> +/** @file
> + * VirtualBox Video driver, common code - iprt and VirtualBox macros and
> + * definitions.
> + */
> +
> +/*
> + * Copyright (C) 2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef ___VBox_VBoxVideoIPRT_h
> +#define ___VBox_VBoxVideoIPRT_h
> +
> +#include <asm/io.h>
> +#include <linux/string.h>
> +#include <linux/version.h>
> +
> +/** @name VirtualBox error macros
> + * @{ */
> +
> +#define VINF_SUCCESS                        0
> +#define VERR_INVALID_PARAMETER              (-2)
> +#define VERR_INVALID_POINTER                (-6)
> +#define VERR_NO_MEMORY                      (-8)
> +#define VERR_NOT_IMPLEMENTED                (-12)
> +#define VERR_INVALID_FUNCTION               (-36)
> +#define VERR_NOT_SUPPORTED                  (-37)
> +#define VERR_TOO_MUCH_DATA                  (-42)
> +#define VERR_INVALID_STATE                  (-79)
> +#define VERR_OUT_OF_RESOURCES               (-80)
> +#define VERR_ALREADY_EXISTS                 (-105)
> +#define VERR_INTERNAL_ERROR                 (-225)
> +
> +#define RT_SUCCESS_NP(rc)   ( (int)(rc) >= VINF_SUCCESS )
> +#define RT_SUCCESS(rc)      ( likely(RT_SUCCESS_NP(rc)) )
> +#define RT_FAILURE(rc)      ( unlikely(!RT_SUCCESS_NP(rc)) )
> +
> +/** @}  */
> +
> +/** @name VirtualBox helper functions
> + * @{ */
> +
> +#define ASMCompilerBarrier() mb()
> +
> +/** @}  */
> +
> +/** @name VirtualBox assertions
> + * @{ */
> +
> +#define Assert(a) WARN_ON_ONCE(!(a))
> +#define AssertPtr(a) WARN_ON_ONCE(!(a))
> +#define AssertReturnVoid(a) do { if (WARN_ON_ONCE(!(a))) return; } while(0)
> +#define AssertRC(a) WARN_ON_ONCE(RT_FAILURE(a))
> +#define AssertPtrNullReturnVoid(a) do {} while(0)
> +#define AssertPtrReturnVoid(a) do { if (WARN_ON_ONCE(!(a))) return; } while(0)
> +
> +extern int RTASSERTVAR[1];
> +#define AssertCompile(expr) \
> +    extern int RTASSERTVAR[1] __attribute__((__unused__)), \
> +    RTASSERTVAR[(expr) ? 1 : 0] __attribute__((__unused__))
> +#define AssertCompileSize(type, size) \
> +    AssertCompile(sizeof(type) == (size))
> +
> +#define VALID_PTR(p) (p != NULL)
> +
> +/** @}  */
> +
> +/** @name Port I/O helpers
> + * @{ */
> +/** Write an 8-bit value to an I/O port. */
> +#define VBVO_PORT_WRITE_U8(Port, Value) \
> +    outb(Value, Port)
> +/** Write a 16-bit value to an I/O port. */
> +#define VBVO_PORT_WRITE_U16(Port, Value) \
> +    outw(Value, Port)
> +/** Write a 32-bit value to an I/O port. */
> +#define VBVO_PORT_WRITE_U32(Port, Value) \
> +    outl(Value, Port)
> +/** Read an 8-bit value from an I/O port. */
> +#define VBVO_PORT_READ_U8(Port) \
> +    inb(Port)
> +/** Read a 16-bit value from an I/O port. */
> +#define VBVO_PORT_READ_U16(Port) \
> +    inw(Port)
> +/** Read a 32-bit value from an I/O port. */
> +#define VBVO_PORT_READ_U32(Port) \
> +    inl(Port)
> +
> +/** @}  */
> +
> +/** @name types for VirtualBox OS-independent code
> + * @{ */
> +
> +/* HGSMI uses 32 bit offsets and sizes. */
> +typedef uint32_t HGSMISIZE;
> +typedef uint32_t HGSMIOFFSET;
> +
> +typedef void RTRECT;
> +
> +#define UINT32_C(val)		(val ## U)
> +#define UINT32_MAX		UINT32_C(0xffffffff)
> +
> +/** @}  */
> +
> +/** @name iprt/desc.h replacement macros
> + * @{ */
> +
> +#define RT_C_DECLS_BEGIN
> +#define RT_C_DECLS_END
> +#define DECLCALLBACK(type) type
> +#define DECLCALLBACKMEMBER(type, name) type (*name)
> +#define DECLHIDDEN(type) __attribute__((visibility("hidden"))) type
> +#define DECLINLINE(type) static __inline__ type
> +#define RT_BOOL(val) (!!(val))
> +#define RT_BIT BIT
> +#define _1K 0x00000400
> +
> +/** @}  */
> +
> +#endif /* ___VBox_VBoxVideoIPRT_h */
> diff --git a/drivers/staging/vboxvideo/osindependent/VBoxVideoVBE.h b/drivers/staging/vboxvideo/osindependent/VBoxVideoVBE.h
> new file mode 100644
> index 000000000000..7ed7d97e3530
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/osindependent/VBoxVideoVBE.h
> @@ -0,0 +1,85 @@
> +/** @file
> + * VirtualBox graphics card port I/O definitions
> + */
> +
> +/*
> + * Copyright (C) 2006-2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef ___VBox_Graphics_VBoxVideoVBE_h
> +#define ___VBox_Graphics_VBoxVideoVBE_h
> +
> +/* GUEST <-> HOST Communication API */
> +
> +/** @todo FIXME: Either dynamicly ask host for this or put somewhere high in
> + *               physical memory like 0xE0000000. */
> +
> +#define VBE_DISPI_BANK_ADDRESS          0xA0000
> +#define VBE_DISPI_BANK_SIZE_KB          64
> +
> +#define VBE_DISPI_MAX_XRES              16384
> +#define VBE_DISPI_MAX_YRES              16384
> +#define VBE_DISPI_MAX_BPP               32
> +
> +#define VBE_DISPI_IOPORT_INDEX          0x01CE
> +#define VBE_DISPI_IOPORT_DATA           0x01CF
> +
> +#define VBE_DISPI_IOPORT_DAC_WRITE_INDEX  0x03C8
> +#define VBE_DISPI_IOPORT_DAC_DATA         0x03C9
> +
> +#define VBE_DISPI_INDEX_ID              0x0
> +#define VBE_DISPI_INDEX_XRES            0x1
> +#define VBE_DISPI_INDEX_YRES            0x2
> +#define VBE_DISPI_INDEX_BPP             0x3
> +#define VBE_DISPI_INDEX_ENABLE          0x4
> +#define VBE_DISPI_INDEX_BANK            0x5
> +#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
> +#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
> +#define VBE_DISPI_INDEX_X_OFFSET        0x8
> +#define VBE_DISPI_INDEX_Y_OFFSET        0x9
> +#define VBE_DISPI_INDEX_VBOX_VIDEO      0xa
> +#define VBE_DISPI_INDEX_FB_BASE_HI      0xb
> +
> +#define VBE_DISPI_ID0                   0xB0C0
> +#define VBE_DISPI_ID1                   0xB0C1
> +#define VBE_DISPI_ID2                   0xB0C2
> +#define VBE_DISPI_ID3                   0xB0C3
> +#define VBE_DISPI_ID4                   0xB0C4
> +
> +#define VBE_DISPI_ID_VBOX_VIDEO         0xBE00
> +/* The VBOX interface id. Indicates support for VBVA shared memory interface. */
> +#define VBE_DISPI_ID_HGSMI              0xBE01
> +#define VBE_DISPI_ID_ANYX               0xBE02
> +
> +#define VBE_DISPI_DISABLED              0x00
> +#define VBE_DISPI_ENABLED               0x01
> +#define VBE_DISPI_GETCAPS               0x02
> +#define VBE_DISPI_8BIT_DAC              0x20
> +/** @note this definition is a BOCHS legacy, used only in the video BIOS
> + *        code and ignored by the emulated hardware. */
> +#define VBE_DISPI_LFB_ENABLED           0x40
> +#define VBE_DISPI_NOCLEARMEM            0x80
> +
> +#define VGA_PORT_HGSMI_HOST             0x3b0
> +#define VGA_PORT_HGSMI_GUEST            0x3d0
> +
> +#endif /* !___VBox_Graphics_VBoxVideoVBE_h */
> +
> diff --git a/drivers/staging/vboxvideo/vbox_drv.c b/drivers/staging/vboxvideo/vbox_drv.c
> new file mode 100644
> index 000000000000..4e033125148a
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_drv.c
> @@ -0,0 +1,287 @@
> +/*
> + * Copyright (C) 2013-2017 Oracle Corporation
> + * This file is based on ast_drv.c
> + * Copyright 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * Authors: Dave Airlie <airlied at redhat.com>
> + *          Michael Thayer <michael.thayer at oracle.com,
> + *          Hans de Goede <hdegoede at redhat.com>
> + */
> +#include "vbox_drv.h"
> +
> +#include <linux/module.h>
> +#include <linux/console.h>
> +#include <linux/vt_kern.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +int vbox_modeset = -1;
> +
> +MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
> +module_param_named(modeset, vbox_modeset, int, 0400);
> +
> +static struct drm_driver driver;
> +
> +static const struct pci_device_id pciidlist[] = {
> +	{ 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
> +	{ 0, 0, 0},
> +};
> +MODULE_DEVICE_TABLE(pci, pciidlist);
> +
> +static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> +	return drm_get_pci_dev(pdev, ent, &driver);
> +}
> +
> +static void vbox_pci_remove(struct pci_dev *pdev)
> +{
> +	struct drm_device *dev = pci_get_drvdata(pdev);
> +
> +	drm_put_dev(dev);
> +}
> +
> +static int vbox_drm_freeze(struct drm_device *dev)
> +{
> +	drm_kms_helper_poll_disable(dev);
> +
> +	pci_save_state(dev->pdev);
> +
> +	console_lock();
> +	vbox_fbdev_set_suspend(dev, 1);
> +	console_unlock();
> +
> +	return 0;
> +}
> +
> +static int vbox_drm_thaw(struct drm_device *dev)
> +{
> +	drm_mode_config_reset(dev);
> +	drm_helper_resume_force_mode(dev);
> +
> +	console_lock();
> +	vbox_fbdev_set_suspend(dev, 0);
> +	console_unlock();
> +
> +	return 0;
> +}
> +
> +static int vbox_drm_resume(struct drm_device *dev)
> +{
> +	int ret;
> +
> +	if (pci_enable_device(dev->pdev))
> +		return -EIO;
> +
> +	ret = vbox_drm_thaw(dev);
> +	if (ret)
> +		return ret;
> +
> +	drm_kms_helper_poll_enable(dev);
> +
> +	return 0;
> +}
> +
> +static int vbox_pm_suspend(struct device *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct drm_device *ddev = pci_get_drvdata(pdev);
> +	int error;
> +
> +	error = vbox_drm_freeze(ddev);
> +	if (error)
> +		return error;
> +
> +	pci_disable_device(pdev);
> +	pci_set_power_state(pdev, PCI_D3hot);
> +
> +	return 0;
> +}
> +
> +static int vbox_pm_resume(struct device *dev)
> +{
> +	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
> +
> +	return vbox_drm_resume(ddev);
> +}
> +
> +static int vbox_pm_freeze(struct device *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct drm_device *ddev = pci_get_drvdata(pdev);
> +
> +	if (!ddev || !ddev->dev_private)
> +		return -ENODEV;
> +
> +	return vbox_drm_freeze(ddev);
> +}
> +
> +static int vbox_pm_thaw(struct device *dev)
> +{
> +	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
> +
> +	return vbox_drm_thaw(ddev);
> +}
> +
> +static int vbox_pm_poweroff(struct device *dev)
> +{
> +	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
> +
> +	return vbox_drm_freeze(ddev);
> +}
> +
> +static const struct dev_pm_ops vbox_pm_ops = {
> +	.suspend = vbox_pm_suspend,
> +	.resume = vbox_pm_resume,
> +	.freeze = vbox_pm_freeze,
> +	.thaw = vbox_pm_thaw,
> +	.poweroff = vbox_pm_poweroff,
> +	.restore = vbox_pm_resume,
> +};
> +
> +static struct pci_driver vbox_pci_driver = {
> +	.name = DRIVER_NAME,
> +	.id_table = pciidlist,
> +	.probe = vbox_pci_probe,
> +	.remove = vbox_pci_remove,
> +	.driver.pm = &vbox_pm_ops,
> +};
> +
> +static const struct file_operations vbox_fops = {
> +	.owner = THIS_MODULE,
> +	.open = drm_open,
> +	.release = drm_release,
> +	.unlocked_ioctl = drm_ioctl,
> +	.mmap = vbox_mmap,
> +	.poll = drm_poll,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = drm_compat_ioctl,
> +#endif
> +	.read = drm_read,
> +};
> +
> +static int vbox_master_set(struct drm_device *dev,
> +			   struct drm_file *file_priv, bool from_open)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +
> +	/*
> +	 * We do not yet know whether the new owner can handle hotplug, so we
> +	 * do not advertise dynamic modes on the first query and send a
> +	 * tentative hotplug notification after that to see if they query again.
> +	 */
> +	vbox->initial_mode_queried = false;
> +
> +	mutex_lock(&vbox->hw_mutex);
> +	/*
> +	 * Disable VBVA when someone releases master in case the next person
> +	 * tries tries to do VESA.
> +	 */
> +	/** @todo work out if anyone is likely to and whether it will work. */
> +	/*
> +	 * Update: we also disable it because if the new master does not do
> +	 * dirty rectangle reporting (e.g. old versions of Plymouth) then at
> +	 * least the first screen will still be updated. We enable it as soon
> +	 * as we receive a dirty rectangle report.
> +	 */
> +	vbox_disable_accel(vbox);
> +	mutex_unlock(&vbox->hw_mutex);
> +
> +	return 0;
> +}
> +
> +static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +
> +	/* See vbox_master_set() */
> +	vbox->initial_mode_queried = false;
> +
> +	mutex_lock(&vbox->hw_mutex);
> +	vbox_disable_accel(vbox);
> +	mutex_unlock(&vbox->hw_mutex);
> +}
> +
> +static struct drm_driver driver = {
> +	.driver_features =
> +	    DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
> +	    DRIVER_PRIME,
> +	.dev_priv_size = 0,
> +
> +	.load = vbox_driver_load,
> +	.unload = vbox_driver_unload,
> +	.lastclose = vbox_driver_lastclose,
> +	.master_set = vbox_master_set,
> +	.master_drop = vbox_master_drop,
> +	.set_busid = drm_pci_set_busid,
> +
> +	.fops = &vbox_fops,
> +	.irq_handler = vbox_irq_handler,
> +	.name = DRIVER_NAME,
> +	.desc = DRIVER_DESC,
> +	.date = DRIVER_DATE,
> +	.major = DRIVER_MAJOR,
> +	.minor = DRIVER_MINOR,
> +	.patchlevel = DRIVER_PATCHLEVEL,
> +
> +	.gem_free_object = vbox_gem_free_object,
> +	.dumb_create = vbox_dumb_create,
> +	.dumb_map_offset = vbox_dumb_mmap_offset,
> +	.dumb_destroy = drm_gem_dumb_destroy,
> +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +	.gem_prime_export = drm_gem_prime_export,
> +	.gem_prime_import = drm_gem_prime_import,
> +	.gem_prime_pin = vbox_gem_prime_pin,
> +	.gem_prime_unpin = vbox_gem_prime_unpin,
> +	.gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
> +	.gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
> +	.gem_prime_vmap = vbox_gem_prime_vmap,
> +	.gem_prime_vunmap = vbox_gem_prime_vunmap,
> +	.gem_prime_mmap = vbox_gem_prime_mmap,
> +};
> +
> +static int __init vbox_init(void)
> +{
> +#ifdef CONFIG_VGA_CONSOLE
> +	if (vgacon_text_force() && vbox_modeset == -1)
> +		return -EINVAL;
> +#endif
> +
> +	if (vbox_modeset == 0)
> +		return -EINVAL;
> +
> +	return drm_pci_init(&driver, &vbox_pci_driver);
> +}
> +
> +static void __exit vbox_exit(void)
> +{
> +	drm_pci_exit(&driver, &vbox_pci_driver);
> +}
> +
> +module_init(vbox_init);
> +module_exit(vbox_exit);
> +
> +MODULE_AUTHOR("Oracle Corporation");
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL and additional rights");
> diff --git a/drivers/staging/vboxvideo/vbox_drv.h b/drivers/staging/vboxvideo/vbox_drv.h
> new file mode 100644
> index 000000000000..c3293b2aa82f
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_drv.h
> @@ -0,0 +1,287 @@
> +/*
> + * Copyright (C) 2013-2017 Oracle Corporation
> + * This file is based on ast_drv.h
> + * Copyright 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * Authors: Dave Airlie <airlied at redhat.com>
> + *          Michael Thayer <michael.thayer at oracle.com,
> + *          Hans de Goede <hdegoede at redhat.com>
> + */
> +#ifndef __VBOX_DRV_H__
> +#define __VBOX_DRV_H__
> +
> +#define LOG_GROUP LOG_GROUP_DEV_VGA
> +
> +#include <VBoxVideoGuest.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_encoder.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_gem.h>
> +
> +#include <drm/ttm/ttm_bo_api.h>
> +#include <drm/ttm/ttm_bo_driver.h>
> +#include <drm/ttm/ttm_placement.h>
> +#include <drm/ttm/ttm_memory.h>
> +#include <drm/ttm/ttm_module.h>
> +
> +#define DRIVER_NAME         "vboxvideo"
> +#define DRIVER_DESC         "Oracle VM VirtualBox Graphics Card"
> +#define DRIVER_DATE         "20130823"
> +
> +#define DRIVER_MAJOR        1
> +#define DRIVER_MINOR        0
> +#define DRIVER_PATCHLEVEL   0
> +
> +#define VBOX_MAX_CURSOR_WIDTH  64
> +#define VBOX_MAX_CURSOR_HEIGHT 64
> +#define CURSOR_PIXEL_COUNT (VBOX_MAX_CURSOR_WIDTH * VBOX_MAX_CURSOR_HEIGHT)
> +#define CURSOR_DATA_SIZE (CURSOR_PIXEL_COUNT * 4 + CURSOR_PIXEL_COUNT / 8)
> +
> +#define VBOX_MAX_SCREENS  32
> +
> +#define GUEST_HEAP_OFFSET(vbox) ((vbox)->full_vram_size - \
> +				 VBVA_ADAPTER_INFORMATION_SIZE)
> +#define GUEST_HEAP_SIZE   VBVA_ADAPTER_INFORMATION_SIZE
> +#define GUEST_HEAP_USABLE_SIZE (VBVA_ADAPTER_INFORMATION_SIZE - \
> +				sizeof(HGSMIHOSTFLAGS))
> +#define HOST_FLAGS_OFFSET GUEST_HEAP_USABLE_SIZE
> +
> +struct vbox_fbdev;
> +
> +struct vbox_private {
> +	struct drm_device *dev;
> +
> +	u8 __iomem *guest_heap;
> +	u8 __iomem *vbva_buffers;
> +	struct gen_pool *guest_pool;
> +	struct VBVABUFFERCONTEXT *vbva_info;
> +	bool any_pitch;
> +	unsigned int num_crtcs;
> +	/** Amount of available VRAM, including space used for buffers. */
> +	u32 full_vram_size;
> +	/** Amount of available VRAM, not including space used for buffers. */
> +	u32 available_vram_size;
> +	/** Array of structures for receiving mode hints. */
> +	VBVAMODEHINT *last_mode_hints;
> +
> +	struct vbox_fbdev *fbdev;
> +
> +	int fb_mtrr;
> +
> +	struct {
> +		struct drm_global_reference mem_global_ref;
> +		struct ttm_bo_global_ref bo_global_ref;
> +		struct ttm_bo_device bdev;
> +		bool mm_initialised;
> +	} ttm;
> +
> +	struct mutex hw_mutex; /* protects modeset and accel/vbva accesses */
> +	bool isr_installed;
> +	/**
> +	 * We decide whether or not user-space supports display hot-plug
> +	 * depending on whether they react to a hot-plug event after the initial
> +	 * mode query.
> +	 */
> +	bool initial_mode_queried;
> +	struct work_struct hotplug_work;
> +	u32 input_mapping_width;
> +	u32 input_mapping_height;
> +	/**
> +	 * Is user-space using an X.Org-style layout of one large frame-buffer
> +	 * encompassing all screen ones or is the fbdev console active?
> +	 */
> +	bool single_framebuffer;
> +	u32 cursor_width;
> +	u32 cursor_height;
> +	u32 cursor_hot_x;
> +	u32 cursor_hot_y;
> +	size_t cursor_data_size;
> +	u8 cursor_data[CURSOR_DATA_SIZE];
> +};
> +
> +#undef CURSOR_PIXEL_COUNT
> +#undef CURSOR_DATA_SIZE
> +
> +int vbox_driver_load(struct drm_device *dev, unsigned long flags);
> +void vbox_driver_unload(struct drm_device *dev);
> +void vbox_driver_lastclose(struct drm_device *dev);
> +
> +struct vbox_gem_object;
> +
> +#ifndef VGA_PORT_HGSMI_HOST
> +#define VGA_PORT_HGSMI_HOST             0x3b0
> +#define VGA_PORT_HGSMI_GUEST            0x3d0
> +#endif
> +
> +struct vbox_connector {
> +	struct drm_connector base;
> +	char name[32];
> +	struct vbox_crtc *vbox_crtc;
> +	struct {
> +		u16 width;
> +		u16 height;
> +		bool disconnected;
> +	} mode_hint;
> +};
> +
> +struct vbox_crtc {
> +	struct drm_crtc base;
> +	bool blanked;
> +	bool disconnected;
> +	unsigned int crtc_id;
> +	u32 fb_offset;
> +	bool cursor_enabled;
> +	u16 x_hint;
> +	u16 y_hint;
> +};
> +
> +struct vbox_encoder {
> +	struct drm_encoder base;
> +};
> +
> +struct vbox_framebuffer {
> +	struct drm_framebuffer base;
> +	struct drm_gem_object *obj;
> +};
> +
> +struct vbox_fbdev {
> +	struct drm_fb_helper helper;
> +	struct vbox_framebuffer afb;
> +	int size;
> +	struct ttm_bo_kmap_obj mapping;
> +	int x1, y1, x2, y2;	/* dirty rect */
> +	spinlock_t dirty_lock;
> +};
> +
> +#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base)
> +#define to_vbox_connector(x) container_of(x, struct vbox_connector, base)
> +#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base)
> +#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base)
> +
> +int vbox_mode_init(struct drm_device *dev);
> +void vbox_mode_fini(struct drm_device *dev);
> +
> +#define DRM_MODE_FB_CMD drm_mode_fb_cmd2
> +#define CRTC_FB(crtc) ((crtc)->primary->fb)
> +
> +void vbox_enable_accel(struct vbox_private *vbox);
> +void vbox_disable_accel(struct vbox_private *vbox);
> +void vbox_report_caps(struct vbox_private *vbox);
> +
> +void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
> +				       struct drm_clip_rect *rects,
> +				       unsigned int num_rects);
> +
> +int vbox_framebuffer_init(struct drm_device *dev,
> +			  struct vbox_framebuffer *vbox_fb,
> +			  const struct DRM_MODE_FB_CMD *mode_cmd,
> +			  struct drm_gem_object *obj);
> +
> +int vbox_fbdev_init(struct drm_device *dev);
> +void vbox_fbdev_fini(struct drm_device *dev);
> +void vbox_fbdev_set_suspend(struct drm_device *dev, int state);
> +void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr);
> +
> +struct vbox_bo {
> +	struct ttm_buffer_object bo;
> +	struct ttm_placement placement;
> +	struct ttm_bo_kmap_obj kmap;
> +	struct drm_gem_object gem;
> +	struct ttm_place placements[3];
> +	int pin_count;
> +};
> +
> +#define gem_to_vbox_bo(gobj) container_of((gobj), struct vbox_bo, gem)
> +
> +static inline struct vbox_bo *vbox_bo(struct ttm_buffer_object *bo)
> +{
> +	return container_of(bo, struct vbox_bo, bo);
> +}
> +
> +#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base)
> +
> +int vbox_dumb_create(struct drm_file *file,
> +		     struct drm_device *dev,
> +		     struct drm_mode_create_dumb *args);
> +
> +void vbox_gem_free_object(struct drm_gem_object *obj);
> +int vbox_dumb_mmap_offset(struct drm_file *file,
> +			  struct drm_device *dev,
> +			  u32 handle, u64 *offset);
> +
> +#define DRM_FILE_PAGE_OFFSET (0x10000000ULL >> PAGE_SHIFT)
> +
> +int vbox_mm_init(struct vbox_private *vbox);
> +void vbox_mm_fini(struct vbox_private *vbox);
> +
> +int vbox_bo_create(struct drm_device *dev, int size, int align,
> +		   u32 flags, struct vbox_bo **pvboxbo);
> +
> +int vbox_gem_create(struct drm_device *dev,
> +		    u32 size, bool iskernel, struct drm_gem_object **obj);
> +
> +int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr);
> +int vbox_bo_unpin(struct vbox_bo *bo);
> +
> +static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait)
> +{
> +	int ret;
> +
> +	ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
> +	if (ret) {
> +		if (ret != -ERESTARTSYS && ret != -EBUSY)
> +			DRM_ERROR("reserve failed %p\n", bo);
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +static inline void vbox_bo_unreserve(struct vbox_bo *bo)
> +{
> +	ttm_bo_unreserve(&bo->bo);
> +}
> +
> +void vbox_ttm_placement(struct vbox_bo *bo, int domain);
> +int vbox_bo_push_sysram(struct vbox_bo *bo);
> +int vbox_mmap(struct file *filp, struct vm_area_struct *vma);
> +
> +/* vbox_prime.c */
> +int vbox_gem_prime_pin(struct drm_gem_object *obj);
> +void vbox_gem_prime_unpin(struct drm_gem_object *obj);
> +struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj);
> +struct drm_gem_object *vbox_gem_prime_import_sg_table(
> +	struct drm_device *dev, struct dma_buf_attachment *attach,
> +	struct sg_table *table);
> +void *vbox_gem_prime_vmap(struct drm_gem_object *obj);
> +void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
> +int vbox_gem_prime_mmap(struct drm_gem_object *obj,
> +			struct vm_area_struct *area);
> +
> +/* vbox_irq.c */
> +int vbox_irq_init(struct vbox_private *vbox);
> +void vbox_irq_fini(struct vbox_private *vbox);
> +void vbox_report_hotplug(struct vbox_private *vbox);
> +irqreturn_t vbox_irq_handler(int irq, void *arg);
> +
> +#endif
> diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c
> new file mode 100644
> index 000000000000..a6dd10cc3cd2
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_fb.c
> @@ -0,0 +1,444 @@
> +/*
> + * Copyright (C) 2013-2017 Oracle Corporation
> + * This file is based on ast_fb.c
> + * Copyright 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * Authors: Dave Airlie <airlied at redhat.com>
> + *          Michael Thayer <michael.thayer at oracle.com,
> + */
> +/* Include from most specific to most general to be able to override things. */
> +#include "vbox_drv.h"
> +#include <VBoxVideo.h>
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/tty.h>
> +#include <linux/sysrq.h>
> +#include <linux/delay.h>
> +#include <linux/fb.h>
> +#include <linux/init.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include "vbox_drv.h"
> +
> +#define VBOX_DIRTY_DELAY (HZ / 30)
> +/**
> + * Tell the host about dirty rectangles to update.
> + */
> +static void vbox_dirty_update(struct vbox_fbdev *fbdev,
> +			      int x, int y, int width, int height)
> +{
> +	struct drm_gem_object *obj;
> +	struct vbox_bo *bo;
> +	int ret = -EBUSY;
> +	bool store_for_later = false;
> +	int x2, y2;
> +	unsigned long flags;
> +	struct drm_clip_rect rect;
> +
> +	obj = fbdev->afb.obj;
> +	bo = gem_to_vbox_bo(obj);
> +
> +	/*
> +	 * try and reserve the BO, if we fail with busy
> +	 * then the BO is being moved and we should
> +	 * store up the damage until later.
> +	 */
> +	if (drm_can_sleep())
> +		ret = vbox_bo_reserve(bo, true);
> +	if (ret) {
> +		if (ret != -EBUSY)
> +			return;
> +
> +		store_for_later = true;
> +	}
> +
> +	x2 = x + width - 1;
> +	y2 = y + height - 1;
> +	spin_lock_irqsave(&fbdev->dirty_lock, flags);
> +
> +	if (fbdev->y1 < y)
> +		y = fbdev->y1;
> +	if (fbdev->y2 > y2)
> +		y2 = fbdev->y2;
> +	if (fbdev->x1 < x)
> +		x = fbdev->x1;
> +	if (fbdev->x2 > x2)
> +		x2 = fbdev->x2;
> +
> +	if (store_for_later) {
> +		fbdev->x1 = x;
> +		fbdev->x2 = x2;
> +		fbdev->y1 = y;
> +		fbdev->y2 = y2;
> +		spin_unlock_irqrestore(&fbdev->dirty_lock, flags);
> +		return;
> +	}
> +
> +	fbdev->x1 = INT_MAX;
> +	fbdev->y1 = INT_MAX;
> +	fbdev->x2 = 0;
> +	fbdev->y2 = 0;
> +
> +	spin_unlock_irqrestore(&fbdev->dirty_lock, flags);
> +
> +	/*
> +	 * Not sure why the original code subtracted 1 here, but I will keep
> +	 * it that way to avoid unnecessary differences.
> +	 */
> +	rect.x1 = x;
> +	rect.x2 = x2 + 1;
> +	rect.y1 = y;
> +	rect.y2 = y2 + 1;
> +	vbox_framebuffer_dirty_rectangles(&fbdev->afb.base, &rect, 1);
> +
> +	vbox_bo_unreserve(bo);
> +}
> +
> +#ifdef CONFIG_FB_DEFERRED_IO
> +static void vbox_deferred_io(struct fb_info *info, struct list_head *pagelist)
> +{
> +	struct vbox_fbdev *fbdev = info->par;
> +	unsigned long start, end, min, max;
> +	struct page *page;
> +	int y1, y2;
> +
> +	min = ULONG_MAX;
> +	max = 0;
> +	list_for_each_entry(page, pagelist, lru) {
> +		start = page->index << PAGE_SHIFT;
> +		end = start + PAGE_SIZE - 1;
> +		min = min(min, start);
> +		max = max(max, end);
> +	}
> +
> +	if (min < max) {
> +		y1 = min / info->fix.line_length;
> +		y2 = (max / info->fix.line_length) + 1;
> +		DRM_INFO("%s: Calling dirty update: 0, %d, %d, %d\n",
> +			 __func__, y1, info->var.xres, y2 - y1 - 1);
> +		vbox_dirty_update(fbdev, 0, y1, info->var.xres, y2 - y1 - 1);
> +	}
> +}
> +
> +static struct fb_deferred_io vbox_defio = {
> +	.delay = VBOX_DIRTY_DELAY,
> +	.deferred_io = vbox_deferred_io,
> +};
> +#endif
> +
> +static void vbox_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
> +{
> +	struct vbox_fbdev *fbdev = info->par;
> +
> +	sys_fillrect(info, rect);
> +	vbox_dirty_update(fbdev, rect->dx, rect->dy, rect->width, rect->height);
> +}
> +
> +static void vbox_copyarea(struct fb_info *info, const struct fb_copyarea *area)
> +{
> +	struct vbox_fbdev *fbdev = info->par;
> +
> +	sys_copyarea(info, area);
> +	vbox_dirty_update(fbdev, area->dx, area->dy, area->width, area->height);
> +}
> +
> +static void vbox_imageblit(struct fb_info *info, const struct fb_image *image)
> +{
> +	struct vbox_fbdev *fbdev = info->par;
> +
> +	sys_imageblit(info, image);
> +	vbox_dirty_update(fbdev, image->dx, image->dy, image->width,
> +			  image->height);
> +}
> +
> +static struct fb_ops vboxfb_ops = {
> +	.owner = THIS_MODULE,
> +	.fb_check_var = drm_fb_helper_check_var,
> +	.fb_set_par = drm_fb_helper_set_par,
> +	.fb_fillrect = vbox_fillrect,
> +	.fb_copyarea = vbox_copyarea,
> +	.fb_imageblit = vbox_imageblit,
> +	.fb_pan_display = drm_fb_helper_pan_display,
> +	.fb_blank = drm_fb_helper_blank,
> +	.fb_setcmap = drm_fb_helper_setcmap,
> +	.fb_debug_enter = drm_fb_helper_debug_enter,
> +	.fb_debug_leave = drm_fb_helper_debug_leave,
> +};
> +
> +static int vboxfb_create_object(struct vbox_fbdev *fbdev,
> +				struct DRM_MODE_FB_CMD *mode_cmd,
> +				struct drm_gem_object **gobj_p)
> +{
> +	struct drm_device *dev = fbdev->helper.dev;
> +	u32 size;
> +	struct drm_gem_object *gobj;
> +	u32 pitch = mode_cmd->pitches[0];
> +	int ret = 0;
> +
> +	size = pitch * mode_cmd->height;
> +	ret = vbox_gem_create(dev, size, true, &gobj);
> +	if (ret)
> +		return ret;
> +
> +	*gobj_p = gobj;
> +	return ret;
> +}
> +
> +static int vboxfb_create(struct drm_fb_helper *helper,
> +			 struct drm_fb_helper_surface_size *sizes)
> +{
> +	struct vbox_fbdev *fbdev =
> +	    container_of(helper, struct vbox_fbdev, helper);
> +	struct drm_device *dev = fbdev->helper.dev;
> +	struct DRM_MODE_FB_CMD mode_cmd;
> +	struct drm_framebuffer *fb;
> +	struct fb_info *info;
> +	struct device *device = &dev->pdev->dev;
> +	struct drm_gem_object *gobj = NULL;
> +	struct vbox_bo *bo = NULL;
> +	int size, ret;
> +	u32 pitch;
> +
> +	mode_cmd.width = sizes->surface_width;
> +	mode_cmd.height = sizes->surface_height;
> +	pitch = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
> +	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
> +							  sizes->surface_depth);
> +	mode_cmd.pitches[0] = pitch;
> +
> +	size = pitch * mode_cmd.height;
> +
> +	ret = vboxfb_create_object(fbdev, &mode_cmd, &gobj);
> +	if (ret) {
> +		DRM_ERROR("failed to create fbcon backing object %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = vbox_framebuffer_init(dev, &fbdev->afb, &mode_cmd, gobj);
> +	if (ret)
> +		return ret;
> +
> +	bo = gem_to_vbox_bo(gobj);
> +
> +	ret = vbox_bo_reserve(bo, false);
> +	if (ret)
> +		return ret;
> +
> +	ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
> +	if (ret) {
> +		vbox_bo_unreserve(bo);
> +		return ret;
> +	}
> +
> +	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> +	vbox_bo_unreserve(bo);
> +	if (ret) {
> +		DRM_ERROR("failed to kmap fbcon\n");
> +		return ret;
> +	}
> +
> +	info = framebuffer_alloc(0, device);
> +	if (!info)
> +		return -ENOMEM;
> +	info->par = fbdev;
> +
> +	fbdev->size = size;
> +
> +	fb = &fbdev->afb.base;
> +	fbdev->helper.fb = fb;
> +	fbdev->helper.fbdev = info;
> +
> +	strcpy(info->fix.id, "vboxdrmfb");
> +
> +	/*
> +	 * The last flag forces a mode set on VT switches even if the kernel
> +	 * does not think it is needed.
> +	 */
> +	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT |
> +		      FBINFO_MISC_ALWAYS_SETPAR;
> +	info->fbops = &vboxfb_ops;
> +
> +	ret = fb_alloc_cmap(&info->cmap, 256, 0);
> +	if (ret)
> +		return -ENOMEM;
> +
> +	/*
> +	 * This seems to be done for safety checking that the framebuffer
> +	 * is not registered twice by different drivers.
> +	 */
> +	info->apertures = alloc_apertures(1);
> +	if (!info->apertures)
> +		return -ENOMEM;
> +	info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
> +	info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
> +
> +	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
> +	drm_fb_helper_fill_var(info, &fbdev->helper, sizes->fb_width,
> +			       sizes->fb_height);
> +
> +	info->screen_base = bo->kmap.virtual;
> +	info->screen_size = size;
> +
> +#ifdef CONFIG_FB_DEFERRED_IO
> +	info->fbdefio = &vbox_defio;
> +	fb_deferred_io_init(info);
> +#endif
> +
> +	info->pixmap.flags = FB_PIXMAP_SYSTEM;
> +
> +	DRM_DEBUG_KMS("allocated %dx%d\n", fb->width, fb->height);
> +
> +	return 0;
> +}
> +
> +static void vbox_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
> +			      u16 blue, int regno)
> +{
> +}
> +
> +static void vbox_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
> +			      u16 *blue, int regno)
> +{
> +	*red = regno;
> +	*green = regno;
> +	*blue = regno;
> +}
> +
> +static struct drm_fb_helper_funcs vbox_fb_helper_funcs = {
> +	.gamma_set = vbox_fb_gamma_set,
> +	.gamma_get = vbox_fb_gamma_get,
> +	.fb_probe = vboxfb_create,
> +};
> +
> +static void vbox_fbdev_destroy(struct drm_device *dev, struct vbox_fbdev *fbdev)
> +{
> +	struct fb_info *info;
> +	struct vbox_framebuffer *afb = &fbdev->afb;
> +
> +	if (fbdev->helper.fbdev) {
> +		info = fbdev->helper.fbdev;
> +		unregister_framebuffer(info);
> +		if (info->cmap.len)
> +			fb_dealloc_cmap(&info->cmap);
> +		framebuffer_release(info);
> +	}
> +
> +	if (afb->obj) {
> +		struct vbox_bo *bo = gem_to_vbox_bo(afb->obj);
> +
> +		if (!vbox_bo_reserve(bo, false)) {
> +			if (bo->kmap.virtual)
> +				ttm_bo_kunmap(&bo->kmap);
> +			/*
> +			 * QXL does this, but is it really needed before
> +			 * freeing?
> +			 */
> +			if (bo->pin_count)
> +				vbox_bo_unpin(bo);
> +			vbox_bo_unreserve(bo);
> +		}
> +		drm_gem_object_unreference_unlocked(afb->obj);
> +		afb->obj = NULL;
> +	}
> +	drm_fb_helper_fini(&fbdev->helper);
> +
> +	drm_framebuffer_unregister_private(&afb->base);
> +	drm_framebuffer_cleanup(&afb->base);
> +}
> +
> +int vbox_fbdev_init(struct drm_device *dev)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +	struct vbox_fbdev *fbdev;
> +	int ret;
> +
> +	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
> +	if (!fbdev)
> +		return -ENOMEM;
> +
> +	vbox->fbdev = fbdev;
> +	spin_lock_init(&fbdev->dirty_lock);
> +
> +	drm_fb_helper_prepare(dev, &fbdev->helper, &vbox_fb_helper_funcs);
> +	ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs);
> +	if (ret)
> +		goto free;
> +
> +	ret = drm_fb_helper_single_add_all_connectors(&fbdev->helper);
> +	if (ret)
> +		goto fini;
> +
> +	/* disable all the possible outputs/crtcs before entering KMS mode */
> +	drm_helper_disable_unused_functions(dev);
> +
> +	ret = drm_fb_helper_initial_config(&fbdev->helper, 32);
> +	if (ret)
> +		goto fini;
> +
> +	return 0;
> +
> +fini:
> +	drm_fb_helper_fini(&fbdev->helper);
> +free:
> +	kfree(fbdev);
> +	vbox->fbdev = NULL;
> +
> +	return ret;
> +}
> +
> +void vbox_fbdev_fini(struct drm_device *dev)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +
> +	if (!vbox->fbdev)
> +		return;
> +
> +	vbox_fbdev_destroy(dev, vbox->fbdev);
> +	kfree(vbox->fbdev);
> +	vbox->fbdev = NULL;
> +}
> +
> +void vbox_fbdev_set_suspend(struct drm_device *dev, int state)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +
> +	if (!vbox->fbdev)
> +		return;
> +
> +	fb_set_suspend(vbox->fbdev->helper.fbdev, state);
> +}
> +
> +void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr)
> +{
> +	vbox->fbdev->helper.fbdev->fix.smem_start =
> +	    vbox->fbdev->helper.fbdev->apertures->ranges[0].base + gpu_addr;
> +	vbox->fbdev->helper.fbdev->fix.smem_len =
> +	    vbox->available_vram_size - gpu_addr;
> +}
> diff --git a/drivers/staging/vboxvideo/vbox_hgsmi.c b/drivers/staging/vboxvideo/vbox_hgsmi.c
> new file mode 100644
> index 000000000000..4f9f50c23543
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_hgsmi.c
> @@ -0,0 +1,114 @@
> +/*
> + * Copyright (C) 2017 Oracle Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * Authors: Hans de Goede <hdegoede at redhat.com>
> + */
> +
> +#include <HGSMIBase.h>
> +#include <VBoxVideoVBE.h>
> +
> +/* One-at-a-Time Hash from http://www.burtleburtle.net/bob/hash/doobs.html */
> +static u32 hgsmi_hash_process(u32 hash, const u8 *data, int size)
> +{
> +	while (size--) {
> +		hash += *data++;
> +		hash += (hash << 10);
> +		hash ^= (hash >> 6);
> +	}
> +
> +	return hash;
> +}
> +
> +static u32 hgsmi_hash_end(u32 hash)
> +{
> +	hash += (hash << 3);
> +	hash ^= (hash >> 11);
> +	hash += (hash << 15);
> +
> +	return hash;
> +}
> +
> +/* Not really a checksum but that is the naming used in all vbox code */
> +static u32 hgsmi_checksum(u32 offset,
> +			  const HGSMIBUFFERHEADER *header,
> +			  const HGSMIBUFFERTAIL *tail)
> +{
> +	u32 checksum;
> +
> +	checksum = hgsmi_hash_process(0, (u8 *)&offset, sizeof(offset));
> +	checksum = hgsmi_hash_process(checksum, (u8 *)header, sizeof(*header));
> +	/* 4 -> Do not checksum the checksum itself */
> +	checksum = hgsmi_hash_process(checksum, (u8 *)tail, 4);
> +
> +	return hgsmi_hash_end(checksum);
> +}
> +
> +void *hgsmi_buffer_alloc(struct gen_pool *guest_pool, size_t size,
> +			 u8 channel, u16 channel_info)
> +{
> +	HGSMIBUFFERHEADER *h;
> +	HGSMIBUFFERTAIL *t;
> +	size_t total_size;
> +	dma_addr_t offset;
> +
> +	total_size = size + sizeof(HGSMIBUFFERHEADER) + sizeof(HGSMIBUFFERTAIL);
> +	h = gen_pool_dma_alloc(guest_pool, total_size, &offset);
> +	if (!h)
> +		return NULL;
> +
> +	t = (HGSMIBUFFERTAIL *)((u8 *)h + sizeof(HGSMIBUFFERHEADER) + size);
> +
> +	h->u8Flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
> +	h->u32DataSize = size;
> +	h->u8Channel = channel;
> +	h->u16ChannelInfo = channel_info;
> +	memset(&h->u.au8Union, 0, sizeof(h->u.au8Union));
> +
> +	t->u32Reserved = 0;
> +	t->u32Checksum = hgsmi_checksum(offset, h, t);
> +
> +	return (u8 *)h + sizeof(HGSMIBUFFERHEADER);
> +}
> +
> +void hgsmi_buffer_free(struct gen_pool *guest_pool, void *buf)
> +{
> +	HGSMIBUFFERHEADER *h =
> +		(HGSMIBUFFERHEADER *)((u8 *)buf - sizeof(HGSMIBUFFERHEADER));
> +	size_t total_size = h->u32DataSize + sizeof(HGSMIBUFFERHEADER) +
> +					     sizeof(HGSMIBUFFERTAIL);
> +
> +	gen_pool_free(guest_pool, (unsigned long)h, total_size);
> +}
> +
> +int hgsmi_buffer_submit(struct gen_pool *guest_pool, void *buf)
> +{
> +	phys_addr_t offset;
> +
> +	offset = gen_pool_virt_to_phys(guest_pool, (unsigned long)buf -
> +						   sizeof(HGSMIBUFFERHEADER));
> +	outl(offset, VGA_PORT_HGSMI_GUEST);
> +	/* Make the compiler aware that the host has changed memory. */
> +	mb();
> +
> +	return VINF_SUCCESS;
> +}
> diff --git a/drivers/staging/vboxvideo/vbox_irq.c b/drivers/staging/vboxvideo/vbox_irq.c
> new file mode 100644
> index 000000000000..8b5499b112de
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_irq.c
> @@ -0,0 +1,207 @@
> +/*
> + * Copyright (C) 2016-2017 Oracle Corporation
> + * This file is based on qxl_irq.c
> + * Copyright 2013 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Dave Airlie
> + *          Alon Levy
> + *          Michael Thayer <michael.thayer at oracle.com,
> + *          Hans de Goede <hdegoede at redhat.com>
> + */
> +
> +#include "vbox_drv.h"
> +
> +#include <VBoxVideo.h>
> +
> +#include <drm/drm_crtc_helper.h>
> +
> +static void vbox_clear_irq(void)
> +{
> +	outl((u32)~0, VGA_PORT_HGSMI_HOST);
> +}
> +
> +static u32 vbox_get_flags(struct vbox_private *vbox)
> +{
> +	return readl(vbox->guest_heap + HOST_FLAGS_OFFSET);
> +}
> +
> +void vbox_report_hotplug(struct vbox_private *vbox)
> +{
> +	schedule_work(&vbox->hotplug_work);
> +}
> +
> +irqreturn_t vbox_irq_handler(int irq, void *arg)
> +{
> +	struct drm_device *dev = (struct drm_device *)arg;
> +	struct vbox_private *vbox = (struct vbox_private *)dev->dev_private;
> +	u32 host_flags = vbox_get_flags(vbox);
> +
> +	if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
> +		return IRQ_NONE;
> +
> +	/*
> +	 * Due to a bug in the initial host implementation of hot-plug irqs,
> +	 * the hot-plug and cursor capability flags were never cleared.
> +	 * Fortunately we can tell when they would have been set by checking
> +	 * that the VSYNC flag is not set.
> +	 */
> +	if (host_flags &
> +	    (HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES) &&
> +	    !(host_flags & HGSMIHOSTFLAGS_VSYNC))
> +		vbox_report_hotplug(vbox);
> +
> +	vbox_clear_irq();
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + * Check that the position hints provided by the host are suitable for GNOME
> + * shell (i.e. all screens disjoint and hints for all enabled screens) and if
> + * not replace them with default ones.  Providing valid hints improves the
> + * chances that we will get a known screen layout for pointer mapping.
> + */
> +static void validate_or_set_position_hints(struct vbox_private *vbox)
> +{
> +	int i, j;
> +	u16 currentx = 0;
> +	bool valid = true;
> +
> +	for (i = 0; i < vbox->num_crtcs; ++i) {
> +		for (j = 0; j < i; ++j) {
> +			struct VBVAMODEHINT *hintsi = &vbox->last_mode_hints[i];
> +			struct VBVAMODEHINT *hintsj = &vbox->last_mode_hints[j];
> +
> +			if (hintsi->fEnabled && hintsj->fEnabled) {
> +				if (hintsi->dx >= 0xffff ||
> +				    hintsi->dy >= 0xffff ||
> +				    hintsj->dx >= 0xffff ||
> +				    hintsj->dy >= 0xffff ||
> +				    (hintsi->dx <
> +					hintsj->dx + (hintsj->cx & 0x8fff) &&
> +				     hintsi->dx + (hintsi->cx & 0x8fff) >
> +					hintsj->dx) ||
> +				    (hintsi->dy <
> +					hintsj->dy + (hintsj->cy & 0x8fff) &&
> +				     hintsi->dy + (hintsi->cy & 0x8fff) >
> +					hintsj->dy))
> +					valid = false;
> +			}
> +		}
> +	}
> +	if (!valid)
> +		for (i = 0; i < vbox->num_crtcs; ++i) {
> +			if (vbox->last_mode_hints[i].fEnabled) {
> +				vbox->last_mode_hints[i].dx = currentx;
> +				vbox->last_mode_hints[i].dy = 0;
> +				currentx +=
> +				    vbox->last_mode_hints[i].cx & 0x8fff;
> +			}
> +		}
> +}
> +
> +/**
> + * Query the host for the most recent video mode hints.
> + */
> +static void vbox_update_mode_hints(struct vbox_private *vbox)
> +{
> +	struct drm_device *dev = vbox->dev;
> +	struct drm_connector *connector;
> +	struct vbox_connector *vbox_connector;
> +	struct VBVAMODEHINT *hints;
> +	u16 flags;
> +	bool disconnected;
> +	unsigned int crtc_id;
> +	int rc;
> +
> +	rc = VBoxHGSMIGetModeHints(vbox->guest_pool, vbox->num_crtcs,
> +				   vbox->last_mode_hints);
> +	if (RT_FAILURE(rc)) {
> +		DRM_ERROR("vboxvideo: VBoxHGSMIGetModeHints failed, rc=%i.\n",
> +			  rc);
> +		return;
> +	}
> +	validate_or_set_position_hints(vbox);
> +	drm_modeset_lock_all(dev);
> +	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> +		vbox_connector = to_vbox_connector(connector);
> +		hints =
> +		    &vbox->last_mode_hints[vbox_connector->vbox_crtc->crtc_id];
> +		if (hints->magic == VBVAMODEHINT_MAGIC) {
> +			disconnected = !(hints->fEnabled);
> +			crtc_id = vbox_connector->vbox_crtc->crtc_id;
> +			flags = VBVA_SCREEN_F_ACTIVE
> +			    | (disconnected ? VBVA_SCREEN_F_DISABLED :
> +			       VBVA_SCREEN_F_BLANK);
> +			vbox_connector->mode_hint.width = hints->cx & 0x8fff;
> +			vbox_connector->mode_hint.height = hints->cy & 0x8fff;
> +			vbox_connector->vbox_crtc->x_hint = hints->dx;
> +			vbox_connector->vbox_crtc->y_hint = hints->dy;
> +			vbox_connector->mode_hint.disconnected = disconnected;
> +			if (vbox_connector->vbox_crtc->disconnected !=
> +			    disconnected) {
> +				VBoxHGSMIProcessDisplayInfo(vbox->guest_pool,
> +							    crtc_id, 0, 0, 0,
> +							    hints->cx * 4,
> +							    hints->cx,
> +							    hints->cy, 0,
> +							    flags);
> +				vbox_connector->vbox_crtc->disconnected =
> +				    disconnected;
> +			}
> +		}
> +	}
> +	drm_modeset_unlock_all(dev);
> +}
> +
> +static void vbox_hotplug_worker(struct work_struct *work)
> +{
> +	struct vbox_private *vbox = container_of(work, struct vbox_private,
> +						 hotplug_work);
> +
> +	vbox_update_mode_hints(vbox);
> +	drm_kms_helper_hotplug_event(vbox->dev);
> +}
> +
> +int vbox_irq_init(struct vbox_private *vbox)
> +{
> +	int ret;
> +
> +	vbox_update_mode_hints(vbox);
> +	ret = drm_irq_install(vbox->dev, vbox->dev->pdev->irq);
> +	if (unlikely(ret != 0)) {
> +		vbox_irq_fini(vbox);
> +		DRM_ERROR("Failed installing irq: %d\n", ret);
> +		return 1;
> +	}
> +	INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
> +	vbox->isr_installed = true;
> +	return 0;
> +}
> +
> +void vbox_irq_fini(struct vbox_private *vbox)
> +{
> +	if (vbox->isr_installed) {
> +		drm_irq_uninstall(vbox->dev);
> +		flush_work(&vbox->hotplug_work);
> +		vbox->isr_installed = false;
> +	}
> +}
> diff --git a/drivers/staging/vboxvideo/vbox_main.c b/drivers/staging/vboxvideo/vbox_main.c
> new file mode 100644
> index 000000000000..7b686e62fb37
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_main.c
> @@ -0,0 +1,512 @@
> +/*
> + * Copyright (C) 2013-2017 Oracle Corporation
> + * This file is based on ast_main.c
> + * Copyright 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * Authors: Dave Airlie <airlied at redhat.com>,
> + *          Michael Thayer <michael.thayer at oracle.com,
> + *          Hans de Goede <hdegoede at redhat.com>
> + */
> +#include "vbox_drv.h"
> +
> +#include <VBoxVideoGuest.h>
> +#include <VBoxVideoVBE.h>
> +
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
> +{
> +	struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
> +
> +	if (vbox_fb->obj)
> +		drm_gem_object_unreference_unlocked(vbox_fb->obj);
> +
> +	drm_framebuffer_cleanup(fb);
> +	kfree(fb);
> +}
> +
> +void vbox_enable_accel(struct vbox_private *vbox)
> +{
> +	unsigned int i;
> +	struct VBVABUFFER *vbva;
> +
> +	if (!vbox->vbva_info || !vbox->vbva_buffers) {
> +		/* Should never happen... */
> +		DRM_ERROR("vboxvideo: failed to set up VBVA.\n");
> +		return;
> +	}
> +
> +	for (i = 0; i < vbox->num_crtcs; ++i) {
> +		if (!vbox->vbva_info[i].pVBVA) {
> +			vbva = (struct VBVABUFFER *)
> +				((u8 *)vbox->vbva_buffers +
> +						     i * VBVA_MIN_BUFFER_SIZE);
> +			if (!VBoxVBVAEnable(&vbox->vbva_info[i],
> +					    vbox->guest_pool, vbva, i)) {
> +				/* very old host or driver error. */
> +				DRM_ERROR("vboxvideo: VBoxVBVAEnable failed - heap allocation error.\n");
> +				return;
> +			}
> +		}
> +	}
> +}
> +
> +void vbox_disable_accel(struct vbox_private *vbox)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < vbox->num_crtcs; ++i)
> +		VBoxVBVADisable(&vbox->vbva_info[i], vbox->guest_pool, i);
> +}
> +
> +void vbox_report_caps(struct vbox_private *vbox)
> +{
> +	u32 caps = VBVACAPS_DISABLE_CURSOR_INTEGRATION
> +	    | VBVACAPS_IRQ | VBVACAPS_USE_VBVA_ONLY;
> +	if (vbox->initial_mode_queried)
> +		caps |= VBVACAPS_VIDEO_MODE_HINTS;
> +	VBoxHGSMISendCapsInfo(vbox->guest_pool, caps);
> +}
> +
> +/**
> + * Send information about dirty rectangles to VBVA.  If necessary we enable
> + * VBVA first, as this is normally disabled after a change of master in case
> + * the new master does not send dirty rectangle information (is this even
> + * allowed?)
> + */
> +void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
> +				       struct drm_clip_rect *rects,
> +				       unsigned int num_rects)
> +{
> +	struct vbox_private *vbox = fb->dev->dev_private;
> +	struct drm_crtc *crtc;
> +	unsigned int i;
> +
> +	mutex_lock(&vbox->hw_mutex);
> +	list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) {
> +		if (CRTC_FB(crtc) == fb) {
> +			vbox_enable_accel(vbox);
> +			for (i = 0; i < num_rects; ++i) {
> +				VBVACMDHDR cmd_hdr;
> +				unsigned int crtc_id =
> +				    to_vbox_crtc(crtc)->crtc_id;
> +
> +				if ((rects[i].x1 >
> +					 crtc->x + crtc->hwmode.hdisplay) ||
> +				    (rects[i].y1 >
> +					 crtc->y + crtc->hwmode.vdisplay) ||
> +				    (rects[i].x2 < crtc->x) ||
> +				    (rects[i].y2 < crtc->y))
> +					continue;
> +
> +				cmd_hdr.x = (s16)rects[i].x1;
> +				cmd_hdr.y = (s16)rects[i].y1;
> +				cmd_hdr.w = (u16)rects[i].x2 - rects[i].x1;
> +				cmd_hdr.h = (u16)rects[i].y2 - rects[i].y1;
> +
> +				if (VBoxVBVABufferBeginUpdate(
> +						&vbox->vbva_info[crtc_id],
> +						vbox->guest_pool)) {
> +					VBoxVBVAWrite(&vbox->vbva_info[crtc_id],
> +						      vbox->guest_pool,
> +						      &cmd_hdr,
> +						      sizeof(cmd_hdr));
> +					VBoxVBVABufferEndUpdate(
> +						&vbox->vbva_info[crtc_id]);
> +				}
> +			}
> +		}
> +	}
> +	mutex_unlock(&vbox->hw_mutex);
> +}
> +
> +static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb,
> +				       struct drm_file *file_priv,
> +				       unsigned int flags, unsigned int color,
> +				       struct drm_clip_rect *rects,
> +				       unsigned int num_rects)
> +{
> +	vbox_framebuffer_dirty_rectangles(fb, rects, num_rects);
> +
> +	return 0;
> +}
> +
> +static const struct drm_framebuffer_funcs vbox_fb_funcs = {
> +	.destroy = vbox_user_framebuffer_destroy,
> +	.dirty = vbox_user_framebuffer_dirty,
> +};
> +
> +int vbox_framebuffer_init(struct drm_device *dev,
> +			  struct vbox_framebuffer *vbox_fb,
> +			  const struct DRM_MODE_FB_CMD *mode_cmd,
> +			  struct drm_gem_object *obj)
> +{
> +	int ret;
> +
> +	drm_helper_mode_fill_fb_struct(dev, &vbox_fb->base, mode_cmd);
> +	vbox_fb->obj = obj;
> +	ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
> +	if (ret) {
> +		DRM_ERROR("framebuffer init failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct drm_framebuffer *vbox_user_framebuffer_create(
> +		struct drm_device *dev,
> +		struct drm_file *filp,
> +		const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	struct drm_gem_object *obj;
> +	struct vbox_framebuffer *vbox_fb;
> +	int ret;
> +
> +	obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
> +	if (!obj)
> +		return ERR_PTR(-ENOENT);
> +
> +	vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
> +	if (!vbox_fb) {
> +		drm_gem_object_unreference_unlocked(obj);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	ret = vbox_framebuffer_init(dev, vbox_fb, mode_cmd, obj);
> +	if (ret) {
> +		drm_gem_object_unreference_unlocked(obj);
> +		kfree(vbox_fb);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return &vbox_fb->base;
> +}
> +
> +static const struct drm_mode_config_funcs vbox_mode_funcs = {
> +	.fb_create = vbox_user_framebuffer_create,
> +};
> +
> +static void vbox_accel_fini(struct vbox_private *vbox)
> +{
> +	if (vbox->vbva_info) {
> +		vbox_disable_accel(vbox);
> +		kfree(vbox->vbva_info);
> +		vbox->vbva_info = NULL;
> +	}
> +	if (vbox->vbva_buffers) {
> +		pci_iounmap(vbox->dev->pdev, vbox->vbva_buffers);
> +		vbox->vbva_buffers = NULL;
> +	}
> +}
> +
> +static int vbox_accel_init(struct vbox_private *vbox)
> +{
> +	unsigned int i;
> +
> +	vbox->vbva_info = kcalloc(vbox->num_crtcs, sizeof(*vbox->vbva_info),
> +				  GFP_KERNEL);
> +	if (!vbox->vbva_info)
> +		return -ENOMEM;
> +
> +	/* Take a command buffer for each screen from the end of usable VRAM. */
> +	vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
> +
> +	vbox->vbva_buffers = pci_iomap_range(vbox->dev->pdev, 0,
> +					     vbox->available_vram_size,
> +					     vbox->num_crtcs *
> +					     VBVA_MIN_BUFFER_SIZE);
> +	if (!vbox->vbva_buffers)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < vbox->num_crtcs; ++i)
> +		VBoxVBVASetupBufferContext(&vbox->vbva_info[i],
> +					   vbox->available_vram_size +
> +					   i * VBVA_MIN_BUFFER_SIZE,
> +					   VBVA_MIN_BUFFER_SIZE);
> +
> +	return 0;
> +}
> +
> +/** Do we support the 4.3 plus mode hint reporting interface? */
> +static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
> +{
> +	u32 have_hints, have_cursor;
> +	int ret;
> +
> +	ret = VBoxQueryConfHGSMI(vbox->guest_pool,
> +				 VBOX_VBVA_CONF32_MODE_HINT_REPORTING,
> +				 &have_hints);
> +	if (RT_FAILURE(ret))
> +		return false;
> +
> +	ret = VBoxQueryConfHGSMI(vbox->guest_pool,
> +				 VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING,
> +				 &have_cursor);
> +	if (RT_FAILURE(ret))
> +		return false;
> +
> +	return have_hints == VINF_SUCCESS && have_cursor == VINF_SUCCESS;
> +}
> +
> +/**
> + * Set up our heaps and data exchange buffers in VRAM before handing the rest
> + * to the memory manager.
> + */
> +static int vbox_hw_init(struct vbox_private *vbox)
> +{
> +	int ret;
> +
> +	vbox->full_vram_size = VBoxVideoGetVRAMSize();
> +	vbox->any_pitch = VBoxVideoAnyWidthAllowed();
> +
> +	DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
> +
> +	/* Map guest-heap at end of vram */
> +	vbox->guest_heap =
> +	    pci_iomap_range(vbox->dev->pdev, 0, GUEST_HEAP_OFFSET(vbox),
> +			    GUEST_HEAP_SIZE);
> +	if (!vbox->guest_heap)
> +		return -ENOMEM;
> +
> +	/* Create guest-heap mem-pool use 2^4 = 16 byte chunks */
> +	vbox->guest_pool = gen_pool_create(4, -1);
> +	if (!vbox->guest_pool)
> +		return -ENOMEM;
> +
> +	ret = gen_pool_add_virt(vbox->guest_pool,
> +				(unsigned long)vbox->guest_heap,
> +				GUEST_HEAP_OFFSET(vbox),
> +				GUEST_HEAP_USABLE_SIZE, -1);
> +	if (ret)
> +		return ret;
> +
> +	/* Reduce available VRAM size to reflect the guest heap. */
> +	vbox->available_vram_size = GUEST_HEAP_OFFSET(vbox);
> +	/* Linux drm represents monitors as a 32-bit array. */
> +	vbox->num_crtcs = min_t(u32, VBoxHGSMIGetMonitorCount(vbox->guest_pool),
> +				VBOX_MAX_SCREENS);
> +
> +	if (!have_hgsmi_mode_hints(vbox))
> +		return -ENOTSUPP;
> +
> +	vbox->last_mode_hints =
> +	    kcalloc(vbox->num_crtcs, sizeof(VBVAMODEHINT), GFP_KERNEL);
> +	if (!vbox->last_mode_hints)
> +		return -ENOMEM;
> +
> +	return vbox_accel_init(vbox);
> +}
> +
> +static void vbox_hw_fini(struct vbox_private *vbox)
> +{
> +	vbox_accel_fini(vbox);
> +	kfree(vbox->last_mode_hints);
> +	vbox->last_mode_hints = NULL;
> +}
> +
> +int vbox_driver_load(struct drm_device *dev, unsigned long flags)
> +{
> +	struct vbox_private *vbox;
> +	int ret = 0;
> +
> +	if (!VBoxHGSMIIsSupported())
> +		return -ENODEV;
> +
> +	vbox = kzalloc(sizeof(*vbox), GFP_KERNEL);
> +	if (!vbox)
> +		return -ENOMEM;
> +
> +	dev->dev_private = vbox;
> +	vbox->dev = dev;
> +
> +	mutex_init(&vbox->hw_mutex);
> +
> +	ret = vbox_hw_init(vbox);
> +	if (ret)
> +		goto out_free;
> +
> +	ret = vbox_mm_init(vbox);
> +	if (ret)
> +		goto out_free;
> +
> +	drm_mode_config_init(dev);
> +
> +	dev->mode_config.funcs = (void *)&vbox_mode_funcs;
> +	dev->mode_config.min_width = 64;
> +	dev->mode_config.min_height = 64;
> +	dev->mode_config.preferred_depth = 24;
> +	dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
> +	dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
> +
> +	ret = vbox_mode_init(dev);
> +	if (ret)
> +		goto out_free;
> +
> +	ret = vbox_irq_init(vbox);
> +	if (ret)
> +		goto out_free;
> +
> +	ret = vbox_fbdev_init(dev);
> +	if (ret)
> +		goto out_free;
> +
> +	return 0;
> +
> +out_free:
> +	vbox_driver_unload(dev);
> +	return ret;
> +}
> +
> +void vbox_driver_unload(struct drm_device *dev)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +
> +	vbox_fbdev_fini(dev);
> +	vbox_irq_fini(vbox);
> +	vbox_mode_fini(dev);
> +	if (dev->mode_config.funcs)
> +		drm_mode_config_cleanup(dev);
> +
> +	vbox_hw_fini(vbox);
> +	vbox_mm_fini(vbox);
> +	if (vbox->guest_pool)
> +		gen_pool_destroy(vbox->guest_pool);
> +	if (vbox->guest_heap)
> +		pci_iounmap(dev->pdev, vbox->guest_heap);
> +	kfree(vbox);
> +	dev->dev_private = NULL;
> +}
> +
> +/**
> + * @note this is described in the DRM framework documentation.  AST does not
> + * have it, but we get an oops on driver unload if it is not present.
> + */
> +void vbox_driver_lastclose(struct drm_device *dev)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +
> +	if (vbox->fbdev)
> +		drm_fb_helper_restore_fbdev_mode_unlocked(&vbox->fbdev->helper);
> +}
> +
> +int vbox_gem_create(struct drm_device *dev,
> +		    u32 size, bool iskernel, struct drm_gem_object **obj)
> +{
> +	struct vbox_bo *vboxbo;
> +	int ret;
> +
> +	*obj = NULL;
> +
> +	size = roundup(size, PAGE_SIZE);
> +	if (size == 0)
> +		return -EINVAL;
> +
> +	ret = vbox_bo_create(dev, size, 0, 0, &vboxbo);
> +	if (ret) {
> +		if (ret != -ERESTARTSYS)
> +			DRM_ERROR("failed to allocate GEM object\n");
> +		return ret;
> +	}
> +
> +	*obj = &vboxbo->gem;
> +
> +	return 0;
> +}
> +
> +int vbox_dumb_create(struct drm_file *file,
> +		     struct drm_device *dev, struct drm_mode_create_dumb *args)
> +{
> +	int ret;
> +	struct drm_gem_object *gobj;
> +	u32 handle;
> +
> +	args->pitch = args->width * ((args->bpp + 7) / 8);
> +	args->size = args->pitch * args->height;
> +
> +	ret = vbox_gem_create(dev, args->size, false, &gobj);
> +	if (ret)
> +		return ret;
> +
> +	ret = drm_gem_handle_create(file, gobj, &handle);
> +	drm_gem_object_unreference_unlocked(gobj);
> +	if (ret)
> +		return ret;
> +
> +	args->handle = handle;
> +
> +	return 0;
> +}
> +
> +static void vbox_bo_unref(struct vbox_bo **bo)
> +{
> +	struct ttm_buffer_object *tbo;
> +
> +	if ((*bo) == NULL)
> +		return;
> +
> +	tbo = &((*bo)->bo);
> +	ttm_bo_unref(&tbo);
> +	if (!tbo)
> +		*bo = NULL;
> +}
> +
> +void vbox_gem_free_object(struct drm_gem_object *obj)
> +{
> +	struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
> +
> +	vbox_bo_unref(&vbox_bo);
> +}
> +
> +static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
> +{
> +	return drm_vma_node_offset_addr(&bo->bo.vma_node);
> +}
> +
> +int
> +vbox_dumb_mmap_offset(struct drm_file *file,
> +		      struct drm_device *dev,
> +		      u32 handle, u64 *offset)
> +{
> +	struct drm_gem_object *obj;
> +	int ret;
> +	struct vbox_bo *bo;
> +
> +	mutex_lock(&dev->struct_mutex);
> +	obj = drm_gem_object_lookup(file, handle);
> +	if (!obj) {
> +		ret = -ENOENT;
> +		goto out_unlock;
> +	}
> +
> +	bo = gem_to_vbox_bo(obj);
> +	*offset = vbox_bo_mmap_offset(bo);
> +
> +	drm_gem_object_unreference(obj);
> +	ret = 0;
> +
> +out_unlock:
> +	mutex_unlock(&dev->struct_mutex);
> +	return ret;
> +}
> diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c
> new file mode 100644
> index 000000000000..d4b990cbac63
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_mode.c
> @@ -0,0 +1,864 @@
> +/*
> + * Copyright (C) 2013-2017 Oracle Corporation
> + * This file is based on ast_mode.c
> + * Copyright 2012 Red Hat Inc.
> + * Parts based on xf86-video-ast
> + * Copyright (c) 2005 ASPEED Technology Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + */
> +/*
> + * Authors: Dave Airlie <airlied at redhat.com>
> + *          Michael Thayer <michael.thayer at oracle.com,
> + *          Hans de Goede <hdegoede at redhat.com>
> + */
> +#include "vbox_drv.h"
> +
> +#include <VBoxVideo.h>
> +
> +#include <linux/export.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
> +			    u32 handle, u32 width, u32 height,
> +			    s32 hot_x, s32 hot_y);
> +static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y);
> +
> +/**
> + * Set a graphics mode.  Poke any required values into registers, do an HGSMI
> + * mode set and tell the host we support advanced graphics functions.
> + */
> +static void vbox_do_modeset(struct drm_crtc *crtc,
> +			    const struct drm_display_mode *mode)
> +{
> +	struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
> +	struct vbox_private *vbox;
> +	int width, height, bpp, pitch;
> +	unsigned int crtc_id;
> +	u16 flags;
> +	s32 x_offset, y_offset;
> +
> +	vbox = crtc->dev->dev_private;
> +	width = mode->hdisplay ? mode->hdisplay : 640;
> +	height = mode->vdisplay ? mode->vdisplay : 480;
> +	crtc_id = vbox_crtc->crtc_id;
> +	bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32;
> +	pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
> +	x_offset = vbox->single_framebuffer ? crtc->x : vbox_crtc->x_hint;
> +	y_offset = vbox->single_framebuffer ? crtc->y : vbox_crtc->y_hint;
> +
> +	/*
> +	 * This is the old way of setting graphics modes.  It assumed one screen
> +	 * and a frame-buffer at the start of video RAM.  On older versions of
> +	 * VirtualBox, certain parts of the code still assume that the first
> +	 * screen is programmed this way, so try to fake it.
> +	 */
> +	if (vbox_crtc->crtc_id == 0 && crtc->enabled &&
> +	    vbox_crtc->fb_offset / pitch < 0xffff - crtc->y &&
> +	    vbox_crtc->fb_offset % (bpp / 8) == 0)
> +		VBoxVideoSetModeRegisters(
> +			width, height, pitch * 8 / bpp,
> +			CRTC_FB(crtc)->format->cpp[0] * 8,
> +			0,
> +			vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x,
> +			vbox_crtc->fb_offset / pitch + crtc->y);
> +
> +	flags = VBVA_SCREEN_F_ACTIVE;
> +	flags |= (crtc->enabled && !vbox_crtc->blanked) ?
> +		 0 : VBVA_SCREEN_F_BLANK;
> +	flags |= vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0;
> +	VBoxHGSMIProcessDisplayInfo(vbox->guest_pool, vbox_crtc->crtc_id,
> +				    x_offset, y_offset,
> +				    crtc->x * bpp / 8 + crtc->y * pitch,
> +				    pitch, width, height,
> +				    vbox_crtc->blanked ? 0 : bpp, flags);
> +}
> +
> +static int vbox_set_view(struct drm_crtc *crtc)
> +{
> +	struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
> +	struct vbox_private *vbox = crtc->dev->dev_private;
> +	void *p;
> +
> +	/*
> +	 * Tell the host about the view.  This design originally targeted the
> +	 * Windows XP driver architecture and assumed that each screen would
> +	 * have a dedicated frame buffer with the command buffer following it,
> +	 * the whole being a "view".  The host works out which screen a command
> +	 * buffer belongs to by checking whether it is in the first view, then
> +	 * whether it is in the second and so on.  The first match wins.  We
> +	 * cheat around this by making the first view be the managed memory
> +	 * plus the first command buffer, the second the same plus the second
> +	 * buffer and so on.
> +	 */
> +	p = VBoxHGSMIBufferAlloc(vbox->guest_pool, sizeof(VBVAINFOVIEW),
> +				 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
> +	if (p) {
> +		VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *) p;
> +
> +		pInfo->u32ViewIndex = vbox_crtc->crtc_id;
> +		pInfo->u32ViewOffset = vbox_crtc->fb_offset;
> +		pInfo->u32ViewSize =
> +		    vbox->available_vram_size - vbox_crtc->fb_offset +
> +		    vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
> +		pInfo->u32MaxScreenSize =
> +		    vbox->available_vram_size - vbox_crtc->fb_offset;
> +		VBoxHGSMIBufferSubmit(vbox->guest_pool, p);
> +		VBoxHGSMIBufferFree(vbox->guest_pool, p);
> +	} else {
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +static void vbox_crtc_load_lut(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
> +{
> +	struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
> +	struct vbox_private *vbox = crtc->dev->dev_private;
> +
> +	switch (mode) {
> +	case DRM_MODE_DPMS_ON:
> +		vbox_crtc->blanked = false;
> +		break;
> +	case DRM_MODE_DPMS_STANDBY:
> +	case DRM_MODE_DPMS_SUSPEND:
> +	case DRM_MODE_DPMS_OFF:
> +		vbox_crtc->blanked = true;
> +		break;
> +	}
> +
> +	mutex_lock(&vbox->hw_mutex);
> +	vbox_do_modeset(crtc, &crtc->hwmode);
> +	mutex_unlock(&vbox->hw_mutex);
> +}
> +
> +static bool vbox_crtc_mode_fixup(struct drm_crtc *crtc,
> +				 const struct drm_display_mode *mode,
> +				 struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +/*
> + * Try to map the layout of virtual screens to the range of the input device.
> + * Return true if we need to re-set the crtc modes due to screen offset
> + * changes.
> + */
> +static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
> +{
> +	struct drm_crtc *crtci;
> +	struct drm_connector *connectori;
> +	struct drm_framebuffer *fb1 = NULL;
> +	bool single_framebuffer = true;
> +	bool old_single_framebuffer = vbox->single_framebuffer;
> +	u16 width = 0, height = 0;
> +
> +	/*
> +	 * Are we using an X.Org-style single large frame-buffer for all crtcs?
> +	 * If so then screen layout can be deduced from the crtc offsets.
> +	 * Same fall-back if this is the fbdev frame-buffer.
> +	 */
> +	list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list, head) {
> +		if (!fb1) {
> +			fb1 = CRTC_FB(crtci);
> +			if (to_vbox_framebuffer(fb1) == &vbox->fbdev->afb)
> +				break;
> +		} else if (CRTC_FB(crtci) && fb1 != CRTC_FB(crtci)) {
> +			single_framebuffer = false;
> +		}
> +	}
> +	if (single_framebuffer) {
> +		list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
> +				    head) {
> +			if (to_vbox_crtc(crtci)->crtc_id == 0) {
> +				vbox->single_framebuffer = true;
> +				vbox->input_mapping_width =
> +				    CRTC_FB(crtci)->width;
> +				vbox->input_mapping_height =
> +				    CRTC_FB(crtci)->height;
> +				return old_single_framebuffer !=
> +				    vbox->single_framebuffer;
> +			}
> +		}
> +	}
> +	/* Otherwise calculate the total span of all screens. */
> +	list_for_each_entry(connectori, &vbox->dev->mode_config.connector_list,
> +			    head) {
> +		struct vbox_connector *vbox_connector =
> +		    to_vbox_connector(connectori);
> +		struct vbox_crtc *vbox_crtc = vbox_connector->vbox_crtc;
> +
> +		width = max_t(u16, width, vbox_crtc->x_hint +
> +					  vbox_connector->mode_hint.width);
> +		height = max_t(u16, height, vbox_crtc->y_hint +
> +					    vbox_connector->mode_hint.height);
> +	}
> +
> +	vbox->single_framebuffer = false;
> +	vbox->input_mapping_width = width;
> +	vbox->input_mapping_height = height;
> +
> +	return old_single_framebuffer != vbox->single_framebuffer;
> +}
> +
> +static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
> +				 struct drm_framebuffer *old_fb, int x, int y)
> +{
> +	struct vbox_private *vbox = crtc->dev->dev_private;
> +	struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
> +	struct drm_gem_object *obj;
> +	struct vbox_framebuffer *vbox_fb;
> +	struct vbox_bo *bo;
> +	int ret;
> +	u64 gpu_addr;
> +
> +	/* Unpin the previous fb. */
> +	if (old_fb) {
> +		vbox_fb = to_vbox_framebuffer(old_fb);
> +		obj = vbox_fb->obj;
> +		bo = gem_to_vbox_bo(obj);
> +		ret = vbox_bo_reserve(bo, false);
> +		if (ret)
> +			return ret;
> +
> +		vbox_bo_unpin(bo);
> +		vbox_bo_unreserve(bo);
> +	}
> +
> +	vbox_fb = to_vbox_framebuffer(CRTC_FB(crtc));
> +	obj = vbox_fb->obj;
> +	bo = gem_to_vbox_bo(obj);
> +
> +	ret = vbox_bo_reserve(bo, false);
> +	if (ret)
> +		return ret;
> +
> +	ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
> +	if (ret) {
> +		vbox_bo_unreserve(bo);
> +		return ret;
> +	}
> +
> +	if (&vbox->fbdev->afb == vbox_fb)
> +		vbox_fbdev_set_base(vbox, gpu_addr);
> +	vbox_bo_unreserve(bo);
> +
> +	/* vbox_set_start_address_crt1(crtc, (u32)gpu_addr); */
> +	vbox_crtc->fb_offset = gpu_addr;
> +	if (vbox_set_up_input_mapping(vbox)) {
> +		struct drm_crtc *crtci;
> +
> +		list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
> +				    head) {
> +			vbox_set_view(crtc);
> +			vbox_do_modeset(crtci, &crtci->mode);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> +				   struct drm_framebuffer *old_fb)
> +{
> +	return vbox_crtc_do_set_base(crtc, old_fb, x, y);
> +}
> +
> +static int vbox_crtc_mode_set(struct drm_crtc *crtc,
> +			      struct drm_display_mode *mode,
> +			      struct drm_display_mode *adjusted_mode,
> +			      int x, int y, struct drm_framebuffer *old_fb)
> +{
> +	struct vbox_private *vbox = crtc->dev->dev_private;
> +	int rc = 0;
> +
> +	vbox_crtc_mode_set_base(crtc, x, y, old_fb);
> +
> +	mutex_lock(&vbox->hw_mutex);
> +	rc = vbox_set_view(crtc);
> +	if (!rc)
> +		vbox_do_modeset(crtc, mode);
> +	VBoxHGSMIUpdateInputMapping(vbox->guest_pool, 0, 0,
> +				    vbox->input_mapping_width,
> +				    vbox->input_mapping_height);
> +	mutex_unlock(&vbox->hw_mutex);
> +
> +	return rc;
> +}
> +
> +static void vbox_crtc_disable(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void vbox_crtc_prepare(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void vbox_crtc_commit(struct drm_crtc *crtc)
> +{
> +}
> +
> +static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
> +	.dpms = vbox_crtc_dpms,
> +	.mode_fixup = vbox_crtc_mode_fixup,
> +	.mode_set = vbox_crtc_mode_set,
> +	/* .mode_set_base = vbox_crtc_mode_set_base, */
> +	.disable = vbox_crtc_disable,
> +	.load_lut = vbox_crtc_load_lut,
> +	.prepare = vbox_crtc_prepare,
> +	.commit = vbox_crtc_commit,
> +};
> +
> +static void vbox_crtc_reset(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void vbox_crtc_destroy(struct drm_crtc *crtc)
> +{
> +	drm_crtc_cleanup(crtc);
> +	kfree(crtc);
> +}
> +
> +static const struct drm_crtc_funcs vbox_crtc_funcs = {
> +	.cursor_move = vbox_cursor_move,
> +	.cursor_set2 = vbox_cursor_set2,
> +	.reset = vbox_crtc_reset,
> +	.set_config = drm_crtc_helper_set_config,
> +	/* .gamma_set = vbox_crtc_gamma_set, */
> +	.destroy = vbox_crtc_destroy,
> +};
> +
> +static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned int i)
> +{
> +	struct vbox_crtc *vbox_crtc;
> +
> +	vbox_crtc = kzalloc(sizeof(*vbox_crtc), GFP_KERNEL);
> +	if (!vbox_crtc)
> +		return NULL;
> +
> +	vbox_crtc->crtc_id = i;
> +
> +	drm_crtc_init(dev, &vbox_crtc->base, &vbox_crtc_funcs);
> +	drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
> +	drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
> +
> +	return vbox_crtc;
> +}
> +
> +static void vbox_encoder_destroy(struct drm_encoder *encoder)
> +{
> +	drm_encoder_cleanup(encoder);
> +	kfree(encoder);
> +}
> +
> +static struct drm_encoder *vbox_best_single_encoder(struct drm_connector
> +						    *connector)
> +{
> +	int enc_id = connector->encoder_ids[0];
> +
> +	/* pick the encoder ids */
> +	if (enc_id)
> +		return drm_encoder_find(connector->dev, enc_id);
> +
> +	return NULL;
> +}
> +
> +static const struct drm_encoder_funcs vbox_enc_funcs = {
> +	.destroy = vbox_encoder_destroy,
> +};
> +
> +static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
> +{
> +}
> +
> +static bool vbox_mode_fixup(struct drm_encoder *encoder,
> +			    const struct drm_display_mode *mode,
> +			    struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +static void vbox_encoder_mode_set(struct drm_encoder *encoder,
> +				  struct drm_display_mode *mode,
> +				  struct drm_display_mode *adjusted_mode)
> +{
> +}
> +
> +static void vbox_encoder_prepare(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void vbox_encoder_commit(struct drm_encoder *encoder)
> +{
> +}
> +
> +static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs = {
> +	.dpms = vbox_encoder_dpms,
> +	.mode_fixup = vbox_mode_fixup,
> +	.prepare = vbox_encoder_prepare,
> +	.commit = vbox_encoder_commit,
> +	.mode_set = vbox_encoder_mode_set,
> +};
> +
> +static struct drm_encoder *vbox_encoder_init(struct drm_device *dev,
> +					     unsigned int i)
> +{
> +	struct vbox_encoder *vbox_encoder;
> +
> +	vbox_encoder = kzalloc(sizeof(*vbox_encoder), GFP_KERNEL);
> +	if (!vbox_encoder)
> +		return NULL;
> +
> +	drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
> +			 DRM_MODE_ENCODER_DAC, NULL);
> +	drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
> +
> +	vbox_encoder->base.possible_crtcs = 1 << i;
> +	return &vbox_encoder->base;
> +}
> +
> +/**
> + * Generate EDID data with a mode-unique serial number for the virtual
> + *  monitor to try to persuade Unity that different modes correspond to
> + *  different monitors and it should not try to force the same resolution on
> + *  them.
> + */
> +static void vbox_set_edid(struct drm_connector *connector, int width,
> +			  int height)
> +{
> +	enum { EDID_SIZE = 128 };
> +	unsigned char edid[EDID_SIZE] = {
> +		0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,	/* header */
> +		0x58, 0x58,	/* manufacturer (VBX) */
> +		0x00, 0x00,	/* product code */
> +		0x00, 0x00, 0x00, 0x00,	/* serial number goes here */
> +		0x01,		/* week of manufacture */
> +		0x00,		/* year of manufacture */
> +		0x01, 0x03,	/* EDID version */
> +		0x80,		/* capabilities - digital */
> +		0x00,		/* horiz. res in cm, zero for projectors */
> +		0x00,		/* vert. res in cm */
> +		0x78,		/* display gamma (120 == 2.2). */
> +		0xEE,		/* features (standby, suspend, off, RGB, std */
> +				/* colour space, preferred timing mode) */
> +		0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
> +		/* chromaticity for standard colour space. */
> +		0x00, 0x00, 0x00,	/* no default timings */
> +		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
> +		    0x01, 0x01,
> +		0x01, 0x01, 0x01, 0x01,	/* no standard timings */
> +		0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02,
> +		    0x02, 0x02,
> +		/* descriptor block 1 goes below */
> +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +		/* descriptor block 2, monitor ranges */
> +		0x00, 0x00, 0x00, 0xFD, 0x00,
> +		0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20,
> +		    0x20, 0x20,
> +		/* 0-200Hz vertical, 0-200KHz horizontal, 1000MHz pixel clock */
> +		0x20,
> +		/* descriptor block 3, monitor name */
> +		0x00, 0x00, 0x00, 0xFC, 0x00,
> +		'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r',
> +		'\n',
> +		/* descriptor block 4: dummy data */
> +		0x00, 0x00, 0x00, 0x10, 0x00,
> +		0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
> +		0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
> +		0x20,
> +		0x00,		/* number of extensions */
> +		0x00		/* checksum goes here */
> +	};
> +	int clock = (width + 6) * (height + 6) * 60 / 10000;
> +	unsigned int i, sum = 0;
> +
> +	edid[12] = width & 0xff;
> +	edid[13] = width >> 8;
> +	edid[14] = height & 0xff;
> +	edid[15] = height >> 8;
> +	edid[54] = clock & 0xff;
> +	edid[55] = clock >> 8;
> +	edid[56] = width & 0xff;
> +	edid[58] = (width >> 4) & 0xf0;
> +	edid[59] = height & 0xff;
> +	edid[61] = (height >> 4) & 0xf0;
> +	for (i = 0; i < EDID_SIZE - 1; ++i)
> +		sum += edid[i];
> +	edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF;
> +	drm_mode_connector_update_edid_property(connector, (struct edid *)edid);
> +}
> +
> +static int vbox_get_modes(struct drm_connector *connector)
> +{
> +	struct vbox_connector *vbox_connector = NULL;
> +	struct drm_display_mode *mode = NULL;
> +	struct vbox_private *vbox = NULL;
> +	unsigned int num_modes = 0;
> +	int preferred_width, preferred_height;
> +
> +	vbox_connector = to_vbox_connector(connector);
> +	vbox = connector->dev->dev_private;
> +	/*
> +	 * Heuristic: we do not want to tell the host that we support dynamic
> +	 * resizing unless we feel confident that the user space client using
> +	 * the video driver can handle hot-plug events.  So the first time modes
> +	 * are queried after a "master" switch we tell the host that we do not,
> +	 * and immediately after we send the client a hot-plug notification as
> +	 * a test to see if they will respond and query again.
> +	 * That is also the reason why capabilities are reported to the host at
> +	 * this place in the code rather than elsewhere.
> +	 * We need to report the flags location before reporting the IRQ
> +	 * capability.
> +	 */
> +	VBoxHGSMIReportFlagsLocation(vbox->guest_pool, GUEST_HEAP_OFFSET(vbox) +
> +				     HOST_FLAGS_OFFSET);
> +	if (vbox_connector->vbox_crtc->crtc_id == 0)
> +		vbox_report_caps(vbox);
> +	if (!vbox->initial_mode_queried) {
> +		if (vbox_connector->vbox_crtc->crtc_id == 0) {
> +			vbox->initial_mode_queried = true;
> +			vbox_report_hotplug(vbox);
> +		}
> +		return drm_add_modes_noedid(connector, 800, 600);
> +	}
> +	num_modes = drm_add_modes_noedid(connector, 2560, 1600);
> +	preferred_width = vbox_connector->mode_hint.width ?
> +			  vbox_connector->mode_hint.width : 1024;
> +	preferred_height = vbox_connector->mode_hint.height ?
> +			   vbox_connector->mode_hint.height : 768;
> +	mode = drm_cvt_mode(connector->dev, preferred_width, preferred_height,
> +			    60, false, false, false);
> +	if (mode) {
> +		mode->type |= DRM_MODE_TYPE_PREFERRED;
> +		drm_mode_probed_add(connector, mode);
> +		++num_modes;
> +	}
> +	vbox_set_edid(connector, preferred_width, preferred_height);
> +	drm_object_property_set_value(
> +		&connector->base, vbox->dev->mode_config.suggested_x_property,
> +		vbox_connector->vbox_crtc->x_hint);
> +	drm_object_property_set_value(
> +		&connector->base, vbox->dev->mode_config.suggested_y_property,
> +		vbox_connector->vbox_crtc->y_hint);
> +
> +	return num_modes;
> +}
> +
> +static int vbox_mode_valid(struct drm_connector *connector,
> +			   struct drm_display_mode *mode)
> +{
> +	return MODE_OK;
> +}
> +
> +static void vbox_connector_destroy(struct drm_connector *connector)
> +{
> +	struct vbox_connector *vbox_connector = NULL;
> +
> +	vbox_connector = to_vbox_connector(connector);
> +	drm_connector_unregister(connector);
> +	drm_connector_cleanup(connector);
> +	kfree(connector);
> +}
> +
> +static enum drm_connector_status
> +vbox_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	struct vbox_connector *vbox_connector = NULL;
> +
> +	(void)force;
> +	vbox_connector = to_vbox_connector(connector);
> +
> +	return vbox_connector->mode_hint.disconnected ?
> +	    connector_status_disconnected : connector_status_connected;
> +}
> +
> +static int vbox_fill_modes(struct drm_connector *connector, u32 max_x,
> +			   u32 max_y)
> +{
> +	struct vbox_connector *vbox_connector;
> +	struct drm_device *dev;
> +	struct drm_display_mode *mode, *iterator;
> +
> +	vbox_connector = to_vbox_connector(connector);
> +	dev = vbox_connector->base.dev;
> +	list_for_each_entry_safe(mode, iterator, &connector->modes, head) {
> +		list_del(&mode->head);
> +		drm_mode_destroy(dev, mode);
> +	}
> +
> +	return drm_helper_probe_single_connector_modes(connector, max_x, max_y);
> +}
> +
> +static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
> +	.mode_valid = vbox_mode_valid,
> +	.get_modes = vbox_get_modes,
> +	.best_encoder = vbox_best_single_encoder,
> +};
> +
> +static const struct drm_connector_funcs vbox_connector_funcs = {
> +	.dpms = drm_helper_connector_dpms,
> +	.detect = vbox_connector_detect,
> +	.fill_modes = vbox_fill_modes,
> +	.destroy = vbox_connector_destroy,
> +};
> +
> +static int vbox_connector_init(struct drm_device *dev,
> +			       struct vbox_crtc *vbox_crtc,
> +			       struct drm_encoder *encoder)
> +{
> +	struct vbox_connector *vbox_connector;
> +	struct drm_connector *connector;
> +
> +	vbox_connector = kzalloc(sizeof(*vbox_connector), GFP_KERNEL);
> +	if (!vbox_connector)
> +		return -ENOMEM;
> +
> +	connector = &vbox_connector->base;
> +	vbox_connector->vbox_crtc = vbox_crtc;
> +
> +	drm_connector_init(dev, connector, &vbox_connector_funcs,
> +			   DRM_MODE_CONNECTOR_VGA);
> +	drm_connector_helper_add(connector, &vbox_connector_helper_funcs);
> +
> +	connector->interlace_allowed = 0;
> +	connector->doublescan_allowed = 0;
> +
> +	drm_mode_create_suggested_offset_properties(dev);
> +	drm_object_attach_property(&connector->base,
> +				   dev->mode_config.suggested_x_property, -1);
> +	drm_object_attach_property(&connector->base,
> +				   dev->mode_config.suggested_y_property, -1);
> +	drm_connector_register(connector);
> +
> +	drm_mode_connector_attach_encoder(connector, encoder);
> +
> +	return 0;
> +}
> +
> +int vbox_mode_init(struct drm_device *dev)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +	struct drm_encoder *encoder;
> +	struct vbox_crtc *vbox_crtc;
> +	unsigned int i;
> +
> +	/* vbox_cursor_init(dev); */
> +	for (i = 0; i < vbox->num_crtcs; ++i) {
> +		vbox_crtc = vbox_crtc_init(dev, i);
> +		if (!vbox_crtc)
> +			return -ENOMEM;
> +		encoder = vbox_encoder_init(dev, i);
> +		if (!encoder)
> +			return -ENOMEM;
> +		vbox_connector_init(dev, vbox_crtc, encoder);
> +	}
> +
> +	return 0;
> +}
> +
> +void vbox_mode_fini(struct drm_device *dev)
> +{
> +	/* vbox_cursor_fini(dev); */
> +}
> +
> +/**
> + * Copy the ARGB image and generate the mask, which is needed in case the host
> + * does not support ARGB cursors.  The mask is a 1BPP bitmap with the bit set
> + * if the corresponding alpha value in the ARGB image is greater than 0xF0.
> + */
> +static void copy_cursor_image(u8 *src, u8 *dst, u32 width, u32 height,
> +			      size_t mask_size)
> +{
> +	size_t line_size = (width + 7) / 8;
> +	u32 i, j;
> +
> +	memcpy(dst + mask_size, src, width * height * 4);
> +	for (i = 0; i < height; ++i)
> +		for (j = 0; j < width; ++j)
> +			if (((u32 *)src)[i * width + j] > 0xf0000000)
> +				dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
> +}
> +
> +static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
> +			    u32 handle, u32 width, u32 height,
> +			    s32 hot_x, s32 hot_y)
> +{
> +	struct vbox_private *vbox = crtc->dev->dev_private;
> +	struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
> +	struct drm_gem_object *obj;
> +	struct vbox_bo *bo;
> +	int ret, rc;
> +	struct ttm_bo_kmap_obj uobj_map;
> +	u8 *src;
> +	u8 *dst = NULL;
> +	u32 caps = 0;
> +	size_t data_size, mask_size;
> +	bool src_isiomem;
> +
> +	/*
> +	 * Re-set this regularly as in 5.0.20 and earlier the information was
> +	 * lost on save and restore.
> +	 */
> +	VBoxHGSMIUpdateInputMapping(vbox->guest_pool, 0, 0,
> +				    vbox->input_mapping_width,
> +				    vbox->input_mapping_height);
> +	if (!handle) {
> +		bool cursor_enabled = false;
> +		struct drm_crtc *crtci;
> +
> +		/* Hide cursor. */
> +		vbox_crtc->cursor_enabled = false;
> +		list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
> +				    head)
> +			if (to_vbox_crtc(crtci)->cursor_enabled)
> +				cursor_enabled = true;
> +
> +		if (!cursor_enabled)
> +			VBoxHGSMIUpdatePointerShape(vbox->guest_pool, 0, 0, 0,
> +						    0, 0, NULL, 0);
> +		return 0;
> +	}
> +	vbox_crtc->cursor_enabled = true;
> +	if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
> +	    width == 0 || height == 0)
> +		return -EINVAL;
> +	rc = VBoxQueryConfHGSMI(vbox->guest_pool,
> +				VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
> +	ret = rc == VINF_SUCCESS ? 0 : rc == VERR_NO_MEMORY ? -ENOMEM : -EINVAL;
> +	if (ret)
> +		return ret;
> +
> +	if (!(caps & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE))
> +		/*
> +		 * -EINVAL means cursor_set2() not supported, -EAGAIN means
> +		 * retry at once.
> +		 */
> +		return -EBUSY;
> +
> +	obj = drm_gem_object_lookup(file_priv, handle);
> +	if (obj) {
> +		bo = gem_to_vbox_bo(obj);
> +		ret = vbox_bo_reserve(bo, false);
> +		if (!ret) {
> +			/*
> +			 * The mask must be calculated based on the alpha
> +			 * channel, one bit per ARGB word, and must be 32-bit
> +			 * padded.
> +			 */
> +			mask_size = ((width + 7) / 8 * height + 3) & ~3;
> +			data_size = width * height * 4 + mask_size;
> +			vbox->cursor_hot_x = min_t(u32, max(hot_x, 0), width);
> +			vbox->cursor_hot_y = min_t(u32, max(hot_y, 0), height);
> +			vbox->cursor_width = width;
> +			vbox->cursor_height = height;
> +			vbox->cursor_data_size = data_size;
> +			dst = vbox->cursor_data;
> +			ret =
> +			    ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
> +					&uobj_map);
> +			if (!ret) {
> +				src =
> +				    ttm_kmap_obj_virtual(&uobj_map,
> +							 &src_isiomem);
> +				if (!src_isiomem) {
> +					u32 flags =
> +					    VBOX_MOUSE_POINTER_VISIBLE |
> +					    VBOX_MOUSE_POINTER_SHAPE |
> +					    VBOX_MOUSE_POINTER_ALPHA;
> +					copy_cursor_image(src, dst, width,
> +							  height, mask_size);
> +					rc = VBoxHGSMIUpdatePointerShape(
> +						vbox->guest_pool, flags,
> +						vbox->cursor_hot_x,
> +						vbox->cursor_hot_y,
> +						width, height, dst, data_size);
> +					ret =
> +					    rc == VINF_SUCCESS ? 0 : rc ==
> +					    VERR_NO_MEMORY ? -ENOMEM : rc ==
> +					    VERR_NOT_SUPPORTED ? -EBUSY :
> +					    -EINVAL;
> +				} else {
> +					DRM_ERROR("src cursor bo should be in main memory\n");
> +				}
> +				ttm_bo_kunmap(&uobj_map);
> +			} else {
> +				vbox->cursor_data_size = 0;
> +			}
> +			vbox_bo_unreserve(bo);
> +		}
> +		drm_gem_object_unreference_unlocked(obj);
> +	} else {
> +		DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
> +		ret = -ENOENT;
> +	}
> +
> +	return ret;
> +}
> +
> +static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y)
> +{
> +	struct vbox_private *vbox = crtc->dev->dev_private;
> +	u32 flags = VBOX_MOUSE_POINTER_VISIBLE |
> +	    VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
> +	s32 crtc_x =
> +	    vbox->single_framebuffer ? crtc->x : to_vbox_crtc(crtc)->x_hint;
> +	s32 crtc_y =
> +	    vbox->single_framebuffer ? crtc->y : to_vbox_crtc(crtc)->y_hint;
> +	u32 host_x, host_y;
> +	u32 hot_x = 0;
> +	u32 hot_y = 0;
> +	int rc;
> +
> +	/*
> +	 * We compare these to unsigned later and don't
> +	 * need to handle negative.
> +	 */
> +	if (x + crtc_x < 0 || y + crtc_y < 0 || vbox->cursor_data_size == 0)
> +		return 0;
> +
> +	rc = VBoxHGSMICursorPosition(vbox->guest_pool, true, x + crtc_x,
> +				     y + crtc_y, &host_x, &host_y);
> +	/* Work around a bug after save and restore in 5.0.20 and earlier. */
> +	if (RT_FAILURE(rc) || (host_x == 0 && host_y == 0))
> +		return rc == VINF_SUCCESS ? 0
> +		    : rc == VERR_NO_MEMORY ? -ENOMEM : -EINVAL;
> +	if (x + crtc_x < host_x)
> +		hot_x = min(host_x - x - crtc_x, vbox->cursor_width);
> +	if (y + crtc_y < host_y)
> +		hot_y = min(host_y - y - crtc_y, vbox->cursor_height);
> +	if (hot_x == vbox->cursor_hot_x && hot_y == vbox->cursor_hot_y)
> +		return 0;
> +	vbox->cursor_hot_x = hot_x;
> +	vbox->cursor_hot_y = hot_y;
> +	rc = VBoxHGSMIUpdatePointerShape(vbox->guest_pool, flags, hot_x, hot_y,
> +					 vbox->cursor_width,
> +					 vbox->cursor_height, vbox->cursor_data,
> +					 vbox->cursor_data_size);
> +	return rc == VINF_SUCCESS ? 0 : rc == VERR_NO_MEMORY ? -ENOMEM : rc ==
> +	    VERR_NOT_SUPPORTED ? -EBUSY : -EINVAL;
> +}
> diff --git a/drivers/staging/vboxvideo/vbox_prime.c b/drivers/staging/vboxvideo/vbox_prime.c
> new file mode 100644
> index 000000000000..b7453e427a1d
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_prime.c
> @@ -0,0 +1,74 @@
> +/*
> + * Copyright (C) 2017 Oracle Corporation
> + * Copyright 2017 Canonical
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Andreas Pokorny
> + */
> +
> +#include "vbox_drv.h"
> +
> +/*
> + * Based on qxl_prime.c:
> + * Empty Implementations as there should not be any other driver for a virtual
> + * device that might share buffers with vboxvideo
> + */
> +
> +int vbox_gem_prime_pin(struct drm_gem_object *obj)
> +{
> +	WARN_ONCE(1, "not implemented");
> +	return -ENOSYS;
> +}
> +
> +void vbox_gem_prime_unpin(struct drm_gem_object *obj)
> +{
> +	WARN_ONCE(1, "not implemented");
> +}
> +
> +struct sg_table *vbox_gem_prime_get_sg_table(struct drm_gem_object *obj)
> +{
> +	WARN_ONCE(1, "not implemented");
> +	return ERR_PTR(-ENOSYS);
> +}
> +
> +struct drm_gem_object *vbox_gem_prime_import_sg_table(
> +	struct drm_device *dev, struct dma_buf_attachment *attach,
> +	struct sg_table *table)
> +{
> +	WARN_ONCE(1, "not implemented");
> +	return ERR_PTR(-ENOSYS);
> +}
> +
> +void *vbox_gem_prime_vmap(struct drm_gem_object *obj)
> +{
> +	WARN_ONCE(1, "not implemented");
> +	return ERR_PTR(-ENOSYS);
> +}
> +
> +void vbox_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
> +{
> +	WARN_ONCE(1, "not implemented");
> +}
> +
> +int vbox_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *area)
> +{
> +	WARN_ONCE(1, "not implemented");
> +	return -ENOSYS;
> +}
> diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c
> new file mode 100644
> index 000000000000..7c8f75f2c11b
> --- /dev/null
> +++ b/drivers/staging/vboxvideo/vbox_ttm.c
> @@ -0,0 +1,477 @@
> +/*
> + * Copyright (C) 2013-2017 Oracle Corporation
> + * This file is based on ast_ttm.c
> + * Copyright 2012 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + *
> + * Authors: Dave Airlie <airlied at redhat.com>
> + *          Michael Thayer <michael.thayer at oracle.com>
> + */
> +#include "vbox_drv.h"
> +#include <ttm/ttm_page_alloc.h>
> +
> +static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd)
> +{
> +	return container_of(bd, struct vbox_private, ttm.bdev);
> +}
> +
> +static int vbox_ttm_mem_global_init(struct drm_global_reference *ref)
> +{
> +	return ttm_mem_global_init(ref->object);
> +}
> +
> +static void vbox_ttm_mem_global_release(struct drm_global_reference *ref)
> +{
> +	ttm_mem_global_release(ref->object);
> +}
> +
> +/**
> + * Adds the vbox memory manager object/structures to the global memory manager.
> + */
> +static int vbox_ttm_global_init(struct vbox_private *vbox)
> +{
> +	struct drm_global_reference *global_ref;
> +	int r;
> +
> +	global_ref = &vbox->ttm.mem_global_ref;
> +	global_ref->global_type = DRM_GLOBAL_TTM_MEM;
> +	global_ref->size = sizeof(struct ttm_mem_global);
> +	global_ref->init = &vbox_ttm_mem_global_init;
> +	global_ref->release = &vbox_ttm_mem_global_release;
> +	r = drm_global_item_ref(global_ref);
> +	if (r != 0) {
> +		DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n");
> +		return r;
> +	}
> +
> +	vbox->ttm.bo_global_ref.mem_glob = vbox->ttm.mem_global_ref.object;
> +	global_ref = &vbox->ttm.bo_global_ref.ref;
> +	global_ref->global_type = DRM_GLOBAL_TTM_BO;
> +	global_ref->size = sizeof(struct ttm_bo_global);
> +	global_ref->init = &ttm_bo_global_init;
> +	global_ref->release = &ttm_bo_global_release;
> +
> +	r = drm_global_item_ref(global_ref);
> +	if (r != 0) {
> +		DRM_ERROR("Failed setting up TTM BO subsystem.\n");
> +		drm_global_item_unref(&vbox->ttm.mem_global_ref);
> +		return r;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * Removes the vbox memory manager object from the global memory manager.
> + */
> +static void vbox_ttm_global_release(struct vbox_private *vbox)
> +{
> +	if (!vbox->ttm.mem_global_ref.release)
> +		return;
> +
> +	drm_global_item_unref(&vbox->ttm.bo_global_ref.ref);
> +	drm_global_item_unref(&vbox->ttm.mem_global_ref);
> +	vbox->ttm.mem_global_ref.release = NULL;
> +}
> +
> +static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> +{
> +	struct vbox_bo *bo;
> +
> +	bo = container_of(tbo, struct vbox_bo, bo);
> +
> +	drm_gem_object_release(&bo->gem);
> +	kfree(bo);
> +}
> +
> +static bool vbox_ttm_bo_is_vbox_bo(struct ttm_buffer_object *bo)
> +{
> +	if (bo->destroy == &vbox_bo_ttm_destroy)
> +		return true;
> +
> +	return false;
> +}
> +
> +static int
> +vbox_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
> +		      struct ttm_mem_type_manager *man)
> +{
> +	switch (type) {
> +	case TTM_PL_SYSTEM:
> +		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
> +		man->available_caching = TTM_PL_MASK_CACHING;
> +		man->default_caching = TTM_PL_FLAG_CACHED;
> +		break;
> +	case TTM_PL_VRAM:
> +		man->func = &ttm_bo_manager_func;
> +		man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
> +		man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
> +		man->default_caching = TTM_PL_FLAG_WC;
> +		break;
> +	default:
> +		DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void
> +vbox_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
> +{
> +	struct vbox_bo *vboxbo = vbox_bo(bo);
> +
> +	if (!vbox_ttm_bo_is_vbox_bo(bo))
> +		return;
> +
> +	vbox_ttm_placement(vboxbo, TTM_PL_FLAG_SYSTEM);
> +	*pl = vboxbo->placement;
> +}
> +
> +static int vbox_bo_verify_access(struct ttm_buffer_object *bo,
> +				 struct file *filp)
> +{
> +	return 0;
> +}
> +
> +static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
> +				   struct ttm_mem_reg *mem)
> +{
> +	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
> +	struct vbox_private *vbox = vbox_bdev(bdev);
> +
> +	mem->bus.addr = NULL;
> +	mem->bus.offset = 0;
> +	mem->bus.size = mem->num_pages << PAGE_SHIFT;
> +	mem->bus.base = 0;
> +	mem->bus.is_iomem = false;
> +	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
> +		return -EINVAL;
> +	switch (mem->mem_type) {
> +	case TTM_PL_SYSTEM:
> +		/* system memory */
> +		return 0;
> +	case TTM_PL_VRAM:
> +		mem->bus.offset = mem->start << PAGE_SHIFT;
> +		mem->bus.base = pci_resource_start(vbox->dev->pdev, 0);
> +		mem->bus.is_iomem = true;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev,
> +				 struct ttm_mem_reg *mem)
> +{
> +}
> +
> +static int vbox_bo_move(struct ttm_buffer_object *bo,
> +			bool evict, bool interruptible,
> +			bool no_wait_gpu, struct ttm_mem_reg *new_mem)
> +{
> +	return ttm_bo_move_memcpy(bo, interruptible, no_wait_gpu, new_mem);
> +}
> +
> +static void vbox_ttm_backend_destroy(struct ttm_tt *tt)
> +{
> +	ttm_tt_fini(tt);
> +	kfree(tt);
> +}
> +
> +static struct ttm_backend_func vbox_tt_backend_func = {
> +	.destroy = &vbox_ttm_backend_destroy,
> +};
> +
> +static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev,
> +					 unsigned long size,
> +					 u32 page_flags,
> +					 struct page *dummy_read_page)
> +{
> +	struct ttm_tt *tt;
> +
> +	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> +	if (!tt)
> +		return NULL;
> +
> +	tt->func = &vbox_tt_backend_func;
> +	if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
> +		kfree(tt);
> +		return NULL;
> +	}
> +
> +	return tt;
> +}
> +
> +static int vbox_ttm_tt_populate(struct ttm_tt *ttm)
> +{
> +	return ttm_pool_populate(ttm);
> +}
> +
> +static void vbox_ttm_tt_unpopulate(struct ttm_tt *ttm)
> +{
> +	ttm_pool_unpopulate(ttm);
> +}
> +
> +struct ttm_bo_driver vbox_bo_driver = {
> +	.ttm_tt_create = vbox_ttm_tt_create,
> +	.ttm_tt_populate = vbox_ttm_tt_populate,
> +	.ttm_tt_unpopulate = vbox_ttm_tt_unpopulate,
> +	.init_mem_type = vbox_bo_init_mem_type,
> +	.eviction_valuable = ttm_bo_eviction_valuable,
> +	.evict_flags = vbox_bo_evict_flags,
> +	.move = vbox_bo_move,
> +	.verify_access = vbox_bo_verify_access,
> +	.io_mem_reserve = &vbox_ttm_io_mem_reserve,
> +	.io_mem_free = &vbox_ttm_io_mem_free,
> +	.io_mem_pfn = ttm_bo_default_io_mem_pfn,
> +};
> +
> +int vbox_mm_init(struct vbox_private *vbox)
> +{
> +	int ret;
> +	struct drm_device *dev = vbox->dev;
> +	struct ttm_bo_device *bdev = &vbox->ttm.bdev;
> +
> +	ret = vbox_ttm_global_init(vbox);
> +	if (ret)
> +		return ret;
> +
> +	ret = ttm_bo_device_init(&vbox->ttm.bdev,
> +				 vbox->ttm.bo_global_ref.ref.object,
> +				 &vbox_bo_driver,
> +				 dev->anon_inode->i_mapping,
> +				 DRM_FILE_PAGE_OFFSET, true);
> +	if (ret) {
> +		DRM_ERROR("Error initialising bo driver; %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> +			     vbox->available_vram_size >> PAGE_SHIFT);
> +	if (ret) {
> +		DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
> +		return ret;
> +	}
> +#ifdef DRM_MTRR_WC
> +	vbox->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
> +				     pci_resource_len(dev->pdev, 0),
> +				     DRM_MTRR_WC);
> +#else
> +	vbox->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
> +					 pci_resource_len(dev->pdev, 0));
> +#endif
> +
> +	vbox->ttm.mm_initialised = true;
> +
> +	return 0;
> +}
> +
> +void vbox_mm_fini(struct vbox_private *vbox)
> +{
> +#ifdef DRM_MTRR_WC
> +	struct drm_device *dev = vbox->dev;
> +#endif
> +	if (!vbox->ttm.mm_initialised)
> +		return;
> +	ttm_bo_device_release(&vbox->ttm.bdev);
> +
> +	vbox_ttm_global_release(vbox);
> +
> +#ifdef DRM_MTRR_WC
> +	drm_mtrr_del(vbox->fb_mtrr,
> +		     pci_resource_start(dev->pdev, 0),
> +		     pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
> +#else
> +	arch_phys_wc_del(vbox->fb_mtrr);
> +#endif
> +}
> +
> +void vbox_ttm_placement(struct vbox_bo *bo, int domain)
> +{
> +	unsigned int i;
> +	u32 c = 0;
> +
> +	bo->placement.placement = bo->placements;
> +	bo->placement.busy_placement = bo->placements;
> +
> +	if (domain & TTM_PL_FLAG_VRAM)
> +		bo->placements[c++].flags =
> +		    TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
> +	if (domain & TTM_PL_FLAG_SYSTEM)
> +		bo->placements[c++].flags =
> +		    TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
> +	if (!c)
> +		bo->placements[c++].flags =
> +		    TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
> +
> +	bo->placement.num_placement = c;
> +	bo->placement.num_busy_placement = c;
> +
> +	for (i = 0; i < c; ++i) {
> +		bo->placements[i].fpfn = 0;
> +		bo->placements[i].lpfn = 0;
> +	}
> +}
> +
> +int vbox_bo_create(struct drm_device *dev, int size, int align,
> +		   u32 flags, struct vbox_bo **pvboxbo)
> +{
> +	struct vbox_private *vbox = dev->dev_private;
> +	struct vbox_bo *vboxbo;
> +	size_t acc_size;
> +	int ret;
> +
> +	vboxbo = kzalloc(sizeof(*vboxbo), GFP_KERNEL);
> +	if (!vboxbo)
> +		return -ENOMEM;
> +
> +	ret = drm_gem_object_init(dev, &vboxbo->gem, size);
> +	if (ret) {
> +		kfree(vboxbo);
> +		return ret;
> +	}
> +
> +	vboxbo->bo.bdev = &vbox->ttm.bdev;
> +
> +	vbox_ttm_placement(vboxbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> +
> +	acc_size = ttm_bo_dma_acc_size(&vbox->ttm.bdev, size,
> +				       sizeof(struct vbox_bo));
> +
> +	ret = ttm_bo_init(&vbox->ttm.bdev, &vboxbo->bo, size,
> +			  ttm_bo_type_device, &vboxbo->placement,
> +			  align >> PAGE_SHIFT, false, NULL, acc_size,
> +			  NULL, NULL, vbox_bo_ttm_destroy);
> +	if (ret)
> +		return ret;
> +
> +	*pvboxbo = vboxbo;
> +
> +	return 0;
> +}
> +
> +static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo)
> +{
> +	return bo->bo.offset;
> +}
> +
> +int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr)
> +{
> +	int i, ret;
> +
> +	if (bo->pin_count) {
> +		bo->pin_count++;
> +		if (gpu_addr)
> +			*gpu_addr = vbox_bo_gpu_offset(bo);
> +
> +		return 0;
> +	}
> +
> +	vbox_ttm_placement(bo, pl_flag);
> +
> +	for (i = 0; i < bo->placement.num_placement; i++)
> +		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> +
> +	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +	if (ret)
> +		return ret;
> +
> +	bo->pin_count = 1;
> +
> +	if (gpu_addr)
> +		*gpu_addr = vbox_bo_gpu_offset(bo);
> +
> +	return 0;
> +}
> +
> +int vbox_bo_unpin(struct vbox_bo *bo)
> +{
> +	int i, ret;
> +
> +	if (!bo->pin_count) {
> +		DRM_ERROR("unpin bad %p\n", bo);
> +		return 0;
> +	}
> +	bo->pin_count--;
> +	if (bo->pin_count)
> +		return 0;
> +
> +	for (i = 0; i < bo->placement.num_placement; i++)
> +		bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
> +
> +	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +/*
> + * Move a vbox-owned buffer object to system memory if no one else has it
> + * pinned.  The caller must have pinned it previously, and this call will
> + * release the caller's pin.
> + */
> +int vbox_bo_push_sysram(struct vbox_bo *bo)
> +{
> +	int i, ret;
> +
> +	if (!bo->pin_count) {
> +		DRM_ERROR("unpin bad %p\n", bo);
> +		return 0;
> +	}
> +	bo->pin_count--;
> +	if (bo->pin_count)
> +		return 0;
> +
> +	if (bo->kmap.virtual)
> +		ttm_bo_kunmap(&bo->kmap);
> +
> +	vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
> +
> +	for (i = 0; i < bo->placement.num_placement; i++)
> +		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> +
> +	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +	if (ret) {
> +		DRM_ERROR("pushing to VRAM failed\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int vbox_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +	struct drm_file *file_priv;
> +	struct vbox_private *vbox;
> +
> +	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
> +		return -EINVAL;
> +
> +	file_priv = filp->private_data;
> +	vbox = file_priv->minor->dev->dev_private;
> +
> +	return ttm_bo_mmap(filp, vma, &vbox->ttm.bdev);
> +}
> 

-- 
Michael Thayer | VirtualBox engineer
ORACLE Deutschland B.V. & Co. KG | Werkstr. 24 | D-71384 Weinstadt

ORACLE Deutschland B.V. & Co. KG
Hauptverwaltung: Riesstraße 25, D-80992 München
Registergericht: Amtsgericht München, HRA 95603

Komplementärin: ORACLE Deutschland Verwaltung B.V.
Hertogswetering 163/167, 3543 AS Utrecht, Niederlande Handelsregister 
der Handelskammer Midden-Nederland, Nr. 30143697
Geschäftsführer: Alexander van der Ven, Jan Schultheiss, Val Maher


More information about the dri-devel mailing list