diff --git a/libmaxsi/c/hsrc/unistd.h b/libmaxsi/c/hsrc/unistd.h index d538dfd8..6844a588 100644 --- a/libmaxsi/c/hsrc/unistd.h +++ b/libmaxsi/c/hsrc/unistd.h @@ -170,7 +170,9 @@ int usleep(useconds_t useconds); #endif int unlink(const char*); ssize_t write(int, const void*, size_t); + #ifdef SORTIX_EXTENSIONS +int memstat(size_t* memused, size_t* memtotal); int writeall(int fd, const void* buffer, size_t len); #endif diff --git a/libmaxsi/memory.cpp b/libmaxsi/memory.cpp index 6a98ba0b..7bdaa809 100644 --- a/libmaxsi/memory.cpp +++ b/libmaxsi/memory.cpp @@ -34,6 +34,11 @@ #include #include + +#else // !SORTIX_KERNEL + +#include "syscall.h" + #endif #define IsGoodChunkPosition(Chunk) ((uintptr_t) Wilderness + WildernessSize <= (uintptr_t) (Chunk) && (uintptr_t) (Chunk) <= (uintptr_t) HeapStart) @@ -72,6 +77,15 @@ namespace Maxsi namespace Memory { +#ifndef SORTIX_KERNEL + DEFN_SYSCALL2(int, SysMemStat, 32, size_t*, size_t*); + + extern "C" int memstat(size_t* memused, size_t* memtotal) + { + return SysMemStat(memused, memtotal); + } +#endif + // This magic word is useful to see if the program has written into the // chunk's header or footer, which means the program has malfunctioned // and ought to be terminated. diff --git a/sortix/memorymanagement.h b/sortix/memorymanagement.h index 460d3ba9..35dbfcdb 100644 --- a/sortix/memorymanagement.h +++ b/sortix/memorymanagement.h @@ -57,6 +57,7 @@ namespace Sortix bool MapUser(addr_t physical, addr_t mapto); addr_t UnmapKernel(addr_t mapto); addr_t UnmapUser(addr_t mapto); + void Statistics(size_t* amountused, size_t* totalmem); #if defined(PLATFORM_X86) const addr_t HEAPLOWER = 0x80000000UL; diff --git a/sortix/syscallnum.h b/sortix/syscallnum.h index 6f4d71e6..485a413b 100644 --- a/sortix/syscallnum.h +++ b/sortix/syscallnum.h @@ -57,7 +57,8 @@ #define SYSCALL_REGISTER_SIGNAL_HANDLER 29 #define SYSCALL_SIGRETURN 30 #define SYSCALL_KILL 31 -#define SYSCALL_MAX_NUM 32 /* index of highest constant + 1 */ +#define SYSCALL_MEMSTAT 32 +#define SYSCALL_MAX_NUM 33 /* index of highest constant + 1 */ #endif diff --git a/sortix/x86-family/memorymanagement.cpp b/sortix/x86-family/memorymanagement.cpp index 988ef893..9be88df5 100644 --- a/sortix/x86-family/memorymanagement.cpp +++ b/sortix/x86-family/memorymanagement.cpp @@ -28,10 +28,11 @@ #include "panic.h" #include "../memorymanagement.h" #include "memorymanagement.h" +#include "syscall.h" namespace Sortix { - const addr_t KERNELEND = 0x200000UL; + const addr_t KERNELEND = 0x400000UL; namespace Page { @@ -39,6 +40,8 @@ namespace Sortix size_t pagesnotonstack; size_t stackused; size_t stacklength; + size_t totalmem; + size_t pagesallocated; } namespace Memory @@ -47,10 +50,15 @@ namespace Sortix void InitCPU(); void AllocateKernelPMLs(); + int SysMemStat(size_t* memused, size_t* memtotal); void Init(multiboot_info_t* bootinfo) { Page::pagesnotonstack = 0; + Page::totalmem = 0; + + // The first mebibytes are reserved for use by the kernel. + Page::pagesallocated = KERNELEND >> 12UL; if ( !( bootinfo->flags & MULTIBOOT_INFO_MEM_MAP ) ) { @@ -84,6 +92,9 @@ namespace Sortix if ( 0xFFFFFFFFULL < mmap->addr + mmap->len ) { length = 0x100000000ULL - mmap->addr; } #endif + // Count the amount of usable RAM (even if reserved for kernel). + Page::totalmem += length; + // Detect if this memory is completely covered by the kernel. if ( base + length <= KERNELEND ) { continue; } @@ -95,6 +106,8 @@ namespace Sortix } Page::InitPushRegion(base, length); + + Syscall::Register(SYSCALL_MEMSTAT, (void*) SysMemStat); } // If the physical allocator couldn't handle the vast amount of @@ -110,6 +123,23 @@ namespace Sortix AllocateKernelPMLs(); } + void Statistics(size_t* amountused, size_t* totalmem) + { + if ( amountused ) { *amountused = Page::pagesallocated << 12Ul; } + if ( totalmem ) { *totalmem = Page::totalmem; } + } + + int SysMemStat(size_t* memused, size_t* memtotal) + { + size_t used; + size_t total; + Statistics(&used, &total); + // TODO: Check if legal user-space buffers! + *memused = used; + *memtotal = total; + return 0; + } + // Prepare the non-forkable kernel PMLs such that forking the kernel // address space will always keep the kernel mapped. void AllocateKernelPMLs() @@ -188,12 +218,15 @@ namespace Sortix // TODO: Set out of memory errno here! if ( unlikely(stackused == 0) ) { return 0; } + pagesallocated++; + return STACK[--stackused]; } void Put(addr_t page) { ASSERT(stackused < MAXSTACKLENGTH); + pagesallocated--; STACK[stackused++] = page; } } diff --git a/utils/Makefile b/utils/Makefile index c66dbbfa..a42d4696 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -14,6 +14,7 @@ mxsh \ clear \ ls \ help \ +memstat \ uname \ idle \ editor \ diff --git a/utils/memstat.cpp b/utils/memstat.cpp new file mode 100644 index 00000000..00fa054e --- /dev/null +++ b/utils/memstat.cpp @@ -0,0 +1,57 @@ +#include +#include +#include + +void printbytes(unsigned long long bytes) +{ + const unsigned BYTES = 0; + const unsigned KIBI = 1; + const unsigned MEBI = 2; + const unsigned GIBI = 3; + const unsigned TEBI = 4; + const unsigned PEBI = 5; + const unsigned EXBI = 6; + + unsigned unit = BYTES; + if ( (bytes >> 10) & 1023 ) { unit = KIBI; } + if ( (bytes >> 20) & 1023 ) { unit = MEBI; } + if ( (bytes >> 30) & 1023 ) { unit = GIBI; } + if ( (bytes >> 40) & 1023 ) { unit = TEBI; } + if ( (bytes >> 50) & 1023 ) { unit = PEBI; } + if ( (bytes >> 60) & 1023 ) { unit = EXBI; } + + switch ( unit ) + { + case EXBI: + printf("%u ZiB ", (bytes >> 60) & 1023); + case PEBI: + printf("%u PiB ", (bytes >> 50) & 1023); + case TEBI: + printf("%u TiB ", (bytes >> 40) & 1023); + case GIBI: + printf("%u GiB ", (bytes >> 30) & 1023); + case MEBI: + printf("%u MiB ", (bytes >> 20) & 1023); + case KIBI: + printf("%u KiB", (bytes >> 10) & 1023); + break; + case BYTES: + printf("%u B", (bytes >> 0) & 1023); + } +} + +int main(int argc, char* argv[]) +{ + size_t memused = 0; + size_t memtotal = 0; + if ( memstat(&memused, &memtotal) ) { perror("memstat"); return 1; } + + printf("memory usage: "); + printbytes(memused); + printf(" free / "); + printbytes(memtotal); + unsigned percent = ((unsigned long long) memused * 100ULL ) / memtotal; + printf(" total (%u%s)\n", percent, "%"); + + return 0; +}