Refactor kernel address space allocation.

This commit is contained in:
Jonas 'Sortie' Termansen 2013-02-09 18:32:45 +01:00
parent 5ce53a2a30
commit 54da838c79
10 changed files with 294 additions and 150 deletions

View File

@ -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 <sortix/kernel/log.h> // DEBUG
#include <sortix/kernel/memorymanagement.h>
#include <sortix/kernel/panic.h>
#include <sortix/kernel/addralloc.h>
#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;

View File

@ -70,6 +70,7 @@ LIBS=\
OBJS=\
$(CPUOBJS) \
addralloc.o \
ata.o \
bga.o \
calltrace.o \

122
sortix/addralloc.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
addralloc.cpp
Class to keep track of mount points.
*******************************************************************************/
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <sortix/kernel/platform.h>
#include <sortix/kernel/addralloc.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/memorymanagement.h>
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

View File

@ -22,18 +22,23 @@
*******************************************************************************/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sortix/kernel/platform.h>
#include <sortix/kernel/addralloc.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/textbuffer.h>
#include <sortix/kernel/video.h>
#include <sortix/kernel/memorymanagement.h>
#include <sortix/kernel/pci.h>
#include <sortix/kernel/string.h>
#include <sortix/mman.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);

View File

@ -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 <http://www.gnu.org/licenses/>.
sortix/kernel/addralloc.h
Class to keep track of mount points.
*******************************************************************************/
#ifndef INCLUDE_SORTIX_KERNEL_ADDRALLOC_H
#define INCLUDE_SORTIX_KERNEL_ADDRALLOC_H
#include <sortix/kernel/decl.h>
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

View File

@ -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);
}
}

View File

@ -23,6 +23,7 @@
*******************************************************************************/
#include <sortix/kernel/platform.h>
#include <sortix/kernel/addralloc.h>
#include <sortix/kernel/vnode.h>
#include <sortix/kernel/descriptor.h>
#include <sortix/kernel/memorymanagement.h>
@ -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"); }

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}