diff --git a/kernel-src/include/kernel/iovec.h b/kernel-src/include/kernel/iovec.h index a51ffa55..8dec9fcf 100644 --- a/kernel-src/include/kernel/iovec.h +++ b/kernel-src/include/kernel/iovec.h @@ -44,6 +44,10 @@ int iovec_iterator_copy_to_buffer(iovec_iterator_t *iovec_iterator, void *buffer // NOTE: the iovec can have userspace addresses. in this case, the copy can possibly fail with EFAULT int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buffer, size_t byte_count); +// sets byte_count bytes in the iovec_iterator to byte +// NOTE: the iovec can have userspace addresses. in this case, the memset can possibly fail with EFAULT +int iovec_iterator_memset(iovec_iterator_t *iovec_iterator, uint8_t byte, size_t byte_count); + // copies byte_count bytes from the iovec_iterator into the ringbuffer // returns the number of bytes copied // NOTE: the iovec can have userspace addresses. in this case, the copy can possibly fail by returning RINGBUFFER_USER_COPY_FAILED diff --git a/kernel-src/io/iovec.c b/kernel-src/io/iovec.c index 9e9e5edb..7d3af8cd 100644 --- a/kernel-src/io/iovec.c +++ b/kernel-src/io/iovec.c @@ -70,17 +70,19 @@ size_t iovec_iterator_set(iovec_iterator_t *iovec_iterator, size_t offset) { int iovec_iterator_copy_to_buffer(iovec_iterator_t *iovec_iterator, void *buffer, size_t byte_count) { size_t iterator_offset_save = iovec_iterator->total_offset; size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset); + size_t total_done = 0; int error = 0; for (;;) { size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset; size_t copy_current = min(remaining_current, remaining_total); - error = USERCOPY_POSSIBLY_FROM_USER(buffer, (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), copy_current); + error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)buffer + total_done), (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), copy_current); if (error) break; iovec_iterator_skip(iovec_iterator, copy_current); + total_done += copy_current; remaining_total -= copy_current; if (iovec_iterator_finished(iovec_iterator) || remaining_total == 0) @@ -96,13 +98,41 @@ int iovec_iterator_copy_to_buffer(iovec_iterator_t *iovec_iterator, void *buffer int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buffer, size_t byte_count) { size_t iterator_offset_save = iovec_iterator->total_offset; size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset); + size_t total_done = 0; int error = 0; for (;;) { size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset; size_t copy_current = min(remaining_current, remaining_total); - error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), buffer, copy_current); + error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), (void *)((uintptr_t)buffer + total_done), copy_current); + if (error) + break; + + iovec_iterator_skip(iovec_iterator, copy_current); + total_done += copy_current; + remaining_total -= copy_current; + + if (iovec_iterator_finished(iovec_iterator) || remaining_total == 0) + break; + } + + if (error) + iovec_iterator_set(iovec_iterator, iterator_offset_save); + + return error; +} + +int iovec_iterator_memset(iovec_iterator_t *iovec_iterator, uint8_t byte, size_t byte_count) { + size_t iterator_offset_save = iovec_iterator->total_offset; + size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset); + int error = 0; + + for (;;) { + size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset; + size_t copy_current = min(remaining_current, remaining_total); + + error = USERCOPY_POSSIBLY_MEMSET_TO_USER((void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), byte, copy_current); if (error) break;