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