diff --git a/Kernel/include/vfs.h b/Kernel/include/vfs.h
index 248a1ac901d65d60c3fa5e2d345a026b86c5fd72..73161a1c857aafc30af0dad831c3da24b4d35976 100644
--- a/Kernel/include/vfs.h
+++ b/Kernel/include/vfs.h
@@ -155,6 +155,7 @@ typedef struct sVFS_Node
 	
 	/**
 	 * \name VFS_Select() fields
+	 * \note Used by the VFS internals, drivers should use VFS_Mark*
 	 * \{
 	 */
 	 int	DataAvaliable;
@@ -166,6 +167,15 @@ typedef struct sVFS_Node
 	/**
 	 * \}
 	 */
+
+	/**
+	 * \name VFS_MMap() fields
+	 * \{
+	 */
+	void	*MMapInfo;
+	/**
+	 * \}
+	 */
 	
 	/**
 	 * \name Common Functions
diff --git a/Kernel/include/vfs_int.h b/Kernel/include/vfs_int.h
index d4a533da8b9f9468f8dd126fcfb1c43aa0dad32a..0d6b3b5dcc09f81e196b6b82d7d581b583f2ff39 100644
--- a/Kernel/include/vfs_int.h
+++ b/Kernel/include/vfs_int.h
@@ -35,6 +35,11 @@ typedef struct sVFS_Proc {
 	tVFS_Handle	Handles[];
 } tVFS_Proc;
 
+typedef struct sVFS_MMapPage {
+	Uint64	FileOffset;
+	tPAddr	PAddr;
+} tVFS_MMapPage;
+
 // === GLOBALS ===
 extern tVFS_Mount	*gVFS_Mounts;
 
diff --git a/Kernel/vfs/mmap.c b/Kernel/vfs/mmap.c
new file mode 100644
index 0000000000000000000000000000000000000000..f8422bbd7dfbafdbeb33b4691cbf628712d62839
--- /dev/null
+++ b/Kernel/vfs/mmap.c
@@ -0,0 +1,112 @@
+/*
+ * Acess2 VFS
+ * - Open, Close and ChDir
+ */
+#define DEBUG	0
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_ext.h>
+#include <vfs_int.h>
+
+#define MMAP_PAGES_PER_BLOCK	16
+
+// === STRUCTURES ===
+typedef struct sVFS_MMapPageBlock
+{
+	tVFS_MMapPageBlock	*Next;
+	Uint64	BaseOffset;	// Must be a multiple of MMAP_PAGES_PER_BLOCK*PAGE_SIZE
+	tPAddr	PhysAddrs[MMAP_PAGES_PER_BLOCK];
+} tVFS_MMapPageBlock;
+
+// === CODE ===
+void *VFS_MMap(int *ErrNo, void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset)
+{
+	tVFS_Handle	*h;
+	void	*mapping_dest;
+	 int	npages, pagenum;
+	tVFS_MMapPageBlock	*pb, *prev;
+	
+	npages = ((Offset & (PAGE_SIZE-1)) + Length) / PAGE_SIZE;
+	pagenum = Offset / PAGE_SIZE;
+
+	mapping_dest = DestHint;	
+
+	// TODO: Locate space for the allocation
+	if( Flags & MAP_ANONYMOUS )
+	{
+		MM_Allocate(mapping_dest);
+		return mapping_dest;
+	}
+
+	h = VFS_GetHandle(FD);
+	if( !h || !h->Node )	return NULL;
+
+	// Search for existing mapping for each page
+	// - Sorted list of 16 page blocks
+	for(
+		pb = h->Node->MMapInfo, prev = NULL;
+		pb && pb->BaseOffset + MMAP_PAGES_PER_BLOCK < pagenum;
+		prev = pb, pb = pb->Next
+		);
+
+	if( !pb || pb->BaseOffset > pagenum )
+	{
+		void	*old_pb = pb;
+		// Allocate if needed
+		pb = malloc( sizeof(tVFS_MMapPageBlock) );
+		if(!pb)	return NULL;
+		pb->Next = old_pb;
+		pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK;
+		memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
+		if(prev)
+			prev->Next = pb;
+		else
+			h->Node->MMapInfo = pb;
+	}
+
+	while( npages -- )
+	{
+		if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
+		{
+			if( h->Node->MMap )
+				h->Node->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest);
+			else
+			{
+				// Allocate pages and read data
+				MM_Allocate(mapping_dest);
+				h->Node->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest);
+			}
+			pb->PhysAddrs[pagenum -> pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
+		}
+		else
+		{
+			MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] );
+		}
+		pagenum ++;
+		mapping_dest += PAGE_SIZE;
+		
+		// Roll on to next block if needed
+		if(pagenum - pb->BaseOffset == MMAP_PAGES_PER_BLOCK)
+		{
+			if( pb->Next && pb->Next->BaseOffset == pagenum )
+				pb = pb->Next;
+			else
+			{
+				tVFS_MMapPageBlock	*oldpb = pb;
+				pb = malloc( sizeof(tVFS_MMapPageBlock) );
+				pb->Next = oldpb->Next;
+				pb->BaseOffset = pagenum;
+				memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
+				oldpb->Next = pb;
+			}
+			pagenum = 0;
+		}
+	}
+	
+	return NULL;
+}
+
+int VFS_MUnmap(int *ErrNo, void *Addr, size_t Length)
+{
+	return 0;
+}