From acf1eebc9861784777a84b52fc0f2070f4dbe730 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 16 Dec 2011 13:24:49 +0100 Subject: [PATCH] Added user-space memory allocation. --- libmaxsi/c/hsrc/unistd.h | 1 + libmaxsi/heap.cpp | 63 +++++++++++++++++++------- libmaxsi/hsrc/memory.h | 6 +-- libmaxsi/init.cpp | 4 ++ libmaxsi/memory.cpp | 6 +++ sortix/elf.cpp | 2 + sortix/process.cpp | 42 +++++++++++++++++ sortix/process.h | 5 ++ sortix/syscallnum.h | 3 +- sortix/x86-family/memorymanagement.cpp | 6 ++- 10 files changed, 114 insertions(+), 24 deletions(-) diff --git a/libmaxsi/c/hsrc/unistd.h b/libmaxsi/c/hsrc/unistd.h index 8f3ccbe5..08c164ab 100644 --- a/libmaxsi/c/hsrc/unistd.h +++ b/libmaxsi/c/hsrc/unistd.h @@ -179,6 +179,7 @@ ssize_t write(int, const void*, size_t); int memstat(size_t* memused, size_t* memtotal); int uptime(uintmax_t* usecssinceboot); int writeall(int fd, const void* buffer, size_t len); +void* sbrk(intptr_t increment); #endif __END_DECLS diff --git a/libmaxsi/heap.cpp b/libmaxsi/heap.cpp index 0363d947..30189b8f 100644 --- a/libmaxsi/heap.cpp +++ b/libmaxsi/heap.cpp @@ -30,6 +30,10 @@ #define HEAP_GROWS_DOWNWARDS #endif +#ifndef SORTIX_KERNEL +#include +#endif + #define PARANOIA 1 #ifdef SORTIX_KERNEL @@ -59,23 +63,19 @@ namespace Maxsi const size_t PAGESIZE = 4UL * 1024UL; // 4 KiB const size_t NUMBINS = 8UL * sizeof(size_t); + extern addr_t wilderness; + +#ifdef SORTIX_KERNEL addr_t GetHeapStart() { - #ifdef SORTIX_KERNEL - return Sortix::Memory::HEAPUPPER; - #endif - return 0; // TODO: Not implemented in User-Space yet! + return Sortix::Memory::HEAPUPPER; } size_t GetHeapMaxSize() { - #ifdef SORTIX_KERNEL - return Sortix::Memory::HEAPUPPER - Sortix::Memory::HEAPLOWER; - #endif - return 0; // TODO: Not implemented in User-Space yet! + return Sortix::Memory::HEAPUPPER - Sortix::Memory::HEAPLOWER; } -#ifdef SORTIX_KERNEL void FreeMemory(addr_t where, size_t bytes) { ASSERT( (bytes & (PAGESIZE-1UL)) == 0 ); @@ -118,15 +118,40 @@ namespace Maxsi return true; } -#else - void FreeMemory(addr_t where, size_t bytes) + + bool ExtendHeap(size_t bytesneeded) { + #ifdef HEAP_GROWS_DOWNWARDS + addr_t newwilderness = wilderness - bytesneeded; + #else + addr_t newwilderness = wilderness + bytesneeded; + #endif + + return AllocateMemory(newwilderness, bytesneeded); + } +#else + addr_t GetHeapStart() + { + addr_t base = (addr_t) sbrk(0); + addr_t unaligned = base % ALIGNMENT; + if ( unaligned ) + { + sbrk(ALIGNMENT-unaligned); + } + addr_t result = (addr_t) sbrk(0); + return result; } - bool AllocateMemory(addr_t where, size_t bytes) + size_t GetHeapMaxSize() { - Error::Set(ENOMEM); - return false; + // TODO: A bit of a hack! + return SIZE_MAX; + } + + bool ExtendHeap(size_t bytesneeded) + { + void* newheapend = sbrk(bytesneeded); + return newheapend != (void*) -1UL; } #endif @@ -395,7 +420,7 @@ namespace Maxsi #endif // Attempt to map pages so our wilderness grows. - if ( !AllocateMemory(newwilderness, bytesneeded) ) { return false; } + if ( !ExtendHeap(bytesneeded) ) { return false; } wildernesssize += bytesneeded; wilderness = newwilderness; @@ -520,7 +545,7 @@ namespace Maxsi #ifdef HEAP_GROWS_DOWNWARDS return heapstart <= (addr_t) chunk + chunk->size; #else - return (addr_t) chunk + chunk->size <= heapstart + heapsize; + return heapstart + heapsize <= (addr_t) chunk + chunk->size; #endif } @@ -619,3 +644,9 @@ namespace Maxsi } } } + +void* operator new(size_t Size) { return Maxsi::Memory::Allocate(Size); } +void* operator new[](size_t Size) { return Maxsi::Memory::Allocate(Size); } +void operator delete (void* Addr) { return Maxsi::Memory::Free(Addr); }; +void operator delete[](void* Addr) { return Maxsi::Memory::Free(Addr); }; + diff --git a/libmaxsi/hsrc/memory.h b/libmaxsi/hsrc/memory.h index 3392c80e..e93c4aea 100644 --- a/libmaxsi/hsrc/memory.h +++ b/libmaxsi/hsrc/memory.h @@ -39,15 +39,11 @@ namespace Maxsi } } +// Placement new. inline void* operator new(size_t, void* p) { return p; } inline void* operator new[](size_t, void* p) { return p; } inline void operator delete (void*, void*) { }; inline void operator delete[](void*, void*) { }; -inline void* operator new(size_t Size) { return Maxsi::Memory::Allocate(Size); } -inline void* operator new[](size_t Size) { return Maxsi::Memory::Allocate(Size); } -inline void operator delete (void* Addr) { return Maxsi::Memory::Free(Addr); }; -inline void operator delete[](void* Addr) { return Maxsi::Memory::Free(Addr); }; - #endif diff --git a/libmaxsi/init.cpp b/libmaxsi/init.cpp index 3bf01e2f..ecc7a296 100644 --- a/libmaxsi/init.cpp +++ b/libmaxsi/init.cpp @@ -27,6 +27,7 @@ #include "signal.h" #include "string.h" #include "io.h" +#include "memory.h" namespace Maxsi { @@ -47,5 +48,8 @@ namespace Maxsi // It's probably best to initialize the Unix signals early on. Signal::Init(); + + // Initialize the dynamic heap. + Memory::Init(); } } diff --git a/libmaxsi/memory.cpp b/libmaxsi/memory.cpp index d2a2e47d..ef940b00 100644 --- a/libmaxsi/memory.cpp +++ b/libmaxsi/memory.cpp @@ -35,11 +35,17 @@ namespace Maxsi { #ifndef SORTIX_KERNEL DEFN_SYSCALL2(int, SysMemStat, SYSCALL_MEMSTAT, size_t*, size_t*); + DEFN_SYSCALL1(void*, SysSbrk, SYSCALL_SBRK, intptr_t); extern "C" int memstat(size_t* memused, size_t* memtotal) { return SysMemStat(memused, memtotal); } + + extern "C" void* sbrk(intptr_t increment) + { + return SysSbrk(increment); + } #endif DUAL_FUNCTION(void*, memcpy, Copy, (void* Dest, const void* Src, size_t Length)) diff --git a/sortix/elf.cpp b/sortix/elf.cpp index 038d5002..ac00d3eb 100644 --- a/sortix/elf.cpp +++ b/sortix/elf.cpp @@ -83,6 +83,7 @@ namespace Sortix if ( segment == NULL ) { return 0; } segment->position = mapto; segment->size = Page::AlignUp(mapbytes); + segment->type = SEG_DATA; // TODO: BUG if ( segment->Intersects(process->segments) ) { @@ -162,6 +163,7 @@ namespace Sortix if ( segment == NULL ) { return 0; } segment->position = mapto; segment->size = Page::AlignUp(mapbytes); + segment->type = SEG_DATA; // TODO: BUG if ( segment->Intersects(process->segments) ) { diff --git a/sortix/process.cpp b/sortix/process.cpp index 31362d88..e0d7aa8a 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -691,6 +691,47 @@ namespace Sortix return 0; } + void* SysSbrk(intptr_t increment) + { + Process* process = CurrentProcess(); + ProcessSegment* dataseg = NULL; + for ( ProcessSegment* iter = process->segments; iter; iter = iter->next ) + { + if ( !iter->type == SEG_DATA ) { continue; } + if ( dataseg && iter->position < dataseg->position ) { continue; } + dataseg = iter; + } + if ( !dataseg ) { Error::Set(ENOMEM); return (void*) -1UL; } + addr_t currentend = dataseg->position + dataseg->size; + addr_t newend = currentend + increment; + if ( newend < dataseg->position ) { Error::Set(EINVAL); return (void*) -1UL; } + if ( newend < currentend ) + { + addr_t unmapfrom = Page::AlignUp(newend); + if ( unmapfrom < currentend ) + { + size_t unmapbytes = Page::AlignUp(currentend - unmapfrom); + Memory::UnmapRangeUser(unmapfrom, unmapbytes); + } + } + else if ( currentend < newend ) + { + // TODO: HACK: Make a safer way of expanding the data segment + // without segments possibly colliding! + addr_t mapfrom = Page::AlignUp(currentend); + if ( mapfrom < newend ) + { + size_t mapbytes = Page::AlignUp(newend - mapfrom); + if ( !Memory::MapRangeUser(mapfrom, mapbytes) ) + { + return (void*) -1UL; + } + } + } + dataseg->size += increment; + return (void*) newend; + } + void Process::Init() { Syscall::Register(SYSCALL_EXEC, (void*) SysExecVE); @@ -700,6 +741,7 @@ namespace Sortix Syscall::Register(SYSCALL_EXIT, (void*) SysExit); Syscall::Register(SYSCALL_WAIT, (void*) SysWait); Syscall::Register(SYSCALL_REGISTER_ERRNO, (void*) SysRegisterErrno); + Syscall::Register(SYSCALL_SBRK, (void*) SysSbrk); nextpidtoallocate = 0; diff --git a/sortix/process.h b/sortix/process.h index b0d360dc..f45ed068 100644 --- a/sortix/process.h +++ b/sortix/process.h @@ -34,6 +34,10 @@ namespace Sortix struct ProcessSegment; const size_t DEFAULT_STACK_SIZE = 64*1024; + const int SEG_TEXT = 0; + const int SEG_DATA = 1; + const int SEG_STACK = 2; + const int SEG_OTHER = 3; struct ProcessSegment { @@ -45,6 +49,7 @@ namespace Sortix ProcessSegment* next; addr_t position; size_t size; + int type; public: bool Intersects(ProcessSegment* segments); diff --git a/sortix/syscallnum.h b/sortix/syscallnum.h index f144cc04..0a7a5179 100644 --- a/sortix/syscallnum.h +++ b/sortix/syscallnum.h @@ -60,7 +60,8 @@ #define SYSCALL_MEMSTAT 32 #define SYSCALL_ISATTY 33 #define SYSCALL_UPTIME 34 -#define SYSCALL_MAX_NUM 35 /* index of highest constant + 1 */ +#define SYSCALL_SBRK 35 +#define SYSCALL_MAX_NUM 36 /* index of highest constant + 1 */ #endif diff --git a/sortix/x86-family/memorymanagement.cpp b/sortix/x86-family/memorymanagement.cpp index cb3cb235..4ba45b7a 100644 --- a/sortix/x86-family/memorymanagement.cpp +++ b/sortix/x86-family/memorymanagement.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "platform.h" +#include #include #include "multiboot.h" #include "panic.h" @@ -30,6 +31,8 @@ #include "memorymanagement.h" #include "syscall.h" +using namespace Maxsi; + namespace Sortix { const addr_t KERNELEND = 0x400000UL; @@ -218,8 +221,7 @@ namespace Sortix addr_t Get() { - // TODO: Set out of memory errno here! - if ( unlikely(stackused == 0) ) { return 0; } + if ( unlikely(stackused == 0) ) { Error::Set(ENOMEM); return 0; } pagesallocated++;