diff options
-rw-r--r-- | Kernel/API/Syscall.h | 10 | ||||
-rw-r--r-- | Kernel/Process.h | 1 | ||||
-rw-r--r-- | Kernel/Syscalls/mmap.cpp | 37 | ||||
-rw-r--r-- | Kernel/VM/Region.h | 12 | ||||
-rw-r--r-- | Libraries/LibC/mman.cpp | 11 | ||||
-rw-r--r-- | Libraries/LibC/mman.h | 1 |
6 files changed, 71 insertions, 1 deletions
diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 2cc1b0ff33..e83a67b5a3 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -195,7 +195,8 @@ namespace Kernel { S(disown) \ S(adjtime) \ S(allocate_tls) \ - S(prctl) + S(prctl) \ + S(mremap) namespace Syscall { @@ -256,6 +257,13 @@ struct SC_mmap_params { StringArgument name; }; +struct SC_mremap_params { + uintptr_t old_address; + size_t old_size; + size_t new_size; + int32_t flags; +}; + struct SC_open_params { int dirfd; StringArgument path; diff --git a/Kernel/Process.h b/Kernel/Process.h index ab674857c2..b014dbc4a4 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -251,6 +251,7 @@ public: int sys$sigreturn(RegisterState& registers); pid_t sys$waitid(Userspace<const Syscall::SC_waitid_params*>); void* sys$mmap(Userspace<const Syscall::SC_mmap_params*>); + void* sys$mremap(Userspace<const Syscall::SC_mremap_params*>); int sys$munmap(void*, size_t size); int sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*>); int sys$mprotect(void*, size_t, int prot); diff --git a/Kernel/Syscalls/mmap.cpp b/Kernel/Syscalls/mmap.cpp index f756946b00..a647cf2020 100644 --- a/Kernel/Syscalls/mmap.cpp +++ b/Kernel/Syscalls/mmap.cpp @@ -28,6 +28,7 @@ #include <Kernel/FileSystem/FileDescription.h> #include <Kernel/Process.h> #include <Kernel/VM/PageDirectory.h> +#include <Kernel/VM/PrivateInodeVMObject.h> #include <Kernel/VM/PurgeableVMObject.h> #include <Kernel/VM/Region.h> #include <Kernel/VM/SharedInodeVMObject.h> @@ -422,6 +423,42 @@ int Process::sys$munmap(void* addr, size_t size) return -EINVAL; } +void* Process::sys$mremap(Userspace<const Syscall::SC_mremap_params*> user_params) +{ + REQUIRE_PROMISE(stdio); + + Syscall::SC_mremap_params params; + if (!copy_from_user(¶ms, user_params)) + return (void*)-EFAULT; + + auto* old_region = find_region_from_range(Range { VirtualAddress(params.old_address), params.old_size }); + if (!old_region) + return (void*)-EINVAL; + + if (!old_region->is_mmap()) + return (void*)-EPERM; + + if (old_region->vmobject().is_shared_inode() && params.flags & MAP_PRIVATE && !(params.flags & MAP_ANONYMOUS) && !(params.flags & MAP_PURGEABLE)) { + auto range = old_region->range(); + auto old_name = old_region->name(); + auto old_prot = region_access_flags_to_prot(old_region->access()); + NonnullRefPtr inode = static_cast<SharedInodeVMObject&>(old_region->vmobject()).inode(); + deallocate_region(*old_region); + + auto new_vmobject = PrivateInodeVMObject::create_with_inode(inode); + auto* new_region = allocate_region_with_vmobject(range.base(), range.size(), new_vmobject, 0, old_name, old_prot); + new_region->set_mmap(true); + + if (!new_region) + return (void*)-ENOMEM; + + return new_region->vaddr().as_ptr(); + } + + dbgln("sys$mremap: Unimplemented remap request (flags={})", params.flags); + return (void*)-ENOTIMPL; +} + void* Process::sys$allocate_tls(size_t size) { REQUIRE_PROMISE(stdio); diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index a81bcd9693..575b595186 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -238,4 +238,16 @@ inline unsigned prot_to_region_access_flags(int prot) return access; } +inline int region_access_flags_to_prot(unsigned access) +{ + int prot = 0; + if (access & Region::Access::Read) + prot |= PROT_READ; + if (access & Region::Access::Write) + prot |= PROT_WRITE; + if (access & Region::Access::Execute) + prot |= PROT_EXEC; + return prot; +} + } diff --git a/Libraries/LibC/mman.cpp b/Libraries/LibC/mman.cpp index 9dd97d6a1e..3df02a46da 100644 --- a/Libraries/LibC/mman.cpp +++ b/Libraries/LibC/mman.cpp @@ -53,6 +53,17 @@ void* mmap_with_name(void* addr, size_t size, int prot, int flags, int fd, off_t return serenity_mmap(addr, size, prot, flags, fd, offset, PAGE_SIZE, name); } +void* mremap(void* old_address, size_t old_size, size_t new_size, int flags) +{ + Syscall::SC_mremap_params params { (uintptr_t)old_address, old_size, new_size, flags }; + ssize_t rc = syscall(SC_mremap, ¶ms); + if (rc < 0 && -rc < EMAXERRNO) { + errno = -rc; + return MAP_FAILED; + } + return (void*)rc; +} + int munmap(void* addr, size_t size) { int rc = syscall(SC_munmap, addr, size); diff --git a/Libraries/LibC/mman.h b/Libraries/LibC/mman.h index 1df98de821..b783554365 100644 --- a/Libraries/LibC/mman.h +++ b/Libraries/LibC/mman.h @@ -56,6 +56,7 @@ __BEGIN_DECLS void* mmap(void* addr, size_t, int prot, int flags, int fd, off_t); void* mmap_with_name(void* addr, size_t, int prot, int flags, int fd, off_t, const char* name); void* serenity_mmap(void* addr, size_t, int prot, int flags, int fd, off_t, size_t alignment, const char* name); +void* mremap(void* old_address, size_t old_size, size_t new_size, int flags); int munmap(void*, size_t); int mprotect(void*, size_t, int prot); int set_mmap_name(void*, size_t, const char*); |