2013-08-21 09:37:21 +00:00
|
|
|
/*
|
|
|
|
* \brief VirtualBox runtime (RT)
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2013-08-20
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2016-06-14 08:18:32 +00:00
|
|
|
* Copyright (C) 2013-2016 Genode Labs GmbH
|
2013-08-21 09:37:21 +00:00
|
|
|
*
|
|
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
|
|
* version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <base/env.h>
|
2016-06-08 18:15:27 +00:00
|
|
|
#include <base/allocator_avl.h>
|
2013-08-21 09:37:21 +00:00
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
|
2013-08-21 09:37:21 +00:00
|
|
|
/* VirtualBox includes */
|
|
|
|
#include <iprt/initterm.h>
|
|
|
|
#include <iprt/mem.h>
|
|
|
|
#include <iprt/err.h>
|
2014-09-23 11:01:47 +00:00
|
|
|
#include <iprt/assert.h>
|
2013-08-21 09:37:21 +00:00
|
|
|
#include <iprt/semaphore.h>
|
|
|
|
#include <iprt/time.h>
|
|
|
|
#include <internal/iprt.h>
|
|
|
|
|
2016-06-08 18:15:27 +00:00
|
|
|
class Avl_ds : public Genode::Avl_node<Avl_ds>
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
Genode::Ram_dataspace_capability _ds;
|
|
|
|
Genode::addr_t _virt;
|
2016-06-14 08:18:32 +00:00
|
|
|
Genode::addr_t const _size;
|
|
|
|
Genode::addr_t _used_size;
|
|
|
|
|
|
|
|
bool _inuse = true;
|
|
|
|
|
|
|
|
static Genode::addr_t _mem_allocated;
|
|
|
|
static Genode::addr_t _mem_unused;
|
|
|
|
|
|
|
|
static Genode::Avl_tree<Avl_ds> _unused_ds;
|
|
|
|
static Genode::Avl_tree<Avl_ds> _runtime_ds;
|
2016-06-08 18:15:27 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
static Genode::addr_t hit;
|
|
|
|
static Genode::addr_t hit_coarse;
|
|
|
|
|
|
|
|
Avl_ds(Genode::Ram_dataspace_capability ds, void * virt,
|
|
|
|
Genode::addr_t size)
|
|
|
|
:
|
|
|
|
_ds(ds), _virt(reinterpret_cast<Genode::addr_t>(virt)),
|
|
|
|
_size(size), _used_size(_size)
|
|
|
|
{
|
|
|
|
_mem_allocated += _size;
|
|
|
|
_runtime_ds.insert(this);
|
|
|
|
}
|
2016-06-08 18:15:27 +00:00
|
|
|
|
|
|
|
~Avl_ds() {
|
2016-06-14 08:18:32 +00:00
|
|
|
Assert (!_inuse);
|
|
|
|
|
|
|
|
_unused_ds.remove(this);
|
|
|
|
_mem_unused -= _size;
|
|
|
|
_mem_allocated -= _size;
|
|
|
|
|
2016-06-08 18:15:27 +00:00
|
|
|
Genode::env()->ram_session()->free(_ds);
|
2016-06-14 08:18:32 +00:00
|
|
|
PWRN("free up %lu %lu/%lu hit=%lu/%lu avail=%zu",
|
|
|
|
_size, _mem_allocated, _mem_unused, hit, hit_coarse,
|
|
|
|
Genode::env()->ram_session()->avail());
|
|
|
|
}
|
|
|
|
|
|
|
|
void unused()
|
|
|
|
{
|
|
|
|
_inuse = false;
|
|
|
|
|
|
|
|
_runtime_ds.remove(this);
|
|
|
|
|
|
|
|
_mem_unused += _size;
|
|
|
|
_unused_ds.insert(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void used(Genode::addr_t size)
|
|
|
|
{
|
|
|
|
_inuse = true;
|
|
|
|
|
|
|
|
_unused_ds.remove(this);
|
|
|
|
_used_size = size;
|
|
|
|
_mem_unused -= _size;
|
|
|
|
_runtime_ds.insert(this);
|
2016-06-08 18:15:27 +00:00
|
|
|
}
|
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
bool higher(Avl_ds *e) {
|
|
|
|
return _inuse ? e->_virt > _virt : e->_size > _size; }
|
2016-06-08 18:15:27 +00:00
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
Avl_ds *find_virt(Genode::addr_t virt)
|
2016-06-08 18:15:27 +00:00
|
|
|
{
|
|
|
|
if (virt == _virt) return this;
|
|
|
|
Avl_ds *obj = this->child(virt > _virt);
|
2016-06-14 08:18:32 +00:00
|
|
|
return obj ? obj->find_virt(virt) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Avl_ds *find_coarse_match(Genode::addr_t size_min, Genode::addr_t size_max)
|
|
|
|
{
|
|
|
|
if (size_min <= _size && _size <= size_max) return this;
|
|
|
|
Avl_ds *obj = this->child(size_max > _size);
|
|
|
|
return obj ? obj->find_coarse_match(size_min, size_max) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Avl_ds *find_size(Genode::addr_t size, bool equal = true)
|
|
|
|
{
|
|
|
|
if (equal ? size == _size : size <= _size) return this;
|
|
|
|
Avl_ds *obj = this->child(size > _size);
|
|
|
|
return obj ? obj->find_size(size, equal) : 0;
|
2016-06-08 18:15:27 +00:00
|
|
|
}
|
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
static Avl_ds *find_match(Genode::addr_t size, bool coarse = false)
|
|
|
|
{
|
|
|
|
Avl_ds * head = _unused_ds.first();
|
|
|
|
if (!head)
|
|
|
|
return head;
|
|
|
|
|
|
|
|
return coarse ? head->find_coarse_match(size, size * 2)
|
|
|
|
: head->find_size(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
Genode::addr_t ds_virt() const { return _virt; }
|
|
|
|
|
|
|
|
static void memory_freeup(Genode::addr_t const cb)
|
|
|
|
{
|
|
|
|
/* free up memory if we hit some chosen limits */
|
|
|
|
enum {
|
|
|
|
MEMORY_MAX = 64 * 1024 * 1024,
|
|
|
|
MEMORY_CACHED = 16 * 1024 * 1024,
|
|
|
|
};
|
|
|
|
|
|
|
|
size_t cbx = cb * 4;
|
|
|
|
while (_unused_ds.first() && cbx &&
|
|
|
|
(_mem_allocated + cb > MEMORY_MAX ||
|
|
|
|
_mem_unused + cb > MEMORY_CACHED ||
|
|
|
|
Genode::env()->ram_session()->avail() < cb * 2
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
Avl_ds * ds_free = _unused_ds.first()->find_size(cbx, false);
|
|
|
|
if (!ds_free) {
|
|
|
|
cbx = cbx / 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
destroy(Genode::env()->heap(), ds_free);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_memory(void * pv, size_t cb)
|
|
|
|
{
|
|
|
|
if (cb % 0x1000)
|
|
|
|
cb = (cb & ~0xFFFUL) + 0x1000UL;
|
|
|
|
|
|
|
|
Avl_ds * ds_obj = Avl_ds::_runtime_ds.first();
|
|
|
|
if (ds_obj)
|
|
|
|
ds_obj = ds_obj->find_virt(reinterpret_cast<Genode::addr_t>(pv));
|
|
|
|
|
|
|
|
if (ds_obj && ds_obj->_used_size == cb)
|
|
|
|
ds_obj->unused();
|
|
|
|
else {
|
|
|
|
PERR("%s unknown memory region %p(%lx)+%zx(%lx)",
|
|
|
|
__func__, pv, ds_obj ? ds_obj->ds_virt() : 0,
|
|
|
|
cb, ds_obj ? ds_obj->_size : 0);
|
|
|
|
}
|
|
|
|
}
|
2016-06-08 18:15:27 +00:00
|
|
|
};
|
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
Genode::Avl_tree<Avl_ds> Avl_ds::_runtime_ds;
|
|
|
|
Genode::Avl_tree<Avl_ds> Avl_ds::_unused_ds;
|
|
|
|
static Genode::Lock lock_ds;
|
|
|
|
|
|
|
|
Genode::addr_t Avl_ds::hit = 0;
|
|
|
|
Genode::addr_t Avl_ds::hit_coarse = 0;
|
|
|
|
Genode::addr_t Avl_ds::_mem_allocated = 0;
|
|
|
|
Genode::addr_t Avl_ds::_mem_unused = 0;
|
2013-08-21 09:37:21 +00:00
|
|
|
|
2014-09-23 11:01:47 +00:00
|
|
|
static void *alloc_mem(size_t cb, const char *pszTag, bool executable = false)
|
2013-08-21 09:37:21 +00:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
if (!cb)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (cb % 0x1000)
|
|
|
|
cb = (cb & ~0xFFFUL) + 0x1000UL;
|
|
|
|
|
|
|
|
Lock::Guard guard(lock_ds);
|
|
|
|
|
|
|
|
if (Avl_ds * ds_free = Avl_ds::find_match(cb)) {
|
|
|
|
ds_free->used(cb);
|
|
|
|
|
|
|
|
Avl_ds::hit++;
|
|
|
|
return reinterpret_cast<void *>(ds_free->ds_virt());
|
|
|
|
} else
|
|
|
|
if (Avl_ds * ds_free = Avl_ds::find_match(cb, true)) {
|
|
|
|
ds_free->used(cb);
|
|
|
|
|
|
|
|
Avl_ds::hit_coarse++;
|
|
|
|
return reinterpret_cast<void *>(ds_free->ds_virt());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for memory freeup, give hint about required memory (cb) */
|
|
|
|
Avl_ds::memory_freeup(cb);
|
|
|
|
|
2014-09-23 11:01:47 +00:00
|
|
|
try {
|
|
|
|
Ram_dataspace_capability ds = env()->ram_session()->alloc(cb);
|
|
|
|
Assert(ds.valid());
|
|
|
|
|
|
|
|
size_t const whole_size = 0;
|
|
|
|
Genode::off_t const offset = 0;
|
|
|
|
bool const any_addr = false;
|
|
|
|
void * any_local_addr = nullptr;
|
2013-08-21 09:37:21 +00:00
|
|
|
|
2016-06-08 18:15:27 +00:00
|
|
|
void * local_addr = env()->rm_session()->attach(ds, whole_size, offset,
|
|
|
|
any_addr, any_local_addr,
|
|
|
|
executable);
|
2014-09-23 11:01:47 +00:00
|
|
|
|
|
|
|
Assert(local_addr);
|
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
new (env()->heap()) Avl_ds(ds, local_addr, cb);
|
2016-06-08 18:15:27 +00:00
|
|
|
|
|
|
|
return local_addr;
|
2014-09-23 11:01:47 +00:00
|
|
|
} catch (...) {
|
2016-06-14 08:18:32 +00:00
|
|
|
PERR("Could not allocate RTMem* memory of size=%zx", cb);
|
2016-06-08 18:15:27 +00:00
|
|
|
return nullptr;
|
2014-09-23 11:01:47 +00:00
|
|
|
}
|
2013-08-21 09:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-23 11:01:47 +00:00
|
|
|
/*
|
|
|
|
* Called by the recompiler to allocate executable RAM
|
|
|
|
*/
|
|
|
|
void *RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
|
|
|
|
{
|
|
|
|
return alloc_mem(cb, pszTag, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-21 09:37:21 +00:00
|
|
|
void *RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The RAM dataspace freshly allocated by 'RTMemExecAllocTag' is zeroed
|
|
|
|
* already.
|
|
|
|
*/
|
2016-06-14 08:18:32 +00:00
|
|
|
void * addr = alloc_mem(cb, pszTag);
|
|
|
|
if (addr)
|
|
|
|
Genode::memset(addr, 0, cb);
|
|
|
|
return addr;
|
2013-08-21 09:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
|
|
|
|
{
|
2014-09-23 11:01:47 +00:00
|
|
|
return alloc_mem(cb, pszTag);
|
2013-08-21 09:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-23 11:01:47 +00:00
|
|
|
void RTMemPageFree(void *pv, size_t cb) RT_NO_THROW
|
|
|
|
{
|
2016-06-14 08:18:32 +00:00
|
|
|
Genode::Lock::Guard guard(lock_ds);
|
2016-06-08 18:15:27 +00:00
|
|
|
|
2016-06-14 08:18:32 +00:00
|
|
|
Avl_ds::free_memory(pv, cb);
|
2014-09-23 11:01:47 +00:00
|
|
|
}
|
|
|
|
|
2013-08-21 09:37:21 +00:00
|
|
|
#include <iprt/buildconfig.h>
|
|
|
|
|
|
|
|
uint32_t RTBldCfgVersionMajor(void) { return VBOX_VERSION_MAJOR; }
|
|
|
|
uint32_t RTBldCfgVersionMinor(void) { return VBOX_VERSION_MINOR; }
|
|
|
|
uint32_t RTBldCfgVersionBuild(void) { return VBOX_VERSION_BUILD; }
|
|
|
|
uint32_t RTBldCfgRevision(void) { return ~0; }
|
|
|
|
|
|
|
|
|
2014-05-23 07:26:57 +00:00
|
|
|
extern "C" DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath)
|
2013-08-21 09:37:21 +00:00
|
|
|
{
|
2014-05-23 07:26:57 +00:00
|
|
|
Genode::strncpy(pszPath, "/virtualbox", cchPath);
|
2013-08-21 09:37:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|