diff --git a/quasar-wayland.cabal b/quasar-wayland.cabal
index b767d0c80cc18410be01d5d07949dc114f4f212f..3e31b23a45e5e7029c27ecfacb00f8a1fe66b868 100644
--- a/quasar-wayland.cabal
+++ b/quasar-wayland.cabal
@@ -99,6 +99,7 @@ library
     network,
     quasar,
     template-haskell,
+    unix,
     unordered-containers,
     utf8-string,
     stm,
diff --git a/src/Quasar/Wayland/Utils/SharedMemory.hs b/src/Quasar/Wayland/Utils/SharedMemory.hs
index 4de2aab8be377a8383e6b645be60190782abaa6e..39767e85f5f8d9987b9f53247cf01ef57175ffe9 100644
--- a/src/Quasar/Wayland/Utils/SharedMemory.hs
+++ b/src/Quasar/Wayland/Utils/SharedMemory.hs
@@ -2,24 +2,28 @@
 {-# LANGUAGE TemplateHaskell #-}
 
 module Quasar.Wayland.Utils.SharedMemory (
-  allocateShmFd,
+  memfdCreate,
+  mmap,
 ) where
 
+import Foreign
+import Foreign.Concurrent qualified as FC
 import Foreign.C.Error
 import Language.C.Inline qualified as C
 import Language.C.Inline.Unsafe qualified as CU
 import Quasar.Prelude
 import Quasar.Wayland.Utils.InlineC
-import System.Posix.Types (COff(..), Fd(Fd))
+import System.Posix.Types (Fd(Fd), COff(..))
 
 C.context ctx
 
 C.verbatim "#define _GNU_SOURCE"
 C.include "<unistd.h>"
+C.include "<stdint.h>"
 C.include "<sys/mman.h>"
 
-allocateShmFd :: COff -> IO Fd
-allocateShmFd size = Fd <$> throwErrnoIfMinus1 "allocateShmFd"
+memfdCreate :: COff -> IO Fd
+memfdCreate size = Fd <$> throwErrnoIfMinus1 "memfd_create/ftruncate"
   [CU.block|
     int {
       int fd = memfd_create("shm", MFD_CLOEXEC | MFD_ALLOW_SEALING);
@@ -34,3 +38,14 @@ allocateShmFd size = Fd <$> throwErrnoIfMinus1 "allocateShmFd"
       return fd;
     }
   |]
+
+mmap :: Fd -> C.CSize -> IO (ForeignPtr Word8)
+mmap (Fd fd) size = do
+  ptr <- fmap intPtrToPtr . throwErrnoIfMinus1 "mmap" $
+    ptrToIntPtr <$> [CU.exp| void*{ mmap(NULL, $(size_t size), PROT_READ | PROT_WRITE, MAP_SHARED, $(int fd), 0) } |]
+  FC.newForeignPtr ptr (munmap ptr size)
+
+munmap :: Ptr a -> C.CSize -> IO ()
+munmap (castPtr -> ptr) size =
+  throwErrnoIfMinus1_ "munmap" $
+    [CU.exp| int { munmap($(void* ptr), $(size_t size)) } |]