vm_session: track dataspaces used by attach

Track the dataspaces used by attach and add handling of flushing VM space
when dataspace gets destroyed (not triggered via the vm_session interface).

Issue #3111
This commit is contained in:
Alexander Boettcher 2019-04-02 17:41:30 +02:00 committed by Christian Helmuth
parent 169c51d50d
commit 450c8dc149
23 changed files with 556 additions and 216 deletions

View File

@ -39,6 +39,7 @@ SRC_CC += stack_area.cc \
thread_start.cc \ thread_start.cc \
trace_session_component.cc \ trace_session_component.cc \
vm_session_component.cc \ vm_session_component.cc \
vm_session_common.cc \
heartbeat.cc heartbeat.cc
INC_DIR += $(REP_DIR)/src/core/include \ INC_DIR += $(REP_DIR)/src/core/include \
@ -72,5 +73,6 @@ vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath core_region_map.cc $(GEN_CORE_DIR) vpath core_region_map.cc $(GEN_CORE_DIR)
vpath platform_rom_modules.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR)
vpath heartbeat.cc $(GEN_CORE_DIR) vpath heartbeat.cc $(GEN_CORE_DIR)
vpath vm_session_common.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core vpath %.cc $(REP_DIR)/src/core
vpath %.cc $(REP_DIR)/src/lib/base vpath %.cc $(REP_DIR)/src/lib/base

View File

@ -21,55 +21,12 @@
#include <vm_session/vm_session.h> #include <vm_session/vm_session.h>
/* Core includes */ /* Core includes */
#include <dataspace_component.h>
#include <cap_mapping.h> #include <cap_mapping.h>
#include <dataspace_component.h>
#include <region_map_component.h>
namespace Genode { class Vm_session_component; struct Vcpu; } namespace Genode { class Vm_session_component; struct Vcpu; }
class Genode::Vm_session_component
:
private Ram_quota_guard,
private Cap_quota_guard,
public Rpc_object<Vm_session, Vm_session_component>
{
private:
Rpc_entrypoint &_ep;
Constrained_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap;
List<Vcpu> _vcpus { };
Cap_mapping _task_vcpu { true };
unsigned _id_alloc { 0 };
protected:
Ram_quota_guard &_ram_quota_guard() { return *this; }
Cap_quota_guard &_cap_quota_guard() { return *this; }
public:
using Ram_quota_guard::upgrade;
using Cap_quota_guard::upgrade;
Vm_session_component(Rpc_entrypoint &, Resources, Label const &,
Diag, Ram_allocator &ram, Region_map &);
~Vm_session_component();
/**************************
** Vm session interface **
**************************/
Dataspace_capability _cpu_state(Vcpu_id);
void _exception_handler(Signal_context_capability, Vcpu_id) { }
void _run(Vcpu_id) { }
void _pause(Vcpu_id) { }
void attach(Dataspace_capability, addr_t) override;
void attach_pic(addr_t) override { }
void detach(addr_t, size_t) override { }
void _create_vcpu(Thread_capability);
};
struct Genode::Vcpu : Genode::List<Vcpu>::Element struct Genode::Vcpu : Genode::List<Vcpu>::Element
{ {
private: private:
@ -92,4 +49,66 @@ struct Genode::Vcpu : Genode::List<Vcpu>::Element
Cap_mapping &recall_cap() { return _recall; } Cap_mapping &recall_cap() { return _recall; }
}; };
class Genode::Vm_session_component
:
private Ram_quota_guard,
private Cap_quota_guard,
public Rpc_object<Vm_session, Vm_session_component>,
public Region_map_detach
{
private:
typedef Constrained_ram_allocator Con_ram_allocator;
typedef Allocator_avl_tpl<Rm_region> Avl_region;
Rpc_entrypoint &_ep;
Con_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap;
Slab _slab { max(sizeof(Vcpu), sizeof(Rm_region)),
4096 - Sliced_heap::meta_data_size(),
nullptr, &_sliced_heap };
Avl_region _map { &_slab };
List<Vcpu> _vcpus { };
Cap_mapping _task_vcpu { true };
unsigned _id_alloc { 0 };
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _detach_vm_memory(addr_t, size_t);
protected:
Ram_quota_guard &_ram_quota_guard() { return *this; }
Cap_quota_guard &_cap_quota_guard() { return *this; }
public:
using Ram_quota_guard::upgrade;
using Cap_quota_guard::upgrade;
Vm_session_component(Rpc_entrypoint &, Resources, Label const &,
Diag, Ram_allocator &ram, Region_map &);
~Vm_session_component();
/*********************************
** Region_map_detach interface **
*********************************/
void detach(Region_map::Local_addr) override;
void unmap_region(addr_t, size_t) override;
/**************************
** Vm session interface **
**************************/
Dataspace_capability _cpu_state(Vcpu_id);
void _exception_handler(Signal_context_capability, Vcpu_id) { }
void _run(Vcpu_id) { }
void _pause(Vcpu_id) { }
void attach(Dataspace_capability, addr_t) override;
void attach_pic(addr_t) override { }
void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability);
};
#endif /* _CORE__VM_SESSION_COMPONENT_H_ */ #endif /* _CORE__VM_SESSION_COMPONENT_H_ */

View File

@ -47,19 +47,30 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
l4_msgtag_t msg = l4_factory_create_vm(L4_BASE_FACTORY_CAP, l4_msgtag_t msg = l4_factory_create_vm(L4_BASE_FACTORY_CAP,
_task_vcpu.local.data()->kcap()); _task_vcpu.local.data()->kcap());
if (l4_error(msg)) { if (l4_error(msg)) {
_cap_quota_guard().replenish(Cap_quota{1});
Genode::error("create_vm failed ", l4_error(msg)); Genode::error("create_vm failed ", l4_error(msg));
throw 1; throw Service_denied();
} }
/* configure managed VM area */
_map.add_range(0, 0UL - 0x1000);
_map.add_range(0UL - 0x1000, 0x1000);
} }
Vm_session_component::~Vm_session_component() Vm_session_component::~Vm_session_component()
{ {
_cap_quota_guard().replenish(Cap_quota{1});
for (;Vcpu * vcpu = _vcpus.first();) { for (;Vcpu * vcpu = _vcpus.first();) {
_vcpus.remove(vcpu); _vcpus.remove(vcpu);
destroy(_sliced_heap, vcpu); destroy(_slab, vcpu);
}
/* detach all regions */
while (true) {
addr_t out_addr = 0;
if (!_map.any_block_addr(&out_addr))
break;
detach(out_addr);
} }
} }
@ -106,7 +117,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
/* allocate vCPU object */ /* allocate vCPU object */
Vcpu * vcpu = nullptr; Vcpu * vcpu = nullptr;
try { try {
vcpu = new (_sliced_heap) Vcpu(_constrained_md_ram_alloc, vcpu = new (_slab) Vcpu(_constrained_md_ram_alloc,
_cap_quota_guard(), _cap_quota_guard(),
Vcpu_id {_id_alloc}); Vcpu_id {_id_alloc});
@ -122,12 +133,12 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
}); });
} catch (int) { } catch (int) {
if (vcpu) if (vcpu)
destroy(_sliced_heap, vcpu); destroy(_slab, vcpu);
return; return;
} catch (...) { } catch (...) {
if (vcpu) if (vcpu)
destroy(_sliced_heap, vcpu); destroy(_slab, vcpu);
throw; throw;
} }
@ -151,41 +162,53 @@ Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
return Dataspace_capability(); return Dataspace_capability();
} }
void Vm_session_component::attach(Dataspace_capability cap, addr_t guest_phys) void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
bool const executable,
bool const writeable)
{ {
if (!cap.valid()) Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
throw Invalid_dataspace(); guest_phys, dsc.size(), guest_phys);
/* check dataspace validity */ using namespace Fiasco;
_ep.apply(cap, [&] (Dataspace_component *ptr) {
if (!ptr)
throw Invalid_dataspace();
Dataspace_component &dsc = *ptr; uint8_t flags = L4_FPAGE_RO;
if (dsc.writable() && writeable)
if (executable)
flags = L4_FPAGE_RWX;
else
flags = L4_FPAGE_RW;
else
if (executable)
flags = L4_FPAGE_RX;
/* unsupported - deny otherwise arbitrary physical memory can be mapped to a VM */ Flexpage page = flex.page();
if (dsc.managed()) while (page.valid()) {
throw Invalid_dataspace(); l4_fpage_t fp = l4_fpage(page.addr, page.log2_order, flags);
l4_msgtag_t msg = l4_task_map(_task_vcpu.local.data()->kcap(),
L4_BASE_TASK_CAP, fp,
l4_map_obj_control(page.hotspot,
L4_MAP_ITEM_MAP));
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(), if (l4_error(msg))
guest_phys, dsc.size(), guest_phys); Genode::error("task map failed ", l4_error(msg));
page = flex.page();
}
}
void Vm_session_component::_detach_vm_memory(addr_t guest_phys, size_t size)
{
Flexpage_iterator flex(guest_phys, size, guest_phys, size, 0);
Flexpage page = flex.page();
while (page.valid()) {
using namespace Fiasco; using namespace Fiasco;
uint8_t const flags = dsc.writable() ? L4_FPAGE_RWX : L4_FPAGE_RX; l4_task_unmap(_task_vcpu.local.data()->kcap(),
l4_fpage(page.addr, page.log2_order, L4_FPAGE_RWX),
L4_FP_ALL_SPACES);
Flexpage page = flex.page(); page = flex.page();
while (page.valid()) { }
l4_fpage_t fp = l4_fpage(page.addr, page.log2_order, flags);
l4_msgtag_t msg = l4_task_map(_task_vcpu.local.data()->kcap(),
L4_BASE_TASK_CAP, fp,
l4_map_obj_control(page.hotspot,
L4_MAP_ITEM_MAP));
if (l4_error(msg))
Genode::error("task map failed ", l4_error(msg));
page = flex.page();
}
});
} }

View File

@ -191,6 +191,7 @@ struct Vcpu : Genode::Thread
Signal_context_capability _signal; Signal_context_capability _signal;
Semaphore _wake_up { 0 }; Semaphore _wake_up { 0 };
Semaphore &_handler_ready; Semaphore &_handler_ready;
Allocator &_alloc;
Vm_session_client::Vcpu_id _id; Vm_session_client::Vcpu_id _id;
addr_t _state { 0 }; addr_t _state { 0 };
addr_t _task { 0 }; addr_t _task { 0 };
@ -1137,12 +1138,16 @@ struct Vcpu : Genode::Thread
Vcpu(Env &env, Signal_context_capability &cap, Vcpu(Env &env, Signal_context_capability &cap,
Semaphore &handler_ready, Semaphore &handler_ready,
Vm_session_client::Vcpu_id &id, enum Virt type) Vm_session_client::Vcpu_id &id, enum Virt type,
Allocator &alloc)
: :
Thread(env, "vcpu_thread", STACK_SIZE), _signal(cap), Thread(env, "vcpu_thread", STACK_SIZE), _signal(cap),
_handler_ready(handler_ready), _id(id), _vm_type(type) _handler_ready(handler_ready), _alloc(alloc),
_id(id), _vm_type(type)
{ } { }
Allocator &allocator() const { return _alloc; }
bool match(Vm_session_client::Vcpu_id id) { return id.id == _id.id; } bool match(Vm_session_client::Vcpu_id id) { return id.id == _id.id; }
Genode::Vm_session_client::Vcpu_id id() const { return _id; } Genode::Vm_session_client::Vcpu_id id() const { return _id; }
@ -1218,7 +1223,8 @@ Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
/* create thread that switches modes between thread/cpu */ /* create thread that switches modes between thread/cpu */
Vcpu * vcpu = new (alloc) Registered<Vcpu>(vcpus, env, handler._cap, Vcpu * vcpu = new (alloc) Registered<Vcpu>(vcpus, env, handler._cap,
handler._done, id, vm_type); handler._done, id, vm_type,
alloc);
try { try {
/* now it gets actually valid - vcpu->cap() becomes valid */ /* now it gets actually valid - vcpu->cap() becomes valid */
@ -1271,3 +1277,11 @@ Dataspace_capability Vm_session_client::cpu_state(Vcpu_id vcpu_id)
return cap; return cap;
} }
Vm_session::~Vm_session()
{
vcpus.for_each([&] (Vcpu &vc) {
Allocator &alloc = vc.allocator();
destroy(alloc, &vc);
});
}

View File

@ -15,6 +15,7 @@ SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
SRC_CC += spec/arm_v7/vm_session_component.cc SRC_CC += spec/arm_v7/vm_session_component.cc
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
SRC_CC += vm_session_common.cc
# add assembly sources # add assembly sources
SRC_S += spec/arm_v7/virtualization/exception_vector.s SRC_S += spec/arm_v7/virtualization/exception_vector.s

View File

@ -16,6 +16,7 @@ SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
SRC_CC += spec/arm_v7/vm_session_component.cc SRC_CC += spec/arm_v7/vm_session_component.cc
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
SRC_CC += vm_session_common.cc
# add assembly sources # add assembly sources
SRC_S += spec/arm_v7/virtualization/exception_vector.s SRC_S += spec/arm_v7/virtualization/exception_vector.s

View File

@ -53,18 +53,12 @@ void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size
} }
void Vm_session_component::attach(Dataspace_capability ds_cap, addr_t vm_addr) void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const vm_addr,
bool const /* executable */,
bool const /* writeable */)
{ {
/* check dataspace validity */ _attach(dsc.phys_addr(), vm_addr, dsc.size());
_ds_ep->apply(ds_cap, [&] (Dataspace_component *dsc) {
if (!dsc) throw Invalid_dataspace();
/* unsupported - deny otherwise arbitrary physical memory can be mapped to a VM */
if (dsc->managed())
throw Invalid_dataspace();
_attach(dsc->phys_addr(), vm_addr, dsc->size());
});
} }
@ -75,9 +69,10 @@ void Vm_session_component::attach_pic(addr_t vm_addr)
} }
void Vm_session_component::detach(addr_t vm_addr, size_t size) { void Vm_session_component::_detach_vm_memory(addr_t vm_addr, size_t size)
_table.remove_translation(vm_addr, size, _table_array.alloc()); } {
_table.remove_translation(vm_addr, size, _table_array.alloc());
}
void * Vm_session_component::_alloc_table() void * Vm_session_component::_alloc_table()
@ -102,8 +97,9 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
: :
Ram_quota_guard(resources.ram_quota), Ram_quota_guard(resources.ram_quota),
Cap_quota_guard(resources.cap_quota), Cap_quota_guard(resources.cap_quota),
_ds_ep(&ds_ep), _ep(ds_ep),
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()), _constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
_sliced_heap(_constrained_md_ram_alloc, region_map),
_region_map(region_map), _region_map(region_map),
_table(*construct_at<Table>(_alloc_table())), _table(*construct_at<Table>(_alloc_table())),
_table_array(*(new (cma()) Array([this] (void * virt) { _table_array(*(new (cma()) Array([this] (void * virt) {
@ -117,11 +113,25 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
_constrained_md_ram_alloc.free(_ds_cap); _constrained_md_ram_alloc.free(_ds_cap);
throw; throw;
} }
/* configure managed VM area */
_map.add_range(0, 0UL - 0x1000);
_map.add_range(0UL - 0x1000, 0x1000);
} }
Vm_session_component::~Vm_session_component() Vm_session_component::~Vm_session_component()
{ {
/* detach all regions */
while (true) {
addr_t out_addr = 0;
if (!_map.any_block_addr(&out_addr))
break;
detach(out_addr);
}
/* free region in allocator */ /* free region in allocator */
if (_ds_cap.valid()) { if (_ds_cap.valid()) {
_region_map.detach(_ds_addr); _region_map.detach(_ds_addr);

View File

@ -16,6 +16,7 @@
/* Genode includes */ /* Genode includes */
#include <base/allocator.h> #include <base/allocator.h>
#include <base/allocator_avl.h>
#include <base/session_object.h> #include <base/session_object.h>
#include <vm_session/vm_session.h> #include <vm_session/vm_session.h>
#include <dataspace/capability.h> #include <dataspace/capability.h>
@ -23,6 +24,7 @@
/* Core includes */ /* Core includes */
#include <object.h> #include <object.h>
#include <region_map_component.h>
#include <translation_table.h> #include <translation_table.h>
#include <kernel/vm.h> #include <kernel/vm.h>
@ -35,10 +37,13 @@ class Genode::Vm_session_component
private Ram_quota_guard, private Ram_quota_guard,
private Cap_quota_guard, private Cap_quota_guard,
public Rpc_object<Vm_session, Vm_session_component>, public Rpc_object<Vm_session, Vm_session_component>,
public Region_map_detach,
private Kernel_object<Kernel::Vm> private Kernel_object<Kernel::Vm>
{ {
private: private:
typedef Allocator_avl_tpl<Rm_region> Avl_region;
/* /*
* Noncopyable * Noncopyable
*/ */
@ -48,8 +53,10 @@ class Genode::Vm_session_component
using Table = Hw::Level_1_stage_2_translation_table; using Table = Hw::Level_1_stage_2_translation_table;
using Array = Table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>; using Array = Table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
Rpc_entrypoint *_ds_ep; Rpc_entrypoint &_ep;
Constrained_ram_allocator _constrained_md_ram_alloc; Constrained_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap;
Avl_region _map { &_sliced_heap };
Region_map &_region_map; Region_map &_region_map;
Ram_dataspace_capability _ds_cap { }; Ram_dataspace_capability _ds_cap { };
Region_map::Local_addr _ds_addr { 0 }; Region_map::Local_addr _ds_addr { 0 };
@ -64,6 +71,9 @@ class Genode::Vm_session_component
void * _alloc_table(); void * _alloc_table();
void _attach(addr_t phys_addr, addr_t vm_addr, size_t size); void _attach(addr_t phys_addr, addr_t vm_addr, size_t size);
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _detach_vm_memory(addr_t, size_t);
protected: protected:
Ram_quota_guard &_ram_quota_guard() { return *this; } Ram_quota_guard &_ram_quota_guard() { return *this; }
@ -79,6 +89,12 @@ class Genode::Vm_session_component
Diag, Ram_allocator &ram, Region_map &); Diag, Ram_allocator &ram, Region_map &);
~Vm_session_component(); ~Vm_session_component();
/*********************************
** Region_map_detach interface **
*********************************/
void detach(Region_map::Local_addr) override;
void unmap_region(addr_t, size_t) override;
/************************** /**************************
** Vm session interface ** ** Vm session interface **

View File

@ -42,6 +42,7 @@ SRC_CC += stack_area.cc \
signal_transmitter_noinit.cc \ signal_transmitter_noinit.cc \
signal_receiver.cc \ signal_receiver.cc \
vm_session_component.cc \ vm_session_component.cc \
vm_session_common.cc \
heartbeat.cc heartbeat.cc
INC_DIR = $(REP_DIR)/src/core/include \ INC_DIR = $(REP_DIR)/src/core/include \
@ -75,4 +76,5 @@ vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath platform_rom_modules.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR)
vpath heartbeat.cc $(GEN_CORE_DIR) vpath heartbeat.cc $(GEN_CORE_DIR)
vpath vm_session_common.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core vpath %.cc $(REP_DIR)/src/core

View File

@ -25,10 +25,14 @@ class Genode::Vm_session_component
: :
private Ram_quota_guard, private Ram_quota_guard,
private Cap_quota_guard, private Cap_quota_guard,
public Rpc_object<Vm_session, Vm_session_component> public Rpc_object<Vm_session, Vm_session_component>,
public Region_map_detach
{ {
private: private:
typedef Constrained_ram_allocator Con_ram_allocator;
typedef Allocator_avl_tpl<Rm_region> Avl_region;
class Vcpu : public List<Vcpu>::Element { class Vcpu : public List<Vcpu>::Element {
public: public:
@ -68,12 +72,16 @@ class Genode::Vm_session_component
static addr_t invalid() { return ~0UL; } static addr_t invalid() { return ~0UL; }
}; };
Rpc_entrypoint &_ep; Rpc_entrypoint &_ep;
Constrained_ram_allocator _constrained_md_ram_alloc; Con_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap; Sliced_heap _sliced_heap;
addr_t _pd_sel { 0 }; Slab _slab { max(sizeof(Vcpu), sizeof(Rm_region)),
unsigned _id_alloc { 0 }; 4096 - Sliced_heap::meta_data_size(),
unsigned _priority; nullptr, &_sliced_heap };
Avl_region _map { &_slab };
addr_t _pd_sel { 0 };
unsigned _id_alloc { 0 };
unsigned _priority;
List<Vcpu> _vcpus { }; List<Vcpu> _vcpus { };
@ -85,6 +93,9 @@ class Genode::Vm_session_component
return nullptr; return nullptr;
} }
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _detach_vm_memory(addr_t, size_t);
protected: protected:
Ram_quota_guard &_ram_quota_guard() { return *this; } Ram_quota_guard &_ram_quota_guard() { return *this; }
@ -99,6 +110,13 @@ class Genode::Vm_session_component
Diag, Ram_allocator &ram, Region_map &); Diag, Ram_allocator &ram, Region_map &);
~Vm_session_component(); ~Vm_session_component();
/*********************************
** Region_map_detach interface **
*********************************/
void detach(Region_map::Local_addr) override;
void unmap_region(addr_t, size_t) override;
/************************** /**************************
** Vm session interface ** ** Vm session interface **
**************************/ **************************/
@ -110,7 +128,7 @@ class Genode::Vm_session_component
void _pause(Vcpu_id) { } void _pause(Vcpu_id) { }
void attach(Dataspace_capability, addr_t) override; void attach(Dataspace_capability, addr_t) override;
void attach_pic(addr_t) override {} void attach_pic(addr_t) override {}
void detach(addr_t, size_t) override { } void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability); void _create_vcpu(Thread_capability);
}; };

View File

@ -150,9 +150,9 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
return; return;
/* allocate vCPU object */ /* allocate vCPU object */
Vcpu &vcpu = *new (_sliced_heap) Vcpu(_constrained_md_ram_alloc, Vcpu &vcpu = *new (_slab) Vcpu(_constrained_md_ram_alloc,
_cap_quota_guard(), _cap_quota_guard(),
Vcpu_id {_id_alloc}); Vcpu_id {_id_alloc});
/* we ran out of caps in core */ /* we ran out of caps in core */
if (!vcpu.ds_cap().valid()) if (!vcpu.ds_cap().valid())
@ -168,7 +168,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
if (res != Nova::NOVA_OK) { if (res != Nova::NOVA_OK) {
error("create_sm = ", res); error("create_sm = ", res);
destroy(_sliced_heap, &vcpu); destroy(_slab, &vcpu);
return; return;
} }
@ -181,7 +181,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
if (res != Nova::NOVA_OK) { if (res != Nova::NOVA_OK) {
error("create_ec = ", res); error("create_ec = ", res);
destroy(_sliced_heap, &vcpu); destroy(_slab, &vcpu);
return; return;
} }
@ -203,7 +203,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
if (res != Nova::NOVA_OK) if (res != Nova::NOVA_OK)
{ {
error("map sm ", res, " ", _id_alloc); error("map sm ", res, " ", _id_alloc);
destroy(_sliced_heap, &vcpu); destroy(_slab, &vcpu);
return; return;
} }
@ -288,10 +288,8 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
_cap_quota_guard().withdraw(Cap_quota{1}); _cap_quota_guard().withdraw(Cap_quota{1});
_pd_sel = cap_map().insert(); _pd_sel = cap_map().insert();
if (!_pd_sel || _pd_sel == Vcpu::invalid()) { if (!_pd_sel || _pd_sel == Vcpu::invalid())
_cap_quota_guard().replenish(Cap_quota{1});
throw Service_denied(); throw Service_denied();
}
addr_t const core_pd = platform_specific().core_pd_sel(); addr_t const core_pd = platform_specific().core_pd_sel();
enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 }; enum { KEEP_FREE_PAGES_NOT_AVAILABLE_FOR_UPGRADE = 2, UPPER_LIMIT_PAGES = 32 };
@ -301,70 +299,85 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
if (res != Nova::NOVA_OK) { if (res != Nova::NOVA_OK) {
error("create_pd = ", res); error("create_pd = ", res);
cap_map().remove(_pd_sel, 0, true); cap_map().remove(_pd_sel, 0, true);
_cap_quota_guard().replenish(Cap_quota{1});
throw Service_denied(); throw Service_denied();
} }
/* configure managed VM area */
_map.add_range(0, 0UL - 0x1000);
_map.add_range(0UL - 0x1000, 0x1000);
} }
Vm_session_component::~Vm_session_component() Vm_session_component::~Vm_session_component()
{ {
for (;Vcpu * vcpu = _vcpus.first();) { for (;Vcpu * vcpu = _vcpus.first();) {
_vcpus.remove(vcpu); _vcpus.remove(vcpu);
destroy(_sliced_heap, vcpu); destroy(_slab, vcpu);
} }
if (_pd_sel && _pd_sel != Vcpu::invalid()) { /* detach all regions */
while (true) {
addr_t out_addr = 0;
if (!_map.any_block_addr(&out_addr))
break;
detach(out_addr);
}
if (_pd_sel && _pd_sel != Vcpu::invalid())
cap_map().remove(_pd_sel, 0, true); cap_map().remove(_pd_sel, 0, true);
_cap_quota_guard().replenish(Cap_quota{1}); }
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
bool const executable,
bool const writeable)
{
using Nova::Utcb;
Utcb & utcb = *reinterpret_cast<Utcb *>(Thread::myself()->utcb());
addr_t const src_pd = platform_specific().core_pd_sel();
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
guest_phys, dsc.size(), guest_phys);
Flexpage page = flex.page();
while (page.valid()) {
Nova::Rights const map_rights (true, dsc.writable() && writeable,
executable);
Nova::Mem_crd const mem(page.addr >> 12, page.log2_order - 12,
map_rights);
utcb.set_msg_word(0);
/* ignore return value as one item always fits into the utcb */
bool const ok = utcb.append_item(mem, 0, true, true);
(void)ok;
/* receive window in destination pd */
Nova::Mem_crd crd_mem(page.hotspot >> 12, page.log2_order - 12,
map_rights);
/* asynchronously map memory */
uint8_t res = _with_kernel_quota_upgrade(_pd_sel, [&] {
return Nova::delegate(src_pd, _pd_sel, crd_mem); });
if (res != Nova::NOVA_OK)
error("could not map VM memory ", res);
page = flex.page();
} }
} }
void Vm_session_component::attach(Dataspace_capability cap, addr_t guest_phys) void Vm_session_component::_detach_vm_memory(addr_t guest_phys, size_t size)
{ {
if (!cap.valid()) Nova::Rights const revoke_rwx(true, true, true);
throw Invalid_dataspace();
/* check dataspace validity */ Flexpage_iterator flex(guest_phys, size, guest_phys, size, 0);
_ep.apply(cap, [&] (Dataspace_component *ptr) { Flexpage page = flex.page();
if (!ptr)
throw Invalid_dataspace();
Dataspace_component &dsc = *ptr; while (page.valid()) {
Nova::Mem_crd mem(page.addr >> 12, page.log2_order - 12, revoke_rwx);
Nova::revoke(mem, true, true, _pd_sel);
/* unsupported - deny otherwise arbitrary physical memory can be mapped to a VM */ page = flex.page();
if (dsc.managed()) }
throw Invalid_dataspace();
using Nova::Utcb;
Utcb & utcb = *reinterpret_cast<Utcb *>(Thread::myself()->utcb());
addr_t const src_pd = platform_specific().core_pd_sel();
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
guest_phys, dsc.size(), guest_phys);
Flexpage page = flex.page();
while (page.valid()) {
Nova::Rights const map_rights (true, dsc.writable(), true);
Nova::Mem_crd const mem(page.addr >> 12, page.log2_order - 12,
map_rights);
utcb.set_msg_word(0);
/* ignore return value as one item always fits into the utcb */
bool const ok = utcb.append_item(mem, 0, true, true);
(void)ok;
/* receive window in destination pd */
Nova::Mem_crd crd_mem(page.hotspot >> 12, page.log2_order - 12,
map_rights);
/* asynchronously map memory */
uint8_t res = _with_kernel_quota_upgrade(_pd_sel, [&] {
return Nova::delegate(src_pd, _pd_sel, crd_mem); });
if (res != Nova::NOVA_OK)
error("could not map VM memory ", res);
page = flex.page();
}
});
} }

View File

@ -36,6 +36,7 @@ struct Vcpu {
private: private:
Signal_dispatcher_base &_obj; Signal_dispatcher_base &_obj;
Allocator &_alloc;
Vm_session_client::Vcpu_id _id; Vm_session_client::Vcpu_id _id;
addr_t _state { 0 }; addr_t _state { 0 };
void *_ep_handler { nullptr }; void *_ep_handler { nullptr };
@ -412,10 +413,13 @@ struct Vcpu {
public: public:
Vcpu(Vm_handler_base &o, unsigned id) : _obj(o), _id({id}) { } Vcpu(Vm_handler_base &o, unsigned id, Allocator &alloc)
: _obj(o), _alloc(alloc), _id({id}) { }
virtual ~Vcpu() { } virtual ~Vcpu() { }
Allocator &allocator() { return _alloc; }
addr_t badge(uint16_t exit) const { addr_t badge(uint16_t exit) const {
return ((0UL + _id.id) << (sizeof(exit) * 8)) | exit; } return ((0UL + _id.id) << (sizeof(exit) * 8)) | exit; }
@ -684,7 +688,7 @@ Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
Thread * ep = reinterpret_cast<Thread *>(&handler._rpc_ep); Thread * ep = reinterpret_cast<Thread *>(&handler._rpc_ep);
call<Rpc_create_vcpu>(ep->cap()); call<Rpc_create_vcpu>(ep->cap());
Vcpu * vcpu = new (alloc) Registered<Vcpu> (vcpus, handler, vcpu_id++); Vcpu * vcpu = new (alloc) Registered<Vcpu> (vcpus, handler, vcpu_id++, alloc);
vcpu->assign_ds_state(env.rm(), call<Rpc_cpu_state>(vcpu->id())); vcpu->assign_ds_state(env.rm(), call<Rpc_cpu_state>(vcpu->id()));
Signal_context_capability dontcare_exit; Signal_context_capability dontcare_exit;
@ -744,3 +748,11 @@ Dataspace_capability Vm_session_client::cpu_state(Vcpu_id vcpu_id)
return cap; return cap;
} }
Vm_session::~Vm_session()
{
vcpus.for_each([&] (Vcpu &vc) {
Allocator &alloc = vc.allocator();
destroy(alloc, &vc);
});
}

View File

@ -1,5 +1,6 @@
GEN_SRC_CC = \ GEN_SRC_CC = \
spec/x86/io_port_session_component.cc spec/x86/io_port_session_component.cc \
vm_session_common.cc
REP_SRC_CC = \ REP_SRC_CC = \
spec/x86/io_port_session_support.cc \ spec/x86/io_port_session_support.cc \

View File

@ -1,5 +1,6 @@
GEN_SRC_CC = \ GEN_SRC_CC = \
spec/x86/io_port_session_component.cc spec/x86/io_port_session_component.cc \
vm_session_common.cc
REP_SRC_CC = \ REP_SRC_CC = \
spec/x86/io_port_session_support.cc \ spec/x86/io_port_session_support.cc \

View File

@ -25,7 +25,8 @@ class Genode::Vm_session_component
: :
private Ram_quota_guard, private Ram_quota_guard,
private Cap_quota_guard, private Cap_quota_guard,
public Rpc_object<Vm_session, Vm_session_component> public Rpc_object<Vm_session, Vm_session_component>,
public Region_map_detach
{ {
private: private:
@ -52,9 +53,13 @@ class Genode::Vm_session_component
Cap_sel notification_cap() const { return _notification; } Cap_sel notification_cap() const { return _notification; }
}; };
typedef Allocator_avl_tpl<Rm_region> Avl_region;
Rpc_entrypoint &_ep; Rpc_entrypoint &_ep;
Constrained_ram_allocator _constrained_md_ram_alloc; Constrained_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap; Sliced_heap _sliced_heap;
Heap _heap;
Avl_region _map { &_heap };
List<Vcpu> _vcpus { }; List<Vcpu> _vcpus { };
unsigned _id_alloc { 0 }; unsigned _id_alloc { 0 };
unsigned _pd_id { 0 }; unsigned _pd_id { 0 };
@ -78,6 +83,9 @@ class Genode::Vm_session_component
return nullptr; return nullptr;
} }
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _detach_vm_memory(addr_t, size_t);
protected: protected:
Ram_quota_guard &_ram_quota_guard() { return *this; } Ram_quota_guard &_ram_quota_guard() { return *this; }
@ -92,6 +100,13 @@ class Genode::Vm_session_component
Diag, Ram_allocator &ram, Region_map &); Diag, Ram_allocator &ram, Region_map &);
~Vm_session_component(); ~Vm_session_component();
/*********************************
** Region_map_detach interface **
*********************************/
void detach(Region_map::Local_addr) override;
void unmap_region(addr_t, size_t) override;
/************************** /**************************
** Vm session interface ** ** Vm session interface **
**************************/ **************************/
@ -103,7 +118,7 @@ class Genode::Vm_session_component
void _pause(Vcpu_id); void _pause(Vcpu_id);
void attach(Dataspace_capability, addr_t) override; void attach(Dataspace_capability, addr_t) override;
void attach_pic(addr_t) override {} void attach_pic(addr_t) override {}
void detach(addr_t, size_t) override {} void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability); void _create_vcpu(Thread_capability);
}; };

View File

@ -11,6 +11,9 @@
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
*/ */
/* base includes */
#include <util/flex_iterator.h>
/* core includes */ /* core includes */
#include <core_env.h> #include <core_env.h>
#include <vm_session_component.h> #include <vm_session_component.h>
@ -18,6 +21,7 @@
#include <cpu_thread_component.h> #include <cpu_thread_component.h>
#include <arch_kernel_object.h> #include <arch_kernel_object.h>
using namespace Genode; using namespace Genode;
void Vm_session_component::Vcpu::_free_up() void Vm_session_component::Vcpu::_free_up()
@ -73,6 +77,7 @@ try
_ep(ep), _ep(ep),
_constrained_md_ram_alloc(ram, _ram_quota_guard(), _cap_quota_guard()), _constrained_md_ram_alloc(ram, _ram_quota_guard(), _cap_quota_guard()),
_sliced_heap(_constrained_md_ram_alloc, local_rm), _sliced_heap(_constrained_md_ram_alloc, local_rm),
_heap(_constrained_md_ram_alloc, local_rm),
_pd_id(Platform_pd::pd_id_alloc().alloc()), _pd_id(Platform_pd::pd_id_alloc().alloc()),
_vm_page_table(platform_specific().core_sel_alloc().alloc()), _vm_page_table(platform_specific().core_sel_alloc().alloc()),
_vm_space(_vm_page_table, _vm_space(_vm_page_table,
@ -114,6 +119,10 @@ try
throw Service_denied(); throw Service_denied();
} }
/* configure managed VM area */
_map.add_range(0, 0UL - 0x1000);
_map.add_range(0UL - 0x1000, 0x1000);
caps.acknowledge(); caps.acknowledge();
ram.acknowledge(); ram.acknowledge();
} catch (...) { } catch (...) {
@ -145,7 +154,17 @@ Vm_session_component::~Vm_session_component()
{ {
for (;Vcpu * vcpu = _vcpus.first();) { for (;Vcpu * vcpu = _vcpus.first();) {
_vcpus.remove(vcpu); _vcpus.remove(vcpu);
destroy(_sliced_heap, vcpu); destroy(_heap, vcpu);
}
/* detach all regions */
while (true) {
addr_t out_addr = 0;
if (!_map.any_block_addr(&out_addr))
break;
detach(out_addr);
} }
if (_vm_page_table.value()) if (_vm_page_table.value())
@ -168,10 +187,10 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
Vcpu * vcpu = nullptr; Vcpu * vcpu = nullptr;
/* code to revert partial allocations in case of Out_of_ram/_quota */ /* code to revert partial allocations in case of Out_of_ram/_quota */
auto free_up = [&] () { if (vcpu) destroy(_sliced_heap, vcpu); }; auto free_up = [&] () { if (vcpu) destroy(_heap, vcpu); };
try { try {
vcpu = new (_sliced_heap) Vcpu(_constrained_md_ram_alloc, vcpu = new (_heap) Vcpu(_constrained_md_ram_alloc,
_cap_quota_guard(), _cap_quota_guard(),
Vcpu_id{_id_alloc}, Vcpu_id{_id_alloc},
_notifications._service); _notifications._service);
@ -211,32 +230,6 @@ Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
return vcpu->ds_cap(); return vcpu->ds_cap();
} }
void Vm_session_component::attach(Dataspace_capability cap, addr_t guest_phys)
{
if (!cap.valid())
throw Invalid_dataspace();
/* check dataspace validity */
_ep.apply(cap, [&] (Dataspace_component *ptr) {
if (!ptr)
throw Invalid_dataspace();
Dataspace_component &dsc = *ptr;
/* unsupported - deny otherwise arbitrary physical memory can be mapped to a VM */
if (dsc.managed())
throw Invalid_dataspace();
_vm_space.alloc_guest_page_tables(guest_phys, dsc.size());
enum { FLUSHABLE = true, EXECUTABLE = true };
_vm_space.map_guest(dsc.phys_addr(), guest_phys, dsc.size() >> 12,
dsc.cacheability(),
dsc.writable(), EXECUTABLE, FLUSHABLE);
});
}
void Vm_session_component::_pause(Vcpu_id const vcpu_id) void Vm_session_component::_pause(Vcpu_id const vcpu_id)
{ {
Vcpu * vcpu = _lookup(vcpu_id); Vcpu * vcpu = _lookup(vcpu_id);
@ -245,3 +238,29 @@ void Vm_session_component::_pause(Vcpu_id const vcpu_id)
vcpu->signal(); vcpu->signal();
} }
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
bool const executable,
bool const writeable)
{
_vm_space.alloc_guest_page_tables(guest_phys, dsc.size());
enum { FLUSHABLE = true };
_vm_space.map_guest(dsc.phys_addr(), guest_phys, dsc.size() >> 12,
dsc.cacheability(),
dsc.writable() && writeable,
executable, FLUSHABLE);
}
void Vm_session_component::_detach_vm_memory(addr_t guest_phys, size_t size)
{
Flexpage_iterator flex(guest_phys, size, guest_phys, size, 0);
Flexpage page = flex.page();
while (page.valid()) {
_vm_space.unmap(page.addr, (1 << page.log2_order) / 4096);
page = flex.page();
}
}

View File

@ -41,6 +41,7 @@ struct Vcpu : Genode::Thread
Signal_context_capability &_signal; Signal_context_capability &_signal;
Semaphore _wake_up { 0 }; Semaphore _wake_up { 0 };
Semaphore &_handler_ready; Semaphore &_handler_ready;
Allocator &_alloc;
Lock _startup { Genode::Lock::LOCKED }; Lock _startup { Genode::Lock::LOCKED };
Vm_session_client::Vcpu_id _id; Vm_session_client::Vcpu_id _id;
addr_t _state { 0 }; addr_t _state { 0 };
@ -740,12 +741,14 @@ struct Vcpu : Genode::Thread
public: public:
Vcpu(Genode::Env &env, Genode::Signal_context_capability &cap, Vcpu(Genode::Env &env, Genode::Signal_context_capability &cap,
Semaphore &handler_ready, unsigned id) Semaphore &handler_ready, unsigned id, Allocator &alloc)
: :
Thread(env, "vcpu_thread", STACK_SIZE), _signal(cap), Thread(env, "vcpu_thread", STACK_SIZE), _signal(cap),
_handler_ready(handler_ready), _id({id}) _handler_ready(handler_ready), _alloc(alloc), _id({id})
{ } { }
Allocator &allocator() { return _alloc; }
void start() override { void start() override {
Thread::start(); Thread::start();
_startup.lock(); _startup.lock();
@ -795,7 +798,7 @@ Genode::Vm_session_client::create_vcpu(Allocator &alloc, Env &env,
Vcpu * vcpu = new (alloc) Genode::Registered<Vcpu> (vcpus, env, Vcpu * vcpu = new (alloc) Genode::Registered<Vcpu> (vcpus, env,
handler._cap, handler._cap,
handler._done, handler._done,
vcpu_id); vcpu_id, alloc);
try { try {
/* now it gets actually valid - vcpu->cap() becomes valid */ /* now it gets actually valid - vcpu->cap() becomes valid */
@ -843,3 +846,11 @@ Genode::Dataspace_capability Genode::Vm_session_client::cpu_state(Vcpu_id vcpu_i
return cap; return cap;
} }
Vm_session::~Vm_session()
{
vcpus.for_each([&] (Vcpu &vc) {
Allocator &alloc = vc.allocator();
destroy(alloc, &vc);
});
}

View File

@ -32,11 +32,12 @@ struct Genode::Vm_session : Session
enum { CAP_QUOTA = 3 }; enum { CAP_QUOTA = 3 };
class Invalid_dataspace : Exception { }; class Invalid_dataspace : Exception { };
class Region_conflict : Exception { };
/** /**
* Destructor * Destructor
*/ */
virtual ~Vm_session() { } virtual ~Vm_session();
/** /**
* Attach dataspace to the guest-physical memory address space * Attach dataspace to the guest-physical memory address space
@ -75,8 +76,9 @@ struct Genode::Vm_session : Session
GENODE_RPC(Rpc_run, void, _run, Vcpu_id); GENODE_RPC(Rpc_run, void, _run, Vcpu_id);
GENODE_RPC(Rpc_pause, void, _pause, Vcpu_id); GENODE_RPC(Rpc_pause, void, _pause, Vcpu_id);
GENODE_RPC_THROW(Rpc_attach, void, attach, GENODE_RPC_THROW(Rpc_attach, void, attach,
GENODE_TYPE_LIST(Invalid_dataspace), GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Region_conflict,
Dataspace_capability, addr_t); Invalid_dataspace),
Dataspace_capability, addr_t);
GENODE_RPC(Rpc_detach, void, detach, addr_t, size_t); GENODE_RPC(Rpc_detach, void, detach, addr_t, size_t);
GENODE_RPC(Rpc_attach_pic, void, attach_pic, addr_t); GENODE_RPC(Rpc_attach_pic, void, attach_pic, addr_t);
GENODE_RPC_THROW(Rpc_create_vcpu, void, _create_vcpu, GENODE_RPC_THROW(Rpc_create_vcpu, void, _create_vcpu,

View File

@ -69,6 +69,8 @@ _ZN6Genode10Ipc_serverC1Ev T
_ZN6Genode10Ipc_serverC2Ev T _ZN6Genode10Ipc_serverC2Ev T
_ZN6Genode10Ipc_serverD1Ev T _ZN6Genode10Ipc_serverD1Ev T
_ZN6Genode10Ipc_serverD2Ev T _ZN6Genode10Ipc_serverD2Ev T
_ZN6Genode10Vm_sessionD0Ev T
_ZN6Genode10Vm_sessionD2Ev T
_ZN6Genode11Sliced_heap4freeEPvm T _ZN6Genode11Sliced_heap4freeEPvm T
_ZN6Genode11Sliced_heap5allocEmPPv T _ZN6Genode11Sliced_heap5allocEmPPv T
_ZN6Genode11Sliced_heapC1ERNS_13Ram_allocatorERNS_10Region_mapE T _ZN6Genode11Sliced_heapC1ERNS_13Ram_allocatorERNS_10Region_mapE T
@ -380,6 +382,7 @@ _ZTIN10__cxxabiv120__si_class_type_infoE D 24
_ZTIN10__cxxabiv121__vmi_class_type_infoE D 24 _ZTIN10__cxxabiv121__vmi_class_type_infoE D 24
_ZTIN10__cxxabiv123__fundamental_type_infoE D 24 _ZTIN10__cxxabiv123__fundamental_type_infoE D 24
_ZTIN5Timer10ConnectionE D 88 _ZTIN5Timer10ConnectionE D 88
_ZTIN6Genode10Vm_sessionE D 24
_ZTIN6Genode11Sliced_heapE D 24 _ZTIN6Genode11Sliced_heapE D 24
_ZTIN6Genode14Rpc_entrypointE D 56 _ZTIN6Genode14Rpc_entrypointE D 56
_ZTIN6Genode14Signal_contextE D 56 _ZTIN6Genode14Signal_contextE D 56
@ -537,6 +540,7 @@ _ZTVN10__cxxabiv120__si_class_type_infoE D 88
_ZTVN10__cxxabiv121__vmi_class_type_infoE D 88 _ZTVN10__cxxabiv121__vmi_class_type_infoE D 88
_ZTVN10__cxxabiv123__fundamental_type_infoE D 64 _ZTVN10__cxxabiv123__fundamental_type_infoE D 64
_ZTVN5Timer10ConnectionE D 320 _ZTVN5Timer10ConnectionE D 320
_ZTVN6Genode10Vm_sessionE D 56
_ZTVN6Genode11Sliced_heapE D 72 _ZTVN6Genode11Sliced_heapE D 72
_ZTVN6Genode14Rpc_entrypointE D 80 _ZTVN6Genode14Rpc_entrypointE D 80
_ZTVN6Genode14Signal_contextE D 32 _ZTVN6Genode14Signal_contextE D 32

View File

@ -0,0 +1,132 @@
/*
* \brief Core-specific instance of the VM session interface
* \author Alexander Boettcher
* \date 2018-08-26
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Base includes */
#include <util/flex_iterator.h>
/* Core includes */
#include <cpu_thread_component.h>
#include <dataspace_component.h>
#include <vm_session_component.h>
using Genode::addr_t;
using Genode::Vm_session_component;
void Vm_session_component::attach(Dataspace_capability const cap,
addr_t const guest_phys)
{
if (!cap.valid())
throw Invalid_dataspace();
/* check dataspace validity */
_ep.apply(cap, [&] (Dataspace_component *ptr) {
if (!ptr)
throw Invalid_dataspace();
Dataspace_component &dsc = *ptr;
/* unsupported - deny otherwise arbitrary physical memory can be mapped to a VM */
if (dsc.managed())
throw Invalid_dataspace();
bool const writeable = true;
bool const executable = true;
unsigned const offset = 0;
switch (_map.alloc_addr(dsc.size(), guest_phys).value) {
case Range_allocator::Alloc_return::OUT_OF_METADATA:
throw Out_of_ram();
case Range_allocator::Alloc_return::RANGE_CONFLICT:
{
Rm_region *region_ptr = _map.metadata((void *)guest_phys);
if (!region_ptr)
throw Region_conflict();
Rm_region &region = *region_ptr;
if (!(cap == region.dataspace().cap()))
throw Region_conflict();
if (guest_phys < region.base() ||
guest_phys > region.base() + region.size() - 1)
throw Region_conflict();
/* re-attach all */
break;
}
case Range_allocator::Alloc_return::OK:
{
/* store attachment info in meta data */
try {
_map.construct_metadata((void *)guest_phys,
guest_phys, dsc.size(),
dsc.writable() && writeable,
dsc, offset, *this, executable);
} catch (Allocator_avl_tpl<Rm_region>::Assign_metadata_failed) {
error("failed to store attachment info");
throw Invalid_dataspace();
}
Rm_region &region = *_map.metadata((void *)guest_phys);
/* inform dataspace about attachment */
dsc.attached_to(region);
break;
}
};
/* kernel specific code to attach memory to guest */
_attach_vm_memory(dsc, guest_phys, executable, writeable);
});
}
void Vm_session_component::detach(addr_t guest_phys, size_t size)
{
if (guest_phys & 0xffful) {
size += 0x1000 - (guest_phys & 0xffful);
guest_phys &= ~0xffful;
}
if (size & 0xffful)
size = align_addr(size, 12);
if (!size)
return;
{
Rm_region *region = _map.metadata(reinterpret_cast<void *>(guest_phys));
if (region && guest_phys == region->base() && region->size() <= size) {
/* inform dataspace */
region->dataspace().detached_from(*region);
/* cleanup metadata */
_map.free(reinterpret_cast<void *>(region->base()));
}
}
/* kernel specific code to detach memory from guest */
_detach_vm_memory(guest_phys, size);
}
void Vm_session_component::detach(Region_map::Local_addr addr)
{
Rm_region *region = _map.metadata(addr);
if (region)
detach(region->base(), region->size());
else
Genode::error(__PRETTY_FUNCTION__, " unknown region");
}
void Vm_session_component::unmap_region(addr_t base, size_t size)
{
Genode::error(__func__, " unimplemented ", base, " ", size);
}

View File

@ -39,3 +39,6 @@ Dataspace_capability Vm_session_client::cpu_state(Vcpu_id const vcpu_id)
{ {
return call<Rpc_cpu_state>(vcpu_id); return call<Rpc_cpu_state>(vcpu_id);
} }
Vm_session::~Vm_session()
{ }

View File

@ -140,7 +140,7 @@ unify_output "vcpu 3 : XX. vm exit - resume vcpu" ""
trim_lines trim_lines
set output_3 $output set output_3 $output
puts "comparing output ..." puts "\ncomparing output ..."
puts $output_0 puts $output_0
set output $output_0 set output $output_0

View File

@ -18,6 +18,7 @@
#include <base/heap.h> #include <base/heap.h>
#include <base/signal.h> #include <base/signal.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <util/reconstructible.h>
#include <vm_session/connection.h> #include <vm_session/connection.h>
#include <vm_session/vm_session.h> #include <vm_session/vm_session.h>
@ -198,8 +199,8 @@ class Vm {
enum { STACK_SIZE = 2*1024*sizeof(long) }; enum { STACK_SIZE = 2*1024*sizeof(long) };
Genode::Vm_connection _vm_con;
Genode::Heap _heap; Genode::Heap _heap;
Genode::Vm_connection _vm_con;
bool _svm; bool _svm;
bool _vmx; bool _vmx;
Genode::Entrypoint &_ep_first; /* running on first CPU */ Genode::Entrypoint &_ep_first; /* running on first CPU */
@ -214,6 +215,9 @@ class Vm {
Timer::Connection _timer; Timer::Connection _timer;
Genode::Signal_handler<Vm> _timer_handler; Genode::Signal_handler<Vm> _timer_handler;
/* trigger destruction of _vm session to test this case also */
Genode::Signal_context_capability _signal_destruction;
void _handle_timer(); void _handle_timer();
bool _cpu_name(char const * name) bool _cpu_name(char const * name)
@ -245,10 +249,10 @@ class Vm {
public: public:
Vm(Genode::Env &env) Vm(Genode::Env &env, Genode::Signal_context_capability destruct_cap)
: :
_vm_con(env),
_heap(env.ram(), env.rm()), _heap(env.ram(), env.rm()),
_vm_con(env),
_svm(_amd() && _vm_feature(env, "svm")), _svm(_amd() && _vm_feature(env, "svm")),
_vmx(_intel() && _vm_feature(env, "vmx")), _vmx(_intel() && _vm_feature(env, "vmx")),
_ep_first(env.ep()), _ep_first(env.ep()),
@ -260,7 +264,8 @@ class Vm {
_vcpu3(_ep_second, _vm_con, _heap, env, *this, _svm, _vmx), _vcpu3(_ep_second, _vm_con, _heap, env, *this, _svm, _vmx),
_memory(env.ram().alloc(4096)), _memory(env.ram().alloc(4096)),
_timer(env), _timer(env),
_timer_handler(_ep_first, *this, &Vm::_handle_timer) _timer_handler(_ep_first, *this, &Vm::_handle_timer),
_signal_destruction(destruct_cap)
{ {
if (!_svm && !_vmx) { if (!_svm && !_vmx) {
Genode::error("no SVM nor VMX support detected"); Genode::error("no SVM nor VMX support detected");
@ -384,7 +389,11 @@ void Vm::_handle_timer()
_vcpu1.skip_instruction(1*2 /* 1x jmp endless loop size */); _vcpu1.skip_instruction(1*2 /* 1x jmp endless loop size */);
_vm_con.run(_vcpu1.id()); _vm_con.run(_vcpu1.id());
} else if (_vcpu1.paused_4th()) { } else if (_vcpu1.paused_4th()) {
Genode::log("vmm test finished"); Genode::log("vcpu test finished - de-arm timer");
_timer.trigger_periodic(0);
/* trigger destruction of VM session */
Genode::Signal_transmitter(_signal_destruction).submit();
} }
} }
@ -479,18 +488,30 @@ void Vcpu::_handle_vm_exception()
_vm_con.run(_vcpu); _vm_con.run(_vcpu);
} }
class Vmm { class Vmm {
private: private:
Vm _vm; Genode::Signal_handler<Vmm> _destruct_handler;
Genode::Reconstructible<Vm> _vm;
void _destruct()
{
Genode::log("destruct vm session");
_vm.destruct();
Genode::log("vmm test finished");
}
public: public:
Vmm(Genode::Env &env) Vmm(Genode::Env &env)
: _vm(env) :
{ } _destruct_handler(env.ep(), *this, &Vmm::_destruct),
_vm(env, _destruct_handler)
{
}
}; };
void Component::construct(Genode::Env & env) { static Vmm vmm(env); } void Component::construct(Genode::Env & env) { static Vmm vmm(env); }