diff --git a/libc/heap.cpp b/libc/heap.cpp index 866cac79..bc17458b 100644 --- a/libc/heap.cpp +++ b/libc/heap.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of the Sortix C Library. @@ -48,6 +48,7 @@ #include // DEBUG #include #include +#include #endif #ifndef _ADDR_T_DECLARED @@ -76,12 +77,7 @@ extern addr_t wilderness; #ifdef SORTIX_KERNEL static addr_t GetHeapStart() { - return Sortix::Memory::GetHeapUpper(); -} - -static size_t GetHeapMaxSize() -{ - return Sortix::Memory::GetHeapUpper() - Sortix::Memory::GetHeapLower(); + return Sortix::GetHeapUpper(); } static void FreeMemory(addr_t where, size_t bytes) @@ -129,13 +125,24 @@ static bool AllocateMemory(addr_t where, size_t bytes) static bool ExtendHeap(size_t bytesneeded) { + size_t got_bytes = Sortix::ExpandHeap(bytesneeded); + if ( !got_bytes ) + return false; + assert(bytesneeded <= got_bytes); + #ifdef HEAP_GROWS_DOWNWARDS - addr_t newwilderness = wilderness - bytesneeded; + addr_t newwilderness = wilderness - got_bytes; #else - addr_t newwilderness = wilderness + bytesneeded; + addr_t newwilderness = wilderness + got_bytes; #endif - return AllocateMemory(newwilderness, bytesneeded); + if ( !AllocateMemory(newwilderness, got_bytes) ) + { + Sortix::ShrinkHeap(got_bytes); + return false; + } + + return true; } #else static addr_t GetHeapStart() @@ -150,12 +157,6 @@ static addr_t GetHeapStart() return result; } -static size_t GetHeapMaxSize() -{ - // TODO: A bit of a hack! - return SIZE_MAX; -} - static bool ExtendHeap(size_t bytesneeded) { void* newheapend = sbrk(bytesneeded); @@ -422,7 +423,7 @@ static bool ValidateHeap() extern "C" void _init_heap() { heapstart = GetHeapStart(); - heapmaxsize = GetHeapMaxSize(); + heapmaxsize = SIZE_MAX; heapsize = 0; wilderness = heapstart; wildernesssize = 0; @@ -450,10 +451,7 @@ static bool ExpandWilderness(size_t bytesneeded) // TODO: Overflow MAY happen here! if ( heapmaxsize <= heapsize + wildernesssize + bytesneeded ) - { - errno = ENOMEM; - return true; - } + return errno = ENOMEM, true; #ifdef HEAP_GROWS_DOWNWARDS addr_t newwilderness = wilderness - bytesneeded; @@ -462,7 +460,8 @@ static bool ExpandWilderness(size_t bytesneeded) #endif // Attempt to map pages so our wilderness grows. - if ( !ExtendHeap(bytesneeded) ) { return false; } + if ( !ExtendHeap(bytesneeded) ) + return false; wildernesssize += bytesneeded; wilderness = newwilderness; diff --git a/sortix/Makefile b/sortix/Makefile index 9119a1f1..cd704bd8 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -70,6 +70,7 @@ LIBS=\ OBJS=\ $(CPUOBJS) \ +addralloc.o \ ata.o \ bga.o \ calltrace.o \ diff --git a/sortix/addralloc.cpp b/sortix/addralloc.cpp new file mode 100644 index 00000000..a9c5c2d8 --- /dev/null +++ b/sortix/addralloc.cpp @@ -0,0 +1,122 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + addralloc.cpp + Class to keep track of mount points. + +*******************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +namespace Sortix { + +size_t aux_allocated = 0; +size_t heap_allocated = 0; +kthread_mutex_t alloc_lock = KTHREAD_MUTEX_INITIALIZER; + +// TODO: Kernel address space is allocated simply by increasing the pointer, +// with no support for freeing it. This is not that big a problem at this point, +// since address space is consumed at boot and then used forever. When it +// becomes normal for devices to come and go, just recode these functions and +// everyone should do the right thing. + +bool AllocateKernelAddress(addralloc_t* ret, size_t size) +{ + size = Page::AlignUp(size); + ScopedLock lock(&alloc_lock); + addr_t kmem_from; + size_t kmem_size; + Memory::GetKernelVirtualArea(&kmem_from, &kmem_size); + addr_t aux_reached = kmem_from + aux_allocated; + size_t heap_reached = kmem_from + kmem_size - heap_allocated; + size_t unused_left = heap_reached - aux_reached; + if ( unused_left < size ) + return errno = ENOMEM, false; + aux_allocated += size; + ret->from = aux_reached; + ret->size = size; + return true; +} + +void FreeKernelAddress(addralloc_t* alloc) +{ + if ( !alloc->from ) + return; + // Currently, nothing to do here. + alloc->from = 0; + alloc->size = 0; +} + +size_t ExpandHeap(size_t increase) +{ + increase = Page::AlignUp(increase); + ScopedLock lock(&alloc_lock); + addr_t kmem_from; + size_t kmem_size; + Memory::GetKernelVirtualArea(&kmem_from, &kmem_size); + addr_t aux_reached = kmem_from + aux_allocated; + size_t heap_reached = kmem_from + kmem_size - heap_allocated; + size_t unused_left = heap_reached - aux_reached; + if ( unused_left < increase ) + return errno = ENOMEM, 0; + heap_allocated += increase; + return increase; +} + +void ShrinkHeap(size_t decrease) +{ + assert(decrease == Page::AlignUp(decrease)); + ScopedLock lock(&alloc_lock); + assert(decrease <= heap_allocated); + heap_allocated -= decrease; +} + +// No need for locks in these three functions, since only the heap calls these +// and it already uses an internal lock, and heap_allocated will not change +// unless the heap calls ExpandHeap. + +addr_t GetHeapLower() +{ + addr_t kmem_from; + size_t kmem_size; + Memory::GetKernelVirtualArea(&kmem_from, &kmem_size); + return kmem_from + kmem_size; +} + +addr_t GetHeapUpper() +{ + addr_t kmem_from; + size_t kmem_size; + Memory::GetKernelVirtualArea(&kmem_from, &kmem_size); + return kmem_from + kmem_size - heap_allocated; +} + +size_t GetHeapSize() +{ + return heap_allocated; +} + +} // namespace Sortix diff --git a/sortix/bga.cpp b/sortix/bga.cpp index c7dc183e..a6a62cb3 100644 --- a/sortix/bga.cpp +++ b/sortix/bga.cpp @@ -22,18 +22,23 @@ *******************************************************************************/ +#include +#include +#include +#include +#include + #include +#include #include #include #include #include #include #include + #include -#include -#include -#include -#include + #include "x86-family/memorymanagement.h" #include "lfbtextbuffer.h" #include "cpu.h" @@ -202,6 +207,8 @@ public: private: bool MapVideoMemory(size_t size); + bool MapVideoMemoryRange(addr_t mapat, size_t from, size_t to); + bool IncreaseVirtual(size_t new_size); bool DetectModes() const; private: @@ -210,6 +217,7 @@ private: char* curmode; size_t lfbmapped; size_t framesize; + addralloc_t addr_allocation; }; @@ -220,11 +228,13 @@ BGADriver::BGADriver() curmode = NULL; lfbmapped = 0; framesize = 0; + memset(&addr_allocation, 0, sizeof(addr_allocation)); } BGADriver::~BGADriver() { MapVideoMemory(0); + FreeKernelAddress(&addr_allocation); for ( size_t i = 0; i < nummodes; i++ ) { delete[] modes[i]; @@ -233,45 +243,78 @@ BGADriver::~BGADriver() delete[] curmode; } -bool BGADriver::MapVideoMemory(size_t size) +bool BGADriver::MapVideoMemoryRange(addr_t mapat, size_t from, size_t to) { - size = Page::AlignUp(size); addr_t phys = bgaframebuffer; - addr_t mapat = Memory::GetVideoMemory(); - - if ( size == lfbmapped ) - return true; - - if ( size < lfbmapped ) - { - for ( size_t i = size; i < size; i += Page::Size() ) - Memory::Unmap(phys + i); - Memory::Flush(); - lfbmapped = size; - return true; - } - - size_t maxsize = Memory::GetMaxVideoMemorySize(); - if ( maxsize < size ) - { - Log::PrintF("Error: Insufficient virtual address space for BGA frame " - "of size 0x%zx bytes, only 0x%zx was available.\n", size, - maxsize); - return false; - } - const addr_t mtype = Memory::PAT_WC; - for ( size_t i = lfbmapped; i < size; i += Page::Size() ) + for ( size_t i = from; i < to; i += Page::Size() ) if ( !Memory::MapPAT(phys+i, mapat+i, PROT_KWRITE | PROT_KREAD, mtype) ) { Log::PrintF("Error: Insufficient memory to map BGA framebuffer " "onto kernel address space: needed 0x%zx bytes but " - "only 0x%zx was available at this point.\n", size, i); - MapVideoMemory(lfbmapped); // Unmap what we added. + "only 0x%zx was available at this point.\n", to, i); + for ( size_t n = from; n < i; n += Page::Size() ) + Memory::Unmap(mapat + n); return false; } + return true; +} + +bool BGADriver::IncreaseVirtual(size_t new_size) +{ + new_size = Page::AlignUp(new_size); + assert(addr_allocation.size < new_size); + + addralloc_t new_addralloc; + if ( !AllocateKernelAddress(&new_addralloc, new_size) ) + { + Log::PrintF("Error: Insufficient virtual address space for BGA " + "frame of size 0x%zx bytes, only 0x%zx was available.\n", + new_size, addr_allocation.size); + return false; + } + + addr_t old_mapat = addr_allocation.from; + addr_t new_mapat = new_addralloc.from; + + if ( !MapVideoMemoryRange(new_mapat, 0, new_size) ) + { + FreeKernelAddress(&addr_allocation); + return false; + } + + for ( size_t i = 0; i < lfbmapped; i += Page::Size() ) + Memory::Unmap(old_mapat + i); + + FreeKernelAddress(&addr_allocation); + + lfbmapped = new_size; + addr_allocation = new_addralloc; + Memory::Flush(); + return true; +} + +bool BGADriver::MapVideoMemory(size_t size) +{ + size = Page::AlignUp(size); + + if ( size == lfbmapped ) + return true; + + if ( addr_allocation.size < size ) + return IncreaseVirtual(size); + + addr_t mapat = addr_allocation.from; + for ( size_t i = size; i < lfbmapped; i+= Page::Size() ) + Memory::Unmap(mapat + i); + lfbmapped = size; + Memory::Flush(); + + if ( !size ) + FreeKernelAddress(&addr_allocation); + return true; } @@ -382,7 +425,7 @@ off_t BGADriver::FrameSize() const ssize_t BGADriver::WriteAt(off_t off, const void* buf, size_t count) { - uint8_t* frame = (uint8_t*) Memory::GetVideoMemory(); + uint8_t* frame = (uint8_t*) addr_allocation.from; if ( (off_t) framesize <= off ) return 0; if ( framesize < off + count ) @@ -393,7 +436,7 @@ ssize_t BGADriver::WriteAt(off_t off, const void* buf, size_t count) ssize_t BGADriver::ReadAt(off_t off, void* buf, size_t count) { - const uint8_t* frame = (const uint8_t*) Memory::GetVideoMemory(); + const uint8_t* frame = (const uint8_t*) addr_allocation.from; if ( (off_t) framesize <= off ) return 0; if ( framesize < off + count ) @@ -442,7 +485,7 @@ bool BGADriver::DetectModes() const TextBuffer* BGADriver::CreateTextBuffer() { - uint8_t* lfb = (uint8_t*) Memory::GetVideoMemory(); + uint8_t* lfb = (uint8_t*) addr_allocation.from; uint32_t lfbformat = curbpp; size_t scansize = curxres * curbpp / 8UL; return CreateLFBTextBuffer(lfb, lfbformat, curxres, curyres, scansize); diff --git a/sortix/include/sortix/kernel/addralloc.h b/sortix/include/sortix/kernel/addralloc.h new file mode 100644 index 00000000..bc3d7b15 --- /dev/null +++ b/sortix/include/sortix/kernel/addralloc.h @@ -0,0 +1,48 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + sortix/kernel/addralloc.h + Class to keep track of mount points. + +*******************************************************************************/ + +#ifndef INCLUDE_SORTIX_KERNEL_ADDRALLOC_H +#define INCLUDE_SORTIX_KERNEL_ADDRALLOC_H + +#include + +namespace Sortix { + +struct addralloc_t +{ + addr_t from; + size_t size; +}; + +bool AllocateKernelAddress(addralloc_t* ret, size_t size); +void FreeKernelAddress(addralloc_t* alloc); +size_t ExpandHeap(size_t increase); +void ShrinkHeap(size_t decrease); +addr_t GetHeapLower(); +addr_t GetHeapUpper(); +size_t GetHeapSize(); + +} // namespace Sortix + +#endif diff --git a/sortix/include/sortix/kernel/memorymanagement.h b/sortix/include/sortix/kernel/memorymanagement.h index 09eedc19..0c7ca357 100644 --- a/sortix/include/sortix/kernel/memorymanagement.h +++ b/sortix/include/sortix/kernel/memorymanagement.h @@ -82,13 +82,7 @@ namespace Sortix void Statistics(size_t* amountused, size_t* totalmem); addr_t GetKernelStack(); size_t GetKernelStackSize(); - addr_t GetInitRD(); - size_t GetInitRDSize(); - void RegisterInitRDSize(size_t size); - addr_t GetHeapLower(); - addr_t GetHeapUpper(); - addr_t GetVideoMemory(); - size_t GetMaxVideoMemorySize(); + void GetKernelVirtualArea(addr_t* from, size_t* size); } } diff --git a/sortix/initrd.cpp b/sortix/initrd.cpp index 3c368cdb..bd0a2d24 100644 --- a/sortix/initrd.cpp +++ b/sortix/initrd.cpp @@ -23,6 +23,7 @@ *******************************************************************************/ #include +#include #include #include #include @@ -46,6 +47,7 @@ namespace Sortix { namespace InitRD { +addralloc_t initrd_addr_alloc; uint8_t* initrd = NULL; size_t initrdsize; const initrd_superblock_t* sb; @@ -204,21 +206,20 @@ void CheckSum() void Init(addr_t phys, size_t size) { assert(!initrd); - // First up, map the initrd onto the kernel's address space. - addr_t virt = Memory::GetInitRD(); - size_t amount = 0; - while ( amount < size ) - { - if ( !Memory::Map(phys + amount, virt + amount, PROT_KREAD) ) - { - Panic("Unable to map the init ramdisk into virtual memory"); - } - amount += 0x1000UL; - } + // Allocate the needed kernel virtual address space. + if ( !AllocateKernelAddress(&initrd_addr_alloc, size) ) + PanicF("Can't allocate 0x%zx bytes of kernel address space for the " + "init ramdisk", size ); + + // Map the physical frames onto our address space. + addr_t mapat = initrd_addr_alloc.from; + for ( size_t i = 0; i < size; i += Page::Size() ) + if ( !Memory::Map(phys + i, mapat + i, PROT_KREAD) ) + Panic("Unable to map the init ramdisk into virtual memory"); Memory::Flush(); - initrd = (uint8_t*) virt; + initrd = (uint8_t*) mapat; initrdsize = size; if ( size < sizeof(*sb) ) { PanicF("initrd is too small"); } diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp index d5151c7a..b7f463ec 100644 --- a/sortix/kernel.cpp +++ b/sortix/kernel.cpp @@ -224,8 +224,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) if ( !initrd ) { PanicF("No init ramdisk provided"); } - Memory::RegisterInitRDSize(initrdsize); - // Initialize paging and virtual memory. Memory::Init(bootinfo); diff --git a/sortix/x64/memorymanagement.cpp b/sortix/x64/memorymanagement.cpp index b1b52a3e..ce6f3b65 100644 --- a/sortix/x64/memorymanagement.cpp +++ b/sortix/x64/memorymanagement.cpp @@ -182,35 +182,14 @@ namespace Sortix const size_t KERNEL_STACK_SIZE = 256UL * 1024UL; const addr_t KERNEL_STACK_END = 0xFFFF800000001000UL; const addr_t KERNEL_STACK_START = KERNEL_STACK_END + KERNEL_STACK_SIZE; - const addr_t VIDEO_MEMORY = KERNEL_STACK_START; - const size_t VIDEO_MEMORY_MAX_SIZE = 4UL * 1024UL * 1024UL * 1024UL; - const addr_t INITRD = VIDEO_MEMORY + VIDEO_MEMORY_MAX_SIZE; - size_t initrdsize = 0; - const addr_t HEAPUPPER = 0xFFFFFE8000000000UL; - addr_t GetInitRD() - { - return INITRD; - } + const addr_t VIRTUAL_AREA_LOWER = KERNEL_STACK_START; + const addr_t VIRTUAL_AREA_UPPER = 0xFFFFFE8000000000UL; - size_t GetInitRDSize() + void GetKernelVirtualArea(addr_t* from, size_t* size) { - return initrdsize; - } - - void RegisterInitRDSize(size_t size) - { - initrdsize = size; - } - - addr_t GetHeapLower() - { - return Page::AlignUp(INITRD + initrdsize); - } - - addr_t GetHeapUpper() - { - return HEAPUPPER; + *from = KERNEL_STACK_END; + *size = VIRTUAL_AREA_UPPER - VIRTUAL_AREA_LOWER; } addr_t GetKernelStack() @@ -222,15 +201,5 @@ namespace Sortix { return KERNEL_STACK_SIZE; } - - addr_t GetVideoMemory() - { - return VIDEO_MEMORY; - } - - size_t GetMaxVideoMemorySize() - { - return VIDEO_MEMORY_MAX_SIZE; - } } } diff --git a/sortix/x86/memorymanagement.cpp b/sortix/x86/memorymanagement.cpp index 3fbc0150..e8b0f952 100644 --- a/sortix/x86/memorymanagement.cpp +++ b/sortix/x86/memorymanagement.cpp @@ -166,35 +166,14 @@ namespace Sortix const size_t KERNEL_STACK_SIZE = 256UL * 1024UL; const addr_t KERNEL_STACK_END = 0x80001000UL; const addr_t KERNEL_STACK_START = KERNEL_STACK_END + KERNEL_STACK_SIZE; - const addr_t VIDEO_MEMORY = KERNEL_STACK_START; - const size_t VIDEO_MEMORY_MAX_SIZE = 384UL * 1024UL * 1024UL; - const addr_t INITRD = VIDEO_MEMORY + VIDEO_MEMORY_MAX_SIZE; - size_t initrdsize = 0; - const addr_t HEAPUPPER = 0xFF400000UL; - addr_t GetInitRD() - { - return INITRD; - } + const addr_t VIRTUAL_AREA_LOWER = KERNEL_STACK_START; + const addr_t VIRTUAL_AREA_UPPER = 0xFF400000UL; - size_t GetInitRDSize() + void GetKernelVirtualArea(addr_t* from, size_t* size) { - return initrdsize; - } - - void RegisterInitRDSize(size_t size) - { - initrdsize = size; - } - - addr_t GetHeapLower() - { - return Page::AlignUp(INITRD + initrdsize); - } - - addr_t GetHeapUpper() - { - return HEAPUPPER; + *from = KERNEL_STACK_END; + *size = VIRTUAL_AREA_UPPER - VIRTUAL_AREA_LOWER; } addr_t GetKernelStack() @@ -206,15 +185,5 @@ namespace Sortix { return KERNEL_STACK_SIZE; } - - addr_t GetVideoMemory() - { - return VIDEO_MEMORY; - } - - size_t GetMaxVideoMemorySize() - { - return VIDEO_MEMORY_MAX_SIZE; - } } }