1e07dc26bSmrg/*
2e07dc26bSmrg * Copyright (C) 2006-2017 Oracle Corporation
3e07dc26bSmrg *
4e07dc26bSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5e07dc26bSmrg * copy of this software and associated documentation files (the "Software"),
6e07dc26bSmrg * to deal in the Software without restriction, including without limitation
7e07dc26bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e07dc26bSmrg * and/or sell copies of the Software, and to permit persons to whom the
9e07dc26bSmrg * Software is furnished to do so, subject to the following conditions:
10e07dc26bSmrg *
11e07dc26bSmrg * The above copyright notice and this permission notice shall be included in
12e07dc26bSmrg * all copies or substantial portions of the Software.
13e07dc26bSmrg *
14e07dc26bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e07dc26bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e07dc26bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17e07dc26bSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18e07dc26bSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19e07dc26bSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20e07dc26bSmrg * OTHER DEALINGS IN THE SOFTWARE.
21e07dc26bSmrg */
22e07dc26bSmrg
23e07dc26bSmrg#include <HGSMIBase.h>
24e07dc26bSmrg#include <VBoxVideoIPRT.h>
25e07dc26bSmrg#include <VBoxVideoGuest.h>
26e07dc26bSmrg#include <VBoxVideoVBE.h>
27e07dc26bSmrg#include <HGSMIChannels.h>
28e07dc26bSmrg#include <HGSMIChSetup.h>
29e07dc26bSmrg
30e07dc26bSmrg/** Detect whether HGSMI is supported by the host. */
31e07dc26bSmrgDECLHIDDEN(bool) VBoxHGSMIIsSupported(void)
32e07dc26bSmrg{
33e07dc26bSmrg    uint16_t DispiId;
34e07dc26bSmrg
35e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
36e07dc26bSmrg    VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
37e07dc26bSmrg
38e07dc26bSmrg    DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
39e07dc26bSmrg
40e07dc26bSmrg    return (DispiId == VBE_DISPI_ID_HGSMI);
41e07dc26bSmrg}
42e07dc26bSmrg
43e07dc26bSmrg
44e07dc26bSmrg/**
45e07dc26bSmrg * Inform the host of the location of the host flags in VRAM via an HGSMI command.
46e07dc26bSmrg * @returns  IPRT status value.
47e07dc26bSmrg * @returns  VERR_NOT_IMPLEMENTED  if the host does not support the command.
48e07dc26bSmrg * @returns  VERR_NO_MEMORY        if a heap allocation fails.
49e07dc26bSmrg * @param    pCtx                  the context of the guest heap to use.
50636c353eSmrg * @param    offLocation           the offset chosen for the flags within guest VRAM.
51e07dc26bSmrg */
52e07dc26bSmrgDECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx, HGSMIOFFSET offLocation)
53e07dc26bSmrg{
54e07dc26bSmrg    HGSMIBUFFERLOCATION *p;
55e07dc26bSmrg
56e07dc26bSmrg    /* Allocate the IO buffer. */
57e07dc26bSmrg    p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_HGSMI,
58e07dc26bSmrg                                                    HGSMI_CC_HOST_FLAGS_LOCATION);
59e07dc26bSmrg    if (!p)
60e07dc26bSmrg        return VERR_NO_MEMORY;
61e07dc26bSmrg
62e07dc26bSmrg    /* Prepare data to be sent to the host. */
63e07dc26bSmrg    p->offLocation = offLocation;
64e07dc26bSmrg    p->cbLocation  = sizeof(HGSMIHOSTFLAGS);
65e07dc26bSmrg    /* No need to check that the buffer is valid as we have just allocated it. */
66e07dc26bSmrg    VBoxHGSMIBufferSubmit(pCtx, p);
67e07dc26bSmrg    /* Free the IO buffer. */
68e07dc26bSmrg    VBoxHGSMIBufferFree(pCtx, p);
69e07dc26bSmrg
70e07dc26bSmrg    return VINF_SUCCESS;
71e07dc26bSmrg}
72e07dc26bSmrg
73e07dc26bSmrg
74e07dc26bSmrg/**
75e07dc26bSmrg * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
76e07dc26bSmrg * @returns  IPRT status value.
77e07dc26bSmrg * @returns  VERR_NOT_IMPLEMENTED  if the host does not support the command.
78e07dc26bSmrg * @returns  VERR_NO_MEMORY        if a heap allocation fails.
79e07dc26bSmrg * @param    pCtx                  the context of the guest heap to use.
80e07dc26bSmrg * @param    fCaps                 the capabilities to report, see VBVACAPS.
81e07dc26bSmrg */
82e07dc26bSmrgDECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t fCaps)
83e07dc26bSmrg{
84e07dc26bSmrg    VBVACAPS *p;
85e07dc26bSmrg
86e07dc26bSmrg    /* Allocate the IO buffer. */
87e07dc26bSmrg    p = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS);
88e07dc26bSmrg
89e07dc26bSmrg    if (!p)
90e07dc26bSmrg        return VERR_NO_MEMORY;
91e07dc26bSmrg
92e07dc26bSmrg    /* Prepare data to be sent to the host. */
93e07dc26bSmrg    p->rc    = VERR_NOT_IMPLEMENTED;
94e07dc26bSmrg    p->fCaps = fCaps;
95e07dc26bSmrg    /* No need to check that the buffer is valid as we have just allocated it. */
96e07dc26bSmrg    VBoxHGSMIBufferSubmit(pCtx, p);
97e07dc26bSmrg
98e07dc26bSmrg    AssertRC(p->rc);
99e07dc26bSmrg    /* Free the IO buffer. */
100e07dc26bSmrg    VBoxHGSMIBufferFree(pCtx, p);
101e07dc26bSmrg    return p->rc;
102e07dc26bSmrg}
103e07dc26bSmrg
104e07dc26bSmrg
105e07dc26bSmrg/**
106e07dc26bSmrg * Get the information needed to map the basic communication structures in
107e07dc26bSmrg * device memory into our address space.  All pointer parameters are optional.
108e07dc26bSmrg *
109e07dc26bSmrg * @param  cbVRAM               how much video RAM is allocated to the device
110e07dc26bSmrg * @param  poffVRAMBaseMapping  where to save the offset from the start of the
111e07dc26bSmrg *                              device VRAM of the whole area to map
112e07dc26bSmrg * @param  pcbMapping           where to save the mapping size
113e07dc26bSmrg * @param  poffGuestHeapMemory  where to save the offset into the mapped area
114e07dc26bSmrg *                              of the guest heap backing memory
115e07dc26bSmrg * @param  pcbGuestHeapMemory   where to save the size of the guest heap
116e07dc26bSmrg *                              backing memory
117e07dc26bSmrg * @param  poffHostFlags        where to save the offset into the mapped area
118e07dc26bSmrg *                              of the host flags
119e07dc26bSmrg */
120e07dc26bSmrgDECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM,
121e07dc26bSmrg                                             uint32_t *poffVRAMBaseMapping,
122e07dc26bSmrg                                             uint32_t *pcbMapping,
123e07dc26bSmrg                                             uint32_t *poffGuestHeapMemory,
124e07dc26bSmrg                                             uint32_t *pcbGuestHeapMemory,
125e07dc26bSmrg                                             uint32_t *poffHostFlags)
126e07dc26bSmrg{
127e07dc26bSmrg    AssertPtrNullReturnVoid(poffVRAMBaseMapping);
128e07dc26bSmrg    AssertPtrNullReturnVoid(pcbMapping);
129e07dc26bSmrg    AssertPtrNullReturnVoid(poffGuestHeapMemory);
130e07dc26bSmrg    AssertPtrNullReturnVoid(pcbGuestHeapMemory);
131e07dc26bSmrg    AssertPtrNullReturnVoid(poffHostFlags);
132e07dc26bSmrg    if (poffVRAMBaseMapping)
133e07dc26bSmrg        *poffVRAMBaseMapping = cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE;
134e07dc26bSmrg    if (pcbMapping)
135e07dc26bSmrg        *pcbMapping = VBVA_ADAPTER_INFORMATION_SIZE;
136e07dc26bSmrg    if (poffGuestHeapMemory)
137e07dc26bSmrg        *poffGuestHeapMemory = 0;
138e07dc26bSmrg    if (pcbGuestHeapMemory)
139e07dc26bSmrg        *pcbGuestHeapMemory =   VBVA_ADAPTER_INFORMATION_SIZE
140e07dc26bSmrg                              - sizeof(HGSMIHOSTFLAGS);
141e07dc26bSmrg    if (poffHostFlags)
142e07dc26bSmrg        *poffHostFlags =   VBVA_ADAPTER_INFORMATION_SIZE
143e07dc26bSmrg                         - sizeof(HGSMIHOSTFLAGS);
144e07dc26bSmrg}
145e07dc26bSmrg
146e07dc26bSmrg/**
147e07dc26bSmrg * Query the host for an HGSMI configuration parameter via an HGSMI command.
148e07dc26bSmrg * @returns iprt status value
149e07dc26bSmrg * @param  pCtx      the context containing the heap used
150e07dc26bSmrg * @param  u32Index  the index of the parameter to query,
151e07dc26bSmrg *                   @see VBVACONF32::u32Index
152e07dc26bSmrg * @param  pulValue  where to store the value of the parameter on success
153e07dc26bSmrg */
154e07dc26bSmrgDECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32Index, uint32_t *pulValue)
155e07dc26bSmrg{
156e07dc26bSmrg    VBVACONF32 *p;
157e07dc26bSmrg
158e07dc26bSmrg    /* Allocate the IO buffer. */
159e07dc26bSmrg    p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_VBVA,
160e07dc26bSmrg                                           VBVA_QUERY_CONF32);
161e07dc26bSmrg    if (!p)
162e07dc26bSmrg        return VERR_NO_MEMORY;
163e07dc26bSmrg
164e07dc26bSmrg    /* Prepare data to be sent to the host. */
165e07dc26bSmrg    p->u32Index = u32Index;
166e07dc26bSmrg    p->u32Value = UINT32_MAX;
167e07dc26bSmrg    /* No need to check that the buffer is valid as we have just allocated it. */
168e07dc26bSmrg    VBoxHGSMIBufferSubmit(pCtx, p);
169e07dc26bSmrg    *pulValue = p->u32Value;
170e07dc26bSmrg    /* Free the IO buffer. */
171e07dc26bSmrg    VBoxHGSMIBufferFree(pCtx, p);
172e07dc26bSmrg    return VINF_SUCCESS;
173e07dc26bSmrg}
174e07dc26bSmrg
175e07dc26bSmrg/**
176e07dc26bSmrg * Pass the host a new mouse pointer shape via an HGSMI command.
177e07dc26bSmrg *
178e07dc26bSmrg * @returns  success or failure
179e07dc26bSmrg * @param  pCtx      the context containing the heap to be used
180e07dc26bSmrg * @param  fFlags    cursor flags, @see VMMDevReqMousePointer::fFlags
181e07dc26bSmrg * @param  cHotX     horizontal position of the hot spot
182e07dc26bSmrg * @param  cHotY     vertical position of the hot spot
183e07dc26bSmrg * @param  cWidth    width in pixels of the cursor
184e07dc26bSmrg * @param  cHeight   height in pixels of the cursor
185e07dc26bSmrg * @param  pPixels   pixel data, @see VMMDevReqMousePointer for the format
186e07dc26bSmrg * @param  cbLength  size in bytes of the pixel data
187e07dc26bSmrg */
188e07dc26bSmrgDECLHIDDEN(int)  VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t fFlags,
189e07dc26bSmrg                                             uint32_t cHotX, uint32_t cHotY, uint32_t cWidth, uint32_t cHeight,
190e07dc26bSmrg                                             uint8_t *pPixels, uint32_t cbLength)
191e07dc26bSmrg{
192e07dc26bSmrg    VBVAMOUSEPOINTERSHAPE *p;
193e07dc26bSmrg    uint32_t cbPixels = 0;
194e07dc26bSmrg    int rc;
195e07dc26bSmrg
196e07dc26bSmrg    if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
197e07dc26bSmrg    {
198e07dc26bSmrg        /*
199e07dc26bSmrg         * Size of the pointer data:
200e07dc26bSmrg         * sizeof (AND mask) + sizeof (XOR_MASK)
201e07dc26bSmrg         */
202e07dc26bSmrg        cbPixels = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
203e07dc26bSmrg                 + cWidth * 4 * cHeight;
204e07dc26bSmrg        if (cbPixels > cbLength)
205e07dc26bSmrg            return VERR_INVALID_PARAMETER;
206e07dc26bSmrg        /*
207e07dc26bSmrg         * If shape is supplied, then always create the pointer visible.
208e07dc26bSmrg         * See comments in 'vboxUpdatePointerShape'
209e07dc26bSmrg         */
210e07dc26bSmrg        fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
211e07dc26bSmrg    }
212e07dc26bSmrg    /* Allocate the IO buffer. */
213e07dc26bSmrg    p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p) + cbPixels, HGSMI_CH_VBVA,
214e07dc26bSmrg                                                      VBVA_MOUSE_POINTER_SHAPE);
215e07dc26bSmrg    if (!p)
216e07dc26bSmrg        return VERR_NO_MEMORY;
217e07dc26bSmrg    /* Prepare data to be sent to the host. */
218e07dc26bSmrg    /* Will be updated by the host. */
219e07dc26bSmrg    p->i32Result = VINF_SUCCESS;
220e07dc26bSmrg    /* We have our custom flags in the field */
221e07dc26bSmrg    p->fu32Flags = fFlags;
222e07dc26bSmrg    p->u32HotX   = cHotX;
223e07dc26bSmrg    p->u32HotY   = cHotY;
224e07dc26bSmrg    p->u32Width  = cWidth;
225e07dc26bSmrg    p->u32Height = cHeight;
226e07dc26bSmrg    if (cbPixels)
227e07dc26bSmrg        /* Copy the actual pointer data. */
228e07dc26bSmrg        memcpy (p->au8Data, pPixels, cbPixels);
229e07dc26bSmrg    /* No need to check that the buffer is valid as we have just allocated it. */
230e07dc26bSmrg    VBoxHGSMIBufferSubmit(pCtx, p);
231e07dc26bSmrg    rc = p->i32Result;
232e07dc26bSmrg    /* Free the IO buffer. */
233e07dc26bSmrg    VBoxHGSMIBufferFree(pCtx, p);
234e07dc26bSmrg    return rc;
235e07dc26bSmrg}
236e07dc26bSmrg
237e07dc26bSmrg
238e07dc26bSmrg/**
239e07dc26bSmrg * Report the guest cursor position.  The host may wish to use this information
240e07dc26bSmrg * to re-position its own cursor (though this is currently unlikely).  The
241e07dc26bSmrg * current host cursor position is returned.
242e07dc26bSmrg * @param  pCtx             The context containing the heap used.
243e07dc26bSmrg * @param  fReportPosition  Are we reporting a position?
244e07dc26bSmrg * @param  x                Guest cursor X position.
245e07dc26bSmrg * @param  y                Guest cursor Y position.
246e07dc26bSmrg * @param  pxHost           Host cursor X position is stored here.  Optional.
247e07dc26bSmrg * @param  pyHost           Host cursor Y position is stored here.  Optional.
248e07dc26bSmrg * @returns  iprt status code.
249e07dc26bSmrg * @returns  VERR_NO_MEMORY      HGSMI heap allocation failed.
250e07dc26bSmrg */
251e07dc26bSmrgDECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition,
252e07dc26bSmrg                                        uint32_t x, uint32_t y, uint32_t *pxHost, uint32_t *pyHost)
253e07dc26bSmrg{
254e07dc26bSmrg    VBVACURSORPOSITION *p;
255e07dc26bSmrg
256e07dc26bSmrg    /* Allocate the IO buffer. */
257e07dc26bSmrg    p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_VBVA,
258e07dc26bSmrg                                                   VBVA_CURSOR_POSITION);
259e07dc26bSmrg    if (!p)
260e07dc26bSmrg        return VERR_NO_MEMORY;
261e07dc26bSmrg    /* Prepare data to be sent to the host. */
262e07dc26bSmrg    p->fReportPosition = fReportPosition;
263e07dc26bSmrg    p->x = x;
264e07dc26bSmrg    p->y = y;
265e07dc26bSmrg    /* No need to check that the buffer is valid as we have just allocated it. */
266e07dc26bSmrg    VBoxHGSMIBufferSubmit(pCtx, p);
267e07dc26bSmrg    if (pxHost)
268e07dc26bSmrg        *pxHost = p->x;
269e07dc26bSmrg    if (pyHost)
270e07dc26bSmrg        *pyHost = p->y;
271e07dc26bSmrg    /* Free the IO buffer. */
272e07dc26bSmrg    VBoxHGSMIBufferFree(pCtx, p);
273e07dc26bSmrg    return VINF_SUCCESS;
274e07dc26bSmrg}
275e07dc26bSmrg
276e07dc26bSmrg
277e07dc26bSmrg/**
278e07dc26bSmrg * @todo Mouse pointer position to be read from VMMDev memory, address of the
279e07dc26bSmrg * memory region can be queried from VMMDev via an IOCTL. This VMMDev memory
280e07dc26bSmrg * region will contain host information which is needed by the guest.
281e07dc26bSmrg *
282e07dc26bSmrg * Reading will not cause a switch to the host.
283e07dc26bSmrg *
284e07dc26bSmrg * Have to take into account:
285e07dc26bSmrg *  * synchronization: host must write to the memory only from EMT,
286e07dc26bSmrg *    large structures must be read under flag, which tells the host
287e07dc26bSmrg *    that the guest is currently reading the memory (OWNER flag?).
288e07dc26bSmrg *  * guest writes: may be allocate a page for the host info and make
289e07dc26bSmrg *    the page readonly for the guest.
290e07dc26bSmrg *  * the information should be available only for additions drivers.
291e07dc26bSmrg *  * VMMDev additions driver will inform the host which version of the info
292e07dc26bSmrg *    it expects, host must support all versions.
293e07dc26bSmrg */
294