/** * @brief Returns any available bytes for dequeue * @param qp handle to the queue pair * @return available bytes for dequeue, appropriate error code * otherwise */ int32 QP_DequeueSpace(QPHandle *qp) { uint32 tail; uint32 phantom; int32 bytesAvailable; if (!QP_CheckHandle(qp)) { return QP_ERROR_INVALID_HANDLE; } tail = qp->consumeQ->tail; phantom = qp->consumeQ->phantom_head; if (tail >= qp->queueSize || phantom >= qp->queueSize) { return QP_ERROR_INVALID_HANDLE; } bytesAvailable = (tail - phantom); if ((int32)bytesAvailable < 0) { bytesAvailable += qp->queueSize; } return bytesAvailable; }
/** * @brief Resets the phantom head pointer and discards any pending * dequeues * @param qp handle to the queue pair * @return QP_SUCCESS on success, QP_ERROR_INVALID_HANDLE if the handle * is malformed * @sideeffects Resets the phantom head pointer */ int32 QP_DequeueReset(QPHandle *qp) { uint32 head; if (!QP_CheckHandle(qp)) return QP_ERROR_INVALID_HANDLE; head = qp->consumeQ->head; if (head >= qp->queueSize) return QP_ERROR_INVALID_HANDLE; qp->consumeQ->phantom_head = head; return QP_SUCCESS; }
/** * @brief Resets the phantom tail pointer and discards any pending * enqueues * @param qp handle to the queue pair * @return QP_SUCCESS on success, QP_ERROR_INVALID_HANDLE if the handle * is malformed * @sideeffects Resets the phantom tail pointer */ int32 QP_EnqueueReset(QPHandle *qp) { uint32 tail; if (!QP_CheckHandle(qp)) return QP_ERROR_INVALID_HANDLE; tail = qp->produceQ->tail; if (tail >= qp->queueSize) return QP_ERROR_INVALID_HANDLE; qp->produceQ->phantom_tail = tail; return QP_SUCCESS; }
/** * @brief Commits any previous DequeueSegment operations to the queue * pair * @param qp handle to the queue pair * @return QP_SUCCESS on success, QP_ERROR_INVALID_HANDLE if the handle * is malformed * @sideeffects Moves the head pointer */ int32 QP_DequeueCommit(QPHandle *qp) { uint32 phantom; if (!QP_CheckHandle(qp)) return QP_ERROR_INVALID_HANDLE; phantom = qp->consumeQ->phantom_head; if (phantom >= qp->queueSize) return QP_ERROR_INVALID_HANDLE; qp->consumeQ->head = phantom; return QP_SUCCESS; }
/** * @brief Commits any previous EnqueueSegment operations to the queue * pair * @param qp handle to the queue pair. * @return QP_SUCCESS on success, appropriate error code otherwise. * @sideeffects May move tail pointer */ int32 QP_EnqueueCommit(QPHandle *qp) { uint32 phantom; if (!QP_CheckHandle(qp)) return QP_ERROR_INVALID_HANDLE; phantom = qp->produceQ->phantom_tail; if (phantom >= qp->queueSize) return QP_ERROR_INVALID_HANDLE; qp->produceQ->tail = phantom; return QP_SUCCESS; }
/** * @brief Dequeues a segment of data from the consumer queue into * a buffer * @param qp handle to the queue pair * @param[out] buf buffer to copy to * @param bytesDesired number of bytes to dequeue * @return number of bytes dequeued on success, appropriate error * code otherwise * @sideeffects May move phantom head pointer */ int32 QP_DequeueSegment(QPHandle *qp, const void *buf, size_t bytesDesired) { uint32 tail; uint32 phantom; int32 bytesAvailable = 0; if (!QP_CheckHandle(qp)) { return QP_ERROR_INVALID_HANDLE; } tail = qp->consumeQ->tail; phantom = qp->consumeQ->phantom_head; /* * This check must go after the assignment above, * otherwise a malicious guest could write bogus * offsets to the queue and cause the memcpy to * copy into unpleasant places. */ if (tail >= qp->queueSize || phantom >= qp->queueSize) { return QP_ERROR_INVALID_HANDLE; } bytesAvailable = (tail - phantom); if ((int32)bytesAvailable < 0) { bytesAvailable += qp->queueSize; } if (bytesDesired <= bytesAvailable) { if (bytesDesired + phantom < qp->queueSize) { memcpy((void*)buf, qp->consumeQ->data + phantom, bytesDesired); phantom += bytesDesired; } else { uint32 written = qp->queueSize - phantom; memcpy((void*)buf, qp->consumeQ->data + phantom, written); memcpy((uint8*)buf + written, qp->consumeQ->data, bytesDesired - written); phantom = bytesDesired - written; } } else { return QP_ERROR_NO_MEM; } qp->consumeQ->phantom_head = phantom; return bytesDesired; }
/** * @brief Enqueues a segment of data into the producer queue * @param qp handle to the queue pair * @param buf data to enqueue * @param bufSize size in bytes to enqueue * @return number of bytes enqueued on success, appropriate error * code otherwise * @sideeffects May move phantom tail pointer */ int32 QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t bufSize) { int32 freeSpace; uint32 head; uint32 phantom; if (!QP_CheckHandle(qp)) { return QP_ERROR_INVALID_HANDLE; } head = qp->produceQ->head; phantom = qp->produceQ->phantom_tail; /* * This check must go after the assignment above, * otherwise a malicious guest could write bogus * offsets to the queue and cause the memcpy to * copy into unpleasant places. */ if (head >= qp->queueSize || phantom >= qp->queueSize) { return QP_ERROR_INVALID_HANDLE; } freeSpace = FreeSpace(head, phantom, qp->queueSize); if (bufSize <= freeSpace) { if (bufSize + phantom < qp->queueSize) { memcpy(qp->produceQ->data + phantom, buf, bufSize); phantom += bufSize; } else { uint32 written = qp->queueSize - phantom; memcpy(qp->produceQ->data + phantom, buf, written); memcpy(qp->produceQ->data, (uint8*)buf + written, bufSize - written); phantom = bufSize - written; } } else { return QP_ERROR_NO_MEM; } qp->produceQ->phantom_tail = phantom; return bufSize; }
/** * @brief Returns available space for enqueue, in bytes * @param qp handle to the queue pair * @return available space in bytes in the queue for enqueue operations, * QP_ERROR_INVALID_HANDLE if the handle is malformed */ int32 QP_EnqueueSpace(QPHandle *qp) { uint32 head; uint32 phantom; if (!QP_CheckHandle(qp)) return QP_ERROR_INVALID_HANDLE; head = qp->produceQ->head; phantom = qp->produceQ->phantom_tail; if (head >= qp->queueSize || phantom >= qp->queueSize) return QP_ERROR_INVALID_HANDLE; return FreeSpace(head, phantom, qp->queueSize); }
int32 QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t bufSize, int kern) { int32 freeSpace; uint32 head; uint32 phantom; if (!QP_CheckHandle(qp)) { return QP_ERROR_INVALID_HANDLE; } head = qp->produceQ->head; phantom = qp->produceQ->phantom_tail; if (head >= qp->queueSize || phantom >= qp->queueSize) { return QP_ERROR_INVALID_HANDLE; } freeSpace = FreeSpace(head, phantom, qp->queueSize); if (bufSize <= freeSpace) { if (bufSize + phantom < qp->queueSize) { if (kern) { memcpy(qp->produceQ->data + phantom, buf, bufSize); } else { if (copy_from_user(qp->produceQ->data + phantom, buf, bufSize)) { return QP_ERROR_INVALID_ARGS; } } phantom += bufSize; } else { uint32 written = qp->queueSize - phantom; if (kern) { memcpy(qp->produceQ->data + phantom, buf, written); memcpy(qp->produceQ->data, (uint8 *)buf + written, bufSize - written); } else { if (copy_from_user(qp->produceQ->data + phantom, buf, written)) { return QP_ERROR_INVALID_ARGS; } if (copy_from_user(qp->produceQ->data, (uint8 *)buf + written, bufSize - written)) { return QP_ERROR_INVALID_ARGS; } } phantom = bufSize - written; } } else { return QP_ERROR_NO_MEM; } qp->produceQ->phantom_tail = phantom; return bufSize; }
int32 QP_DequeueSegment(QPHandle *qp, void *buf, size_t bytesDesired, int kern) { uint32 tail; uint32 phantom; int32 bytesAvailable = 0; if (!QP_CheckHandle(qp)) { return QP_ERROR_INVALID_HANDLE; } tail = qp->consumeQ->tail; phantom = qp->consumeQ->phantom_head; if (tail >= qp->queueSize || phantom >= qp->queueSize) { return QP_ERROR_INVALID_HANDLE; } bytesAvailable = (tail - phantom); if ((int32)bytesAvailable < 0) { bytesAvailable += qp->queueSize; } if (bytesDesired <= bytesAvailable) { if (bytesDesired + phantom < qp->queueSize) { if (kern) { memcpy(buf, qp->consumeQ->data + phantom, bytesDesired); } else { if (copy_to_user(buf, qp->consumeQ->data + phantom, bytesDesired)) { return QP_ERROR_INVALID_ARGS; } } phantom += bytesDesired; } else { uint32 written = qp->queueSize - phantom; if (kern) { memcpy(buf, qp->consumeQ->data + phantom, written); memcpy((uint8 *)buf + written, qp->consumeQ->data, bytesDesired - written); } else { if (copy_to_user(buf, qp->consumeQ->data + phantom, written)) { return QP_ERROR_INVALID_ARGS; } if (copy_to_user((uint8 *)buf + written, qp->consumeQ->data, bytesDesired - written)) { return QP_ERROR_INVALID_ARGS; } } phantom = bytesDesired - written; } } else { return QP_ERROR_NO_MEM; } qp->consumeQ->phantom_head = phantom; return bytesDesired; }