/** * Get most recent video mode hints. * @param pCtx the context containing the heap to use * @param cScreens the number of screens to query hints for, starting at 0. * @param pHints array of VBVAMODEHINT structures for receiving the hints. * @returns iprt status code * @returns VERR_NO_MEMORY HGSMI heap allocation failed. * @returns VERR_NOT_SUPPORTED Host does not support this command. */ RTDECL(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx, unsigned cScreens, VBVAMODEHINT *paHints) { int rc; AssertPtrReturn(paHints, VERR_INVALID_POINTER); void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAQUERYMODEHINTS) + cScreens * sizeof(VBVAMODEHINT), HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS); if (!p) { LogFunc(("HGSMIHeapAlloc failed\n")); return VERR_NO_MEMORY; } else { VBVAQUERYMODEHINTS *pQuery = (VBVAQUERYMODEHINTS *)p; pQuery->cHintsQueried = cScreens; pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT); pQuery->rc = VERR_NOT_SUPPORTED; VBoxHGSMIBufferSubmit(pCtx, p); rc = pQuery->rc; if (RT_SUCCESS(rc)) memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS), cScreens * sizeof(VBVAMODEHINT)); VBoxHGSMIBufferFree(pCtx, p); } return rc; }
/** * 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 */ RTDECL(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32Index, uint32_t *pulValue) { int rc = VINF_SUCCESS; VBVACONF32 *p; LogFunc(("u32Index = %d\n", u32Index)); /* Allocate the IO buffer. */ p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACONF32), HGSMI_CH_VBVA, VBVA_QUERY_CONF32); if (p) { /* Prepare data to be sent to the host. */ p->u32Index = u32Index; p->u32Value = 0; rc = VBoxHGSMIBufferSubmit(pCtx, p); if (RT_SUCCESS(rc)) { *pulValue = p->u32Value; LogFunc(("u32Value = %d\n", p->u32Value)); } /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; LogFunc(("rc = %d\n", rc)); return rc; }
void VBoxCmdVbvaSubmitUnlock(PVBOXMP_DEVEXT pDevExt, VBOXCMDVBVA *pVbva, VBOXCMDVBVA_HDR* pCmd, uint32_t u32FenceID) { if (u32FenceID) pVbva->u32FenceSubmitted = u32FenceID; else WARN(("no cmd fence specified")); pCmd->u8State = VBOXCMDVBVA_STATE_SUBMITTED; pCmd->u2.u32FenceID = u32FenceID; VBoxVBVAExBufferEndUpdate(&pVbva->Vbva); if (!VBoxVBVAExIsProcessing(&pVbva->Vbva)) { /* Issue the submit command. */ HGSMIGUESTCOMMANDCONTEXT *pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx; VBVACMDVBVASUBMIT *pSubmit = (VBVACMDVBVASUBMIT*)VBoxHGSMIBufferAlloc(pCtx, sizeof (VBVACMDVBVASUBMIT), HGSMI_CH_VBVA, VBVA_CMDVBVA_SUBMIT); if (!pSubmit) { WARN(("VBoxHGSMIBufferAlloc failed\n")); return; } pSubmit->u32Reserved = 0; VBoxHGSMIBufferSubmit(pCtx, pSubmit); VBoxHGSMIBufferFree(pCtx, pSubmit); } }
/** Notify the host of HGSMI-related guest capabilities via an HGSMI command. */ static int vboxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t fCaps) { VBVACAPS *pCaps; int rc = VINF_SUCCESS; /* Allocate the IO buffer. */ pCaps = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACAPS), HGSMI_CH_VBVA, VBVA_INFO_CAPS); if (pCaps) { /* Prepare data to be sent to the host. */ pCaps->rc = VERR_NOT_IMPLEMENTED; pCaps->fCaps = fCaps; rc = VBoxHGSMIBufferSubmit(pCtx, pCaps); if (RT_SUCCESS(rc)) { AssertRC(pCaps->rc); rc = pCaps->rc; } /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, pCaps); } else rc = VERR_NO_MEMORY; 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. */ RTDECL(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y, uint32_t *pxHost, uint32_t *pyHost) { int rc = VINF_SUCCESS; VBVACURSORPOSITION *p; Log(("%s: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y)); /* Allocate the IO buffer. */ p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACURSORPOSITION), HGSMI_CH_VBVA, VBVA_CURSOR_POSITION); if (p) { /* Prepare data to be sent to the host. */ p->fReportPosition = fReportPosition ? 1 : 0; p->x = x; p->y = y; rc = VBoxHGSMIBufferSubmit(pCtx, p); if (RT_SUCCESS(rc)) { if (pxHost) *pxHost = p->x; if (pyHost) *pyHost = p->y; Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y)); } /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; LogFunc(("rc = %d\n", rc)); return rc; }
static void vboxHwBufferFlush (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO *pVbva) { /* Issue the flush command. */ void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, sizeof (VBVAFLUSH), HGSMI_CH_VBVA, VBVA_FLUSH); Assert(p); if (!p) { LOGREL(("HGSMIHeapAlloc failed")); } else { VBVAFLUSH *pFlush = (VBVAFLUSH *)p; pFlush->u32Reserved = 0; VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); VBoxHGSMIBufferFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); } return; }
static int vbox_set_view(struct drm_crtc *crtc) { struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc); struct vbox_private *vbox = crtc->dev->dev_private; void *p; LogFunc(("vboxvideo: %d: vbox_crtc=%p\n", __LINE__, vbox_crtc)); /* Tell the host about the view. This design originally targeted the * Windows XP driver architecture and assumed that each screen would have * a dedicated frame buffer with the command buffer following it, the whole * being a "view". The host works out which screen a command buffer belongs * to by checking whether it is in the first view, then whether it is in the * second and so on. The first match wins. We cheat around this by making * the first view be the managed memory plus the first command buffer, the * second the same plus the second buffer and so on. */ p = VBoxHGSMIBufferAlloc(&vbox->Ctx, sizeof(VBVAINFOVIEW), HGSMI_CH_VBVA, VBVA_INFO_VIEW); if (p) { VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p; pInfo->u32ViewIndex = vbox_crtc->crtc_id; pInfo->u32ViewOffset = vbox_crtc->offFB; pInfo->u32ViewSize = vbox->vram_size - vbox_crtc->offFB + vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE; pInfo->u32MaxScreenSize = vbox->vram_size - vbox_crtc->offFB; VBoxHGSMIBufferSubmit(&vbox->Ctx, p); VBoxHGSMIBufferFree(&vbox->Ctx, p); } else return -ENOMEM; LogFunc(("vboxvideo: %d: p=%p\n", __LINE__, p)); return 0; }
/** Report the rectangle relative to which absolute pointer events should be * expressed. This information remains valid until the next VBVA resize event * for any screen, at which time it is reset to the bounding rectangle of all * virtual screens. * @param pCtx The context containing the heap to use. * @param cOriginX Upper left X co-ordinate relative to the first screen. * @param cOriginY Upper left Y co-ordinate relative to the first screen. * @param cWidth Rectangle width. * @param cHeight Rectangle height. * @returns iprt status code. * @returns VERR_NO_MEMORY HGSMI heap allocation failed. */ RTDECL(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY, uint32_t cWidth, uint32_t cHeight) { int rc = VINF_SUCCESS; VBVAREPORTINPUTMAPPING *p; Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX, (unsigned)cWidth, (unsigned)cHeight)); /* Allocate the IO buffer. */ p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA, VBVA_REPORT_INPUT_MAPPING); if (p) { /* Prepare data to be sent to the host. */ p->x = cOriginX; p->y = cOriginY; p->cx = cWidth; p->cy = cHeight; rc = VBoxHGSMIBufferSubmit(pCtx, p); /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; LogFunc(("rc = %d\n", rc)); return rc; }
DECLINLINE(void) vbvaVhwaCommandRelease(PVBOXMP_DEVEXT pDevExt, VBOXVHWACMD* pCmd) { uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs); Assert(cRefs < UINT32_MAX / 2); if(!cRefs) { VBoxHGSMIBufferFree(&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, pCmd); } }
static bool vboxVBVAInformHost(PVBVABUFFERCONTEXT pCtx, PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, int32_t cScreen, bool bEnable) { bool bRc = false; #if 0 /* All callers check this */ if (ppdev->bHGSMISupported) #endif { void *p = VBoxHGSMIBufferAlloc(pHGSMICtx, sizeof (VBVAENABLE_EX), HGSMI_CH_VBVA, VBVA_ENABLE); if (!p) { LogFunc(("HGSMIHeapAlloc failed\n")); } else { VBVAENABLE_EX *pEnable = (VBVAENABLE_EX *)p; pEnable->Base.u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE; pEnable->Base.u32Offset = pCtx->offVRAMBuffer; pEnable->Base.i32Result = VERR_NOT_SUPPORTED; if (cScreen >= 0) { pEnable->Base.u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET; pEnable->u32ScreenId = cScreen; } VBoxHGSMIBufferSubmit(pHGSMICtx, p); if (bEnable) { bRc = RT_SUCCESS(pEnable->Base.i32Result); } else { bRc = true; } VBoxHGSMIBufferFree(pHGSMICtx, p); } } return bRc; }
/** * Tell the host about how VRAM is divided up between each screen via an HGSMI * command. It is acceptable to specifiy identical data for each screen if * they share a single framebuffer. * * @returns iprt status code, either VERR_NO_MEMORY or the status returned by * @a pfnFill * @todo What was I thinking of with that callback function? It * would be much simpler to just pass in a structure in normal * memory and copy it. * @param pCtx the context containing the heap to use * @param u32Count the number of screens we are activating * @param pfnFill a callback which initialises the VBVAINFOVIEW structures * for all screens * @param pvData context data for @a pfnFill */ RTDECL(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32Count, PFNHGSMIFILLVIEWINFO pfnFill, void *pvData) { int rc; /* Issue the screen info command. */ void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count, HGSMI_CH_VBVA, VBVA_INFO_VIEW); if (p) { VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p; rc = pfnFill(pvData, pInfo, u32Count); if (RT_SUCCESS(rc)) VBoxHGSMIBufferSubmit (pCtx, p); VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; return rc; }
static int vboxCmdVbvaFlush(PVBOXMP_DEVEXT pDevExt, HGSMIGUESTCOMMANDCONTEXT *pCtx, bool fBufferOverflow) { /* Issue the flush command. */ VBVACMDVBVAFLUSH *pFlush = (VBVACMDVBVAFLUSH*)VBoxHGSMIBufferAlloc(pCtx, sizeof (VBVACMDVBVAFLUSH), HGSMI_CH_VBVA, VBVA_CMDVBVA_FLUSH); if (!pFlush) { WARN(("VBoxHGSMIBufferAlloc failed\n")); return VERR_OUT_OF_RESOURCES; } pFlush->u32Flags = fBufferOverflow ? VBVACMDVBVAFLUSH_F_GUEST_BUFFER_OVERFLOW : 0; VBoxHGSMIBufferSubmit(pCtx, pFlush); VBoxHGSMIBufferFree(pCtx, pFlush); return VINF_SUCCESS; }
/** * Set a video mode via an HGSMI request. The views must have been * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being * set on the first display then it must be set first using registers. * @param cDisplay the screen number * @param cOriginX the horizontal displacement relative to the first screen * @param cOriginY the vertical displacement relative to the first screen * @param offStart the offset of the visible area of the framebuffer * relative to the framebuffer start * @param cbPitch the offset in bytes between the starts of two adjecent * scan lines in video RAM * @param cWidth the mode width * @param cHeight the mode height * @param cBPP the colour depth of the mode */ RTDECL(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t cDisplay, int32_t cOriginX, int32_t cOriginY, uint32_t offStart, uint32_t cbPitch, uint32_t cWidth, uint32_t cHeight, uint16_t cBPP, uint16_t fFlags) { /* Issue the screen info command. */ void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof (VBVAINFOSCREEN), HGSMI_CH_VBVA, VBVA_INFO_SCREEN); if (!p) { LogFunc(("HGSMIHeapAlloc failed\n")); } else { VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p; pScreen->u32ViewIndex = cDisplay; pScreen->i32OriginX = cOriginX; pScreen->i32OriginY = cOriginY; pScreen->u32StartOffset = offStart; pScreen->u32LineSize = cbPitch; pScreen->u32Width = cWidth; pScreen->u32Height = cHeight; pScreen->u16BitsPerPixel = cBPP; pScreen->u16Flags = fFlags; VBoxHGSMIBufferSubmit(pCtx, p); VBoxHGSMIBufferFree(pCtx, p); } }
static int vboxVBVAInformHost (PVBOXMP_DEVEXT pDevExt, VBOXVBVAINFO * pVbva, BOOL bEnable) { int rc = VERR_NO_MEMORY; void *p = VBoxHGSMIBufferAlloc (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, sizeof (VBVAENABLE_EX), HGSMI_CH_VBVA, VBVA_ENABLE); Assert(p); if (!p) { LOGREL(("HGSMIHeapAlloc failed")); rc = VERR_NO_MEMORY; } else { VBVAENABLE_EX *pEnableEx = (VBVAENABLE_EX *)p; pEnableEx->u32ScreenId = pVbva->srcId; VBVAENABLE *pEnable = &pEnableEx->Base; pEnable->u32Flags = bEnable? VBVA_F_ENABLE: VBVA_F_DISABLE; pEnable->u32Flags |= VBVA_F_EXTENDED | VBVA_F_ABSOFFSET; pEnable->u32Offset = (uint32_t)pVbva->offVBVA; pEnable->i32Result = VERR_NOT_SUPPORTED; VBoxHGSMIBufferSubmit (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); if (bEnable) { rc = pEnable->i32Result; AssertRC(rc); } else rc = VINF_SUCCESS; VBoxHGSMIBufferFree (&VBoxCommonFromDeviceExt(pDevExt)->guestCtx, p); } return rc; }
/** Tell the host about the location of the area of VRAM set aside for the host * heap. */ static int vboxHGSMIReportHostArea(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32AreaOffset, uint32_t u32AreaSize) { VBVAINFOHEAP *p; int rc = VINF_SUCCESS; /* Allocate the IO buffer. */ p = (VBVAINFOHEAP *)VBoxHGSMIBufferAlloc(pCtx, sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA, VBVA_INFO_HEAP); if (p) { /* Prepare data to be sent to the host. */ p->u32HeapOffset = u32AreaOffset; p->u32HeapSize = u32AreaSize; rc = VBoxHGSMIBufferSubmit(pCtx, p); /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; return rc; }
/** Inform the host of the location of the host flags in VRAM via an HGSMI * command. */ static int vboxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx, HGSMIOFFSET offLocation) { HGSMIBUFFERLOCATION *p; int rc = VINF_SUCCESS; /* Allocate the IO buffer. */ p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(HGSMIBUFFERLOCATION), HGSMI_CH_HGSMI, HGSMI_CC_HOST_FLAGS_LOCATION); if (p) { /* Prepare data to be sent to the host. */ p->offLocation = offLocation; p->cbLocation = sizeof(HGSMIHOSTFLAGS); rc = VBoxHGSMIBufferSubmit(pCtx, p); /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; return rc; }
static void vboxHwBufferFlush(PHGSMIGUESTCOMMANDCONTEXT pCtx) { /* Issue the flush command. */ void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof (VBVAFLUSH), HGSMI_CH_VBVA, VBVA_FLUSH); if (!p) { LogFunc(("HGSMIHeapAlloc failed\n")); } else { VBVAFLUSH *pFlush = (VBVAFLUSH *)p; pFlush->u32Reserved = 0; VBoxHGSMIBufferSubmit(pCtx, p); VBoxHGSMIBufferFree(pCtx, p); } return; }
static void VBoxDispVHWACommandFree(PVBOXDISPDEV pDev, VBOXVHWACMD* pCmd) { VBoxHGSMIBufferFree(&pDev->hgsmi.ctx, pCmd); }
/** * Pass the host a new mouse pointer shape via an HGSMI command. * * @returns success or failure * @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 */ RTDECL(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 cbData = 0; int rc = VINF_SUCCESS; if (fFlags & VBOX_MOUSE_POINTER_SHAPE) { /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */ cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3) + cWidth * 4 * cHeight; /* If shape is supplied, then always create the pointer visible. * See comments in 'vboxUpdatePointerShape' */ fFlags |= VBOX_MOUSE_POINTER_VISIBLE; } LogFlowFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight)); if (cbData > cbLength) { LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n", cbData, cbLength)); return VERR_INVALID_PARAMETER; } /* Allocate the IO buffer. */ p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAMOUSEPOINTERSHAPE) + cbData, HGSMI_CH_VBVA, VBVA_MOUSE_POINTER_SHAPE); if (p) { /* 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 (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE) /* Copy the actual pointer data. */ memcpy (p->au8Data, pPixels, cbData); rc = VBoxHGSMIBufferSubmit(pCtx, p); if (RT_SUCCESS(rc)) rc = p->i32Result; /* Free the IO buffer. */ VBoxHGSMIBufferFree(pCtx, p); } else rc = VERR_NO_MEMORY; LogFlowFunc(("rc %d\n", rc)); return rc; }