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; }