diff --git a/include/kernel/vm-region.h b/include/kernel/vm-region.h index e2cbfe1..ef0c374 100644 --- a/include/kernel/vm-region.h +++ b/include/kernel/vm-region.h @@ -122,6 +122,15 @@ extern virt_addr_t vm_region_get_base_address(const struct vm_region *region); extern void vm_region_dump(struct vm_region *region); +/* read data from the user-space area of a vm-region into a kernel-mode buffer + */ +extern kern_status_t vm_region_read_kernel( + struct vm_region *src_region, + virt_addr_t src_ptr, + size_t count, + void *dest, + size_t *nr_read); + extern kern_status_t vm_region_memmove( struct vm_region *dest_region, virt_addr_t dest_ptr, diff --git a/vm/vm-region.c b/vm/vm-region.c index 0f135ac..bef0c48 100644 --- a/vm/vm-region.c +++ b/vm/vm-region.c @@ -1239,6 +1239,46 @@ virt_addr_t vm_region_get_base_address(const struct vm_region *region) return entry_absolute_address(®ion->vr_entry); } +kern_status_t vm_region_read_kernel( + struct vm_region *src_region, + virt_addr_t src_ptr, + size_t count, + void *destp, + size_t *nr_read) +{ + struct vm_iterator src; + char *dest = destp; + + vm_iterator_begin( + &src, + src_region, + src_ptr, + VM_PROT_READ | VM_PROT_USER); + + kern_status_t status = KERN_OK; + size_t r = 0; + + while (r < count && src.it_max) { + size_t remaining = count - r; + size_t to_move = MIN(src.it_max, remaining); + memmove(dest, src.it_buf, to_move); + + status = vm_iterator_seek(&src, to_move); + if (status != KERN_OK) { + break; + } + + r += to_move; + dest += to_move; + } + + if (nr_read) { + *nr_read = r; + } + + return status; +} + kern_status_t vm_region_memmove( struct vm_region *dest_region, virt_addr_t dest_ptr,