git: 97e24b41d2d2 - main - vchiq: Merge two commits from Linux
Mark Johnston <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.cvs.src |
|---|---|
| Message-ID | <6a886782.367c0.46db733d__6434.32643716864$1787324327$gmane$org@gitrepo.freebsd.org> |
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=97e24b41d2d224cfb4043f1ae84fc23d9033d0a1 commit 97e24b41d2d224cfb4043f1ae84fc23d9033d0a1 Author: Mark Johnston <[email protected]> AuthorDate: 2026-08-21 14:53:54 +0000 Commit: Mark Johnston <[email protected]> CommitDate: 2026-08-21 14:57:31 +0000 vchiq: Merge two commits from Linux 6e474d8e3981 ("staging: vchiq_shim: avoid code duplication") refactors some code which makes applying the subsequent patch easier. 49bec49fd7f2 ("staging: vc04_services: remove vchiq_copy_from_user") addresses a user-triggerable integer overflow via the VCHIQ_IOC_QUEUE_MESSAGE ioctl on /dev/vchiq (which has mode 0600 by default). It also addresses insufficient validation of user-controlled addresses in vchiq_copy_from_user(). Update the bcm2835_audio driver to follow the change to vchi_msg_queue(). Reported by: Vicki Pfau Reviewed by: Abdelkader Boudih <[email protected]> Tested by: Abdelkader Boudih <[email protected]> Tested by: Marco Devesas Campos <[email protected]> MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D58889 --- sys/arm/broadcom/bcm2835/bcm2835_audio.c | 38 +-- sys/contrib/vchiq/interface/vchi/vchi.h | 25 +- .../vchiq/interface/vchiq_arm/vchiq_2835_arm.c | 14 -- sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c | 103 +++++++- sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c | 269 +++++++++++++-------- sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h | 3 - sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h | 9 +- sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c | 116 ++++----- 8 files changed, 342 insertions(+), 235 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_audio.c b/sys/arm/broadcom/bcm2835/bcm2835_audio.c index 82a98d9f6107..556edce502f0 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_audio.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_audio.c @@ -173,6 +173,16 @@ struct bcm2835_audio_info { /* Useful for circular buffer calcs */ #define MOD_DIFF(front,rear,mod) (((mod) + (front) - (rear)) % (mod)) +static ssize_t +bcm2835_memcpy_wrapper(void *_src, void *_dst, size_t offset, size_t size) +{ + uint8_t *src = _src; + uint8_t *dst = _dst; + + memcpy(dst + offset, src + offset, size); + + return (size); +} static const char * dest_description(uint32_t dest) @@ -389,8 +399,8 @@ bcm2835_audio_start(struct bcm2835_audio_chinfo *ch) if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { m.type = VC_AUDIO_MSG_TYPE_START; - ret = vchi_msg_queue(sc->vchi_handle, - &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + &m, sizeof m); if (ret != 0) BCM2835_LOG_ERROR(sc, @@ -411,8 +421,8 @@ bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch) m.u.stop.draining = 0; BCM2835_LOG_INFO(sc,"sending stop\n"); - ret = vchi_msg_queue(sc->vchi_handle, - &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + &m, sizeof m); if (ret != 0) BCM2835_LOG_ERROR(sc, @@ -429,8 +439,8 @@ bcm2835_audio_open(struct bcm2835_audio_info *sc) if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { m.type = VC_AUDIO_MSG_TYPE_OPEN; - ret = vchi_msg_queue(sc->vchi_handle, - &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + &m, sizeof m); if (ret != 0) BCM2835_LOG_ERROR(sc, @@ -453,8 +463,8 @@ bcm2835_audio_update_controls(struct bcm2835_audio_info *sc, uint32_t volume, ui db = db_levels[volume/5]; m.u.control.volume = VCHIQ_AUDIO_VOLUME(db); - ret = vchi_msg_queue(sc->vchi_handle, - &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + &m, sizeof m); if (ret != 0) BCM2835_LOG_ERROR(sc, @@ -475,8 +485,8 @@ bcm2835_audio_update_params(struct bcm2835_audio_info *sc, uint32_t fmt, uint32_ m.u.config.samplerate = speed; m.u.config.bps = AFMT_BIT(fmt); - ret = vchi_msg_queue(sc->vchi_handle, - &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + &m, sizeof m); if (ret != 0) BCM2835_LOG_ERROR(sc, @@ -537,8 +547,8 @@ bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch, void *buf, uint32_t #endif m.u.write.silence = 0; - ret = vchi_msg_queue(sc->vchi_handle, - &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + &m, sizeof m); if (ret != 0) BCM2835_LOG_ERROR(sc, "%s: vchi_msg_queue failed (err %d)\n", @@ -546,8 +556,8 @@ bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch, void *buf, uint32_t while (count > 0) { int bytes = MIN((int)m.u.write.max_packet, (int)count); - ret = vchi_msg_queue(sc->vchi_handle, - buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); + ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper, + buf, bytes); if (ret != 0) BCM2835_LOG_ERROR(sc, "%s: vchi_msg_queue failed: %d\n", __func__, ret); diff --git a/sys/contrib/vchiq/interface/vchi/vchi.h b/sys/contrib/vchiq/interface/vchi/vchi.h index c80b25510728..dc7ba082fd90 100644 --- a/sys/contrib/vchiq/interface/vchi/vchi.h +++ b/sys/contrib/vchiq/interface/vchi/vchi.h @@ -226,25 +226,12 @@ extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle, int value); // Routine to send a message across a service -extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle, - const void *data, - uint32_t data_size, - VCHI_FLAGS_T flags, - void *msg_handle ); - -// scatter-gather (vector) and send message -int32_t vchi_msg_queuev_ex( VCHI_SERVICE_HANDLE_T handle, - VCHI_MSG_VECTOR_EX_T *vector, - uint32_t count, - VCHI_FLAGS_T flags, - void *msg_handle ); - -// legacy scatter-gather (vector) and send message, only handles pointers -int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle, - VCHI_MSG_VECTOR_T *vector, - uint32_t count, - VCHI_FLAGS_T flags, - void *msg_handle ); +extern int32_t + vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + uint32_t data_size); // Routine to receive a msg from a service // Dequeue is equivalent to hold, copy into client buffer, release diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c index 383dff43047e..1502d30df722 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c @@ -318,20 +318,6 @@ vchiq_platform_get_arm_state(VCHIQ_STATE_T *state) return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state; } -VCHIQ_STATUS_T -vchiq_copy_from_user(void *dst, const void *src, int size) -{ - - if (((vm_offset_t)(src)) < VM_MIN_KERNEL_ADDRESS) { - int error = copyin(src, dst, size); - return error ? VCHIQ_ERROR : VCHIQ_SUCCESS; - } - else - bcopy(src, dst, size); - - return VCHIQ_SUCCESS; -} - VCHIQ_STATUS_T vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle, void *offset, int size, int dir) diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c index d780f3807cee..9d983ae788a5 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c @@ -415,6 +415,107 @@ static void close_delivered(USER_SERVICE_T *user_service) } } +struct vchiq_io_copy_callback_context { + VCHIQ_ELEMENT_T *current_element; + size_t current_element_offset; + unsigned long elements_to_go; + size_t current_offset; +}; + +static ssize_t +vchiq_ioc_copy_element_data( + void *context, + void *dest, + size_t offset, + size_t maxsize) +{ + long res; + size_t bytes_this_round; + struct vchiq_io_copy_callback_context *copy_context = + (struct vchiq_io_copy_callback_context *)context; + + if (offset != copy_context->current_offset) + return 0; + + if (!copy_context->elements_to_go) + return 0; + + /* + * Complex logic here to handle the case of 0 size elements + * in the middle of the array of elements. + * + * Need to skip over these 0 size elements. + */ + while (1) { + bytes_this_round = min(copy_context->current_element->size - + copy_context->current_element_offset, + maxsize); + + if (bytes_this_round) + break; + + copy_context->elements_to_go--; + copy_context->current_element++; + copy_context->current_element_offset = 0; + + if (!copy_context->elements_to_go) + return 0; + } + + res = copy_from_user(dest, + (const uint8_t *)copy_context->current_element->data + + copy_context->current_element_offset, + bytes_this_round); + + if (res != 0) + return -EFAULT; + + copy_context->current_element_offset += bytes_this_round; + copy_context->current_offset += bytes_this_round; + + /* + * Check if done with current element, and if so advance to the next. + */ + if (copy_context->current_element_offset == + copy_context->current_element->size) { + copy_context->elements_to_go--; + copy_context->current_element++; + copy_context->current_element_offset = 0; + } + + return bytes_this_round; +} + +/************************************************************************** + * + * vchiq_ioc_queue_message + * + **************************************************************************/ +static VCHIQ_STATUS_T +vchiq_ioc_queue_message(VCHIQ_SERVICE_HANDLE_T handle, + VCHIQ_ELEMENT_T *elements, + unsigned long count) +{ + struct vchiq_io_copy_callback_context context; + unsigned long i; + size_t total_size = 0; + + context.current_element = elements; + context.current_element_offset = 0; + context.elements_to_go = count; + context.current_offset = 0; + + for (i = 0; i < count; i++) { + if (!elements[i].data && elements[i].size != 0) + return -EFAULT; + + total_size += elements[i].size; + } + + return vchiq_queue_message(handle, vchiq_ioc_copy_element_data, + &context, total_size); +} + /**************************************************************************** * * vchiq_ioctl @@ -759,7 +860,7 @@ _CF32_FORK( args.count * sizeof(VCHIQ_ELEMENT_T)); ) if (cp_ret == 0) - status = vchiq_queue_message + status = vchiq_ioc_queue_message (args.handle, elements, args.count); else diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c index 923cf56f10ee..a96ce23fb6c5 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c @@ -492,8 +492,8 @@ remote_event_pollall(VCHIQ_STATE_T *state) ** enough for a header. This relies on header size being a power of two, which ** has been verified earlier by a static assertion. */ -static inline unsigned int -calc_stride(unsigned int size) +static inline size_t +calc_stride(size_t size) { /* Allow room for the header */ size += sizeof(VCHIQ_HEADER_T); @@ -572,7 +572,7 @@ request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type) /* Called from queue_message, by the slot handler and application threads, ** with slot_mutex held */ static VCHIQ_HEADER_T * -reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking) +reserve_space(VCHIQ_STATE_T *state, size_t space, int is_blocking) { VCHIQ_SHARED_STATE_T *local = state->local; int tx_pos = state->local_tx_pos; @@ -775,18 +775,66 @@ process_free_queue(VCHIQ_STATE_T *state) } } +static ssize_t +memcpy_copy_callback( + void *context, void *dest, + size_t offset, size_t maxsize) +{ + void *src = context; + + memcpy((uint8_t *)dest + offset, (uint8_t *)src + offset, maxsize); + return maxsize; +} + +static ssize_t +copy_message_data( + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + void *dest, + size_t size) +{ + size_t pos = 0; + + while (pos < size) { + ssize_t callback_result; + size_t max_bytes = size - pos; + + callback_result = + copy_callback(context, (uint8_t *)dest + pos, + pos, max_bytes); + + if (callback_result < 0) + return callback_result; + + if (!callback_result) + return -EIO; + + if (callback_result > max_bytes) + return -EIO; + + pos += callback_result; + } + + return size; +} + /* Called by the slot handler and application threads */ static VCHIQ_STATUS_T queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, - int msgid, const VCHIQ_ELEMENT_T *elements, - int count, int size, int flags) + int msgid, + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + size_t size, + int flags) { VCHIQ_SHARED_STATE_T *local; VCHIQ_SERVICE_QUOTA_T *service_quota = NULL; VCHIQ_HEADER_T *header; int type = VCHIQ_MSG_TYPE(msgid); - unsigned int stride; + size_t stride; local = state->local; @@ -851,7 +899,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, service_quota->slot_quota))) { spin_unlock("a_spinlock); vchiq_log_trace(vchiq_core_log_level, - "%d: qm:%d %s,%x - quota stall " + "%d: qm:%d %s,%zx - quota stall " "(msg %d, slot %d)", state->id, service->localport, msg_type_str(type), size, @@ -893,12 +941,12 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, } if (type == VCHIQ_MSG_DATA) { - int i, pos; + ssize_t callback_result; int tx_end_index; int slot_use_count; vchiq_log_info(vchiq_core_log_level, - "%d: qm %s@%p,%x (%d->%d)", + "%d: qm %s@%p,%zx (%d->%d)", state->id, msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size, @@ -908,25 +956,23 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, BUG_ON(!service); BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | QMFLAGS_NO_MUTEX_UNLOCK)) != 0); - for (i = 0, pos = 0; i < (unsigned int)count; - pos += elements[i++].size) - if (elements[i].size) { - if (vchiq_copy_from_user - (header->data + pos, elements[i].data, - (size_t) elements[i].size) != - VCHIQ_SUCCESS) { - lmutex_unlock(&state->slot_mutex); - VCHIQ_SERVICE_STATS_INC(service, + + callback_result = + copy_message_data(copy_callback, context, + header->data, size); + if (callback_result < 0) { + lmutex_unlock(&state->slot_mutex); + VCHIQ_SERVICE_STATS_INC(service, error_count); - return VCHIQ_ERROR; - } - } + return VCHIQ_ERROR; + } if (SRVTRACE_ENABLED(service, - VCHIQ_LOG_INFO)) + VCHIQ_LOG_INFO)) vchiq_log_dump_mem("Sent", 0, - header->data, - min(16, pos)); + header->data, + min((size_t)64, + (size_t)callback_result)); spin_lock("a_spinlock); service_quota->message_use_count++; @@ -954,7 +1000,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, if (slot_use_count) vchiq_log_trace(vchiq_core_log_level, - "%d: qm:%d %s,%x - slot_use->%d (hdr %p)", + "%d: qm:%d %s,%zx - slot_use->%d (hdr %p)", state->id, service->localport, msg_type_str(VCHIQ_MSG_TYPE(msgid)), size, slot_use_count, header); @@ -963,15 +1009,23 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size); } else { vchiq_log_info(vchiq_core_log_level, - "%d: qm %s@%p,%x (%d->%d)", state->id, + "%d: qm %s@%p,%zx (%d->%d)", state->id, msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size, VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid)); if (size != 0) { - WARN_ON(!((count == 1) && (size == elements[0].size))); - memcpy(header->data, elements[0].data, - elements[0].size); + /* It is assumed for now that this code path + * only happens from calls inside this file. + * + * External callers are through the vchiq_queue_message + * path which always sets the type to be VCHIQ_MSG_DATA + * + * At first glance this appears to be correct but + * more review is needed. + */ + copy_message_data(copy_callback, context, + header->data, size); } VCHIQ_STATS_INC(state, ctrl_tx_count); } @@ -987,7 +1041,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); vchiq_log_info(SRVTRACE_LEVEL(service), - "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d", + "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%zu", msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid), VCHIQ_FOURCC_AS_4CHARS(svc_fourcc), @@ -1017,11 +1071,16 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, /* Called by the slot handler and application threads */ static VCHIQ_STATUS_T queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, - int msgid, const VCHIQ_ELEMENT_T *elements, - int count, int size, int is_blocking) + int msgid, + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + int size, + int is_blocking) { VCHIQ_SHARED_STATE_T *local; VCHIQ_HEADER_T *header; + ssize_t callback_result; local = state->local; @@ -1044,49 +1103,35 @@ queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, state->id, oldmsgid); } - if (service) { - int i, pos; - vchiq_log_info(vchiq_sync_log_level, - "%d: qms %s@%p,%x (%d->%d)", state->id, - msg_type_str(VCHIQ_MSG_TYPE(msgid)), - header, size, - VCHIQ_MSG_SRCPORT(msgid), - VCHIQ_MSG_DSTPORT(msgid)); + vchiq_log_info(vchiq_sync_log_level, + "%d: qms %s@%p,%x (%d->%d)", state->id, + msg_type_str(VCHIQ_MSG_TYPE(msgid)), + header, size, VCHIQ_MSG_SRCPORT(msgid), + VCHIQ_MSG_DSTPORT(msgid)); - for (i = 0, pos = 0; i < (unsigned int)count; - pos += elements[i++].size) - if (elements[i].size) { - if (vchiq_copy_from_user - (header->data + pos, elements[i].data, - (size_t) elements[i].size) != - VCHIQ_SUCCESS) { - lmutex_unlock(&state->sync_mutex); - VCHIQ_SERVICE_STATS_INC(service, - error_count); - return VCHIQ_ERROR; - } - } + callback_result = + copy_message_data(copy_callback, context, + header->data, size); + + if (callback_result < 0) { + lmutex_unlock(&state->sync_mutex); + VCHIQ_SERVICE_STATS_INC(service, + error_count); + return VCHIQ_ERROR; + } - if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) - vchiq_log_dump_mem("Sent Sync", - 0, header->data, - min(16, pos)); + if (service) { + if (SRVTRACE_ENABLED(service, + VCHIQ_LOG_INFO)) + vchiq_log_dump_mem("Sent Sync", 0, + header->data, + min((size_t)64, + (size_t)callback_result)); VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count); VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size); } else { - vchiq_log_info(vchiq_sync_log_level, - "%d: qms %s@%p,%x (%d->%d)", state->id, - msg_type_str(VCHIQ_MSG_TYPE(msgid)), - header, size, - VCHIQ_MSG_SRCPORT(msgid), - VCHIQ_MSG_DSTPORT(msgid)); - if (size != 0) { - WARN_ON(!((count == 1) && (size == elements[0].size))); - memcpy(header->data, elements[0].data, - elements[0].size); - } VCHIQ_STATS_INC(state, ctrl_tx_count); } @@ -1196,11 +1241,16 @@ notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue, VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE; int msgid = VCHIQ_MAKE_MSG(msgtype, service->localport, service->remoteport); - VCHIQ_ELEMENT_T element = { &bulk->actual, 4 }; /* Only reply to non-dummy bulk requests */ if (bulk->remote_data) { - status = queue_message(service->state, NULL, - msgid, &element, 1, 4, 0); + status = queue_message( + service->state, + NULL, + msgid, + memcpy_copy_callback, + &bulk->actual, + 4, + 0); if (status != VCHIQ_SUCCESS) break; } @@ -1564,10 +1614,6 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) struct vchiq_openack_payload ack_payload = { service->version }; - VCHIQ_ELEMENT_T body = { - &ack_payload, - sizeof(ack_payload) - }; if (state->version_common < VCHIQ_VERSION_SYNCHRONOUS_MODE) @@ -1577,21 +1623,28 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) if (service->sync && (state->version_common >= VCHIQ_VERSION_SYNCHRONOUS_MODE)) { - if (queue_message_sync(state, NULL, + if (queue_message_sync( + state, + NULL, VCHIQ_MAKE_MSG( VCHIQ_MSG_OPENACK, service->localport, remoteport), - &body, 1, sizeof(ack_payload), + memcpy_copy_callback, + &ack_payload, + sizeof(ack_payload), 0) == VCHIQ_RETRY) goto bail_not_ready; } else { - if (queue_message(state, NULL, - VCHIQ_MAKE_MSG( + if (queue_message(state, + NULL, + VCHIQ_MAKE_MSG( VCHIQ_MSG_OPENACK, service->localport, remoteport), - &body, 1, sizeof(ack_payload), + memcpy_copy_callback, + &ack_payload, + sizeof(ack_payload), 0) == VCHIQ_RETRY) goto bail_not_ready; } @@ -2722,14 +2775,19 @@ vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id) service->version, service->version_min }; - VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) }; VCHIQ_STATUS_T status = VCHIQ_SUCCESS; service->client_id = client_id; vchiq_use_service_internal(service); - status = queue_message(service->state, NULL, - VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0), - &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING); + status = queue_message(service->state, + NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, + service->localport, + 0), + memcpy_copy_callback, + &payload, + sizeof(payload), + QMFLAGS_IS_BLOCKING); if (status == VCHIQ_SUCCESS) { /* Wait for the ACK/NAK */ if (down_interruptible(&service->remove_event) != 0) { @@ -3402,15 +3460,18 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY); } else { uint32_t payload[2] = { (uint32_t)(uintptr_t)bulk->data, bulk->size }; - VCHIQ_ELEMENT_T element = { payload, sizeof(payload) }; - status = queue_message(state, NULL, - VCHIQ_MAKE_MSG(dir_msgtype, - service->localport, service->remoteport), - &element, 1, sizeof(payload), - QMFLAGS_IS_BLOCKING | - QMFLAGS_NO_MUTEX_LOCK | - QMFLAGS_NO_MUTEX_UNLOCK); + status = queue_message(state, + NULL, + VCHIQ_MAKE_MSG(dir_msgtype, + service->localport, + service->remoteport), + memcpy_copy_callback, + &payload, + sizeof(payload), + QMFLAGS_IS_BLOCKING | + QMFLAGS_NO_MUTEX_LOCK | + QMFLAGS_NO_MUTEX_UNLOCK); if (status != VCHIQ_SUCCESS) { goto unlock_both_error_exit; } @@ -3456,26 +3517,22 @@ error_exit: VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, - const VCHIQ_ELEMENT_T *elements, unsigned int count) + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + size_t size) { VCHIQ_SERVICE_T *service = find_service_by_handle(handle); VCHIQ_STATUS_T status = VCHIQ_ERROR; - unsigned int size = 0; - unsigned int i; - if (!service || (vchiq_check_service(service) != VCHIQ_SUCCESS)) goto error_exit; - for (i = 0; i < (unsigned int)count; i++) { - if (elements[i].size) { - if (elements[i].data == NULL) { - VCHIQ_SERVICE_STATS_INC(service, error_count); - goto error_exit; - } - size += elements[i].size; - } + if (!size) { + VCHIQ_SERVICE_STATS_INC(service, error_count); + goto error_exit; + } if (size > VCHIQ_MAX_MSG_SIZE) { @@ -3489,14 +3546,14 @@ vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, service->localport, service->remoteport), - elements, count, size, 1); + copy_callback, context, size, 1); break; case VCHIQ_SRVSTATE_OPENSYNC: status = queue_message_sync(service->state, service, VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, service->localport, service->remoteport), - elements, count, size, 1); + copy_callback, context, size, 1); break; default: status = VCHIQ_ERROR; diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h index 4e3f41203bc4..87774c8ef146 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h @@ -643,9 +643,6 @@ vchiq_transfer_bulk(VCHIQ_BULK_T *bulk); extern void vchiq_complete_bulk(VCHIQ_BULK_T *bulk); -extern VCHIQ_STATUS_T -vchiq_copy_from_user(void *dst, const void *src, int size); - extern void remote_event_signal(REMOTE_EVENT_T *event); diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h index a5fb12863c73..b2b58dc3dc28 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h @@ -141,9 +141,12 @@ extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service); extern VCHIQ_STATUS_T vchiq_use_service_no_resume( VCHIQ_SERVICE_HANDLE_T service); extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service); - -extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service, - const VCHIQ_ELEMENT_T *elements, unsigned int count); +extern VCHIQ_STATUS_T +vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + size_t size); extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_HEADER_T *header); extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c index f33c545cea45..de165a5a3e0b 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c @@ -146,10 +146,10 @@ EXPORT_SYMBOL(vchi_msg_remove); * Name: vchi_msg_queue * * Arguments: VCHI_SERVICE_HANDLE_T handle, - * const void *data, - * uint32_t data_size, - * VCHI_FLAGS_T flags, - * void *msg_handle, + * ssize_t (*copy_callback)(void *context, void *dest, + * size_t offset, size_t maxsize), + * void *context, + * uint32_t data_size * * Description: Thin wrapper to queue a message onto a connection * @@ -157,28 +157,29 @@ EXPORT_SYMBOL(vchi_msg_remove); * ***********************************************************/ int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, - const void *data, - uint32_t data_size, - VCHI_FLAGS_T flags, - void *msg_handle) + ssize_t (*copy_callback)(void *context, void *dest, + size_t offset, size_t maxsize), + void *context, + uint32_t data_size) { SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; - VCHIQ_ELEMENT_T element = {data, data_size}; VCHIQ_STATUS_T status; - (void)msg_handle; - - WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); + while (1) { + status = vchiq_queue_message(service->handle, + copy_callback, + context, + data_size); - status = vchiq_queue_message(service->handle, &element, 1); + /* + * vchiq_queue_message() may return VCHIQ_RETRY, so we need to + * implement a retry mechanism since this function is supposed + * to block until queued + */ + if (status != VCHIQ_RETRY) + break; - /* vchiq_queue_message() may return VCHIQ_RETRY, so we need to - ** implement a retry mechanism since this function is supposed - ** to block until queued - */ - while (status == VCHIQ_RETRY) { msleep(1); - status = vchiq_queue_message(service->handle, &element, 1); } return vchiq_status_to_vchi(status); @@ -227,17 +228,18 @@ int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, return vchiq_status_to_vchi(VCHIQ_ERROR); } - status = vchiq_bulk_receive(service->handle, data_dst, data_size, - bulk_handle, mode); - - /* vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to - ** implement a retry mechanism since this function is supposed - ** to block until queued - */ - while (status == VCHIQ_RETRY) { - msleep(1); + while (1) { status = vchiq_bulk_receive(service->handle, data_dst, data_size, bulk_handle, mode); + /* + * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to + * implement a retry mechanism since this function is supposed + * to block until queued + */ + if (status != VCHIQ_RETRY) + break; + + msleep(1); } return vchiq_status_to_vchi(status); @@ -287,17 +289,19 @@ int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, return vchiq_status_to_vchi(VCHIQ_ERROR); } - status = vchiq_bulk_transmit(service->handle, data_src, data_size, - bulk_handle, mode); - - /* vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to - ** implement a retry mechanism since this function is supposed - ** to block until queued - */ - while (status == VCHIQ_RETRY) { - msleep(1); + while (1) { status = vchiq_bulk_transmit(service->handle, data_src, data_size, bulk_handle, mode); + + /* + * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to + * implement a retry mechanism since this function is supposed + * to block until queued + */ + if (status != VCHIQ_RETRY) + break; + + msleep(1); } return vchiq_status_to_vchi(status); @@ -347,44 +351,6 @@ int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, } EXPORT_SYMBOL(vchi_msg_dequeue); -/*********************************************************** - * Name: vchi_msg_queuev - * - * Arguments: VCHI_SERVICE_HANDLE_T handle, - * VCHI_MSG_VECTOR_T *vector, - * uint32_t count, - * VCHI_FLAGS_T flags, - * void *msg_handle - * - * Description: Thin wrapper to queue a message onto a connection - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ - -vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T)); -vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == - offsetof(VCHIQ_ELEMENT_T, data)); -vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == - offsetof(VCHIQ_ELEMENT_T, size)); - -int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle, - VCHI_MSG_VECTOR_T *vector, - uint32_t count, - VCHI_FLAGS_T flags, - void *msg_handle) -{ - SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; - - (void)msg_handle; - - WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED); - - return vchiq_status_to_vchi(vchiq_queue_message(service->handle, - (const VCHIQ_ELEMENT_T *)vector, count)); -} -EXPORT_SYMBOL(vchi_msg_queuev); - /*********************************************************** * Name: vchi_held_msg_release *