diff --git a/repos/dde_linux/src/include/lx_emul/alloc.h b/repos/dde_linux/src/include/lx_emul/alloc.h index 8f5fbbddf4..60bfa59a3e 100644 --- a/repos/dde_linux/src/include/lx_emul/alloc.h +++ b/repos/dde_linux/src/include/lx_emul/alloc.h @@ -23,6 +23,7 @@ void * lx_emul_mem_alloc_uncached(unsigned long size); void * lx_emul_mem_alloc_aligned(unsigned long size, unsigned long align); void * lx_emul_mem_alloc_aligned_uncached(unsigned long size, unsigned long align); unsigned long lx_emul_mem_dma_addr(void * addr); +unsigned long lx_emul_mem_virt_addr(void * dma_addr); void lx_emul_mem_free(const void * ptr); unsigned long lx_emul_mem_size(const void * ptr); void lx_emul_mem_cache_clean_invalidate(const void * ptr, unsigned long size); diff --git a/repos/dde_linux/src/include/lx_kit/memory.h b/repos/dde_linux/src/include/lx_kit/memory.h index 737626db3a..20dbab7104 100644 --- a/repos/dde_linux/src/include/lx_kit/memory.h +++ b/repos/dde_linux/src/include/lx_kit/memory.h @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include namespace Platform { class Connection; }; namespace Lx_kit { @@ -31,7 +32,7 @@ class Lx_kit::Mem_allocator { private: - class Buffer : Interface + class Buffer { private: @@ -45,18 +46,56 @@ class Lx_kit::Mem_allocator addr_t dma_addr) : _ds(rm, cap), _dma_addr(dma_addr) {} - addr_t dma_addr() const { return _dma_addr; } - Attached_dataspace & ds() { return _ds; } + size_t dma_addr() const { return _dma_addr; } + size_t size() const { return _ds.size(); } + size_t virt_addr() const { + return (addr_t) _ds.local_addr(); } + + Attached_dataspace & ds() { return _ds; } }; - using Buffer_registry = Registry>; + struct Buffer_info + { + struct Key { addr_t addr; } key; + Buffer & buffer; + + size_t size() const { return buffer.size(); } + + bool higher(Key const other_key) const + { + return key.addr > other_key.addr; + } + + struct Query_range + { + addr_t addr; + size_t size; + + bool matches(Buffer_info const & bi) const + { + Lx_kit::Byte_range buf_range { bi.key.addr, bi.size() }; + Lx_kit::Byte_range range { addr, size }; + + return buf_range.intersects(range); + } + + Key key() const { return Key { addr }; } + }; + + struct Query_addr : Query_range + { + Query_addr(void const * addr) + : Query_range{(addr_t)addr, 1} { } + }; + }; Env & _env; Heap & _heap; Platform::Connection & _platform; Cache _cache_attr; Allocator_avl _mem; - Buffer_registry _buffers {}; + Map _virt_to_dma { _heap }; + Map _dma_to_virt { _heap }; public: @@ -69,8 +108,8 @@ class Lx_kit::Mem_allocator void * alloc(size_t size, size_t align); addr_t dma_addr(void * addr); + addr_t virt_addr(void * dma_addr); size_t size(const void * ptr); - void free(Attached_dataspace * ds); bool free(const void * ptr); }; diff --git a/repos/dde_linux/src/lib/lx_emul/alloc.cc b/repos/dde_linux/src/lib/lx_emul/alloc.cc index 4c11920b0c..fa46c24137 100644 --- a/repos/dde_linux/src/lib/lx_emul/alloc.cc +++ b/repos/dde_linux/src/lib/lx_emul/alloc.cc @@ -64,6 +64,17 @@ extern "C" unsigned long lx_emul_mem_dma_addr(void * addr) } +extern "C" unsigned long lx_emul_mem_virt_addr(void * dma_addr) +{ + unsigned long ret = Lx_kit::env().memory.virt_addr(dma_addr); + if (ret) + return ret; + if (!(ret = Lx_kit::env().uncached_memory.virt_addr(dma_addr))) + Genode::error(__func__, " called with invalid addr ", dma_addr); + return ret; +} + + extern "C" void lx_emul_mem_free(const void * ptr) { if (!ptr) diff --git a/repos/dde_linux/src/lib/lx_kit/memory.cc b/repos/dde_linux/src/lib/lx_kit/memory.cc index a7dc51ea95..85a8f3fd95 100644 --- a/repos/dde_linux/src/lib/lx_kit/memory.cc +++ b/repos/dde_linux/src/lib/lx_kit/memory.cc @@ -19,6 +19,8 @@ /* local includes */ #include +#include +#include Genode::Attached_dataspace & Lx_kit::Mem_allocator::alloc_dataspace(size_t size) @@ -26,17 +28,18 @@ Genode::Attached_dataspace & Lx_kit::Mem_allocator::alloc_dataspace(size_t size) Ram_dataspace_capability ds_cap; try { - size_t ds_size = align_addr(size, 12); - ds_cap = _platform.alloc_dma_buffer(ds_size, _cache_attr); - addr_t dma_addr = _platform.dma_addr(ds_cap); + Ram_dataspace_capability ds_cap = + _platform.alloc_dma_buffer(align_addr(size, 12), _cache_attr); Buffer & buffer = *new (_heap) - Registered(_buffers, _env.rm(), ds_cap, dma_addr); - addr_t addr = (addr_t)buffer.ds().local_addr(); + Buffer(_env.rm(), ds_cap, _platform.dma_addr(ds_cap)); /* map eager by touching all pages once */ - for (size_t sz = 0; sz < ds_size; sz += 4096) { - touch_read((unsigned char const volatile*)(addr + sz)); } + for (size_t sz = 0; sz < buffer.size(); sz += 4096) { + touch_read((unsigned char const volatile*)(buffer.virt_addr() + sz)); } + + _virt_to_dma.insert(buffer.virt_addr(), buffer); + _dma_to_virt.insert(buffer.dma_addr(), buffer); return buffer.ds(); } catch (Out_of_caps) { @@ -70,7 +73,8 @@ void * Lx_kit::Mem_allocator::alloc(size_t size, size_t align) * and physical addresses of a multi-page allocation are always * contiguous. */ - Attached_dataspace & ds = alloc_dataspace(max(size + 1, min_buffer_size)); + Attached_dataspace & ds = alloc_dataspace(max(size + 1, + min_buffer_size)); _mem.add_range((addr_t)ds.local_addr(), ds.size() - 1); @@ -93,15 +97,24 @@ Genode::addr_t Lx_kit::Mem_allocator::dma_addr(void * addr) { addr_t ret = 0UL; - _buffers.for_each([&] (Buffer & b) { - addr_t other = (addr_t)addr; - addr_t addr = (addr_t)b.ds().local_addr(); - if (addr > other || (addr+b.ds().size()) <= other) - return; + _virt_to_dma.apply(Buffer_info::Query_addr(addr), + [&] (Buffer_info const & info) { + addr_t const offset = (addr_t)addr - info.buffer.virt_addr(); + ret = info.buffer.dma_addr() + offset; + }); - /* byte offset of 'addr' from start of block */ - addr_t const offset = other - addr; - ret = b.dma_addr() + offset; + return ret; +} + + +Genode::addr_t Lx_kit::Mem_allocator::virt_addr(void * dma_addr) +{ + addr_t ret = 0UL; + + _dma_to_virt.apply(Buffer_info::Query_addr(dma_addr), + [&] (Buffer_info const & info) { + addr_t const offset = (addr_t)dma_addr - info.buffer.dma_addr(); + ret = info.buffer.virt_addr() + offset; }); return ret; @@ -118,21 +131,6 @@ bool Lx_kit::Mem_allocator::free(const void * ptr) } -void Lx_kit::Mem_allocator::free(Attached_dataspace * ds) -{ - Dataspace_capability cap = ds->cap(); - - Registered * buffer = nullptr; - _buffers.for_each([&] (Buffer & b) { - if (&b.ds() == ds) - buffer = static_cast*>(&b); - }); - - destroy(_heap, buffer); - _platform.free_dma_buffer(static_cap_cast(cap)); -} - - Genode::size_t Lx_kit::Mem_allocator::size(const void * ptr) { return ptr ? _mem.size_at(ptr) : 0;