diff --git a/kernel-src/include/kernel/iovec.h b/kernel-src/include/kernel/iovec.h index 8dec9fcf..207fd312 100644 --- a/kernel-src/include/kernel/iovec.h +++ b/kernel-src/include/kernel/iovec.h @@ -64,8 +64,9 @@ size_t iovec_iterator_read_from_ringbuffer(iovec_iterator_t *iovec_iterator, rin size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count, uintmax_t ringbuffer_offset); // returns the physical address of the next page in the iovec_iterator, adding a reference count while at it -// fails with EINVAL if the iterator does not currently point to the start of a page or there is not enough space for a page +// sets the page_offset to the offset in the page, page_remaining to the remaining number of bytes in the page and page to the physical address of the page +// if no more pages in iovec_iterator, returns success with page being set to NULL // fails with EFAULT if the page is not mapped -int iovec_iterator_next_page(iovec_iterator_t *iovec_iterator, void **page); +int iovec_iterator_next_page(iovec_iterator_t *iovec_iterator, size_t *page_offset, size_t *page_remaining, void **page); #endif diff --git a/kernel-src/io/iovec.c b/kernel-src/io/iovec.c index 7d3af8cd..9a1a4d4d 100644 --- a/kernel-src/io/iovec.c +++ b/kernel-src/io/iovec.c @@ -224,19 +224,23 @@ size_t iovec_iterator_read_from_ringbuffer(iovec_iterator_t *iovec_iterator, rin return done; } -int iovec_iterator_next_page(iovec_iterator_t *iovec_iterator, void **page) { +int iovec_iterator_next_page(iovec_iterator_t *iovec_iterator, size_t *page_offset, size_t *page_remaining, void **page) { void *addr = (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset); - if ((uintptr_t)addr % PAGE_SIZE) - return EINVAL; - + size_t offset_in_page = ((uintptr_t)addr % PAGE_SIZE); size_t remaining = iovec_iterator->current->len - iovec_iterator->current_offset; - if (remaining < PAGE_SIZE) - return EINVAL; - void *phys = vmm_getphysical(addr, true); + if (remaining == 0) { + *page = NULL; + return 0; + } + + void *phys = vmm_getphysical((void *)((uintptr_t)addr - offset_in_page), true); if (phys == NULL) return EFAULT; + *page_offset = offset_in_page; + *page_remaining = min(PAGE_SIZE, remaining); *page = phys; + iovec_iterator_skip(iovec_iterator, *page_remaining); return 0; }