HGSMICommon.cpp revision 8b2529a5ddb7e6170c5ab2399a8fc4ef102f8e3d
87902654924b5893d165c3f31f1d8a50f87205b4vboxsync * VBox Host Guest Shared Memory Interface (HGSMI) - Functions common to both host and guest.
32b1164f35483be483177be7b5235002a4a5afbevboxsync * Copyright (C) 2006-2014 Oracle Corporation
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * available from http://www.virtualbox.org. This file is free software;
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * you can redistribute it and/or modify it under the terms of the GNU
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * General Public License (GPL) as published by the Free Software
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf5f6bf2704d4fff443139e10bccc6a0a7fa4b85vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
87902654924b5893d165c3f31f1d8a50f87205b4vboxsync#define LOG_DISABLED /* Maybe we can enabled it all the time now? */
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* Channel flags. */
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* Assertions for situations which could happen and normally must be processed properly
9bee881471745317e907eefbacf9ef344c74c899vboxsync * but must be investigated during development: guest misbehaving, etc.
9bee881471745317e907eefbacf9ef344c74c899vboxsync#define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
9bee881471745317e907eefbacf9ef344c74c899vboxsync#endif /* !HGSMI_STRICT */
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* One-at-a-Time Hash from
9bee881471745317e907eefbacf9ef344c74c899vboxsync * ub4 one_at_a_time(char *key, ub4 len)
9bee881471745317e907eefbacf9ef344c74c899vboxsync * ub4 hash, i;
9bee881471745317e907eefbacf9ef344c74c899vboxsync * for (hash=0, i=0; i<len; ++i)
9bee881471745317e907eefbacf9ef344c74c899vboxsync * hash += key[i];
9bee881471745317e907eefbacf9ef344c74c899vboxsync * hash += (hash << 10);
9bee881471745317e907eefbacf9ef344c74c899vboxsync * hash ^= (hash >> 6);
9bee881471745317e907eefbacf9ef344c74c899vboxsync * hash += (hash << 3);
9bee881471745317e907eefbacf9ef344c74c899vboxsync * hash ^= (hash >> 11);
9bee881471745317e907eefbacf9ef344c74c899vboxsync * hash += (hash << 15);
9bee881471745317e907eefbacf9ef344c74c899vboxsync * return hash;
9bee881471745317e907eefbacf9ef344c74c899vboxsync const void *pvData,
9bee881471745317e907eefbacf9ef344c74c899vboxsync u32Checksum = hgsmiHashProcess (u32Checksum, &offBuffer, sizeof (offBuffer));
9bee881471745317e907eefbacf9ef344c74c899vboxsync u32Checksum = hgsmiHashProcess (u32Checksum, pHeader, sizeof (HGSMIBUFFERHEADER));
9bee881471745317e907eefbacf9ef344c74c899vboxsync u32Checksum = hgsmiHashProcess (u32Checksum, pTail, RT_OFFSETOF(HGSMIBUFFERTAIL, u32Checksum));
9bee881471745317e907eefbacf9ef344c74c899vboxsyncstatic HGSMIOFFSET hgsmiBufferInitializeSingle (const HGSMIAREA *pArea,
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* Buffer must be within the area:
9bee881471745317e907eefbacf9ef344c74c899vboxsync * * header data size do not exceed the maximum data size;
9bee881471745317e907eefbacf9ef344c74c899vboxsync * * buffer address is greater than the area base address;
9bee881471745317e907eefbacf9ef344c74c899vboxsync * * buffer address is lower than the maximum allowed for the given data size.
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMISIZE cbMaximumDataSize = pArea->offLast - pArea->offBase;
9bee881471745317e907eefbacf9ef344c74c899vboxsync || (uint8_t *)pHeader > pArea->pu8Base + cbMaximumDataSize - u32DataSize)
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMIOFFSET offBuffer = HGSMIPointerToOffset (pArea, pHeader);
9bee881471745317e907eefbacf9ef344c74c899vboxsync pHeader->u8Flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
9bee881471745317e907eefbacf9ef344c74c899vboxsync memset (pHeader->u.au8Union, 0, sizeof (pHeader->u.au8Union));
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
9bee881471745317e907eefbacf9ef344c74c899vboxsync pTail->u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
9bee881471745317e907eefbacf9ef344c74c899vboxsyncint HGSMIAreaInitialize (HGSMIAREA *pArea, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase)
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync || cbArea < HGSMIBufferMinimumSize () /* Large enough. */
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync || pu8Base + cbArea < pu8Base /* No address space wrap. */
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync || offBase > UINT32_C(0xFFFFFFFF) - cbArea /* Area within the 32 bit space: offBase + cbMem <= 0xFFFFFFFF */
9bee881471745317e907eefbacf9ef344c74c899vboxsync pArea->offLast = cbArea - HGSMIBufferMinimumSize () + offBase;
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* Initialize the memory buffer including its checksum.
9bee881471745317e907eefbacf9ef344c74c899vboxsync * No changes alloed to the header and the tail after that.
9bee881471745317e907eefbacf9ef344c74c899vboxsyncHGSMIOFFSET HGSMIBufferInitializeSingle (const HGSMIAREA *pArea,
9bee881471745317e907eefbacf9ef344c74c899vboxsync return hgsmiBufferInitializeSingle (pArea, pHeader, cbBuffer - HGSMIBufferMinimumSize (), u8Channel, u16ChannelInfo);
9bee881471745317e907eefbacf9ef344c74c899vboxsync int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync pHeap->u.hOff = (RTHEAPOFFSET)((uint8_t *)pvBase + offHeapHandle);
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync pHeap->u.hPtr = (RTHEAPSIMPLE)((uint8_t *)pvBase + offHeapHandle);
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync rc = RTHeapSimpleRelocate (pHeap->u.hPtr, offDelta); AssertRC(rc);
8b2529a5ddb7e6170c5ab2399a8fc4ef102f8e3dvboxsync /* HGSMI_HEAP_TYPE_MA does not need the relocation. */
8b2529a5ddb7e6170c5ab2399a8fc4ef102f8e3dvboxsync int rc = HGSMIAreaInitialize(&pHeap->area, pvBase, cbArea, offBase);
8b2529a5ddb7e6170c5ab2399a8fc4ef102f8e3dvboxsync rc = HGSMIMAInit(&pHeap->u.ma, &pHeap->area, paDescriptors, cBlocks, cbMaxBlock, pEnv);
9bee881471745317e907eefbacf9ef344c74c899vboxsync int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
32b1164f35483be483177be7b5235002a4a5afbevboxsync rc = HGSMIMAInit(&pHeap->u.ma, &pHeap->area, NULL, 0, 0, pEnv);
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync rc = RTHeapSimpleInit (&pHeap->u.hPtr, pvBase, cbArea);
8f1c8e96fab0c5f5a8dcabeb4e20a56a8b4cea18vboxsync rc = RTHeapOffsetInit (&pHeap->u.hOff, pvBase, cbArea);
32b1164f35483be483177be7b5235002a4a5afbevboxsync HGSMISIZE cbAlloc = HGSMIBufferRequiredSize (cbData);
d0a71f63bd810b54e0359223fe53b07730154dc5vboxsync HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)HGSMIHeapBufferAlloc (pHeap, cbAlloc);
9bee881471745317e907eefbacf9ef344c74c899vboxsync hgsmiBufferInitializeSingle (&pHeap->area, pHeader, cbData, u8Channel, u16ChannelInfo);
9bee881471745317e907eefbacf9ef344c74c899vboxsyncHGSMIOFFSET HGSMIHeapBufferOffset (HGSMIHEAP *pHeap,
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMIOFFSET offBuffer = HGSMIPointerToOffset (&pHeap->area, pHeader);
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
d0a71f63bd810b54e0359223fe53b07730154dc5vboxsyncvoid* HGSMIHeapBufferAlloc (HGSMIHEAP *pHeap, HGSMISIZE cbBuffer)
32b1164f35483be483177be7b5235002a4a5afbevboxsync else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_POINTER)
d0a71f63bd810b54e0359223fe53b07730154dc5vboxsync pvBuf = RTHeapSimpleAlloc (pHeap->u.hPtr, cbBuffer, 0);
32b1164f35483be483177be7b5235002a4a5afbevboxsync else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_OFFSET)
d0a71f63bd810b54e0359223fe53b07730154dc5vboxsync pvBuf = RTHeapOffsetAlloc (pHeap->u.hOff, cbBuffer, 0);
32b1164f35483be483177be7b5235002a4a5afbevboxsync else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_POINTER)
32b1164f35483be483177be7b5235002a4a5afbevboxsync else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_OFFSET)
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* Verify that the given offBuffer points to a valid buffer, which is within the area.
9bee881471745317e907eefbacf9ef344c74c899vboxsyncstatic const HGSMIBUFFERHEADER *hgsmiVerifyBuffer (const HGSMIAREA *pArea,
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n", offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
32b1164f35483be483177be7b5235002a4a5afbevboxsync const HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)HGSMIOffsetToPointer (pArea, offBuffer);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* Quick check of the data size, it should be less than the maximum
9bee881471745317e907eefbacf9ef344c74c899vboxsync * data size for the buffer at this offset.
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFlowFunc(("datasize check: pHeader->u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
9bee881471745317e907eefbacf9ef344c74c899vboxsync if (pHeader->u32DataSize <= pArea->offLast - offBuffer)
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* At least both pHeader and pTail structures are in the area. Check the checksum. */
9bee881471745317e907eefbacf9ef344c74c899vboxsync uint32_t u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n", u32Checksum, pTail->u32Checksum));
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n", u32Checksum, pTail->u32Checksum));
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* A wrapper to safely call the handler.
9bee881471745317e907eefbacf9ef344c74c899vboxsyncint HGSMIChannelHandlerCall (const HGSMICHANNELHANDLER *pHandler,
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFlowFunc(("pHandler %p, pHeader %p\n", pHandler, pHeader));
9bee881471745317e907eefbacf9ef344c74c899vboxsync rc = pHandler->pfnHandler (pHandler->pvHandler, pHeader->u16ChannelInfo, pvBuffer, cbBuffer);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* It is a NOOP case here. */
9bee881471745317e907eefbacf9ef344c74c899vboxsync * Process a guest buffer.
9bee881471745317e907eefbacf9ef344c74c899vboxsync * @thread EMT
9bee881471745317e907eefbacf9ef344c74c899vboxsyncstatic int hgsmiBufferProcess (const HGSMICHANNEL *pChannel,
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFlowFunc(("pChannel %p, pHeader %p\n", pChannel, pHeader));
9bee881471745317e907eefbacf9ef344c74c899vboxsync int rc = HGSMIChannelHandlerCall (&pChannel->handler,
9bee881471745317e907eefbacf9ef344c74c899vboxsyncHGSMICHANNEL *HGSMIChannelFindById (HGSMICHANNELINFO * pChannelInfo,
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMICHANNEL *pChannel = &pChannelInfo->Channels[u8Channel];
9bee881471745317e907eefbacf9ef344c74c899vboxsync LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea, offBuffer));
9bee881471745317e907eefbacf9ef344c74c899vboxsync// VM_ASSERT_EMT(pIns->pVM);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* Guest has prepared a command description at 'offBuffer'. */
9bee881471745317e907eefbacf9ef344c74c899vboxsync const HGSMIBUFFERHEADER *pHeader = hgsmiVerifyBuffer (pArea, offBuffer);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* Pass the command to the appropriate handler registered with this instance.
9bee881471745317e907eefbacf9ef344c74c899vboxsync * Start with the handler list head, which is the preallocated HGSMI setup channel.
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMICHANNEL *pChannel = HGSMIChannelFindById (pChannelInfo, pHeader->u8Channel);
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMI_STRICT_ASSERT(hgsmiVerifyBuffer (pArea, offBuffer) != NULL);
9bee881471745317e907eefbacf9ef344c74c899vboxsync// LogRel(("HGSMI[%s]: ignored invalid guest buffer 0x%08X!!!\n", pIns->pszName, offBuffer));
9bee881471745317e907eefbacf9ef344c74c899vboxsync/* Register a new VBVA channel by index.
9bee881471745317e907eefbacf9ef344c74c899vboxsyncint HGSMIChannelRegister (HGSMICHANNELINFO * pChannelInfo,
9bee881471745317e907eefbacf9ef344c74c899vboxsync const char *pszName,
9bee881471745317e907eefbacf9ef344c74c899vboxsync AssertPtrReturn(pOldHandler, VERR_INVALID_PARAMETER);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* Check whether the channel is already registered. */
9bee881471745317e907eefbacf9ef344c74c899vboxsync HGSMICHANNEL *pChannel = HGSMIChannelFindById (pChannelInfo, u8Channel);
9bee881471745317e907eefbacf9ef344c74c899vboxsync /* Channel is not yet registered. */