]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - ubuntu/vbox/vboxvideo/HGSMIBase.c
UBUNTU: SAUCE: update vbox
[mirror_ubuntu-artful-kernel.git] / ubuntu / vbox / vboxvideo / HGSMIBase.c
1 /* $Id: HGSMIBase.cpp $ */
2 /** @file
3 * VirtualBox Video driver, common code - HGSMI initialisation and helper
4 * functions.
5 */
6
7 /*
8 * Copyright (C) 2006-2016 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19 #include <VBox/VBoxVideoGuest.h>
20 #include <VBox/VBoxVideo.h>
21 #include <VBox/VBoxGuest.h>
22 #include <VBox/Hardware/VBoxVideoVBE.h>
23 #include <VBox/VMMDev.h>
24
25 #include <iprt/asm.h>
26 #include <iprt/log.h>
27 #include <iprt/string.h>
28
29 /** Send completion notification to the host for the command located at offset
30 * @a offt into the host command buffer. */
31 static void HGSMINotifyHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, HGSMIOFFSET offt)
32 {
33 VBoxVideoCmnPortWriteUlong(pCtx->port, offt);
34 }
35
36
37 /**
38 * Inform the host that a command has been handled.
39 *
40 * @param pCtx the context containing the heap to be used
41 * @param pvMem pointer into the heap as mapped in @a pCtx to the command to
42 * be completed
43 */
44 DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx,
45 void *pvMem)
46 {
47 HGSMIBUFFERHEADER *pHdr = HGSMIBufferHeaderFromData(pvMem);
48 HGSMIOFFSET offMem = HGSMIPointerToOffset(&pCtx->areaCtx, pHdr);
49 Assert(offMem != HGSMIOFFSET_VOID);
50 if(offMem != HGSMIOFFSET_VOID)
51 {
52 HGSMINotifyHostCmdComplete(pCtx, offMem);
53 }
54 }
55
56
57 /** Submit an incoming host command to the appropriate handler. */
58 static void hgsmiHostCmdProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx,
59 HGSMIOFFSET offBuffer)
60 {
61 int rc = HGSMIBufferProcess(&pCtx->areaCtx, &pCtx->channels, offBuffer);
62 Assert(!RT_FAILURE(rc));
63 if(RT_FAILURE(rc))
64 {
65 /* failure means the command was not submitted to the handler for some reason
66 * it's our responsibility to notify its completion in this case */
67 HGSMINotifyHostCmdComplete(pCtx, offBuffer);
68 }
69 /* if the cmd succeeded it's responsibility of the callback to complete it */
70 }
71
72 /** Get the next command from the host. */
73 static HGSMIOFFSET hgsmiGetHostBuffer(PHGSMIHOSTCOMMANDCONTEXT pCtx)
74 {
75 return VBoxVideoCmnPortReadUlong(pCtx->port);
76 }
77
78
79 /** Get and handle the next command from the host. */
80 static void hgsmiHostCommandQueryProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx)
81 {
82 HGSMIOFFSET offset = hgsmiGetHostBuffer(pCtx);
83 AssertReturnVoid(offset != HGSMIOFFSET_VOID);
84 hgsmiHostCmdProcess(pCtx, offset);
85 }
86
87
88 /** Drain the host command queue. */
89 DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx)
90 {
91 while (pCtx->pfHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
92 {
93 if (!ASMAtomicCmpXchgBool(&pCtx->fHostCmdProcessing, true, false))
94 return;
95 hgsmiHostCommandQueryProcess(pCtx);
96 ASMAtomicWriteBool(&pCtx->fHostCmdProcessing, false);
97 }
98 }
99
100
101 /** Detect whether HGSMI is supported by the host. */
102 DECLHIDDEN(bool) VBoxHGSMIIsSupported(void)
103 {
104 uint16_t DispiId;
105
106 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
107 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
108
109 DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
110
111 return (DispiId == VBE_DISPI_ID_HGSMI);
112 }
113
114
115 /**
116 * Allocate and initialise a command descriptor in the guest heap for a
117 * guest-to-host command.
118 *
119 * @returns pointer to the descriptor's command data buffer
120 * @param pCtx the context containing the heap to be used
121 * @param cbData the size of the command data to go into the descriptor
122 * @param u8Ch the HGSMI channel to be used, set to the descriptor
123 * @param u16Op the HGSMI command to be sent, set to the descriptor
124 */
125 DECLHIDDEN(void *) VBoxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx,
126 HGSMISIZE cbData,
127 uint8_t u8Ch,
128 uint16_t u16Op)
129 {
130 #ifdef VBOX_WDDM_MINIPORT
131 return VBoxSHGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
132 #else
133 return HGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
134 #endif
135 }
136
137
138 /**
139 * Free a descriptor allocated by @a VBoxHGSMIBufferAlloc.
140 *
141 * @param pCtx the context containing the heap used
142 * @param pvBuffer the pointer returned by @a VBoxHGSMIBufferAlloc
143 */
144 DECLHIDDEN(void) VBoxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx,
145 void *pvBuffer)
146 {
147 #ifdef VBOX_WDDM_MINIPORT
148 VBoxSHGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
149 #else
150 HGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
151 #endif
152 }
153
154
155 /**
156 * Submit a command descriptor allocated by @a VBoxHGSMIBufferAlloc.
157 *
158 * @param pCtx the context containing the heap used
159 * @param pvBuffer the pointer returned by @a VBoxHGSMIBufferAlloc
160 */
161 DECLHIDDEN(int) VBoxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx,
162 void *pvBuffer)
163 {
164 /* Initialize the buffer and get the offset for port IO. */
165 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (HGSMIGUESTCMDHEAP_GET(&pCtx->heapCtx), pvBuffer);
166
167 Assert(offBuffer != HGSMIOFFSET_VOID);
168 if (offBuffer != HGSMIOFFSET_VOID)
169 {
170 /* Submit the buffer to the host. */
171 VBoxVideoCmnPortWriteUlong(pCtx->port, offBuffer);
172 /* Make the compiler aware that the host has changed memory. */
173 ASMCompilerBarrier();
174 return VINF_SUCCESS;
175 }
176
177 return VERR_INVALID_PARAMETER;
178 }
179
180
181 /** Inform the host of the location of the host flags in VRAM via an HGSMI
182 * command. */
183 static int vboxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
184 HGSMIOFFSET offLocation)
185 {
186 HGSMIBUFFERLOCATION *p;
187 int rc = VINF_SUCCESS;
188
189 /* Allocate the IO buffer. */
190 p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx,
191 sizeof(HGSMIBUFFERLOCATION),
192 HGSMI_CH_HGSMI,
193 HGSMI_CC_HOST_FLAGS_LOCATION);
194 if (p)
195 {
196 /* Prepare data to be sent to the host. */
197 p->offLocation = offLocation;
198 p->cbLocation = sizeof(HGSMIHOSTFLAGS);
199 rc = VBoxHGSMIBufferSubmit(pCtx, p);
200 /* Free the IO buffer. */
201 VBoxHGSMIBufferFree(pCtx, p);
202 }
203 else
204 rc = VERR_NO_MEMORY;
205 return rc;
206 }
207
208
209 /**
210 * Inform the host of the location of the host flags in VRAM via an HGSMI
211 * command.
212 * @returns IPRT status value.
213 * @returns VERR_NOT_IMPLEMENTED if the host does not support the command.
214 * @returns VERR_NO_MEMORY if a heap allocation fails.
215 * @param pCtx the context of the guest heap to use.
216 * @param offLocation the offset chosen for the flags withing guest
217 * VRAM.
218 */
219 DECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
220 HGSMIOFFSET offLocation)
221 {
222 return vboxHGSMIReportFlagsLocation(pCtx, offLocation);
223 }
224
225
226 /** Notify the host of HGSMI-related guest capabilities via an HGSMI command.
227 */
228 static int vboxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
229 uint32_t fCaps)
230 {
231 VBVACAPS *pCaps;
232 int rc = VINF_SUCCESS;
233
234 /* Allocate the IO buffer. */
235 pCaps = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx,
236 sizeof(VBVACAPS), HGSMI_CH_VBVA,
237 VBVA_INFO_CAPS);
238
239 if (pCaps)
240 {
241 /* Prepare data to be sent to the host. */
242 pCaps->rc = VERR_NOT_IMPLEMENTED;
243 pCaps->fCaps = fCaps;
244 rc = VBoxHGSMIBufferSubmit(pCtx, pCaps);
245 if (RT_SUCCESS(rc))
246 {
247 AssertRC(pCaps->rc);
248 rc = pCaps->rc;
249 }
250 /* Free the IO buffer. */
251 VBoxHGSMIBufferFree(pCtx, pCaps);
252 }
253 else
254 rc = VERR_NO_MEMORY;
255 return rc;
256 }
257
258
259 /**
260 * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
261 * @returns IPRT status value.
262 * @returns VERR_NOT_IMPLEMENTED if the host does not support the command.
263 * @returns VERR_NO_MEMORY if a heap allocation fails.
264 * @param pCtx the context of the guest heap to use.
265 * @param fCaps the capabilities to report, see VBVACAPS.
266 */
267 DECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
268 uint32_t fCaps)
269 {
270 return vboxHGSMISendCapsInfo(pCtx, fCaps);
271 }
272
273
274 /** Tell the host about the location of the area of VRAM set aside for the host
275 * heap. */
276 static int vboxHGSMIReportHostArea(PHGSMIGUESTCOMMANDCONTEXT pCtx,
277 uint32_t u32AreaOffset, uint32_t u32AreaSize)
278 {
279 VBVAINFOHEAP *p;
280 int rc = VINF_SUCCESS;
281
282 /* Allocate the IO buffer. */
283 p = (VBVAINFOHEAP *)VBoxHGSMIBufferAlloc(pCtx,
284 sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA,
285 VBVA_INFO_HEAP);
286 if (p)
287 {
288 /* Prepare data to be sent to the host. */
289 p->u32HeapOffset = u32AreaOffset;
290 p->u32HeapSize = u32AreaSize;
291 rc = VBoxHGSMIBufferSubmit(pCtx, p);
292 /* Free the IO buffer. */
293 VBoxHGSMIBufferFree(pCtx, p);
294 }
295 else
296 rc = VERR_NO_MEMORY;
297 return rc;
298 }
299
300
301 /**
302 * Get the information needed to map the basic communication structures in
303 * device memory into our address space. All pointer parameters are optional.
304 *
305 * @param cbVRAM how much video RAM is allocated to the device
306 * @param poffVRAMBaseMapping where to save the offset from the start of the
307 * device VRAM of the whole area to map
308 * @param pcbMapping where to save the mapping size
309 * @param poffGuestHeapMemory where to save the offset into the mapped area
310 * of the guest heap backing memory
311 * @param pcbGuestHeapMemory where to save the size of the guest heap
312 * backing memory
313 * @param poffHostFlags where to save the offset into the mapped area
314 * of the host flags
315 */
316 DECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM,
317 uint32_t *poffVRAMBaseMapping,
318 uint32_t *pcbMapping,
319 uint32_t *poffGuestHeapMemory,
320 uint32_t *pcbGuestHeapMemory,
321 uint32_t *poffHostFlags)
322 {
323 AssertPtrNullReturnVoid(poffVRAMBaseMapping);
324 AssertPtrNullReturnVoid(pcbMapping);
325 AssertPtrNullReturnVoid(poffGuestHeapMemory);
326 AssertPtrNullReturnVoid(pcbGuestHeapMemory);
327 AssertPtrNullReturnVoid(poffHostFlags);
328 if (poffVRAMBaseMapping)
329 *poffVRAMBaseMapping = cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE;
330 if (pcbMapping)
331 *pcbMapping = VBVA_ADAPTER_INFORMATION_SIZE;
332 if (poffGuestHeapMemory)
333 *poffGuestHeapMemory = 0;
334 if (pcbGuestHeapMemory)
335 *pcbGuestHeapMemory = VBVA_ADAPTER_INFORMATION_SIZE
336 - sizeof(HGSMIHOSTFLAGS);
337 if (poffHostFlags)
338 *poffHostFlags = VBVA_ADAPTER_INFORMATION_SIZE
339 - sizeof(HGSMIHOSTFLAGS);
340 }
341
342
343 /**
344 * Set up the HGSMI guest-to-host command context.
345 * @returns iprt status value
346 * @param pCtx the context to set up
347 * @param pvGuestHeapMemory a pointer to the mapped backing memory for
348 * the guest heap
349 * @param cbGuestHeapMemory the size of the backing memory area
350 * @param offVRAMGuestHeapMemory the offset of the memory pointed to by
351 * @a pvGuestHeapMemory within the video RAM
352 */
353 DECLHIDDEN(int) VBoxHGSMISetupGuestContext(PHGSMIGUESTCOMMANDCONTEXT pCtx,
354 void *pvGuestHeapMemory,
355 uint32_t cbGuestHeapMemory,
356 uint32_t offVRAMGuestHeapMemory,
357 const HGSMIENV *pEnv)
358 {
359 /** @todo should we be using a fixed ISA port value here? */
360 pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
361 #ifdef VBOX_WDDM_MINIPORT
362 return VBoxSHGSMIInit(&pCtx->heapCtx, pvGuestHeapMemory,
363 cbGuestHeapMemory, offVRAMGuestHeapMemory, pEnv);
364 #else
365 return HGSMIHeapSetup(&pCtx->heapCtx, pvGuestHeapMemory,
366 cbGuestHeapMemory, offVRAMGuestHeapMemory, pEnv);
367 #endif
368 }
369
370
371 /**
372 * Get the information needed to map the area used by the host to send back
373 * requests.
374 *
375 * @param pCtx the context containing the heap to use
376 * @param cbVRAM how much video RAM is allocated to the device
377 * @param offVRAMBaseMapping the offset of the basic communication structures
378 * into the guest's VRAM
379 * @param poffVRAMHostArea where to store the offset into VRAM of the host
380 * heap area
381 * @param pcbHostArea where to store the size of the host heap area
382 */
383 DECLHIDDEN(void) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx,
384 uint32_t cbVRAM,
385 uint32_t offVRAMBaseMapping,
386 uint32_t *poffVRAMHostArea,
387 uint32_t *pcbHostArea)
388 {
389 uint32_t offVRAMHostArea = offVRAMBaseMapping, cbHostArea = 0;
390
391 AssertPtrReturnVoid(poffVRAMHostArea);
392 AssertPtrReturnVoid(pcbHostArea);
393 VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbHostArea);
394 if (cbHostArea != 0)
395 {
396 uint32_t cbHostAreaMaxSize = cbVRAM / 4;
397 /** @todo what is the idea of this? */
398 if (cbHostAreaMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
399 {
400 cbHostAreaMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
401 }
402 if (cbHostArea > cbHostAreaMaxSize)
403 {
404 cbHostArea = cbHostAreaMaxSize;
405 }
406 /* Round up to 4096 bytes. */
407 cbHostArea = (cbHostArea + 0xFFF) & ~0xFFF;
408 offVRAMHostArea = offVRAMBaseMapping - cbHostArea;
409 }
410
411 *pcbHostArea = cbHostArea;
412 *poffVRAMHostArea = offVRAMHostArea;
413 LogFunc(("offVRAMHostArea = 0x%08X, cbHostArea = 0x%08X\n",
414 offVRAMHostArea, cbHostArea));
415 }
416
417
418 /**
419 * Initialise the host context structure.
420 *
421 * @param pCtx the context structure to initialise
422 * @param pvBaseMapping where the basic HGSMI structures are mapped at
423 * @param offHostFlags the offset of the host flags into the basic HGSMI
424 * structures
425 * @param pvHostAreaMapping where the area for the host heap is mapped at
426 * @param offVRAMHostArea offset of the host heap area into VRAM
427 * @param cbHostArea size in bytes of the host heap area
428 */
429 DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx,
430 void *pvBaseMapping,
431 uint32_t offHostFlags,
432 void *pvHostAreaMapping,
433 uint32_t offVRAMHostArea,
434 uint32_t cbHostArea)
435 {
436 uint8_t *pu8HostFlags = ((uint8_t *)pvBaseMapping) + offHostFlags;
437 pCtx->pfHostFlags = (HGSMIHOSTFLAGS *)pu8HostFlags;
438 /** @todo should we really be using a fixed ISA port value here? */
439 pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_HOST;
440 HGSMIAreaInitialize(&pCtx->areaCtx, pvHostAreaMapping, cbHostArea,
441 offVRAMHostArea);
442 }
443
444
445 /**
446 * Tell the host about the ways it can use to communicate back to us via an
447 * HGSMI command
448 *
449 * @returns iprt status value
450 * @param pCtx the context containing the heap to use
451 * @param offVRAMFlagsLocation where we wish the host to place its flags
452 * relative to the start of the VRAM
453 * @param fCaps additions HGSMI capabilities the guest
454 * supports
455 * @param offVRAMHostArea offset into VRAM of the host heap area
456 * @param cbHostArea size in bytes of the host heap area
457 */
458 DECLHIDDEN(int) VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
459 HGSMIOFFSET offVRAMFlagsLocation,
460 uint32_t fCaps,
461 uint32_t offVRAMHostArea,
462 uint32_t cbHostArea)
463 {
464 Log(("VBoxVideo::vboxSetupAdapterInfo\n"));
465
466 /* setup the flags first to ensure they are initialized by the time the
467 * host heap is ready */
468 int rc = vboxHGSMIReportFlagsLocation(pCtx, offVRAMFlagsLocation);
469 AssertRC(rc);
470 if (RT_SUCCESS(rc) && fCaps)
471 {
472 /* Inform about caps */
473 rc = vboxHGSMISendCapsInfo(pCtx, fCaps);
474 AssertRC(rc);
475 }
476 if (RT_SUCCESS (rc))
477 {
478 /* Report the host heap location. */
479 rc = vboxHGSMIReportHostArea(pCtx, offVRAMHostArea, cbHostArea);
480 AssertRC(rc);
481 }
482 Log(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
483 return rc;
484 }
485
486
487 /** Sanity test on first call. We do not worry about concurrency issues. */
488 static int testQueryConf(PHGSMIGUESTCOMMANDCONTEXT pCtx)
489 {
490 static bool cOnce = false;
491 uint32_t ulValue = 0;
492 int rc;
493
494 if (cOnce)
495 return VINF_SUCCESS;
496 cOnce = true;
497 rc = VBoxQueryConfHGSMI(pCtx, UINT32_MAX, &ulValue);
498 if (RT_SUCCESS(rc) && ulValue == UINT32_MAX)
499 return VINF_SUCCESS;
500 cOnce = false;
501 if (RT_FAILURE(rc))
502 return rc;
503 return VERR_INTERNAL_ERROR;
504 }
505
506
507 /**
508 * Query the host for an HGSMI configuration parameter via an HGSMI command.
509 * @returns iprt status value
510 * @param pCtx the context containing the heap used
511 * @param u32Index the index of the parameter to query,
512 * @see VBVACONF32::u32Index
513 * @param u32DefValue defaut value
514 * @param pulValue where to store the value of the parameter on success
515 */
516 DECLHIDDEN(int) VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx,
517 uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue)
518 {
519 int rc = VINF_SUCCESS;
520 VBVACONF32 *p;
521 LogFunc(("u32Index = %d\n", u32Index));
522
523 rc = testQueryConf(pCtx);
524 if (RT_FAILURE(rc))
525 return rc;
526 /* Allocate the IO buffer. */
527 p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx,
528 sizeof(VBVACONF32), HGSMI_CH_VBVA,
529 VBVA_QUERY_CONF32);
530 if (p)
531 {
532 /* Prepare data to be sent to the host. */
533 p->u32Index = u32Index;
534 p->u32Value = u32DefValue;
535 rc = VBoxHGSMIBufferSubmit(pCtx, p);
536 if (RT_SUCCESS(rc))
537 {
538 *pulValue = p->u32Value;
539 LogFunc(("u32Value = %d\n", p->u32Value));
540 }
541 /* Free the IO buffer. */
542 VBoxHGSMIBufferFree(pCtx, p);
543 }
544 else
545 rc = VERR_NO_MEMORY;
546 LogFunc(("rc = %d\n", rc));
547 return rc;
548 }
549
550 DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
551 uint32_t u32Index, uint32_t *pulValue)
552 {
553 return VBoxQueryConfHGSMIDef(pCtx, u32Index, UINT32_MAX, pulValue);
554 }
555
556 /**
557 * Pass the host a new mouse pointer shape via an HGSMI command.
558 *
559 * @returns success or failure
560 * @param fFlags cursor flags, @see VMMDevReqMousePointer::fFlags
561 * @param cHotX horizontal position of the hot spot
562 * @param cHotY vertical position of the hot spot
563 * @param cWidth width in pixels of the cursor
564 * @param cHeight height in pixels of the cursor
565 * @param pPixels pixel data, @see VMMDevReqMousePointer for the format
566 * @param cbLength size in bytes of the pixel data
567 */
568 DECLHIDDEN(int) VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx,
569 uint32_t fFlags,
570 uint32_t cHotX,
571 uint32_t cHotY,
572 uint32_t cWidth,
573 uint32_t cHeight,
574 uint8_t *pPixels,
575 uint32_t cbLength)
576 {
577 VBVAMOUSEPOINTERSHAPE *p;
578 uint32_t cbData = 0;
579 int rc = VINF_SUCCESS;
580
581 if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
582 {
583 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
584 cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
585 + cWidth * 4 * cHeight;
586 /* If shape is supplied, then always create the pointer visible.
587 * See comments in 'vboxUpdatePointerShape'
588 */
589 fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
590 }
591 LogFlowFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight));
592 if (cbData > cbLength)
593 {
594 LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n",
595 cbData, cbLength));
596 return VERR_INVALID_PARAMETER;
597 }
598 /* Allocate the IO buffer. */
599 p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx,
600 sizeof(VBVAMOUSEPOINTERSHAPE)
601 + cbData,
602 HGSMI_CH_VBVA,
603 VBVA_MOUSE_POINTER_SHAPE);
604 if (p)
605 {
606 /* Prepare data to be sent to the host. */
607 /* Will be updated by the host. */
608 p->i32Result = VINF_SUCCESS;
609 /* We have our custom flags in the field */
610 p->fu32Flags = fFlags;
611 p->u32HotX = cHotX;
612 p->u32HotY = cHotY;
613 p->u32Width = cWidth;
614 p->u32Height = cHeight;
615 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
616 /* Copy the actual pointer data. */
617 memcpy (p->au8Data, pPixels, cbData);
618 rc = VBoxHGSMIBufferSubmit(pCtx, p);
619 if (RT_SUCCESS(rc))
620 rc = p->i32Result;
621 /* Free the IO buffer. */
622 VBoxHGSMIBufferFree(pCtx, p);
623 }
624 else
625 rc = VERR_NO_MEMORY;
626 LogFlowFunc(("rc %d\n", rc));
627 return rc;
628 }
629
630
631 /**
632 * Report the guest cursor position. The host may wish to use this information
633 * to re-position its own cursor (though this is currently unlikely). The
634 * current host cursor position is returned.
635 * @param pCtx The context containing the heap used.
636 * @param fReportPosition Are we reporting a position?
637 * @param x Guest cursor X position.
638 * @param y Guest cursor Y position.
639 * @param pxHost Host cursor X position is stored here. Optional.
640 * @param pyHost Host cursor Y position is stored here. Optional.
641 * @returns iprt status code.
642 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
643 */
644 DECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y,
645 uint32_t *pxHost, uint32_t *pyHost)
646 {
647 int rc = VINF_SUCCESS;
648 VBVACURSORPOSITION *p;
649 Log(("%s: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));
650
651 /* Allocate the IO buffer. */
652 p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACURSORPOSITION), HGSMI_CH_VBVA, VBVA_CURSOR_POSITION);
653 if (p)
654 {
655 /* Prepare data to be sent to the host. */
656 p->fReportPosition = fReportPosition ? 1 : 0;
657 p->x = x;
658 p->y = y;
659 rc = VBoxHGSMIBufferSubmit(pCtx, p);
660 if (RT_SUCCESS(rc))
661 {
662 if (pxHost)
663 *pxHost = p->x;
664 if (pyHost)
665 *pyHost = p->y;
666 Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)p->x, (unsigned)p->y));
667 }
668 /* Free the IO buffer. */
669 VBoxHGSMIBufferFree(pCtx, p);
670 }
671 else
672 rc = VERR_NO_MEMORY;
673 LogFunc(("rc = %d\n", rc));
674 return rc;
675 }
676
677
678 /** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
679 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
680 * host information which is needed by the guest.
681 *
682 * Reading will not cause a switch to the host.
683 *
684 * Have to take into account:
685 * * synchronization: host must write to the memory only from EMT,
686 * large structures must be read under flag, which tells the host
687 * that the guest is currently reading the memory (OWNER flag?).
688 * * guest writes: may be allocate a page for the host info and make
689 * the page readonly for the guest.
690 * * the information should be available only for additions drivers.
691 * * VMMDev additions driver will inform the host which version of the info it expects,
692 * host must support all versions.
693 *
694 */