kernel: iovec: implement iterating through an iovec list stored in userspace

This commit is contained in:
2026-02-21 11:17:16 +00:00
parent aa0933be10
commit 0680b73461
2 changed files with 73 additions and 3 deletions

View File

@@ -5,6 +5,9 @@
#include <stddef.h> #include <stddef.h>
struct iovec_iterator { 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; const struct iovec *it_vecs;
size_t it_nr_vecs; size_t it_nr_vecs;
size_t it_vec_ptr; size_t it_vec_ptr;
@@ -17,6 +20,11 @@ extern void iovec_iterator_begin(
struct iovec_iterator *it, struct iovec_iterator *it,
const struct iovec *vecs, const struct iovec *vecs,
size_t nr_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); extern void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes);

View File

@@ -1,6 +1,62 @@
#include <kernel/iovec.h> #include <kernel/iovec.h>
#include <kernel/libc/string.h> #include <kernel/libc/string.h>
#include <kernel/util.h> #include <kernel/util.h>
#include <kernel/vm-region.h>
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( void iovec_iterator_begin(
struct iovec_iterator *it, struct iovec_iterator *it,
@@ -20,6 +76,8 @@ void iovec_iterator_begin(
} }
if (it->it_vec_ptr >= nr_vecs) { if (it->it_vec_ptr >= nr_vecs) {
it->it_len = 0;
it->it_base = 0;
return; return;
} }
@@ -39,10 +97,12 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes)
} }
nr_bytes -= to_seek; nr_bytes -= to_seek;
struct iovec iov;
it->it_vec_ptr++; it->it_vec_ptr++;
while (it->it_vec_ptr < it->it_nr_vecs) { 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; 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) { if (it->it_vec_ptr >= it->it_nr_vecs) {
it->it_len = 0;
it->it_base = 0;
return; return;
} }
it->it_base = it->it_vecs[it->it_vec_ptr].io_base; it->it_base = iov.io_base;
it->it_len = it->it_vecs[it->it_vec_ptr].io_len; it->it_len = iov.io_len;
} }
} }