From 35fc9e3bf502663695e350bcdbdfbab7b3b07b9e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 19 Aug 2014 07:50:06 +0800 Subject: [PATCH] Kernel - MMap fixed (non-fixed mappings, bad search), SHM mmap only working --- KernelLand/Kernel/drv/shm.c | 106 ++++++++++++++++++++++++++++++-- KernelLand/Kernel/include/vfs.h | 2 +- KernelLand/Kernel/vfs/io.c | 1 + KernelLand/Kernel/vfs/mmap.c | 49 +++++++++++++-- 4 files changed, 148 insertions(+), 10 deletions(-) diff --git a/KernelLand/Kernel/drv/shm.c b/KernelLand/Kernel/drv/shm.c index f825a0ef..da321413 100644 --- a/KernelLand/Kernel/drv/shm.c +++ b/KernelLand/Kernel/drv/shm.c @@ -12,6 +12,8 @@ #include #include +#define PAGE_COUNT(v) (((v)+(PAGE_SIZE-1))/PAGE_SIZE) + // === TYPES === #define PAGES_PER_BLOCK 1024 typedef struct sSHM_BufferBlock @@ -23,6 +25,7 @@ typedef struct { tMemFS_FileHdr FileHdr; tVFS_Node Node; + size_t nPages; tSHM_BufferBlock FirstBlock; } tSHM_Buffer; @@ -30,6 +33,7 @@ typedef struct int SHM_Install(char **Arguments); int SHM_Uninstall(void); tSHM_Buffer *SHM_CreateBuffer(const char *Name); +bool SHM_AddPages(tSHM_Buffer *Buffer, size_t num); void SHM_DeleteBuffer(tSHM_Buffer *Buffer); // - Root directory int SHM_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]); @@ -39,9 +43,10 @@ tVFS_Node *SHM_MkNod(tVFS_Node *Node, const char *Name, Uint Flags); // - Buffers void SHM_Reference(tVFS_Node *Node); void SHM_Close(tVFS_Node *Node); +off_t SHM_Truncate(tVFS_Node *Node, off_t NewSize); size_t SHM_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags); size_t SHM_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags); - int SHM_MMap(struct sVFS_Node *Node, off_t Offset, int Length, void *Dest); + int SHM_MMap(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest); // === GLOBALS === MODULE_DEFINE(0, 0x0100, SHM, SHM_Install, SHM_Uninstall, NULL); @@ -61,6 +66,7 @@ tVFS_NodeType gSHM_FileNodeType = { .Write = SHM_Write, .Close = SHM_Close, .MMap = SHM_MMap, + .Truncate = SHM_Truncate, .Reference = SHM_Reference, }; tDevFS_Driver gSHM_DriverInfo = { @@ -96,6 +102,40 @@ tSHM_Buffer *SHM_CreateBuffer(const char *Name) ret->Node.ReferenceCount = 1; return ret; } +bool SHM_AddPages(tSHM_Buffer *Buffer, size_t num) +{ + tSHM_BufferBlock *block = &Buffer->FirstBlock; + // Search for final block + size_t idx = Buffer->nPages; + while( block->Next ) { + block = block->Next; + idx -= PAGES_PER_BLOCK; + } + ASSERTC(idx, <=, PAGES_PER_BLOCK); + + for( size_t i = 0; i < num; i ++ ) + { + if( idx == PAGES_PER_BLOCK ) + { + block->Next = calloc(1, sizeof(tSHM_BufferBlock)); + if(!block->Next) { + Log_Warning("SHM", "Out of memory, allocating new buffer block"); + return false; + } + block = block->Next; + idx = 0; + } + ASSERT(block->Pages[idx] == 0); + block->Pages[idx] = MM_AllocPhys(); + if( !block->Pages[idx] ) { + Log_Warning("SHM", "Out of memory, allocating page"); + return false; + } + Buffer->nPages += 1; + idx ++; + } + return true; +} void SHM_DeleteBuffer(tSHM_Buffer *Buffer) { ASSERTCR(Buffer->Node.ReferenceCount,==,0,); @@ -185,6 +225,35 @@ void SHM_Close(tVFS_Node *Node) UNIMPLEMENTED(); } } +off_t SHM_Truncate(tVFS_Node *Node, off_t NewSize) +{ + ENTER("pNode XNewSize", Node, NewSize); + tSHM_Buffer *buffer = Node->ImplPtr; + LOG("Node->Size = 0x%llx", Node->Size); + if( PAGE_COUNT(NewSize) != PAGE_COUNT(Node->Size) ) + { + int page_difference = PAGE_COUNT(NewSize) - PAGE_COUNT(Node->Size); + LOG("page_difference = %i", page_difference); + if( page_difference < 0 ) + { + // Truncate down + // TODO: What if underlying pages are mapped?... should it matter? + UNIMPLEMENTED(); + } + else + { + // Truncate up + SHM_AddPages(buffer, page_difference); + } + } + else + { + LOG("Page count hasn't changed"); + } + Node->Size = NewSize; + LEAVE('X', NewSize); + return NewSize; +} size_t SHM_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) { UNIMPLEMENTED(); @@ -196,9 +265,38 @@ size_t SHM_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffe UNIMPLEMENTED(); return -1; } -int SHM_MMap(struct sVFS_Node *Node, off_t Offset, int Length, void *Dest) +int SHM_MMap(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest) { - UNIMPLEMENTED(); - return 1; + tSHM_Buffer *buf = Node->ImplPtr; + if( Offset > Node->Size ) return 1; + if( Offset + Length > Node->Size ) return 1; + + const int pagecount = (Length + Offset % PAGE_SIZE) / PAGE_SIZE; + int pagenum = Offset / PAGE_SIZE; + + tSHM_BufferBlock *block = &buf->FirstBlock; + while( pagenum > PAGES_PER_BLOCK ) { + block = block->Next; + ASSERT(block); + pagenum -= PAGES_PER_BLOCK; + } + + tPage *dst = Dest; + for( int i = 0; i < pagecount; i ++ ) + { + if( pagenum == PAGES_PER_BLOCK ) { + block = block->Next; + ASSERT(block); + pagenum = 0; + } + + ASSERT(block->Pages[pagenum]); + LOG("%p => %i:%P", dst, pagenum, block->Pages[pagenum]); + MM_Map(dst, block->Pages[pagenum]); + + pagenum ++; + dst ++; + } + return 0; } diff --git a/KernelLand/Kernel/include/vfs.h b/KernelLand/Kernel/include/vfs.h index 72c6cbd3..b030627e 100644 --- a/KernelLand/Kernel/include/vfs.h +++ b/KernelLand/Kernel/include/vfs.h @@ -313,7 +313,7 @@ struct sVFS_NodeType * \return Boolean Failure * \note If NULL, the VFS implements it using .Read */ - int (*MMap)(struct sVFS_Node *Node, off_t Offset, int Length, void *Dest); + int (*MMap)(struct sVFS_Node *Node, off_t Offset, size_t Length, void *Dest); /** * \brief Resize a file diff --git a/KernelLand/Kernel/vfs/io.c b/KernelLand/Kernel/vfs/io.c index cb0140ac..35c1ebf8 100644 --- a/KernelLand/Kernel/vfs/io.c +++ b/KernelLand/Kernel/vfs/io.c @@ -263,6 +263,7 @@ off_t VFS_Truncate(int FD, off_t Size) if( !h->Node->Type->Truncate) { + Log_Notice("VFS", "Nodetype '%s' doesn't have a Truncate method", h->Node->Type->TypeName); errno = ENOTIMPL; return -1; } diff --git a/KernelLand/Kernel/vfs/mmap.c b/KernelLand/Kernel/vfs/mmap.c index 9a7fa44b..9016d564 100644 --- a/KernelLand/Kernel/vfs/mmap.c +++ b/KernelLand/Kernel/vfs/mmap.c @@ -10,6 +10,7 @@ #include #include #include +#include // MM_USER_MAX #define MMAP_PAGES_PER_BLOCK 16 @@ -27,17 +28,19 @@ struct sVFS_MMapPageBlock 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) { - 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; 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; @@ -50,16 +53,38 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, else { Log_Warning("VFS", "MMap: TODO Handle non-fixed mappings"); - if( DestHint == NULL ) + + // 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 ) { - // TODO: Locate space for the allocation - Log_Warning("VFS", "Mmap: Handle NULL destination hint"); + Log_Warning("VFS", "MMap: Out of address space"); + errno = ENOMEM; LEAVE('n'); return NULL; } } tPage *mapping_dest = (void*)(mapping_base & ~(PAGE_SIZE-1)); + if( !_range_free(mapping_dest, npages) ) + { + 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 if( Flags & MMAP_MAP_ANONYMOUS ) { @@ -80,7 +105,7 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, // - Sorted list of 16 page blocks for( pb = h->Node->MMapInfo; pb; pb_pnp = &pb->Next, pb = pb->Next ) { - if( pb->BaseOffset + MMAP_PAGES_PER_BLOCK <= pagenum ) + if( pb->BaseOffset + MMAP_PAGES_PER_BLOCK > pagenum ) break; } @@ -283,5 +308,19 @@ int VFS_MMap_MapPage(tVFS_Node *Node, unsigned int pagenum, tVFS_MMapPageBlock * 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; +} -- 2.20.1