From 0680b73461fd7759d57d3b1eda16928790d5a6e0 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 21 Feb 2026 11:17:16 +0000 Subject: [PATCH] kernel: iovec: implement iterating through an iovec list stored in userspace --- include/kernel/iovec.h | 8 +++++ kernel/iovec.c | 68 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/include/kernel/iovec.h b/include/kernel/iovec.h index f6c9649..5545869 100644 --- a/include/kernel/iovec.h +++ b/include/kernel/iovec.h @@ -5,6 +5,9 @@ #include struct iovec_iterator { + /* if this is set, we are iterating over a list of iovecs stored in + * userspace, and must go through this region to retrieve the data. */ + struct vm_region *it_region; const struct iovec *it_vecs; size_t it_nr_vecs; size_t it_vec_ptr; @@ -17,6 +20,11 @@ extern void iovec_iterator_begin( struct iovec_iterator *it, const struct iovec *vecs, size_t nr_vecs); +extern void iovec_iterator_begin_user( + struct iovec_iterator *it, + struct vm_region *address_space, + const struct iovec *vecs, + size_t nr_vecs); extern void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes); diff --git a/kernel/iovec.c b/kernel/iovec.c index b9099fa..f4c310f 100644 --- a/kernel/iovec.c +++ b/kernel/iovec.c @@ -1,6 +1,62 @@ #include #include #include +#include + +static bool read_iovec( + struct iovec_iterator *it, + size_t index, + struct iovec *out) +{ + if (index >= it->it_nr_vecs) { + return false; + } + + if (!it->it_region) { + memcpy(out, &it->it_vecs[index], sizeof *out); + return true; + } + + size_t nr_read = 0; + kern_status_t status = vm_region_read_kernel( + it->it_region, + (virt_addr_t)it->it_vecs + (index * sizeof(struct iovec)), + sizeof(struct iovec), + out, + &nr_read); + + return (status == KERN_OK && nr_read != sizeof(struct iovec)); +} + +void iovec_iterator_begin_user( + struct iovec_iterator *it, + struct vm_region *region, + const struct iovec *vecs, + size_t nr_vecs) +{ + memset(it, 0x0, sizeof *it); + it->it_region = region; + it->it_vecs = vecs; + it->it_nr_vecs = nr_vecs; + + struct iovec iov; + + while (it->it_vec_ptr < nr_vecs) { + read_iovec(it, it->it_vec_ptr, &iov); + if (iov.io_len > 0) { + break; + } + + it->it_vec_ptr++; + } + + if (it->it_vec_ptr >= nr_vecs) { + return; + } + + it->it_base = iov.io_base; + it->it_len = iov.io_len; +} void iovec_iterator_begin( struct iovec_iterator *it, @@ -20,6 +76,8 @@ void iovec_iterator_begin( } if (it->it_vec_ptr >= nr_vecs) { + it->it_len = 0; + it->it_base = 0; return; } @@ -39,10 +97,12 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes) } nr_bytes -= to_seek; + struct iovec iov; it->it_vec_ptr++; while (it->it_vec_ptr < it->it_nr_vecs) { - if (it->it_vecs[it->it_vec_ptr].io_len > 0) { + read_iovec(it, it->it_vec_ptr, &iov); + if (iov.io_len > 0) { break; } @@ -50,10 +110,12 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes) } if (it->it_vec_ptr >= it->it_nr_vecs) { + it->it_len = 0; + it->it_base = 0; return; } - it->it_base = it->it_vecs[it->it_vec_ptr].io_base; - it->it_len = it->it_vecs[it->it_vec_ptr].io_len; + it->it_base = iov.io_base; + it->it_len = iov.io_len; } }