#include #include #include #include #include kern_status_t sys_vm_object_create( const char *name, size_t name_len, size_t data_len, vm_prot_t prot, kern_handle_t *out_handle) { struct task *self = get_current_task(); if ((name || name_len) && !validate_access_r(self, name, name_len)) { put_current_task(self); return KERN_MEMORY_FAULT; } if (!validate_access_w(self, out_handle, sizeof *out_handle)) { put_current_task(self); return KERN_MEMORY_FAULT; } struct vm_object *obj = vm_object_create(name, name_len, data_len, prot); if (!obj) { return KERN_NO_MEMORY; } kern_status_t status = task_open_handle(self, &obj->vo_base, 0, out_handle); object_unref(&obj->vo_base); put_current_task(self); return status; } kern_status_t sys_vm_object_read( kern_handle_t object, void *dst, off_t offset, size_t count, size_t *nr_read) { struct task *self = get_current_task(); if (!validate_access_w(self, dst, count)) { put_current_task(self); return KERN_MEMORY_FAULT; } if (nr_read && !validate_access_w(self, nr_read, sizeof *nr_read)) { put_current_task(self); return KERN_MEMORY_FAULT; } struct object *obj = NULL; handle_flags_t flags = 0; unsigned long irq_flags = 0; task_lock_irqsave(self, &irq_flags); kern_status_t status = task_resolve_handle(self, object, &obj, &flags); task_unlock_irqrestore(self, irq_flags); put_current_task(self); if (status != KERN_OK) { return status; } struct vm_object *vmo = vm_object_cast(obj); if (!vmo) { object_unref(obj); return KERN_INVALID_ARGUMENT; } vm_object_lock_irqsave(vmo, &irq_flags); status = vm_object_prefetch(vmo, offset, count, &irq_flags); if (status == KERN_OK) { status = vm_object_read(vmo, dst, offset, count, nr_read); } vm_object_unlock_irqrestore(vmo, irq_flags); object_unref(obj); return status; } kern_status_t sys_vm_object_write( kern_handle_t object, const void *src, off_t offset, size_t count, size_t *nr_written) { struct task *self = get_current_task(); if (!validate_access_r(self, src, count)) { put_current_task(self); return KERN_MEMORY_FAULT; } if (nr_written && !validate_access_w(self, nr_written, sizeof *nr_written)) { put_current_task(self); return KERN_MEMORY_FAULT; } struct object *obj = NULL; handle_flags_t flags = 0; unsigned long irq_flags = 0; task_lock_irqsave(self, &irq_flags); kern_status_t status = task_resolve_handle(self, object, &obj, &flags); task_unlock_irqrestore(self, irq_flags); put_current_task(self); if (status != KERN_OK) { return status; } struct vm_object *vmo = vm_object_cast(obj); if (!vmo) { return KERN_INVALID_ARGUMENT; } vm_object_lock_irqsave(vmo, &irq_flags); status = vm_object_write(vmo, src, offset, count, nr_written); vm_object_unlock_irqrestore(vmo, irq_flags); return status; } kern_status_t sys_vm_object_copy( kern_handle_t dst, off_t dst_offset, kern_handle_t src, off_t src_offset, size_t count, size_t *nr_copied) { tracek("vm_object_copy(%x, %zx, %x, %zx, %zx, %p)", dst, dst_offset, src, src_offset, count, nr_copied); struct task *self = get_current_task(); if (nr_copied && !validate_access_w(self, nr_copied, sizeof *nr_copied)) { put_current_task(self); return KERN_MEMORY_FAULT; } unsigned long flags; task_lock_irqsave(self, &flags); kern_status_t status; struct object *dst_obj = NULL, *src_obj = NULL; handle_flags_t dst_flags = 0, src_flags = 0; status = task_resolve_handle(self, dst, &dst_obj, &dst_flags); if (status != KERN_OK) { task_unlock_irqrestore(self, flags); put_current_task(self); return status; } status = task_resolve_handle(self, src, &src_obj, &src_flags); if (status != KERN_OK) { task_unlock_irqrestore(self, flags); put_current_task(self); return status; } task_unlock_irqrestore(self, flags); put_current_task(self); struct vm_object *dst_vmo = vm_object_cast(dst_obj); if (!dst_vmo) { return KERN_INVALID_ARGUMENT; } struct vm_object *src_vmo = vm_object_cast(src_obj); if (!src_vmo) { object_unref(dst_obj); return KERN_INVALID_ARGUMENT; } unsigned long irq_flags = 0; vm_object_lock_irqsave(src_vmo, &irq_flags); status = vm_object_prefetch(src_vmo, src_offset, count, &irq_flags); vm_object_unlock_irqrestore(src_vmo, irq_flags); if (status != KERN_OK) { object_unref(src_obj); object_unref(dst_obj); return status; } vm_object_lock_pair_irqsave(src_vmo, dst_vmo, &irq_flags); status = vm_object_copy( dst_vmo, dst_offset, src_vmo, src_offset, count, nr_copied); vm_object_unlock_pair_irqrestore(src_vmo, dst_vmo, irq_flags); object_unref(src_obj); object_unref(dst_obj); return status; }