summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-12-29 02:11:47 +0100
committerAndreas Kling <kling@serenityos.org>2020-12-29 02:20:43 +0100
commit30dbe9c78a50e98befe1e6fa331aaa46ab60a162 (patch)
treec85d776ae59aaede4362fa005b64fcefff44b666
parentc1360ef22e1bf0a3e8745d63ad4f07b13d3acd2c (diff)
downloadserenity-30dbe9c78a50e98befe1e6fa331aaa46ab60a162.zip
Kernel+LibC: Add a very limited sys$mremap() implementation
This syscall can currently only remap a shared file-backed mapping into a private file-backed mapping.
-rw-r--r--Kernel/API/Syscall.h10
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/Syscalls/mmap.cpp37
-rw-r--r--Kernel/VM/Region.h12
-rw-r--r--Libraries/LibC/mman.cpp11
-rw-r--r--Libraries/LibC/mman.h1
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(&params, 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, &params);
+ 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*);