mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-21 03:55:04 +00:00
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:
parent
169c51d50d
commit
450c8dc149
@ -39,6 +39,7 @@ SRC_CC += stack_area.cc \
|
||||
thread_start.cc \
|
||||
trace_session_component.cc \
|
||||
vm_session_component.cc \
|
||||
vm_session_common.cc \
|
||||
heartbeat.cc
|
||||
|
||||
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 platform_rom_modules.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/lib/base
|
||||
|
@ -21,55 +21,12 @@
|
||||
#include <vm_session/vm_session.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <dataspace_component.h>
|
||||
#include <cap_mapping.h>
|
||||
#include <dataspace_component.h>
|
||||
#include <region_map_component.h>
|
||||
|
||||
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
|
||||
{
|
||||
private:
|
||||
@ -92,4 +49,66 @@ struct Genode::Vcpu : Genode::List<Vcpu>::Element
|
||||
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_ */
|
||||
|
@ -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,
|
||||
_task_vcpu.local.data()->kcap());
|
||||
if (l4_error(msg)) {
|
||||
_cap_quota_guard().replenish(Cap_quota{1});
|
||||
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()
|
||||
{
|
||||
_cap_quota_guard().replenish(Cap_quota{1});
|
||||
|
||||
for (;Vcpu * vcpu = _vcpus.first();) {
|
||||
_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 */
|
||||
Vcpu * vcpu = nullptr;
|
||||
try {
|
||||
vcpu = new (_sliced_heap) Vcpu(_constrained_md_ram_alloc,
|
||||
vcpu = new (_slab) Vcpu(_constrained_md_ram_alloc,
|
||||
_cap_quota_guard(),
|
||||
Vcpu_id {_id_alloc});
|
||||
|
||||
@ -122,12 +133,12 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||
});
|
||||
} catch (int) {
|
||||
if (vcpu)
|
||||
destroy(_sliced_heap, vcpu);
|
||||
destroy(_slab, vcpu);
|
||||
|
||||
return;
|
||||
} catch (...) {
|
||||
if (vcpu)
|
||||
destroy(_sliced_heap, vcpu);
|
||||
destroy(_slab, vcpu);
|
||||
|
||||
throw;
|
||||
}
|
||||
@ -151,41 +162,53 @@ Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
|
||||
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())
|
||||
throw Invalid_dataspace();
|
||||
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
|
||||
guest_phys, dsc.size(), guest_phys);
|
||||
|
||||
/* check dataspace validity */
|
||||
_ep.apply(cap, [&] (Dataspace_component *ptr) {
|
||||
if (!ptr)
|
||||
throw Invalid_dataspace();
|
||||
using namespace Fiasco;
|
||||
|
||||
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 */
|
||||
if (dsc.managed())
|
||||
throw Invalid_dataspace();
|
||||
Flexpage 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));
|
||||
|
||||
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
|
||||
guest_phys, dsc.size(), guest_phys);
|
||||
if (l4_error(msg))
|
||||
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;
|
||||
|
||||
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();
|
||||
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();
|
||||
}
|
||||
});
|
||||
page = flex.page();
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +191,7 @@ struct Vcpu : Genode::Thread
|
||||
Signal_context_capability _signal;
|
||||
Semaphore _wake_up { 0 };
|
||||
Semaphore &_handler_ready;
|
||||
Allocator &_alloc;
|
||||
Vm_session_client::Vcpu_id _id;
|
||||
addr_t _state { 0 };
|
||||
addr_t _task { 0 };
|
||||
@ -1137,12 +1138,16 @@ struct Vcpu : Genode::Thread
|
||||
|
||||
Vcpu(Env &env, Signal_context_capability &cap,
|
||||
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),
|
||||
_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; }
|
||||
|
||||
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 */
|
||||
Vcpu * vcpu = new (alloc) Registered<Vcpu>(vcpus, env, handler._cap,
|
||||
handler._done, id, vm_type);
|
||||
handler._done, id, vm_type,
|
||||
alloc);
|
||||
|
||||
try {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
Vm_session::~Vm_session()
|
||||
{
|
||||
vcpus.for_each([&] (Vcpu &vc) {
|
||||
Allocator &alloc = vc.allocator();
|
||||
destroy(alloc, &vc);
|
||||
});
|
||||
}
|
||||
|
@ -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/vm_session_component.cc
|
||||
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
|
||||
# add assembly sources
|
||||
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
||||
|
@ -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/vm_session_component.cc
|
||||
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
|
||||
# add assembly sources
|
||||
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
||||
|
@ -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 */
|
||||
_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());
|
||||
});
|
||||
_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) {
|
||||
_table.remove_translation(vm_addr, size, _table_array.alloc()); }
|
||||
|
||||
void Vm_session_component::_detach_vm_memory(addr_t vm_addr, size_t size)
|
||||
{
|
||||
_table.remove_translation(vm_addr, size, _table_array.alloc());
|
||||
}
|
||||
|
||||
|
||||
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),
|
||||
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()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Table>(_alloc_table())),
|
||||
_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);
|
||||
throw;
|
||||
}
|
||||
|
||||
/* configure managed VM area */
|
||||
_map.add_range(0, 0UL - 0x1000);
|
||||
_map.add_range(0UL - 0x1000, 0x1000);
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
if (_ds_cap.valid()) {
|
||||
_region_map.detach(_ds_addr);
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/session_object.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
#include <dataspace/capability.h>
|
||||
@ -23,6 +24,7 @@
|
||||
|
||||
/* Core includes */
|
||||
#include <object.h>
|
||||
#include <region_map_component.h>
|
||||
#include <translation_table.h>
|
||||
#include <kernel/vm.h>
|
||||
|
||||
@ -35,10 +37,13 @@ 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 Kernel_object<Kernel::Vm>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Allocator_avl_tpl<Rm_region> Avl_region;
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
@ -48,8 +53,10 @@ class Genode::Vm_session_component
|
||||
using Table = Hw::Level_1_stage_2_translation_table;
|
||||
using Array = Table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
|
||||
Rpc_entrypoint *_ds_ep;
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_md_ram_alloc;
|
||||
Sliced_heap _sliced_heap;
|
||||
Avl_region _map { &_sliced_heap };
|
||||
Region_map &_region_map;
|
||||
Ram_dataspace_capability _ds_cap { };
|
||||
Region_map::Local_addr _ds_addr { 0 };
|
||||
@ -64,6 +71,9 @@ class Genode::Vm_session_component
|
||||
void * _alloc_table();
|
||||
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:
|
||||
|
||||
Ram_quota_guard &_ram_quota_guard() { return *this; }
|
||||
@ -79,6 +89,12 @@ class Genode::Vm_session_component
|
||||
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 **
|
||||
|
@ -42,6 +42,7 @@ SRC_CC += stack_area.cc \
|
||||
signal_transmitter_noinit.cc \
|
||||
signal_receiver.cc \
|
||||
vm_session_component.cc \
|
||||
vm_session_common.cc \
|
||||
heartbeat.cc
|
||||
|
||||
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 stack_area.cc $(GEN_CORE_DIR)
|
||||
vpath heartbeat.cc $(GEN_CORE_DIR)
|
||||
vpath vm_session_common.cc $(GEN_CORE_DIR)
|
||||
vpath %.cc $(REP_DIR)/src/core
|
||||
|
@ -25,10 +25,14 @@ class Genode::Vm_session_component
|
||||
:
|
||||
private Ram_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:
|
||||
|
||||
typedef Constrained_ram_allocator Con_ram_allocator;
|
||||
typedef Allocator_avl_tpl<Rm_region> Avl_region;
|
||||
|
||||
class Vcpu : public List<Vcpu>::Element {
|
||||
|
||||
public:
|
||||
@ -68,12 +72,16 @@ class Genode::Vm_session_component
|
||||
static addr_t invalid() { return ~0UL; }
|
||||
};
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_md_ram_alloc;
|
||||
Sliced_heap _sliced_heap;
|
||||
addr_t _pd_sel { 0 };
|
||||
unsigned _id_alloc { 0 };
|
||||
unsigned _priority;
|
||||
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 };
|
||||
addr_t _pd_sel { 0 };
|
||||
unsigned _id_alloc { 0 };
|
||||
unsigned _priority;
|
||||
|
||||
List<Vcpu> _vcpus { };
|
||||
|
||||
@ -85,6 +93,9 @@ class Genode::Vm_session_component
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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; }
|
||||
@ -99,6 +110,13 @@ class Genode::Vm_session_component
|
||||
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 **
|
||||
**************************/
|
||||
@ -110,7 +128,7 @@ class Genode::Vm_session_component
|
||||
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 detach(addr_t, size_t) override;
|
||||
void _create_vcpu(Thread_capability);
|
||||
};
|
||||
|
||||
|
@ -150,9 +150,9 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||
return;
|
||||
|
||||
/* allocate vCPU object */
|
||||
Vcpu &vcpu = *new (_sliced_heap) Vcpu(_constrained_md_ram_alloc,
|
||||
_cap_quota_guard(),
|
||||
Vcpu_id {_id_alloc});
|
||||
Vcpu &vcpu = *new (_slab) Vcpu(_constrained_md_ram_alloc,
|
||||
_cap_quota_guard(),
|
||||
Vcpu_id {_id_alloc});
|
||||
|
||||
/* we ran out of caps in core */
|
||||
if (!vcpu.ds_cap().valid())
|
||||
@ -168,7 +168,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||
|
||||
if (res != Nova::NOVA_OK) {
|
||||
error("create_sm = ", res);
|
||||
destroy(_sliced_heap, &vcpu);
|
||||
destroy(_slab, &vcpu);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||
|
||||
if (res != Nova::NOVA_OK) {
|
||||
error("create_ec = ", res);
|
||||
destroy(_sliced_heap, &vcpu);
|
||||
destroy(_slab, &vcpu);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -203,7 +203,7 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||
if (res != Nova::NOVA_OK)
|
||||
{
|
||||
error("map sm ", res, " ", _id_alloc);
|
||||
destroy(_sliced_heap, &vcpu);
|
||||
destroy(_slab, &vcpu);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -288,10 +288,8 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
|
||||
_cap_quota_guard().withdraw(Cap_quota{1});
|
||||
|
||||
_pd_sel = cap_map().insert();
|
||||
if (!_pd_sel || _pd_sel == Vcpu::invalid()) {
|
||||
_cap_quota_guard().replenish(Cap_quota{1});
|
||||
if (!_pd_sel || _pd_sel == Vcpu::invalid())
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
addr_t const core_pd = platform_specific().core_pd_sel();
|
||||
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) {
|
||||
error("create_pd = ", res);
|
||||
cap_map().remove(_pd_sel, 0, true);
|
||||
_cap_quota_guard().replenish(Cap_quota{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()
|
||||
{
|
||||
for (;Vcpu * vcpu = _vcpus.first();) {
|
||||
_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_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())
|
||||
throw Invalid_dataspace();
|
||||
Nova::Rights const revoke_rwx(true, true, true);
|
||||
|
||||
/* check dataspace validity */
|
||||
_ep.apply(cap, [&] (Dataspace_component *ptr) {
|
||||
if (!ptr)
|
||||
throw Invalid_dataspace();
|
||||
Flexpage_iterator flex(guest_phys, size, guest_phys, size, 0);
|
||||
Flexpage page = flex.page();
|
||||
|
||||
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 */
|
||||
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();
|
||||
}
|
||||
});
|
||||
page = flex.page();
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ struct Vcpu {
|
||||
private:
|
||||
|
||||
Signal_dispatcher_base &_obj;
|
||||
Allocator &_alloc;
|
||||
Vm_session_client::Vcpu_id _id;
|
||||
addr_t _state { 0 };
|
||||
void *_ep_handler { nullptr };
|
||||
@ -412,10 +413,13 @@ struct Vcpu {
|
||||
|
||||
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() { }
|
||||
|
||||
Allocator &allocator() { return _alloc; }
|
||||
|
||||
addr_t badge(uint16_t exit) const {
|
||||
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);
|
||||
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()));
|
||||
|
||||
Signal_context_capability dontcare_exit;
|
||||
@ -744,3 +748,11 @@ Dataspace_capability Vm_session_client::cpu_state(Vcpu_id vcpu_id)
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
Vm_session::~Vm_session()
|
||||
{
|
||||
vcpus.for_each([&] (Vcpu &vc) {
|
||||
Allocator &alloc = vc.allocator();
|
||||
destroy(alloc, &vc);
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
GEN_SRC_CC = \
|
||||
spec/x86/io_port_session_component.cc
|
||||
spec/x86/io_port_session_component.cc \
|
||||
vm_session_common.cc
|
||||
|
||||
REP_SRC_CC = \
|
||||
spec/x86/io_port_session_support.cc \
|
||||
|
@ -1,5 +1,6 @@
|
||||
GEN_SRC_CC = \
|
||||
spec/x86/io_port_session_component.cc
|
||||
spec/x86/io_port_session_component.cc \
|
||||
vm_session_common.cc
|
||||
|
||||
REP_SRC_CC = \
|
||||
spec/x86/io_port_session_support.cc \
|
||||
|
@ -25,7 +25,8 @@ class Genode::Vm_session_component
|
||||
:
|
||||
private Ram_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:
|
||||
|
||||
@ -52,9 +53,13 @@ class Genode::Vm_session_component
|
||||
Cap_sel notification_cap() const { return _notification; }
|
||||
};
|
||||
|
||||
typedef Allocator_avl_tpl<Rm_region> Avl_region;
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_md_ram_alloc;
|
||||
Sliced_heap _sliced_heap;
|
||||
Heap _heap;
|
||||
Avl_region _map { &_heap };
|
||||
List<Vcpu> _vcpus { };
|
||||
unsigned _id_alloc { 0 };
|
||||
unsigned _pd_id { 0 };
|
||||
@ -78,6 +83,9 @@ class Genode::Vm_session_component
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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; }
|
||||
@ -92,6 +100,13 @@ class Genode::Vm_session_component
|
||||
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 **
|
||||
**************************/
|
||||
@ -103,7 +118,7 @@ class Genode::Vm_session_component
|
||||
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 detach(addr_t, size_t) override;
|
||||
void _create_vcpu(Thread_capability);
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,9 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* base includes */
|
||||
#include <util/flex_iterator.h>
|
||||
|
||||
/* core includes */
|
||||
#include <core_env.h>
|
||||
#include <vm_session_component.h>
|
||||
@ -18,6 +21,7 @@
|
||||
#include <cpu_thread_component.h>
|
||||
#include <arch_kernel_object.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
void Vm_session_component::Vcpu::_free_up()
|
||||
@ -73,6 +77,7 @@ try
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, local_rm),
|
||||
_heap(_constrained_md_ram_alloc, local_rm),
|
||||
_pd_id(Platform_pd::pd_id_alloc().alloc()),
|
||||
_vm_page_table(platform_specific().core_sel_alloc().alloc()),
|
||||
_vm_space(_vm_page_table,
|
||||
@ -114,6 +119,10 @@ try
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
/* configure managed VM area */
|
||||
_map.add_range(0, 0UL - 0x1000);
|
||||
_map.add_range(0UL - 0x1000, 0x1000);
|
||||
|
||||
caps.acknowledge();
|
||||
ram.acknowledge();
|
||||
} catch (...) {
|
||||
@ -145,7 +154,17 @@ Vm_session_component::~Vm_session_component()
|
||||
{
|
||||
for (;Vcpu * vcpu = _vcpus.first();) {
|
||||
_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())
|
||||
@ -168,10 +187,10 @@ void Vm_session_component::_create_vcpu(Thread_capability cap)
|
||||
Vcpu * vcpu = nullptr;
|
||||
|
||||
/* 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 {
|
||||
vcpu = new (_sliced_heap) Vcpu(_constrained_md_ram_alloc,
|
||||
vcpu = new (_heap) Vcpu(_constrained_md_ram_alloc,
|
||||
_cap_quota_guard(),
|
||||
Vcpu_id{_id_alloc},
|
||||
_notifications._service);
|
||||
@ -211,32 +230,6 @@ Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
|
||||
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)
|
||||
{
|
||||
Vcpu * vcpu = _lookup(vcpu_id);
|
||||
@ -245,3 +238,29 @@ void Vm_session_component::_pause(Vcpu_id const vcpu_id)
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ struct Vcpu : Genode::Thread
|
||||
Signal_context_capability &_signal;
|
||||
Semaphore _wake_up { 0 };
|
||||
Semaphore &_handler_ready;
|
||||
Allocator &_alloc;
|
||||
Lock _startup { Genode::Lock::LOCKED };
|
||||
Vm_session_client::Vcpu_id _id;
|
||||
addr_t _state { 0 };
|
||||
@ -740,12 +741,14 @@ struct Vcpu : Genode::Thread
|
||||
public:
|
||||
|
||||
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),
|
||||
_handler_ready(handler_ready), _id({id})
|
||||
_handler_ready(handler_ready), _alloc(alloc), _id({id})
|
||||
{ }
|
||||
|
||||
Allocator &allocator() { return _alloc; }
|
||||
|
||||
void start() override {
|
||||
Thread::start();
|
||||
_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,
|
||||
handler._cap,
|
||||
handler._done,
|
||||
vcpu_id);
|
||||
vcpu_id, alloc);
|
||||
|
||||
try {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
Vm_session::~Vm_session()
|
||||
{
|
||||
vcpus.for_each([&] (Vcpu &vc) {
|
||||
Allocator &alloc = vc.allocator();
|
||||
destroy(alloc, &vc);
|
||||
});
|
||||
}
|
||||
|
@ -32,11 +32,12 @@ struct Genode::Vm_session : Session
|
||||
enum { CAP_QUOTA = 3 };
|
||||
|
||||
class Invalid_dataspace : Exception { };
|
||||
class Region_conflict : Exception { };
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Vm_session() { }
|
||||
virtual ~Vm_session();
|
||||
|
||||
/**
|
||||
* 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_pause, void, _pause, Vcpu_id);
|
||||
GENODE_RPC_THROW(Rpc_attach, void, attach,
|
||||
GENODE_TYPE_LIST(Invalid_dataspace),
|
||||
Dataspace_capability, addr_t);
|
||||
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Region_conflict,
|
||||
Invalid_dataspace),
|
||||
Dataspace_capability, addr_t);
|
||||
GENODE_RPC(Rpc_detach, void, detach, addr_t, size_t);
|
||||
GENODE_RPC(Rpc_attach_pic, void, attach_pic, addr_t);
|
||||
GENODE_RPC_THROW(Rpc_create_vcpu, void, _create_vcpu,
|
||||
|
@ -69,6 +69,8 @@ _ZN6Genode10Ipc_serverC1Ev T
|
||||
_ZN6Genode10Ipc_serverC2Ev T
|
||||
_ZN6Genode10Ipc_serverD1Ev T
|
||||
_ZN6Genode10Ipc_serverD2Ev T
|
||||
_ZN6Genode10Vm_sessionD0Ev T
|
||||
_ZN6Genode10Vm_sessionD2Ev T
|
||||
_ZN6Genode11Sliced_heap4freeEPvm T
|
||||
_ZN6Genode11Sliced_heap5allocEmPPv 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__cxxabiv123__fundamental_type_infoE D 24
|
||||
_ZTIN5Timer10ConnectionE D 88
|
||||
_ZTIN6Genode10Vm_sessionE D 24
|
||||
_ZTIN6Genode11Sliced_heapE D 24
|
||||
_ZTIN6Genode14Rpc_entrypointE 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__cxxabiv123__fundamental_type_infoE D 64
|
||||
_ZTVN5Timer10ConnectionE D 320
|
||||
_ZTVN6Genode10Vm_sessionE D 56
|
||||
_ZTVN6Genode11Sliced_heapE D 72
|
||||
_ZTVN6Genode14Rpc_entrypointE D 80
|
||||
_ZTVN6Genode14Signal_contextE D 32
|
||||
|
132
repos/base/src/core/vm_session_common.cc
Normal file
132
repos/base/src/core/vm_session_common.cc
Normal 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 ®ion = *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 ®ion = *_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);
|
||||
}
|
@ -39,3 +39,6 @@ Dataspace_capability Vm_session_client::cpu_state(Vcpu_id const vcpu_id)
|
||||
{
|
||||
return call<Rpc_cpu_state>(vcpu_id);
|
||||
}
|
||||
|
||||
Vm_session::~Vm_session()
|
||||
{ }
|
||||
|
@ -140,7 +140,7 @@ unify_output "vcpu 3 : XX. vm exit - resume vcpu" ""
|
||||
trim_lines
|
||||
set output_3 $output
|
||||
|
||||
puts "comparing output ..."
|
||||
puts "\ncomparing output ..."
|
||||
|
||||
puts $output_0
|
||||
set output $output_0
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <base/heap.h>
|
||||
#include <base/signal.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <util/reconstructible.h>
|
||||
#include <vm_session/connection.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
|
||||
@ -198,8 +199,8 @@ class Vm {
|
||||
|
||||
enum { STACK_SIZE = 2*1024*sizeof(long) };
|
||||
|
||||
Genode::Vm_connection _vm_con;
|
||||
Genode::Heap _heap;
|
||||
Genode::Vm_connection _vm_con;
|
||||
bool _svm;
|
||||
bool _vmx;
|
||||
Genode::Entrypoint &_ep_first; /* running on first CPU */
|
||||
@ -214,6 +215,9 @@ class Vm {
|
||||
Timer::Connection _timer;
|
||||
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();
|
||||
|
||||
bool _cpu_name(char const * name)
|
||||
@ -245,10 +249,10 @@ class Vm {
|
||||
|
||||
public:
|
||||
|
||||
Vm(Genode::Env &env)
|
||||
Vm(Genode::Env &env, Genode::Signal_context_capability destruct_cap)
|
||||
:
|
||||
_vm_con(env),
|
||||
_heap(env.ram(), env.rm()),
|
||||
_vm_con(env),
|
||||
_svm(_amd() && _vm_feature(env, "svm")),
|
||||
_vmx(_intel() && _vm_feature(env, "vmx")),
|
||||
_ep_first(env.ep()),
|
||||
@ -260,7 +264,8 @@ class Vm {
|
||||
_vcpu3(_ep_second, _vm_con, _heap, env, *this, _svm, _vmx),
|
||||
_memory(env.ram().alloc(4096)),
|
||||
_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) {
|
||||
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 */);
|
||||
_vm_con.run(_vcpu1.id());
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
||||
class Vmm {
|
||||
|
||||
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:
|
||||
|
||||
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); }
|
||||
|
Loading…
Reference in New Issue
Block a user