#include <memfs_helpers.h>
#include <semaphore.h>
+#define PAGE_COUNT(v) (((v)+(PAGE_SIZE-1))/PAGE_SIZE)
+
// === TYPES ===
#define PAGES_PER_BLOCK 1024
typedef struct sSHM_BufferBlock
{
tMemFS_FileHdr FileHdr;
tVFS_Node Node;
+ size_t nPages;
tSHM_BufferBlock FirstBlock;
} tSHM_Buffer;
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]);
// - 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);
.Write = SHM_Write,
.Close = SHM_Close,
.MMap = SHM_MMap,
+ .Truncate = SHM_Truncate,
.Reference = SHM_Reference,
};
tDevFS_Driver gSHM_DriverInfo = {
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,);
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();
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;
}
#include <vfs.h>
#include <vfs_ext.h>
#include <vfs_int.h>
+#include <mm_virt.h> // MM_USER_MAX
#define MMAP_PAGES_PER_BLOCK 16
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;
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 )
{
// - 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;
}
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;
+}