diff --git a/ports-foc/lib/mk/l4lx.mk b/ports-foc/lib/mk/l4lx.mk index 250320048b..ea9a52f0e8 100644 --- a/ports-foc/lib/mk/l4lx.mk +++ b/ports-foc/lib/mk/l4lx.mk @@ -26,6 +26,7 @@ SRC_CC += env.cc \ l4lx_memory.cc \ l4lx_task.cc \ l4lx_thread.cc \ + l4x_pagefault.cc \ rm.cc \ startup.cc diff --git a/ports-foc/src/lib/l4lx/dataspace.cc b/ports-foc/src/lib/l4lx/dataspace.cc index efe22f7d86..9064ecda05 100644 --- a/ports-foc/src/lib/l4lx/dataspace.cc +++ b/ports-foc/src/lib/l4lx/dataspace.cc @@ -24,7 +24,8 @@ L4lx::Dataspace* L4lx::Dataspace_tree::insert(const char* name, using namespace L4lx; Genode::Dataspace_client dsc(cap); - Dataspace *ds = new (Genode::env()->heap()) Dataspace(name, dsc.size(), cap); + Dataspace *ds = + new (Genode::env()->heap()) Single_dataspace(name, dsc.size(), cap); insert(ds); return ds; } diff --git a/ports-foc/src/lib/l4lx/include/dataspace.h b/ports-foc/src/lib/l4lx/include/dataspace.h index c95e3f402d..b3708f67d3 100644 --- a/ports-foc/src/lib/l4lx/include/dataspace.h +++ b/ports-foc/src/lib/l4lx/include/dataspace.h @@ -17,7 +17,9 @@ /* Genode includes */ #include #include +#include #include +#include namespace Fiasco { #include @@ -29,10 +31,9 @@ namespace L4lx { { private: - const char* _name; - Genode::size_t _size; - Genode::Dataspace_capability _cap; - Fiasco::l4_cap_idx_t _ref; + const char* _name; + Genode::size_t _size; + Fiasco::l4_cap_idx_t _ref; public: @@ -40,17 +41,10 @@ namespace L4lx { ** Constructors ** ******************/ - Dataspace(const char* name, - Genode::size_t size, - Genode::Dataspace_capability ds, - Fiasco::l4_cap_idx_t ref) - : _name(name), _size(size), _cap(ds), _ref(ref) {} - - Dataspace(const char* name, - Genode::size_t size, - Genode::Dataspace_capability ds) - : _name(name), _size(size), _cap(ds), - _ref(Genode::cap_idx_alloc()->alloc_range(1)->kcap()) {} + Dataspace(const char* name, + Genode::size_t size, + Fiasco::l4_cap_idx_t ref) + : _name(name), _size(size), _ref(ref) {} /*************** @@ -59,9 +53,10 @@ namespace L4lx { const char* name() const { return _name; } Genode::size_t size() { return _size; } - Genode::Dataspace_capability cap() { return _cap; } Fiasco::l4_cap_idx_t ref() { return _ref; } + virtual Genode::Dataspace_capability cap() = 0; + virtual bool map(Genode::size_t offset) = 0; /************************ ** Avl_node interface ** @@ -79,6 +74,100 @@ namespace L4lx { }; + class Single_dataspace : public Dataspace + { + private: + + Genode::Dataspace_capability _cap; + + public: + + Single_dataspace(const char* name, + Genode::size_t size, + Genode::Dataspace_capability ds, + Fiasco::l4_cap_idx_t ref = + Genode::cap_idx_alloc()->alloc_range(1)->kcap()) + : Dataspace(name, size, ref), _cap(ds) {} + + Genode::Dataspace_capability cap() { return _cap; } + bool map(Genode::size_t offset) { return true; } + }; + + + class Chunked_dataspace : public Dataspace + { + private: + + class Chunk : public Genode::Avl_node + { + private: + + Genode::size_t _offset; + Genode::size_t _size; + Genode::Dataspace_capability _cap; + + public: + + Chunk(Genode::size_t off, Genode::size_t size, + Genode::Dataspace_capability cap) + : _offset(off), _size(size), _cap(cap) {} + + Genode::size_t offset() { return _offset; } + Genode::size_t size() { return _size; } + Genode::Dataspace_capability cap() { return _cap; } + + bool higher(Chunk *n) { return n->_offset > _offset; } + + Chunk *find_by_offset(Genode::size_t off) + { + if (off >= _offset && off < _offset+_size) return this; + + Chunk *n = Genode::Avl_node::child(off > _offset); + return n ? n->find_by_offset(off) : 0; + } + }; + + Genode::Rm_connection _rm; + Genode::Avl_tree _chunks; + Genode::size_t _chunk_size; + Genode::size_t _chunk_size_log2; + + public: + + Chunked_dataspace(const char* name, + Genode::size_t size, + Fiasco::l4_cap_idx_t ref, + Genode::size_t chunk_size) + : Dataspace(name, size, ref), _rm(0, size), _chunk_size(chunk_size), + _chunk_size_log2(Genode::log2(_chunk_size)) {} + + Genode::Dataspace_capability cap() { return _rm.dataspace(); } + + bool map(Genode::size_t off) + { + off = Genode::align_addr((off-(_chunk_size-1)), _chunk_size_log2); + + Chunk* c = _chunks.first() ? _chunks.first()->find_by_offset(off) : 0; + if (c) return true; + + try { + Genode::Dataspace_capability cap = + Genode::env()->ram_session()->alloc(_chunk_size); + _chunks.insert(new (Genode::env()->heap()) + Chunk(off, _chunk_size, cap)); + _rm.attach(cap, 0, 0, true, off); + return true; + } catch(Genode::Ram_session::Quota_exceeded) { + PWRN("Could not allocate new dataspace chunk"); + } catch(Genode::Rm_session::Attach_failed) { + PWRN("Attach of chunk dataspace of size %zx to %p failed", + _chunk_size, (void*) off); + } + return false; + } + }; + + class Dataspace_tree : public Genode::Avl_tree { public: 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 01aa3db4d2..69487b2222 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 @@ -57,34 +57,16 @@ extern "C" { if (DEBUG) PDBG("size=%lx mem=%lx flags=%lx", size, mem, flags); - Genode::Dataspace_capability cap; - + Dataspace *ds; 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(); + ds = new (Genode::env()->heap()) + Chunked_dataspace("lx_memory", size, mem, chunk_size); } else { - cap = Genode::env()->ram_session()->alloc(size); + Genode::Dataspace_capability cap = + Genode::env()->ram_session()->alloc(size); + ds = new (Genode::env()->heap()) + Single_dataspace("lx_memory", size, cap, mem); } - - Dataspace *ds = new (Genode::env()->heap()) - Dataspace("lx_memory", size, cap, mem); Env::env()->dataspaces()->insert(ds); return 0; } diff --git a/ports-foc/src/lib/l4lx/l4_re_env.cc b/ports-foc/src/lib/l4lx/l4_re_env.cc index 1abdde9e51..85362fe016 100644 --- a/ports-foc/src/lib/l4lx/l4_re_env.cc +++ b/ports-foc/src/lib/l4lx/l4_re_env.cc @@ -57,7 +57,7 @@ extern "C" { l4re_env_cap_entry_t *entry = new (Genode::env()->heap()) l4re_env_cap_entry_t(); Dataspace *ds = new (Genode::env()->heap()) - Dataspace("initrd", size, cap); + Single_dataspace("initrd", size, cap); Env::env()->dataspaces()->insert(ds); entry->cap = ds->ref(); return entry; diff --git a/ports-foc/src/lib/l4lx/l4x_pagefault.cc b/ports-foc/src/lib/l4lx/l4x_pagefault.cc new file mode 100644 index 0000000000..260399f912 --- /dev/null +++ b/ports-foc/src/lib/l4lx/l4x_pagefault.cc @@ -0,0 +1,28 @@ +#include +#include + +namespace Fiasco { +#include +#include +} + +extern "C" L4_CV int l4x_forward_pf(Fiasco::l4_umword_t addr, + Fiasco::l4_umword_t pc, int extra_write) +{ + using namespace Fiasco; + + Genode::size_t size = L4_PAGESIZE; + Genode::addr_t ds_start_addr = addr; + L4lx::Region *r = L4lx::Env::env()->rm()->find_region(&ds_start_addr, &size); + L4lx::Dataspace *ds = r ? r->ds() : 0; + if (ds && !ds->map(addr - r->addr())) + return 0; + + if (!extra_write) + l4_touch_ro((void*)l4_trunc_page(addr), L4_LOG2_PAGESIZE); + else + l4_touch_rw((void*)l4_trunc_page(addr), L4_LOG2_PAGESIZE); + return 1; +} + + diff --git a/ports-foc/src/lib/l4lx/rm.cc b/ports-foc/src/lib/l4lx/rm.cc index 4165c284fe..2a21c4a537 100644 --- a/ports-foc/src/lib/l4lx/rm.cc +++ b/ports-foc/src/lib/l4lx/rm.cc @@ -159,8 +159,9 @@ Region* Region_manager::reserve_range(Genode::size_t size, int align, void Region_manager::reserve_range(Genode::addr_t addr, Genode::size_t size, const char *name) { + Genode::Dataspace_capability cap; L4lx::Dataspace *ds = new (Genode::env()->heap()) - L4lx::Dataspace(name, size, Genode::reinterpret_cap_cast(Genode::Native_capability())); + L4lx::Single_dataspace(name, size, cap); L4lx::Env::env()->dataspaces()->insert(ds); alloc_addr(size, (Genode::addr_t)addr); metadata((void*)addr, Region(addr, size, ds));