From 570156b38c7a11f581c05d86275c35350d84c1f6 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Tue, 19 Mar 2013 14:59:10 +0100 Subject: [PATCH] l4lx: allocate memory in chunks When L4Linux tries to allocate a dataspace of the size of its physical memory, this allocation can fail, because the 'l4re_ma_alloc()' function in the 'l4lx' library always tries to allocate a contiguous dataspace of the given size and there might be no contiguous free area left. With this patch, memory gets allocated in chunks: if the size to be allocated exceeds the configured chunk size, a managed dataspace gets created and filled with multiple memory chunks of at most the chunk size. The chunk size is 16M by default and can be configured in an l4linux config node: Fixes #695. --- base/include/rm_session/client.h | 5 ++- base/include/rm_session/rm_session.h | 2 +- ports-foc/src/lib/l4lx/l4_re_c_mem_alloc.cc | 47 ++++++++++++++++++++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/base/include/rm_session/client.h b/base/include/rm_session/client.h index 4df534935..4a8962618 100644 --- a/base/include/rm_session/client.h +++ b/base/include/rm_session/client.h @@ -24,8 +24,9 @@ namespace Genode { explicit Rm_session_client(Rm_session_capability session) : Rpc_client(session) { } - Local_addr attach(Dataspace_capability ds, size_t size, off_t offset, - bool use_local_addr, Local_addr local_addr, + Local_addr attach(Dataspace_capability ds, size_t size = 0, + off_t offset = 0, bool use_local_addr = false, + Local_addr local_addr = 0, bool executable = false) { return call(ds, size, offset, diff --git a/base/include/rm_session/rm_session.h b/base/include/rm_session/rm_session.h index 1142c0995..ef5c650e7 100644 --- a/base/include/rm_session/rm_session.h +++ b/base/include/rm_session/rm_session.h @@ -129,7 +129,7 @@ namespace Genode { virtual Local_addr attach(Dataspace_capability ds, size_t size = 0, off_t offset = 0, bool use_local_addr = false, - Local_addr local_addr = (addr_t)0, + Local_addr local_addr = 0, bool executable = false) = 0; /** diff --git a/ports-foc/src/lib/l4lx/l4_re_c_mem_alloc.cc b/ports-foc/src/lib/l4lx/l4_re_c_mem_alloc.cc index c7b20ad93..157c31afd 100644 --- a/ports-foc/src/lib/l4lx/l4_re_c_mem_alloc.cc +++ b/ports-foc/src/lib/l4lx/l4_re_c_mem_alloc.cc @@ -14,6 +14,8 @@ /* Genode includes */ #include #include +#include +#include /* L4lx includes */ #include @@ -29,15 +31,58 @@ static const bool DEBUG = false; extern "C" { + static const unsigned long _chunk_size() + { + enum { DEFAULT_CHUNK_SIZE = 16*1024*1024 }; + + Genode::Number_of_bytes result = DEFAULT_CHUNK_SIZE; + + try { + Genode::config()->xml_node().sub_node("ram") + .attribute("chunk_size") + .value(&result); + } catch(...) { } + + return result; + } + + long l4re_ma_alloc(unsigned long size, l4re_ds_t const mem, unsigned long flags) { + static const unsigned long chunk_size = _chunk_size(); + using namespace L4lx; if (DEBUG) PDBG("size=%lx mem=%lx flags=%lx", size, mem, flags); - Genode::Dataspace_capability cap = Genode::env()->ram_session()->alloc(size); + Genode::Dataspace_capability cap; + + if (size > chunk_size) { + Genode::Rm_connection *rmc = new (Genode::env()->heap()) + Genode::Rm_connection(0, size); + + const unsigned long num_chunks = size / chunk_size; + const unsigned long remainder = size % chunk_size; + + for (unsigned long i = 0; i < num_chunks; i++) { + Genode::Dataspace_capability cap = + Genode::env()->ram_session()->alloc(chunk_size); + rmc->attach(cap); + } + + if (remainder > 0) { + Genode::Dataspace_capability cap = + Genode::env()->ram_session()->alloc(remainder); + rmc->attach(cap); + } + + cap = rmc->dataspace(); + } else { + cap = Genode::env()->ram_session()->alloc(size); + } + Dataspace *ds = new (Genode::env()->heap()) Dataspace("lx_memory", size, cap, mem); Env::env()->dataspaces()->insert(ds);