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