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 \
|
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
|
||||||
|
@ -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_ */
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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 **
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -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 \
|
||||||
|
@ -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 \
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
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);
|
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
|
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
|
||||||
|
@ -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); }
|
||||||
|
Loading…
Reference in New Issue
Block a user