2026-02-19 19:19:48 +00:00
|
|
|
#include <kernel/iovec.h>
|
|
|
|
|
#include <kernel/libc/string.h>
|
|
|
|
|
#include <kernel/util.h>
|
2026-02-21 11:17:16 +00:00
|
|
|
#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;
|
|
|
|
|
}
|
2026-02-19 19:19:48 +00:00
|
|
|
|
|
|
|
|
void iovec_iterator_begin(
|
|
|
|
|
struct iovec_iterator *it,
|
|
|
|
|
const struct iovec *vecs,
|
|
|
|
|
size_t nr_vecs)
|
|
|
|
|
{
|
|
|
|
|
memset(it, 0x0, sizeof *it);
|
|
|
|
|
it->it_vecs = vecs;
|
|
|
|
|
it->it_nr_vecs = nr_vecs;
|
|
|
|
|
|
|
|
|
|
while (it->it_vec_ptr < nr_vecs) {
|
|
|
|
|
if (vecs[it->it_vec_ptr].io_len > 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it->it_vec_ptr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (it->it_vec_ptr >= nr_vecs) {
|
2026-02-21 11:17:16 +00:00
|
|
|
it->it_len = 0;
|
|
|
|
|
it->it_base = 0;
|
2026-02-19 19:19:48 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it->it_base = vecs[it->it_vec_ptr].io_base;
|
|
|
|
|
it->it_len = vecs[it->it_vec_ptr].io_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes)
|
|
|
|
|
{
|
|
|
|
|
while (nr_bytes > 0) {
|
|
|
|
|
size_t to_seek = MIN(nr_bytes, it->it_len);
|
|
|
|
|
|
|
|
|
|
if (to_seek < it->it_len) {
|
|
|
|
|
it->it_len -= to_seek;
|
|
|
|
|
it->it_base += to_seek;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nr_bytes -= to_seek;
|
2026-02-21 11:17:16 +00:00
|
|
|
struct iovec iov;
|
2026-02-19 19:19:48 +00:00
|
|
|
|
|
|
|
|
it->it_vec_ptr++;
|
|
|
|
|
while (it->it_vec_ptr < it->it_nr_vecs) {
|
2026-02-21 11:17:16 +00:00
|
|
|
read_iovec(it, it->it_vec_ptr, &iov);
|
|
|
|
|
if (iov.io_len > 0) {
|
2026-02-19 19:19:48 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it->it_vec_ptr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (it->it_vec_ptr >= it->it_nr_vecs) {
|
2026-02-21 11:17:16 +00:00
|
|
|
it->it_len = 0;
|
|
|
|
|
it->it_base = 0;
|
2026-02-19 19:19:48 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-21 11:17:16 +00:00
|
|
|
it->it_base = iov.io_base;
|
|
|
|
|
it->it_len = iov.io_len;
|
2026-02-19 19:19:48 +00:00
|
|
|
}
|
|
|
|
|
}
|