+void *VFS_MMap_Anon(void *Destination, size_t Length, Uint FlagsSet, Uint FlagsMask)
+{
+ size_t ofs = (tVAddr)Destination & (PAGE_SIZE-1);
+ tPage *mapping_dest = (void*)( (char*)Destination - ofs );
+
+ if( ofs > 0 )
+ {
+ size_t bytes = MIN(PAGE_SIZE - ofs, Length);
+
+ // Allocate a partial page
+ if( MM_GetPhysAddr(mapping_dest) )
+ {
+ // Already allocated page, clear the area we're touching
+ ASSERT( ofs + bytes <= PAGE_SIZE );
+
+ // TODO: Double check that this area isn't already zero
+ memset( Destination, 0, bytes );
+
+ MM_SetFlags(mapping_dest, FlagsSet, FlagsMask);
+
+ LOG("#1: Clear %i from %p", Length, Destination);
+ }
+ else
+ {
+ MM_AllocateZero(mapping_dest);
+ LOG("#1: Allocate for %p", Destination);
+ }
+ mapping_dest ++;
+ Length -= bytes;
+ }
+ while( Length >= PAGE_SIZE )
+ {
+ if( MM_GetPhysAddr( mapping_dest ) )
+ {
+ // We're allocating entire pages here, so free this page and replace with a COW zero
+ MM_Deallocate(mapping_dest);
+ LOG("Replace %p with zero page", mapping_dest);
+ }
+ else
+ {
+ LOG("Allocate zero at %p", mapping_dest);
+ }
+ MM_AllocateZero(mapping_dest);
+
+ mapping_dest ++;
+ Length -= PAGE_SIZE;
+ }
+ if( Length > 0 )
+ {
+ ASSERT(Length < PAGE_SIZE);
+
+ // Tail page
+ if( MM_GetPhysAddr(mapping_dest) )
+ {
+ // TODO: Don't touch page if already zero
+ memset( mapping_dest, 0, Length );
+ LOG("Clear %i in %p", Length, mapping_dest);
+ }
+ else
+ {
+ MM_AllocateZero(mapping_dest);
+ LOG("Anon map to %p", mapping_dest);
+ }
+ }
+
+ return Destination;
+}
+
+int VFS_MMap_MapPage(tVFS_Node *Node, unsigned int pagenum, tVFS_MMapPageBlock *pb, void *mapping_dest, unsigned int Protection)
+{
+ if( pb->PhysAddrs[pagenum - pb->BaseOffset] != 0 )
+ {
+ 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]);
+ }
+ else
+ {
+ tVFS_NodeType *nt = Node->Type;
+ if( !nt )
+ {
+ // TODO: error
+ }
+ else if( nt->MMap )
+ nt->MMap(Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest);
+ else
+ {
+ int read_len;
+ // Allocate pages and read data
+ if( MM_Allocate(mapping_dest) == 0 ) {
+ // TODO: Unwrap
+ return 1;
+ }
+ // TODO: Clip read length
+ read_len = nt->Read(Node, pagenum*PAGE_SIZE, PAGE_SIZE, mapping_dest, 0);
+ // TODO: This was commented out, why?
+ if( read_len != PAGE_SIZE ) {
+ memset( (char*)mapping_dest + read_len, 0, PAGE_SIZE-read_len );
+ }
+ }
+ pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
+ MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], 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]);
+ }
+ // TODO: Huh?
+ 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);
+ }
+
+ return 0;
+}
+