#include <vfs.h>
#include <vfs_ext.h>
#include <vfs_int.h>
+#include <mm_virt.h> // MM_USER_MAX
#define MMAP_PAGES_PER_BLOCK 16
// === PROTOTYPES ===
//void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset);
void *VFS_MMap_Anon(void *Destination, size_t Length, Uint FlagsSet, Uint FlagsMask);
+int VFS_MMap_MapPage(tVFS_Node *Node, unsigned int PageNum, tVFS_MMapPageBlock *pb, void *mapping_dest, unsigned int Protection);
//int VFS_MUnmap(void *Addr, size_t Length);
+bool _range_free(const tPage *Base, Uint NumPages);
// === CODE ===
void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset)
{
- tVAddr mapping_base;
- int npages, pagenum;
- tVFS_MMapPageBlock *pb, *prev;
-
- ENTER("pDestHint iLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset);
+ ENTER("pDestHint xLength 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 - 1)) / PAGE_SIZE;
- pagenum = Offset / PAGE_SIZE;
+ unsigned int npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
+ unsigned int pagenum = Offset / PAGE_SIZE;
+ LOG("npages=%u,pagenum=%u", npages, pagenum);
+
+ tVAddr mapping_base = (tVAddr)DestHint;
- mapping_base = (tVAddr)DestHint;
+ if( Flags & MMAP_MAP_FIXED )
+ {
+ ASSERT( (Flags & MMAP_MAP_FIXED) && DestHint != NULL );
+ // Keep and use the hint
+ // - TODO: Validate that the region pointed to by the hint is correct
+ }
+ else
+ {
+ Log_Warning("VFS", "MMap: TODO Handle non-fixed mappings");
+
+ // Locate a free location in the address space (between brk and MM_USER_MAX)
+ // TODO: Prefer first location after DestHint, but can go below
+
+ // Search downwards from the top of user memory
+ mapping_base = 0;
+ for( tPage *dst = (tPage*)MM_USER_MAX - npages; dst > (tPage*)PAGE_SIZE; dst -- )
+ {
+ if( _range_free(dst, npages) ) {
+ mapping_base = (tVAddr)dst;
+ break;
+ }
+ }
+ if( mapping_base == 0 )
+ {
+ Log_Warning("VFS", "MMap: Out of address space");
+ errno = ENOMEM;
+ LEAVE('n');
+ return NULL;
+ }
+ }
tPage *mapping_dest = (void*)(mapping_base & ~(PAGE_SIZE-1));
- if( DestHint == NULL )
+ if( !_range_free(mapping_dest, npages) )
{
- // TODO: Locate space for the allocation
- LEAVE('n');
- return NULL;
+ LOG("Specified range is not free");
+ //errno = EINVAL;
+ //LEAVE('n');
+ //return NULL;
+ Log_Warning("VFS", "MMap: Overwriting/replacing maps at %p+%x", mapping_base, Length);
}
// Handle anonymous mappings
Mutex_Acquire( &h->Node->Lock );
+ tVFS_MMapPageBlock *pb, **pb_pnp = (tVFS_MMapPageBlock**)&h->Node->MMapInfo;
// 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
- )
- ;
+ for( pb = h->Node->MMapInfo; pb; pb_pnp = &pb->Next, pb = pb->Next )
+ {
+ if( pb->BaseOffset + MMAP_PAGES_PER_BLOCK > pagenum )
+ break;
+ }
LOG("pb = %p, pb->BaseOffset = %X", pb, pb ? pb->BaseOffset : 0);
}
pb->Next = old_pb;
pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK;
- if(prev)
- prev->Next = pb;
- else
- h->Node->MMapInfo = pb;
+ *pb_pnp = pb;
}
// - Map (and allocate) pages
while( npages -- )
{
- assert( pagenum >= pb->BaseOffset );
- assert( pagenum - pb->BaseOffset < MMAP_PAGES_PER_BLOCK );
+ ASSERTC( pagenum, >=, pb->BaseOffset );
+ ASSERTC( pagenum - pb->BaseOffset, <, MMAP_PAGES_PER_BLOCK );
if( MM_GetPhysAddr( mapping_dest ) == 0 )
{
- if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
- {
- tVFS_NodeType *nt = h->Node->Type;
- if( !nt )
- {
- // TODO: error
- }
- else if( nt->MMap )
- nt->MMap(h->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
- Mutex_Release( &h->Node->Lock );
- LEAVE('n');
- return NULL;
- }
- // TODO: Clip read length
- read_len = nt->Read(h->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], 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
+ LOG("Map page to %p", mapping_dest);
+ if( VFS_MMap_MapPage(h->Node, pagenum, pb, mapping_dest, Protection) )
{
- 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);
+ Mutex_Release( &h->Node->Lock );
+ LEAVE('n');
+ return NULL;
}
}
else
MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
}
}
- if( Flags & MMAP_MAP_PRIVATE )
+ if( Flags & MMAP_MAP_PRIVATE ) {
+ // TODO: Don't allow the page to change underneath either
MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
+ }
pagenum ++;
mapping_dest ++;
// 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
+ if( !pb->Next || pb->Next->BaseOffset != pagenum )
{
- 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;
+ if( pb->Next ) ASSERTC(pb->Next->BaseOffset % MMAP_PAGES_PER_BLOCK, ==, 0);
+ tVFS_MMapPageBlock *newpb = malloc( sizeof(tVFS_MMapPageBlock) );
+ newpb->Next = pb->Next;
+ newpb->BaseOffset = pagenum;
+ memset(newpb->PhysAddrs, 0, sizeof(newpb->PhysAddrs));
+ pb->Next = newpb;
}
+
+ pb = pb->Next;
}
}
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;
+}
+
int VFS_MUnmap(void *Addr, size_t Length)
{
+ UNIMPLEMENTED();
return 0;
}
+
+bool _range_free(const tPage *Base, Uint NumPages)
+{
+ for( int i = 0; i < NumPages; i ++ )
+ {
+ if( MM_GetPhysAddr(Base + i) )
+ {
+ // Oh.
+ return false;
+ }
+ }
+ return true;
+}