diff --git a/base-linux/include/base/platform_env.h b/base-linux/include/base/platform_env.h index 7cc4d367d..d485c8855 100644 --- a/base-linux/include/base/platform_env.h +++ b/base-linux/include/base/platform_env.h @@ -31,7 +31,11 @@ namespace Genode { - class Platform_env : public Env + /** + * Common base class of the 'Platform_env' implementations for core and + * non-core processes. + */ + class Platform_env_base : public Env { private: @@ -146,6 +150,12 @@ namespace Genode { } }; + protected: + + /* + * 'Rm_session_mmap' is 'protected' because it is instantiated by + * 'Platform_env::Local_parent::session()'. + */ /* * On Linux, we use a local region manager session that attaches @@ -186,6 +196,36 @@ namespace Genode { void _add_to_rmap(Region const &); + /** + * Map dataspace into local address space + */ + static void *_map_local(Dataspace_capability ds, + Genode::size_t size, + addr_t offset, + bool use_local_addr, + addr_t local_addr, + bool executable); + + /** + * Determine size of dataspace + * + * For core, this function performs a local lookup of the + * 'Dataspace_component' object. For non-core programs, the + * dataspace size is determined via an RPC to core + * (calling 'Dataspace::size()'). + */ + static size_t _dataspace_size(Capability); + + /** + * Determine file descriptor of dataspace + */ + static int _dataspace_fd(Capability); + + /** + * Determine whether dataspace is writable + */ + static bool _dataspace_writable(Capability); + public: Rm_session_mmap(bool sub_rm, size_t size = ~0) @@ -240,6 +280,7 @@ namespace Genode { } }; + private: class Expanding_ram_session_client : public Ram_session_client { @@ -274,6 +315,55 @@ namespace Genode { }; + /******************************* + ** Platform-specific members ** + *******************************/ + + Ram_session_capability _ram_session_cap; + Expanding_ram_session_client _ram_session_client; + Cpu_session_capability _cpu_session_cap; + Linux_cpu_session_client _cpu_session_client; + Rm_session_mmap _rm_session_mmap; + Pd_session_client _pd_session_client; + + public: + + /** + * Constructor + */ + Platform_env_base(Ram_session_capability ram_cap, + Cpu_session_capability cpu_cap, + Pd_session_capability pd_cap) + : + _ram_session_cap(ram_cap), + _ram_session_client(_ram_session_cap), + _cpu_session_cap(cpu_cap), + _cpu_session_client(static_cap_cast(cpu_cap)), + _rm_session_mmap(false), + _pd_session_client(pd_cap) + { } + + + /******************* + ** Env interface ** + *******************/ + + Ram_session *ram_session() { return &_ram_session_client; } + Ram_session_capability ram_session_cap() { return _ram_session_cap; } + Rm_session *rm_session() { return &_rm_session_mmap; } + Linux_cpu_session *cpu_session() { return &_cpu_session_client; } + Cpu_session_capability cpu_session_cap() { return _cpu_session_cap; } + Pd_session *pd_session() { return &_pd_session_client; } + }; + + + /** + * 'Platform_env' used by all processes except for core + */ + class Platform_env : public Platform_env_base + { + private: + /** * Local interceptor of parent requests * @@ -308,62 +398,32 @@ namespace Genode { Local_parent(Parent_capability parent_cap); }; + /** + * Obtain singleton instance of parent interface + */ + static Local_parent &_parent(); + + Heap _heap; + /************************************* ** Linux-specific helper functions ** *************************************/ - /** - * Read Unix environment variable as long value - */ - static unsigned long _get_env_ulong(const char *key); - - - Parent_capability _parent_cap() - { - long local_name = _get_env_ulong("parent_local_name"); - - /* produce typed capability manually */ - typedef Native_capability::Dst Dst; - Dst const dst(PARENT_SOCKET_HANDLE); - return reinterpret_cap_cast(Native_capability(dst, local_name)); - } - - - /******************************* - ** Platform-specific members ** - *******************************/ - - Local_parent _parent; - Ram_session_capability _ram_session_cap; - Expanding_ram_session_client _ram_session_client; - Cpu_session_capability _cpu_session_cap; - Linux_cpu_session_client _cpu_session_client; - Rm_session_mmap _rm_session_mmap; - Pd_session_client _pd_session_client; - Heap _heap; - public: - /** - * Standard constructor - */ Platform_env() : - _parent(_parent_cap()), - _ram_session_cap(static_cap_cast(parent()->session("Env::ram_session", ""))), - _ram_session_client(_ram_session_cap), - _cpu_session_cap(static_cap_cast(parent()->session("Env::cpu_session", ""))), - _cpu_session_client(static_cap_cast(parent()->session("Env::cpu_session", ""))), - _rm_session_mmap(false), - _pd_session_client(static_cap_cast(parent()->session("Env::pd_session", ""))), - _heap(&_ram_session_client, &_rm_session_mmap) + Platform_env_base(static_cap_cast(_parent().session("Env::ram_session", "")), + static_cap_cast(_parent().session("Env::cpu_session", "")), + static_cap_cast (_parent().session("Env::pd_session", ""))), + _heap(Platform_env_base::ram_session(), Platform_env_base::rm_session()) { } /** * Destructor */ - ~Platform_env() { parent()->exit(0); } + ~Platform_env() { _parent().exit(0); } /** * Reload parent capability and reinitialize environment resources @@ -378,14 +438,8 @@ namespace Genode { ** Env interface ** *******************/ - Parent *parent() { return &_parent; } - Ram_session *ram_session() { return &_ram_session_client; } - Ram_session_capability ram_session_cap() { return _ram_session_cap; } - Rm_session *rm_session() { return &_rm_session_mmap; } - Heap *heap() { return &_heap; } - Linux_cpu_session *cpu_session() { return &_cpu_session_client; } - Cpu_session_capability cpu_session_cap() { return _cpu_session_cap; } - Pd_session *pd_session() { return &_pd_session_client; } + Parent *parent() { return &_parent(); } + Heap *heap() { return &_heap; } }; } diff --git a/base-linux/src/base/env/platform_env.cc b/base-linux/src/base/env/platform_env.cc index 3b4c890d4..5b9585439 100644 --- a/base-linux/src/base/env/platform_env.cc +++ b/base-linux/src/base/env/platform_env.cc @@ -14,11 +14,39 @@ #include #include #include +#include #include using namespace Genode; +/**************************************************** + ** Support for Platform_env_base::Rm_session_mmap ** + ****************************************************/ + +Genode::size_t +Platform_env_base::Rm_session_mmap::_dataspace_size(Dataspace_capability ds) +{ + if (ds.valid()) + return Dataspace_client(ds).size(); + + return Dataspace_capability::deref(ds)->size(); +} + + +int Platform_env_base::Rm_session_mmap::_dataspace_fd(Dataspace_capability ds) +{ + return Linux_dataspace_client(ds).fd().dst().socket; +} + + +bool +Platform_env_base::Rm_session_mmap::_dataspace_writable(Dataspace_capability ds) +{ + return Dataspace_client(ds).writable(); +} + + /******************************** ** Platform_env::Local_parent ** ********************************/ @@ -83,7 +111,7 @@ extern char **lx_environ; /** * Read environment variable as long value */ -unsigned long Platform_env::_get_env_ulong(const char *key) +static unsigned long get_env_ulong(const char *key) { for (char **curr = lx_environ; curr && *curr; curr++) { @@ -96,6 +124,24 @@ unsigned long Platform_env::_get_env_ulong(const char *key) } +static Parent_capability obtain_parent_cap() +{ + long local_name = get_env_ulong("parent_local_name"); + + /* produce typed capability manually */ + typedef Native_capability::Dst Dst; + Dst const dst(PARENT_SOCKET_HANDLE); + return reinterpret_cap_cast(Native_capability(dst, local_name)); +} + + +Platform_env::Local_parent &Platform_env::_parent() +{ + static Local_parent local_parent(obtain_parent_cap()); + return local_parent; +} + + /***************************** ** Support for IPC library ** *****************************/ diff --git a/base-linux/src/base/env/rm_session_mmap.cc b/base-linux/src/base/env/rm_session_mmap.cc index 956a8f1e6..587f01b2c 100644 --- a/base-linux/src/base/env/rm_session_mmap.cc +++ b/base-linux/src/base/env/rm_session_mmap.cc @@ -19,15 +19,6 @@ using namespace Genode; -static Genode::size_t dataspace_size(Dataspace_capability ds) -{ - if (ds.valid()) - return Dataspace_client(ds).size(); - - return Dataspace_capability::deref(ds)->size(); -} - - static bool is_sub_rm_session(Dataspace_capability ds) { if (ds.valid()) @@ -37,12 +28,16 @@ static bool is_sub_rm_session(Dataspace_capability ds) } -static void *map_local(Dataspace_capability ds, Genode::size_t size, - addr_t offset, bool use_local_addr, addr_t local_addr, - bool executable) +void * +Platform_env_base::Rm_session_mmap::_map_local(Dataspace_capability ds, + Genode::size_t size, + addr_t offset, + bool use_local_addr, + addr_t local_addr, + bool executable) { - int const fd = Linux_dataspace_client(ds).fd().dst().socket; - bool const writable = Dataspace_client(ds).writable(); + int const fd = _dataspace_fd(ds); + bool const writable = _dataspace_writable(ds); int const flags = MAP_SHARED | (use_local_addr ? MAP_FIXED : 0); int const prot = PROT_READ @@ -60,7 +55,7 @@ static void *map_local(Dataspace_capability ds, Genode::size_t size, lx_close(fd); if (((long)addr_out < 0) && ((long)addr_out > -4095)) { - PERR("map_local: return value of mmap is %ld", (long)addr_out); + PERR("_map_local: return value of mmap is %ld", (long)addr_out); throw Rm_session::Region_conflict(); } @@ -97,8 +92,8 @@ Platform_env::Rm_session_mmap::attach(Dataspace_capability ds, throw Region_conflict(); } - size_t const remaining_ds_size = dataspace_size(ds) > (addr_t)offset - ? dataspace_size(ds) - (addr_t)offset : 0; + size_t const remaining_ds_size = _dataspace_size(ds) > (addr_t)offset + ? _dataspace_size(ds) - (addr_t)offset : 0; /* determine size of virtual address region */ size_t const region_size = size ? min(remaining_ds_size, size) @@ -148,7 +143,7 @@ Platform_env::Rm_session_mmap::attach(Dataspace_capability ds, * and map it. */ if (_is_attached()) - map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable); + _map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable); return (void *)local_addr; @@ -194,9 +189,9 @@ Platform_env::Rm_session_mmap::attach(Dataspace_capability ds, if (!region.used()) continue; - map_local(region.dataspace(), region.size(), region.offset(), - true, rm->_base + region.start() + region.offset(), - executable); + _map_local(region.dataspace(), region.size(), region.offset(), + true, rm->_base + region.start() + region.offset(), + executable); } return rm->_base; @@ -208,8 +203,8 @@ Platform_env::Rm_session_mmap::attach(Dataspace_capability ds, * * Boring, a plain dataspace is attached to a root RM session. */ - void *addr = map_local(ds, region_size, offset, use_local_addr, - local_addr, executable); + void *addr = _map_local(ds, region_size, offset, use_local_addr, + local_addr, executable); _add_to_rmap(Region((addr_t)addr, offset, ds, region_size)); diff --git a/base-linux/src/core/include/core_env.h b/base-linux/src/core/include/core_env.h new file mode 100644 index 000000000..62bb13256 --- /dev/null +++ b/base-linux/src/core/include/core_env.h @@ -0,0 +1,213 @@ +/* + * \brief Core-specific environment for Linux + * \author Norman Feske + * \author Christian Helmuth + * \date 2006-07-28 + * + * The Core-specific environment ensures that all sessions of Core's + * environment a local. + */ + +/* + * Copyright (C) 2006-2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _CORE__INCLUDE__CORE_ENV_H_ +#define _CORE__INCLUDE__CORE_ENV_H_ + +/* Genode includes */ +#include + +/* core includes */ +#include +#include +#include +#include + + +namespace Genode { + + /** + * Lock-guarded version of a RAM-session implementation + * + * \param RAM_SESSION_IMPL non-thread-safe RAM-session class + * + * In contrast to normal processes, core's 'env()->ram_session()' is not + * synchronized by an RPC interface. However, it is accessed by different + * threads using the 'env()->heap()' and the sliced heap used for + * allocating sessions to core's services. + */ + template + class Synchronized_ram_session : public RAM_SESSION_IMPL + { + private: + + Lock _lock; + + public: + + /** + * Constructor + */ + Synchronized_ram_session(Rpc_entrypoint *ds_ep, + Rpc_entrypoint *ram_session_ep, + Range_allocator *ram_alloc, + Allocator *md_alloc, + const char *args, + size_t quota_limit = 0) + : + RAM_SESSION_IMPL(ds_ep, ram_session_ep, ram_alloc, md_alloc, args, quota_limit) + { } + + + /*************************** + ** RAM-session interface ** + ***************************/ + + Ram_dataspace_capability alloc(size_t size, bool cached) + { + Lock::Guard lock_guard(_lock); + return RAM_SESSION_IMPL::alloc(size, cached); + } + + void free(Ram_dataspace_capability ds) + { + Lock::Guard lock_guard(_lock); + RAM_SESSION_IMPL::free(ds); + } + + int ref_account(Ram_session_capability session) + { + Lock::Guard lock_guard(_lock); + return RAM_SESSION_IMPL::ref_account(session); + } + + int transfer_quota(Ram_session_capability session, size_t size) + { + Lock::Guard lock_guard(_lock); + return RAM_SESSION_IMPL::transfer_quota(session, size); + } + + size_t quota() + { + Lock::Guard lock_guard(_lock); + return RAM_SESSION_IMPL::quota(); + } + + size_t used() + { + Lock::Guard lock_guard(_lock); + return RAM_SESSION_IMPL::used(); + } + }; + + + class Core_env : public Platform_env_base + { + public: + + /** + * Entrypoint with support for local object access + * + * Within core, there are a few cases where the RPC objects must + * be invoked by direct function calls instead of using RPC. + * I.e., when an entrypoint dispatch function performs a memory + * allocation via the 'Sliced_heap', the 'attach' function of + * 'Rm_session_mmap' tries to obtain the dataspace's size and fd. + * Normally, this would be done by calling the entrypoint but the + * entrypoint cannot call itself. To support this special case, + * the 'Entrypoint' extends the 'Rpc_entrypoint' with the + * functionality needed to lookup an RPC object by its capability. + */ + struct Entrypoint : Rpc_entrypoint + { + enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) }; + + template + T *lookup(Capability cap) + { + Rpc_object_base *obj = obj_by_cap(cap); + return obj ? dynamic_cast(obj) : 0; + } + + Entrypoint(Cap_session *cap_session) + : + Rpc_entrypoint(cap_session, STACK_SIZE, "entrypoint") + { } + }; + + private: + + typedef Synchronized_ram_session Core_ram_session; + + Core_parent _core_parent; + Cap_session_component _cap_session; + Entrypoint _entrypoint; + Core_ram_session _ram_session; + Heap _heap; + Ram_session_capability const _ram_session_cap; + + public: + + /** + * Constructor + */ + Core_env() + : + Platform_env_base(Ram_session_capability(), + Cpu_session_capability(), + Pd_session_capability()), + _entrypoint(&_cap_session), + _ram_session(&_entrypoint, &_entrypoint, + platform()->ram_alloc(), platform()->core_mem_alloc(), + "ram_quota=4M", platform()->ram_alloc()->avail()), + _heap(&_ram_session, Platform_env_base::rm_session()), + _ram_session_cap(_entrypoint.manage(&_ram_session)) + { } + + /** + * Destructor + */ + ~Core_env() { parent()->exit(0); } + + + /************************************** + ** Core-specific accessor functions ** + **************************************/ + + Cap_session *cap_session() { return &_cap_session; } + Entrypoint *entrypoint() { return &_entrypoint; } + + + /******************* + ** Env interface ** + *******************/ + + Parent *parent() { return &_core_parent; } + Ram_session *ram_session() { return &_ram_session; } + Ram_session_capability ram_session_cap() { return _ram_session_cap; } + Allocator *heap() { return &_heap; } + + Cpu_session_capability cpu_session_cap() { + PWRN("%s:%u not implemented", __FILE__, __LINE__); + return Cpu_session_capability(); + } + + Pd_session *pd_session() + { + PWRN("%s:%u not implemented", __FILE__, __LINE__); + return 0; + } + }; + + + /** + * Request pointer to static environment of Core + */ + extern Core_env *core_env(); +} + +#endif /* _CORE__INCLUDE__CORE_ENV_H_ */ diff --git a/base-linux/src/core/include/platform.h b/base-linux/src/core/include/platform.h index 048606a6a..fc4a78fdc 100644 --- a/base-linux/src/core/include/platform.h +++ b/base-linux/src/core/include/platform.h @@ -31,7 +31,43 @@ namespace Genode { { private: - Synchronized_range_allocator _ram_alloc; /* RAM allocator */ + /** + * Allocator for core-internal meta data + */ + Synchronized_range_allocator _core_mem_alloc; + + /** + * Allocator for pseudo physical memory + */ + struct Pseudo_ram_allocator : Range_allocator + { + bool alloc(size_t size, void **out_addr) + { + *out_addr = 0; + return true; + } + + Alloc_return alloc_aligned(size_t, void **out_addr, int) + { + *out_addr = 0; + return Alloc_return::OK; + } + + Alloc_return alloc_addr(size_t, addr_t) + { + return Alloc_return::OK;; + } + + int add_range(addr_t, size_t) { return 0; } + int remove_range(addr_t, size_t) { return 0; } + void free(void *) { } + void free(void *, size_t) { } + size_t avail() { return ~0; } + bool valid_addr(addr_t) { return true; } + size_t overhead(size_t) { return 0; } + }; + + Pseudo_ram_allocator _ram_alloc; public: @@ -45,7 +81,7 @@ namespace Genode { ** Generic platform interface ** ********************************/ - Range_allocator *core_mem_alloc() { return &_ram_alloc; } + Range_allocator *core_mem_alloc() { return &_core_mem_alloc; } Range_allocator *ram_alloc() { return &_ram_alloc; } Range_allocator *io_mem_alloc() { return 0; } Range_allocator *io_port_alloc() { return 0; } diff --git a/base-linux/src/core/platform.cc b/base-linux/src/core/platform.cc index 4f47d2005..6906e46a9 100644 --- a/base-linux/src/core/platform.cc +++ b/base-linux/src/core/platform.cc @@ -13,6 +13,7 @@ /* Genode includes */ #include +#include /* local includes */ #include "platform.h" @@ -26,7 +27,10 @@ using namespace Genode; -static char _some_mem[80*1024*1024]; +/** + * Memory pool used for for core-local meta data + */ +static char _core_mem[80*1024*1024]; static Lock _wait_for_exit_lock(Lock::LOCKED); /* exit() sync */ @@ -37,7 +41,7 @@ static void signal_handler(int signum) Platform::Platform() -: _ram_alloc(0) +: _core_mem_alloc(0) { /* catch control-c */ lx_sigaction(2, signal_handler); @@ -45,7 +49,7 @@ Platform::Platform() /* create resource directory under /tmp */ lx_mkdir(resource_path(), S_IRWXU); - _ram_alloc.add_range((addr_t)_some_mem, sizeof(_some_mem)); + _core_mem_alloc.add_range((addr_t)_core_mem, sizeof(_core_mem)); /* * Occupy the socket handle that will be used to propagate the parent @@ -95,3 +99,46 @@ namespace Genode { } } + +/**************************************************** + ** Support for Platform_env_base::Rm_session_mmap ** + ****************************************************/ + +Genode::size_t +Platform_env_base::Rm_session_mmap::_dataspace_size(Capability ds_cap) +{ + if (!ds_cap.valid()) + return Dataspace_capability::deref(ds_cap)->size(); + + /* use RPC if called from a different thread */ + if (!core_env()->entrypoint()->is_myself()) + return Dataspace_client(ds_cap).size(); + + /* use local function call if called from the entrypoint */ + Dataspace *ds = core_env()->entrypoint()->lookup(ds_cap); + return ds ? ds->size() : 0; +} + + +int Platform_env_base::Rm_session_mmap::_dataspace_fd(Capability ds_cap) +{ + if (!core_env()->entrypoint()->is_myself()) + return Linux_dataspace_client(ds_cap).fd().dst().socket; + + Capability lx_ds_cap = static_cap_cast(ds_cap); + + Linux_dataspace *ds = core_env()->entrypoint()->lookup(lx_ds_cap); + + return ds ? ds->fd().dst().socket : -1; +} + + +bool Platform_env_base::Rm_session_mmap::_dataspace_writable(Dataspace_capability ds_cap) +{ + if (!core_env()->entrypoint()->is_myself()) + return Dataspace_client(ds_cap).writable(); + + Dataspace *ds = core_env()->entrypoint()->lookup(ds_cap); + + return ds ? ds->writable() : false; +} diff --git a/base-linux/src/core/ram_session_support.cc b/base-linux/src/core/ram_session_support.cc index a0e945178..7911a387f 100644 --- a/base-linux/src/core/ram_session_support.cc +++ b/base-linux/src/core/ram_session_support.cc @@ -61,7 +61,4 @@ void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) } -void Ram_session_component::_clear_ds(Dataspace_component *ds) -{ - memset((void *)ds->phys_addr(), 0, ds->size()); -} +void Ram_session_component::_clear_ds(Dataspace_component *ds) { } diff --git a/base-linux/src/core/target.mk b/base-linux/src/core/target.mk index 98f54c823..a5746d4db 100644 --- a/base-linux/src/core/target.mk +++ b/base-linux/src/core/target.mk @@ -21,7 +21,8 @@ SRC_CC = main.cc \ thread.cc \ thread_linux.cc \ context_area.cc \ - debug.cc + debug.cc \ + rm_session_mmap.cc INC_DIR += $(REP_DIR)/src/core/include \ $(GEN_CORE_DIR)/include \ @@ -38,4 +39,5 @@ vpath platform_services.cc $(GEN_CORE_DIR) vpath signal_session_component.cc $(GEN_CORE_DIR) vpath signal_source_component.cc $(GEN_CORE_DIR) vpath debug.cc $(REP_DIR)/src/base/env +vpath rm_session_mmap.cc $(REP_DIR)/src/base/env vpath %.cc $(PRG_DIR) diff --git a/base/include/base/rpc_server.h b/base/include/base/rpc_server.h index 37a72cdcf..27761620f 100644 --- a/base/include/base/rpc_server.h +++ b/base/include/base/rpc_server.h @@ -399,6 +399,11 @@ namespace Genode { * answering the original call. */ void explicit_reply(Untyped_capability reply_cap, int return_value); + + /** + * Return true if the caller corresponds to the entrypoint called + */ + bool is_myself() const; }; } diff --git a/base/src/base/server/common.cc b/base/src/base/server/common.cc index 11e17bd6b..e45cc8b59 100644 --- a/base/src/base/server/common.cc +++ b/base/src/base/server/common.cc @@ -91,6 +91,12 @@ void Rpc_entrypoint::activate() } +bool Rpc_entrypoint::is_myself() const +{ + return (Thread_base::myself() == this); +} + + Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size, char const *name, bool start_on_construction) :