diff --git a/repos/ports/ports/virtualbox5.hash b/repos/ports/ports/virtualbox5.hash index 9fb306d8b1..4e564ada8e 100644 --- a/repos/ports/ports/virtualbox5.hash +++ b/repos/ports/ports/virtualbox5.hash @@ -1 +1 @@ -1544b2568499a11bfd400f6bb1361e39f9f1022d +0db2b02901c5b62cd181d817ba71c3b0d417a40a diff --git a/repos/ports/src/virtualbox5/patches/rem_mem.patch b/repos/ports/src/virtualbox5/patches/rem_mem.patch new file mode 100644 index 0000000000..d4b765fabb --- /dev/null +++ b/repos/ports/src/virtualbox5/patches/rem_mem.patch @@ -0,0 +1,34 @@ +--- a/src/app/virtualbox/include/iprt/mem.h ++++ b/src/app/virtualbox/include/iprt/mem.h +@@ -1014,6 +1014,14 @@ + */ + RTDECL(void *) RTMemEfDupExNP(const void *pvSrc, size_t cbSrc, size_t cbExtra, const char *pszTag) RT_NO_THROW_PROTO; + ++/** ++ * REM memory allocations must be within 1<<31 window - use specific calls ++ */ ++RTDECL(void *) RTMemTCGAlloc(size_t cb) RT_NO_THROW_PROTO; ++RTDECL(void *) RTMemTCGAllocZ(size_t cb) RT_NO_THROW_PROTO; ++RTDECL(void *) RTMemTCGRealloc(void *pvOld, size_t cbNew) RT_NO_THROW_PROTO; ++RTDECL(void) RTMemTCGFree(void *pv) RT_NO_THROW_PROTO; ++ + /** @} */ + + RT_C_DECLS_END +--- a/src/app/virtualbox/src/recompiler/osdep.h ++++ b/src/app/virtualbox/src/recompiler/osdep.h +@@ -21,10 +21,10 @@ + RTLogPrintfV((pszFormat), (args)) + + /**@todo the following macros belongs elsewhere */ +-#define qemu_malloc(cb) RTMemAlloc(cb) +-#define qemu_mallocz(cb) RTMemAllocZ(cb) +-#define qemu_realloc(ptr, cb) RTMemRealloc(ptr, cb) +-#define qemu_free(pv) RTMemFree(pv) ++#define qemu_malloc(cb) RTMemTCGAlloc(cb) ++#define qemu_mallocz(cb) RTMemTCGAllocZ(cb) ++#define qemu_realloc(ptr, cb) RTMemTCGRealloc(ptr, cb) ++#define qemu_free(pv) RTMemTCGFree(pv) + #define qemu_strdup(psz) RTStrDup(psz) + + /* Misc wrappers */ diff --git a/repos/ports/src/virtualbox5/patches/series b/repos/ports/src/virtualbox5/patches/series index 955302538c..3ec7c43b28 100644 --- a/repos/ports/src/virtualbox5/patches/series +++ b/repos/ports/src/virtualbox5/patches/series @@ -32,3 +32,4 @@ tm_tpr.patch tm_4s.patch rem_tss.patch mem_leak.patch +rem_mem.patch diff --git a/repos/ports/src/virtualbox5/rt.cc b/repos/ports/src/virtualbox5/rt.cc index 08392c3c29..2a4e0b60f8 100644 --- a/repos/ports/src/virtualbox5/rt.cc +++ b/repos/ports/src/virtualbox5/rt.cc @@ -14,6 +14,7 @@ /* Genode includes */ #include #include +#include /* VirtualBox includes */ @@ -29,7 +30,7 @@ #include "vmm.h" enum { - MEMORY_MAX = 64 * 1024 * 1024, + MEMORY_MAX = 128 * 1024 * 1024, MEMORY_CACHED = 16 * 1024 * 1024, }; @@ -132,6 +133,18 @@ class Avl_ds : public Genode::Avl_node : head->find_size(size); } + static Genode::addr_t max_size_at(void * p) + { + Avl_ds * ds_obj = Avl_ds::_runtime_ds.first(); + if (ds_obj) + ds_obj = ds_obj->find_virt(reinterpret_cast(p)); + + if (!ds_obj) + return 0; + + return ds_obj->_size; + } + Genode::addr_t ds_virt() const { return _virt; } static void memory_freeup(Genode::addr_t const cb) @@ -273,6 +286,137 @@ void RTMemPageFree(void *pv, size_t cb) Avl_ds::free_memory(pv, cb); } +/** + * The tiny code generator (TCG) of the REM allocates quite a hugh amount + * of individal TCG_CACHED_SIZE blocks. Using a dataspace per allocation + * increases the cap count significantly (e.g. 9G RAM caused 2500 allocations). + * Using a Slab for the known size avoids the cap issue. + */ + +enum { TCG_CACHE = 4 * 1024 * 1024, TCG_CACHED_SIZE = 0x4000 }; + +typedef Genode::Bit_allocator Tcg_idx_allocator; + +struct Tcg_slab : Genode::List::Element { + Tcg_idx_allocator _slots; + Genode::addr_t _base { 0 }; + bool _full { false }; + + Tcg_slab(void *memory) + : _base(reinterpret_cast(memory)) { }; + + void * alloc() + { + unsigned idx = _slots.alloc(); + return reinterpret_cast(_base + idx * TCG_CACHED_SIZE); + } + + Genode::addr_t contains(Genode::addr_t const ptr) const { + return _base <= ptr && ptr < _base + TCG_CACHED_SIZE; } +}; + +static Genode::List list; + +void * RTMemTCGAlloc(size_t cb) +{ + if (cb != TCG_CACHED_SIZE) + return alloc_mem(cb, __func__); + + { + Genode::Lock::Guard guard(lock_ds); + + for (Tcg_slab * tcg = list.first(); tcg; tcg = tcg->next()) { + if (tcg->_full) + continue; + + try { + return tcg->alloc(); + } catch (Tcg_idx_allocator::Out_of_indices) { + tcg->_full = true; + /* try on another slab */ + } + } + } + + Tcg_slab * tcg = new (vmm_heap()) Tcg_slab(alloc_mem(TCG_CACHE, __func__)); + if (tcg && tcg->_base) { + { + Genode::Lock::Guard guard(lock_ds); + list.insert(tcg); + } + return RTMemTCGAlloc(cb); + } + + Genode::error("no memory left for TCG"); + + if (tcg) + destroy(vmm_heap(), tcg); + + return nullptr; +} + + +void * RTMemTCGAllocZ(size_t cb) +{ + void * ptr = RTMemTCGAlloc(cb); + if (ptr) + Genode::memset(ptr, 0, cb); + + return ptr; +} + +void RTMemTCGFree(void *pv) +{ + Genode::Lock::Guard guard(lock_ds); + + Genode::addr_t const ptr = reinterpret_cast(pv); + for (Tcg_slab * tcg = list.first(); tcg; tcg = tcg->next()) { + if (!tcg->contains(ptr)) + continue; + + Genode::warning("could not free up TCG memory ", pv); + return; + } + Avl_ds::free_memory(pv, Avl_ds::max_size_at(pv)); +} + +void * RTMemTCGRealloc(void *ptr, size_t size) +{ + if (!ptr && size) + return RTMemTCGAllocZ(size); + + if (!size) { + if (ptr) + RTMemTCGFree(ptr); + return nullptr; + } + + Genode::addr_t max_size = 0; + { + Genode::Lock::Guard guard(lock_ds); + + max_size = Avl_ds::max_size_at(ptr); + if (!max_size) { + Genode::error("bug - unknown pointer"); + return nullptr; + } + + if (size <= max_size) + return ptr; + } + + void * new_ptr = RTMemTCGAllocZ(size); + if (!new_ptr) { + Genode::error("no memory left ", size); + return nullptr; + } + Genode::memcpy(new_ptr, ptr, max_size); + + RTMemTCGFree(ptr); + + return new_ptr; +} + #include uint32_t RTBldCfgVersionMajor(void) { return VBOX_VERSION_MAJOR; }