summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp
blob: 5cc7d6a07fbc73123529a9bdf53dc1f73def36ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/* $Id: HGSMIBase.cpp $ */
/** @file
 * VirtualBox Video driver, common code - HGSMI guest-to-host communication.
 */

/*
 * Copyright (C) 2006-2019 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 AUTHORS OR COPYRIGHT
 * HOLDERS 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 <HGSMIBase.h>
#include <VBoxVideoIPRT.h>
#include <VBoxVideoGuest.h>
#include <VBoxVideoVBE.h>
#include <HGSMIChannels.h>
#include <HGSMIChSetup.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)
{

    /* Allocate the IO buffer. */
    HGSMIBUFFERLOCATION RT_UNTRUSTED_VOLATILE_HOST *p =
        (HGSMIBUFFERLOCATION RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_HGSMI,
                                                                               HGSMI_CC_HOST_FLAGS_LOCATION);
    if (!p)
        return VERR_NO_MEMORY;

    /* Prepare data to be sent to the host. */
    p->offLocation = offLocation;
    p->cbLocation  = sizeof(HGSMIHOSTFLAGS);
    /* No need to check that the buffer is valid as we have just allocated it. */
    VBoxHGSMIBufferSubmit(pCtx, p);
    /* Free the IO buffer. */
    VBoxHGSMIBufferFree(pCtx, p);

    return VINF_SUCCESS;
}


/**
 * 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)
{

    /* Allocate the IO buffer. */
    VBVACAPS RT_UNTRUSTED_VOLATILE_HOST *p =
        (VBVACAPS RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS);

    if (!p)
        return VERR_NO_MEMORY;

    /* Prepare data to be sent to the host. */
    p->rc    = VERR_NOT_IMPLEMENTED;
    p->fCaps = fCaps;
    /* No need to check that the buffer is valid as we have just allocated it. */
    VBoxHGSMIBufferSubmit(pCtx, p);

    AssertRC(p->rc);
    /* Free the IO buffer. */
    VBoxHGSMIBufferFree(pCtx, p);
    return p->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);
}

/**
 * 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  pulValue  where to store the value of the parameter on success
 */
DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32Index, uint32_t *pulValue)
{
    VBVACONF32 *p;

    /* Allocate the IO buffer. */
    p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_VBVA, VBVA_QUERY_CONF32);
    if (!p)
        return VERR_NO_MEMORY;

    /* Prepare data to be sent to the host. */
    p->u32Index = u32Index;
    p->u32Value = UINT32_MAX;
    /* No need to check that the buffer is valid as we have just allocated it. */
    VBoxHGSMIBufferSubmit(pCtx, p);
    *pulValue = p->u32Value;
    /* Free the IO buffer. */
    VBoxHGSMIBufferFree(pCtx, p);
    return VINF_SUCCESS;
}

/**
 * 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 cbPixels = 0;
    int rc;

    if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
    {
        /*
         * Size of the pointer data:
         * sizeof (AND mask) + sizeof (XOR_MASK)
         */
        cbPixels = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
                 + cWidth * 4 * cHeight;
        if (cbPixels > cbLength)
            return VERR_INVALID_PARAMETER;
        /*
         * If shape is supplied, then always create the pointer visible.
         * See comments in 'vboxUpdatePointerShape'
         */
        fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
    }
    /* Allocate the IO buffer. */
    p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p) + cbPixels, HGSMI_CH_VBVA,
                                                      VBVA_MOUSE_POINTER_SHAPE);
    if (!p)
        return VERR_NO_MEMORY;
    /* 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 (cbPixels)
        /* Copy the actual pointer data. */
        memcpy (p->au8Data, pPixels, cbPixels);
    /* No need to check that the buffer is valid as we have just allocated it. */
    VBoxHGSMIBufferSubmit(pCtx, p);
    rc = p->i32Result;
    /* Free the IO buffer. */
    VBoxHGSMIBufferFree(pCtx, p);
    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)
{
    VBVACURSORPOSITION *p;

    /* Allocate the IO buffer. */
    p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(*p), HGSMI_CH_VBVA,
                                                   VBVA_CURSOR_POSITION);
    if (!p)
        return VERR_NO_MEMORY;
    /* Prepare data to be sent to the host. */
    p->fReportPosition = fReportPosition;
    p->x = x;
    p->y = y;
    /* No need to check that the buffer is valid as we have just allocated it. */
    VBoxHGSMIBufferSubmit(pCtx, p);
    if (pxHost)
        *pxHost = p->x;
    if (pyHost)
        *pyHost = p->y;
    /* Free the IO buffer. */
    VBoxHGSMIBufferFree(pCtx, p);
    return VINF_SUCCESS;
}


/**
 * @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.
 */