diff --git a/Cargo.lock b/Cargo.lock
index 32ff40ab7532ee9e58e4fbb12eae07f931566f2b..d2097dc850342c701930a1c5369d20b3db5d7ec5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "ahash"
@@ -233,8 +233,8 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.7"
-source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#f3fc45a1b74debc4a188276640fdfb8be47ccc25"
+version = "0.5.8"
+source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#3d786423f1d9c71d408bc3c9a64648b883aaf36b"
 dependencies = [
  "bitflags 2.6.0",
 ]
diff --git a/src/context/memory.rs b/src/context/memory.rs
index 615b610801d6fcfe849364c52133967d8ddfd510..890eb5b21e7a960cafa389decea4963491c5b480 100644
--- a/src/context/memory.rs
+++ b/src/context/memory.rs
@@ -1102,6 +1102,22 @@ pub struct GrantFileRef {
 impl Grant {
     // TODO: PageCount newtype, to avoid confusion between bytes and pages?
 
+    // `base` must be mapped by the caller.
+    pub fn allocated_one_page_nomap(base: Page, flags: PageFlags<RmmA>) -> Grant {
+        Grant {
+            base,
+            info: GrantInfo {
+                page_count: 1,
+                flags,
+                mapped: true,
+                provider: Provider::Allocated {
+                    cow_file_ref: None,
+                    phys_contiguous: false,
+                },
+            },
+        }
+    }
+
     // TODO: is_pinned
     pub fn allocated_shared_one_page(
         frame: Frame,
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 0ab2b16052c02ceb8632c169a1498369b16d01b6..bf294ed4aebd661874eea3f462b584bf27f1c13c 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -370,6 +370,11 @@ impl RaiiFrame {
     pub fn get(&self) -> Frame {
         self.inner
     }
+    pub fn take(self) -> Frame {
+        let f = self.get();
+        core::mem::forget(self);
+        f
+    }
 }
 
 impl Drop for RaiiFrame {
diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index 43fbdbc2349e9ac01135ede43def75aab1ab6c9b..62f0753c29d860b20b06785a003c95df5f0a9fd6 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -1,4 +1,6 @@
 //! Filesystem syscalls
+use core::num::NonZeroUsize;
+
 use alloc::{sync::Arc, vec::Vec};
 use redox_path::RedoxPath;
 use spin::RwLock;
@@ -7,7 +9,7 @@ use crate::{
     context::{
         self,
         file::{FileDescription, FileDescriptor, InternalFlags},
-        memory::{AddrSpace, PageSpan},
+        memory::{AddrSpace, GenericFlusher, Grant, PageSpan, TlbShootdownActions},
         process,
     },
     paging::{Page, VirtualAddress, PAGE_SIZE},
@@ -491,16 +493,51 @@ pub fn mremap(
     let new_page_count = new_size.div_ceil(PAGE_SIZE);
     let requested_dst_base = Some(new_base).filter(|_| new_address != 0);
 
-    let base = addr_space.r#move(
-        None,
-        src_span,
-        requested_dst_base,
-        new_page_count,
-        map_flags,
-        &mut Vec::new(),
-    )?;
+    if mremap_flags.contains(MremapFlags::KEEP_OLD) {
+        // TODO: This is a hack! Find a better interface for replacing this, perhaps a capability
+        // for non-CoW-borrowed i.e. owned frames, that can be inserted into address spaces.
+        if new_page_count != 1 {
+            return Err(Error::new(EOPNOTSUPP));
+        }
+
+        let raii_frame = addr_space.borrow_frame_enforce_rw_allocated(src_span.base)?;
+
+        let base = addr_space.acquire_write().mmap(
+            &addr_space,
+            requested_dst_base,
+            NonZeroUsize::new(1).unwrap(),
+            map_flags,
+            &mut Vec::new(),
+            |page, page_flags, mapper, flusher| {
+                let frame = raii_frame.take();
+                // XXX: add_ref(RefKind::Shared) is internally done by borrow_frame_enforce_rw_allocated(src_span.base).
+                // The page does not get unref-ed as we call take() on the `raii_frame`.
+                unsafe {
+                    mapper
+                        .map_phys(page.start_address(), frame.base(), page_flags)
+                        .ok_or(Error::new(ENOMEM))?
+                        .ignore();
+
+                    flusher.queue(frame, None, TlbShootdownActions::NEW_MAPPING);
+                }
+
+                Ok(Grant::allocated_one_page_nomap(page, page_flags))
+            },
+        )?;
 
-    Ok(base.start_address().data())
+        Ok(base.start_address().data())
+    } else {
+        let base = addr_space.r#move(
+            None,
+            src_span,
+            requested_dst_base,
+            new_page_count,
+            map_flags,
+            &mut Vec::new(),
+        )?;
+
+        Ok(base.start_address().data())
+    }
 }
 
 pub fn lseek(fd: FileHandle, pos: i64, whence: usize) -> Result<usize> {