Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
[tpg/acess2.git] / Kernel / vfs / mmap.c
index 7c3fdf4..9fe9282 100644 (file)
@@ -1,6 +1,9 @@
 /*
- * Acess2 VFS
- * - Open, Close and ChDir
+ * Acess2 Kernel VFS
+ * - By John Hodge (thePowersGang)
+ *
+ * mmap.c
+ * - VFS_MMap support
  */
 #define DEBUG  0
 #include <acess.h>
@@ -9,7 +12,6 @@
 #include <vfs_int.h>
 
 #define MMAP_PAGES_PER_BLOCK   16
-#define PAGE_SIZE      0x1000  // Should be in mm_virt.h
 
 // === STRUCTURES ===
 typedef struct sVFS_MMapPageBlock      tVFS_MMapPageBlock;
@@ -24,26 +26,58 @@ struct sVFS_MMapPageBlock
 void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset)
 {
        tVFS_Handle     *h;
-       tVAddr  mapping_dest;
+       tVAddr  mapping_dest, mapping_base;
         int    npages, pagenum;
        tVFS_MMapPageBlock      *pb, *prev;
+
+       ENTER("pDestHint iLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset);
+
+       if( Flags & MMAP_MAP_ANONYMOUS )
+               Offset = (tVAddr)DestHint & 0xFFF;
        
-       npages = ((Offset & (PAGE_SIZE-1)) + Length) / PAGE_SIZE;
+       npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
        pagenum = Offset / PAGE_SIZE;
 
-       mapping_dest = (tVAddr)DestHint;        
+       mapping_base = (tVAddr)DestHint;
+       mapping_dest = mapping_base & ~(PAGE_SIZE-1);
 
-#if 0
        // TODO: Locate space for the allocation
-       if( Flags & MAP_ANONYMOUS )
+
+       // Handle anonymous mappings
+       if( Flags & MMAP_MAP_ANONYMOUS )
        {
-               MM_Allocate(mapping_dest);
-               return (void*)mapping_dest;
+               size_t  ofs = 0;
+               LOG("%i pages anonymous to %p", npages, mapping_dest);
+               for( ; npages --; mapping_dest += PAGE_SIZE, ofs += PAGE_SIZE )
+               {
+                       if( MM_GetPhysAddr(mapping_dest) ) {
+                               // TODO: Set flags to COW if needed (well, if shared)
+                               MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
+                               LOG("clear from %p, %i bytes", (void*)(mapping_base + ofs),
+                                       PAGE_SIZE - (mapping_base & (PAGE_SIZE-1))
+                                       );
+                               memset( (void*)(mapping_base + ofs), 0, PAGE_SIZE - (mapping_base & (PAGE_SIZE-1)));
+                       }
+                       else {
+                               LOG("New empty page");
+                               // TODO: Map a COW zero page instead
+                               if( !MM_Allocate(mapping_dest) ) {
+                                       // TODO: Error
+                                       Log_Warning("VFS", "VFS_MMap: Anon alloc to %p failed", mapping_dest);
+                               }
+                               memset((void*)mapping_dest, 0, PAGE_SIZE);
+                               LOG("Anon map to %p", mapping_dest);
+                       }
+               }
+               LEAVE_RET('p', (void*)mapping_base);
        }
-#endif
 
        h = VFS_GetHandle(FD);
-       if( !h || !h->Node )    return NULL;
+       if( !h || !h->Node )    LEAVE_RET('n', NULL);
+
+       LOG("h = %p", h);
+       
+       Mutex_Acquire( &h->Node->Lock );
 
        // Search for existing mapping for each page
        // - Sorted list of 16 page blocks
@@ -53,12 +87,17 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
                prev = pb, pb = pb->Next
                );
 
+       LOG("pb = %p, pb->BaseOffset = %X", pb, pb ? pb->BaseOffset : 0);
+
        // - Allocate a block if needed
        if( !pb || pb->BaseOffset > pagenum )
        {
                void    *old_pb = pb;
                pb = malloc( sizeof(tVFS_MMapPageBlock) );
-               if(!pb) return NULL;
+               if(!pb) {
+                       Mutex_Release( &h->Node->Lock );
+                       LEAVE_RET('n', NULL);
+               }
                pb->Next = old_pb;
                pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK;
                memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
@@ -71,29 +110,76 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
        // - Map (and allocate) pages
        while( npages -- )
        {
-               if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
+               if( MM_GetPhysAddr(mapping_dest) == 0 )
                {
-                       if( h->Node->MMap )
-                               h->Node->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
-                       else
+                       if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
                        {
-                               // Allocate pages and read data
-                               if( MM_Allocate(mapping_dest) == 0 ) {
-                                       // TODO: Unwrap
-                                       return NULL;
+                               tVFS_NodeType   *nt = h->Node->Type;
+                               if( !nt ) 
+                               {
+                                       // TODO: error
+                               }
+                               else if( nt->MMap )
+                                       nt->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+                               else
+                               {
+                                        int    read_len;
+                                       // Allocate pages and read data
+                                       if( MM_Allocate(mapping_dest) == 0 ) {
+                                               // TODO: Unwrap
+                                               Mutex_Release( &h->Node->Lock );
+                                               LEAVE('n');
+                                               return NULL;
+                                       }
+                                       // TODO: Clip read length
+                                       read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+//                                     if( read_len != PAGE_SIZE ) {
+//                                             memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
+//                                     }
                                }
-                               h->Node->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
+                               pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
+                               MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node );
+                               MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                               LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
+                                       pb->PhysAddrs[pagenum - pb->BaseOffset]);
+                       }
+                       else
+                       {
+                               MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                               MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                               LOG("Cached map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
+                                       pb->PhysAddrs[pagenum - pb->BaseOffset]);
+                       }
+                       h->Node->ReferenceCount ++;
+               
+                       // Set flags
+                       if( !(Protection & MMAP_PROT_WRITE) ) {
+                               MM_SetFlags(mapping_dest, MM_PFLAG_RO, MM_PFLAG_RO);
+                       }
+                       else {
+                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
+                       }
+                       
+                       if( Protection & MMAP_PROT_EXEC ) {
+                               MM_SetFlags(mapping_dest, MM_PFLAG_EXEC, MM_PFLAG_EXEC);
+                       }
+                       else {
+                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_EXEC);
                        }
-                       pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
-//                     MM_SetPageInfo( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node, pagenum*PAGE_SIZE );
                }
                else
                {
-                       MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] );
+                       LOG("Flag update on %p", mapping_dest);
+                       if( (MM_GetFlags(mapping_dest) & MM_PFLAG_RO) && (Protection & MMAP_PROT_WRITE) )
+                       {
+                               MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
+                       }
                }
+               if( Flags & MMAP_MAP_PRIVATE )
+                       MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
                pagenum ++;
                mapping_dest += PAGE_SIZE;
-               
+
                // Roll on to next block if needed
                if(pagenum - pb->BaseOffset == MMAP_PAGES_PER_BLOCK)
                {
@@ -112,7 +198,10 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
                }
        }
        
-       return NULL;
+       Mutex_Release( &h->Node->Lock );
+
+       LEAVE('p', mapping_base);
+       return (void*)mapping_base;
 }
 
 int VFS_MUnmap(void *Addr, size_t Length)

UCC git Repository :: git.ucc.asn.au