#include #include #include #include #include #include #include static vm_prot_t vm_prot_from_mmap_prot(int prot) { vm_prot_t vm_prot = VM_PROT_USER; if (prot & PROT_READ) { vm_prot |= VM_PROT_READ; } if (prot & PROT_WRITE) { vm_prot |= VM_PROT_WRITE; } if (prot & PROT_EXEC) { vm_prot |= VM_PROT_EXEC; } return vm_prot; } static int get_vmo_anon( int fd, int prot, int flags, size_t length, kern_handle_t *out) { vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot); kern_status_t status = vm_object_create(NULL, 0, length, vm_prot, out); return __errno_from_kern_status(status); } static int get_vmo( int fd, int prot, int flags, size_t length, kern_handle_t *out) { if (fd == -1) { return get_vmo_anon(fd, prot, flags, length, out); } int err = 0; kern_status_t status = fs_map(fd, prot, flags, &err, out); if (status != KERN_OK) { return __errno_from_kern_status(status); } return err; } void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { int tmp = 0; if (flags & MAP_SHARED) { tmp++; } if (flags & MAP_SHARED_VALIDATE) { tmp++; } if (flags & MAP_PRIVATE) { tmp++; } if (tmp != 1) { __set_errno(EINVAL); return MAP_FAILED; } if ((flags & MAP_ANONYMOUS) && fd != -1) { __set_errno(EINVAL); return MAP_FAILED; } if (!(flags & MAP_ANONYMOUS) && fd == -1) { __set_errno(EINVAL); return MAP_FAILED; } kern_status_t status = KERN_OK; kern_handle_t self = KERN_HANDLE_INVALID, address_space = KERN_HANDLE_INVALID; status = task_self(&self); if (status != KERN_OK) { __set_errno(__errno_from_kern_status(status)); return MAP_FAILED; } status = task_get_address_space(self, &address_space); kern_handle_close(self); if (status != KERN_OK) { __set_errno(__errno_from_kern_status(status)); return MAP_FAILED; } kern_handle_t vmo = KERN_HANDLE_INVALID; int err = get_vmo(fd, prot, flags, length, &vmo); if (err != SUCCESS) { kern_handle_close(address_space); __set_errno(err); return MAP_FAILED; } virt_addr_t map_address = 0; vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot); if (addr && (flags & MAP_FIXED)) { status = address_space_map( address_space, (virt_addr_t)addr, vmo, offset, length, vm_prot, &map_address); } else { status = address_space_map( address_space, MAP_ADDRESS_ANY, vmo, offset, length, vm_prot, &map_address); } kern_handle_close(vmo); kern_handle_close(address_space); if (status != KERN_OK) { __set_errno(__errno_from_kern_status(status)); return MAP_FAILED; } return (void *)map_address; }