X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fvfs%2Fmmap.c;h=9fe9282c309b4a52cc15dad8e41f5e74f3910099;hb=a2495c6ea4f4cab16b5d339ae511428e92e89e73;hp=dbdd4b2a9b7234ac6b8e2d05fafbd66f23a4d96c;hpb=e9391ef54c88fb5180d6330a7a1b43c3115befb8;p=tpg%2Facess2.git diff --git a/Kernel/vfs/mmap.c b/Kernel/vfs/mmap.c index dbdd4b2a..9fe9282c 100644 --- a/Kernel/vfs/mmap.c +++ b/Kernel/vfs/mmap.c @@ -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 @@ -9,7 +12,6 @@ #include #define MMAP_PAGES_PER_BLOCK 16 -#define PAGE_SIZE 0x1000 // Should be in mm_virt.h // === STRUCTURES === typedef struct sVFS_MMapPageBlock tVFS_MMapPageBlock; @@ -21,27 +23,61 @@ struct sVFS_MMapPageBlock }; // === CODE === -void *VFS_MMap(int *ErrNo, void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset) +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 = DestHint; + mapping_base = (tVAddr)DestHint; + mapping_dest = mapping_base & ~(PAGE_SIZE-1); // 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); } 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 @@ -51,12 +87,17 @@ void *VFS_MMap(int *ErrNo, void *DestHint, size_t Length, int Protection, int Fl 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; - // Allocate if needed 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)); @@ -66,27 +107,79 @@ void *VFS_MMap(int *ErrNo, void *DestHint, size_t Length, int Protection, int Fl h->Node->MMapInfo = pb; } + // - 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); + 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, (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 ); +// } + } + 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 { - // Allocate pages and read data - MM_Allocate(mapping_dest); - h->Node->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest); + 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 ); } 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) { @@ -105,10 +198,13 @@ void *VFS_MMap(int *ErrNo, void *DestHint, size_t Length, int Protection, int Fl } } - return NULL; + Mutex_Release( &h->Node->Lock ); + + LEAVE('p', mapping_base); + return (void*)mapping_base; } -int VFS_MUnmap(int *ErrNo, void *Addr, size_t Length) +int VFS_MUnmap(void *Addr, size_t Length) { return 0; }