From 450c8dc1493986e31d4a46d267bcb21f07e8b365 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 2 Apr 2019 17:41:30 +0200 Subject: [PATCH] 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 --- repos/base-foc/lib/mk/core-foc.inc | 2 + .../src/core/include/vm_session_component.h | 109 +++++++++------ .../base-foc/src/core/vm_session_component.cc | 95 ++++++++----- repos/base-foc/src/lib/base/x86/vm_session.cc | 20 ++- repos/base-hw/lib/mk/spec/arndale/core-hw.mk | 1 + .../lib/mk/spec/imx7d_sabre/core-hw.mk | 1 + .../virtualization/vm_session_component.cc | 40 ++++-- .../virtualization/vm_session_component.h | 18 ++- repos/base-nova/lib/mk/core-nova.inc | 2 + .../src/core/include/vm_session_component.h | 34 +++-- .../src/core/vm_session_component.cc | 127 +++++++++-------- repos/base-nova/src/lib/base/vm_session.cc | 16 ++- .../base-sel4/lib/mk/spec/x86_32/core-sel4.mk | 3 +- .../base-sel4/lib/mk/spec/x86_64/core-sel4.mk | 3 +- .../src/core/include/vm_session_component.h | 19 ++- .../src/core/spec/x86/vm_session_component.cc | 77 ++++++---- .../base-sel4/src/lib/base/x86/vm_session.cc | 17 ++- repos/base/include/vm_session/vm_session.h | 8 +- repos/base/lib/symbols/ld | 4 + repos/base/src/core/vm_session_common.cc | 132 ++++++++++++++++++ repos/base/src/lib/base/vm_session.cc | 3 + repos/os/run/vmm_x86.run | 2 +- repos/os/src/test/vmm_x86/component.cc | 39 ++++-- 23 files changed, 556 insertions(+), 216 deletions(-) create mode 100644 repos/base/src/core/vm_session_common.cc diff --git a/repos/base-foc/lib/mk/core-foc.inc b/repos/base-foc/lib/mk/core-foc.inc index 7c496c853c..a7854b1a02 100644 --- a/repos/base-foc/lib/mk/core-foc.inc +++ b/repos/base-foc/lib/mk/core-foc.inc @@ -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 diff --git a/repos/base-foc/src/core/include/vm_session_component.h b/repos/base-foc/src/core/include/vm_session_component.h index c6d1a927f8..abe2bab4f0 100644 --- a/repos/base-foc/src/core/include/vm_session_component.h +++ b/repos/base-foc/src/core/include/vm_session_component.h @@ -21,55 +21,12 @@ #include /* Core includes */ -#include #include +#include +#include namespace Genode { class Vm_session_component; struct Vcpu; } -class Genode::Vm_session_component -: - private Ram_quota_guard, - private Cap_quota_guard, - public Rpc_object -{ - private: - - Rpc_entrypoint &_ep; - Constrained_ram_allocator _constrained_md_ram_alloc; - Sliced_heap _sliced_heap; - List _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::Element { private: @@ -92,4 +49,66 @@ struct Genode::Vcpu : Genode::List::Element Cap_mapping &recall_cap() { return _recall; } }; +class Genode::Vm_session_component +: + private Ram_quota_guard, + private Cap_quota_guard, + public Rpc_object, + public Region_map_detach +{ + private: + + typedef Constrained_ram_allocator Con_ram_allocator; + typedef Allocator_avl_tpl 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 _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_ */ diff --git a/repos/base-foc/src/core/vm_session_component.cc b/repos/base-foc/src/core/vm_session_component.cc index 9f6346218c..afa4dfe8ca 100644 --- a/repos/base-foc/src/core/vm_session_component.cc +++ b/repos/base-foc/src/core/vm_session_component.cc @@ -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(); + } } diff --git a/repos/base-foc/src/lib/base/x86/vm_session.cc b/repos/base-foc/src/lib/base/x86/vm_session.cc index c1e39ebbd5..09e9b63704 100644 --- a/repos/base-foc/src/lib/base/x86/vm_session.cc +++ b/repos/base-foc/src/lib/base/x86/vm_session.cc @@ -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(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); + }); +} diff --git a/repos/base-hw/lib/mk/spec/arndale/core-hw.mk b/repos/base-hw/lib/mk/spec/arndale/core-hw.mk index 7ef450c088..0ba68ffb77 100644 --- a/repos/base-hw/lib/mk/spec/arndale/core-hw.mk +++ b/repos/base-hw/lib/mk/spec/arndale/core-hw.mk @@ -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 diff --git a/repos/base-hw/lib/mk/spec/imx7d_sabre/core-hw.mk b/repos/base-hw/lib/mk/spec/imx7d_sabre/core-hw.mk index 3d7c762f71..feeb6797ba 100644 --- a/repos/base-hw/lib/mk/spec/imx7d_sabre/core-hw.mk +++ b/repos/base-hw/lib/mk/spec/imx7d_sabre/core-hw.mk @@ -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 diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.cc index eaf1f660a9..1614d53923 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.cc @@ -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(_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); diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.h b/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.h index 28c11c5903..5144886ac7 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.h +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/vm_session_component.h @@ -16,6 +16,7 @@ /* Genode includes */ #include +#include #include #include #include @@ -23,6 +24,7 @@ /* Core includes */ #include +#include #include #include @@ -35,10 +37,13 @@ class Genode::Vm_session_component private Ram_quota_guard, private Cap_quota_guard, public Rpc_object, + public Region_map_detach, private Kernel_object { private: + typedef Allocator_avl_tpl 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; - 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 ** diff --git a/repos/base-nova/lib/mk/core-nova.inc b/repos/base-nova/lib/mk/core-nova.inc index b09b78242d..9df0b67e8f 100644 --- a/repos/base-nova/lib/mk/core-nova.inc +++ b/repos/base-nova/lib/mk/core-nova.inc @@ -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 diff --git a/repos/base-nova/src/core/include/vm_session_component.h b/repos/base-nova/src/core/include/vm_session_component.h index 791c01ef51..7f99a9a759 100644 --- a/repos/base-nova/src/core/include/vm_session_component.h +++ b/repos/base-nova/src/core/include/vm_session_component.h @@ -25,10 +25,14 @@ class Genode::Vm_session_component : private Ram_quota_guard, private Cap_quota_guard, - public Rpc_object + public Rpc_object, + public Region_map_detach { private: + typedef Constrained_ram_allocator Con_ram_allocator; + typedef Allocator_avl_tpl Avl_region; + class Vcpu : public List::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 _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); }; diff --git a/repos/base-nova/src/core/vm_session_component.cc b/repos/base-nova/src/core/vm_session_component.cc index 8a26e9cf95..efdbde44b4 100644 --- a/repos/base-nova/src/core/vm_session_component.cc +++ b/repos/base-nova/src/core/vm_session_component.cc @@ -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(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(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(); + } } diff --git a/repos/base-nova/src/lib/base/vm_session.cc b/repos/base-nova/src/lib/base/vm_session.cc index 730b6450e2..471b88f09f 100644 --- a/repos/base-nova/src/lib/base/vm_session.cc +++ b/repos/base-nova/src/lib/base/vm_session.cc @@ -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(&handler._rpc_ep); call(ep->cap()); - Vcpu * vcpu = new (alloc) Registered (vcpus, handler, vcpu_id++); + Vcpu * vcpu = new (alloc) Registered (vcpus, handler, vcpu_id++, alloc); vcpu->assign_ds_state(env.rm(), call(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); + }); +} diff --git a/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk b/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk index 05987a1d2d..732de2cbdf 100644 --- a/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk +++ b/repos/base-sel4/lib/mk/spec/x86_32/core-sel4.mk @@ -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 \ diff --git a/repos/base-sel4/lib/mk/spec/x86_64/core-sel4.mk b/repos/base-sel4/lib/mk/spec/x86_64/core-sel4.mk index 984ee4915d..a54a2b4684 100644 --- a/repos/base-sel4/lib/mk/spec/x86_64/core-sel4.mk +++ b/repos/base-sel4/lib/mk/spec/x86_64/core-sel4.mk @@ -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 \ diff --git a/repos/base-sel4/src/core/include/vm_session_component.h b/repos/base-sel4/src/core/include/vm_session_component.h index 4767b53081..e9bbdd25e7 100644 --- a/repos/base-sel4/src/core/include/vm_session_component.h +++ b/repos/base-sel4/src/core/include/vm_session_component.h @@ -25,7 +25,8 @@ class Genode::Vm_session_component : private Ram_quota_guard, private Cap_quota_guard, - public Rpc_object + public Rpc_object, + 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 Avl_region; + Rpc_entrypoint &_ep; Constrained_ram_allocator _constrained_md_ram_alloc; Sliced_heap _sliced_heap; + Heap _heap; + Avl_region _map { &_heap }; List _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); }; diff --git a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc index fc8d995e19..8f43183386 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc @@ -11,6 +11,9 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* base includes */ +#include + /* core includes */ #include #include @@ -18,6 +21,7 @@ #include #include + 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(); + } +} diff --git a/repos/base-sel4/src/lib/base/x86/vm_session.cc b/repos/base-sel4/src/lib/base/x86/vm_session.cc index 4af7009585..1b9e3f92c6 100644 --- a/repos/base-sel4/src/lib/base/x86/vm_session.cc +++ b/repos/base-sel4/src/lib/base/x86/vm_session.cc @@ -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 (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); + }); +} diff --git a/repos/base/include/vm_session/vm_session.h b/repos/base/include/vm_session/vm_session.h index 0306f4cde9..fd39db7db6 100644 --- a/repos/base/include/vm_session/vm_session.h +++ b/repos/base/include/vm_session/vm_session.h @@ -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, diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 08842a5098..2056de8336 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -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 diff --git a/repos/base/src/core/vm_session_common.cc b/repos/base/src/core/vm_session_common.cc new file mode 100644 index 0000000000..ec63b08018 --- /dev/null +++ b/repos/base/src/core/vm_session_common.cc @@ -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 + +/* Core includes */ +#include +#include +#include + +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::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(guest_phys)); + if (region && guest_phys == region->base() && region->size() <= size) { + /* inform dataspace */ + region->dataspace().detached_from(*region); + /* cleanup metadata */ + _map.free(reinterpret_cast(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); +} diff --git a/repos/base/src/lib/base/vm_session.cc b/repos/base/src/lib/base/vm_session.cc index ccd3c360a0..fe8be6307e 100644 --- a/repos/base/src/lib/base/vm_session.cc +++ b/repos/base/src/lib/base/vm_session.cc @@ -39,3 +39,6 @@ Dataspace_capability Vm_session_client::cpu_state(Vcpu_id const vcpu_id) { return call(vcpu_id); } + +Vm_session::~Vm_session() +{ } diff --git a/repos/os/run/vmm_x86.run b/repos/os/run/vmm_x86.run index 2927a0d74f..3bf6da60e8 100644 --- a/repos/os/run/vmm_x86.run +++ b/repos/os/run/vmm_x86.run @@ -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 diff --git a/repos/os/src/test/vmm_x86/component.cc b/repos/os/src/test/vmm_x86/component.cc index 1b3fc01558..1bfbd58db7 100644 --- a/repos/os/src/test/vmm_x86/component.cc +++ b/repos/os/src/test/vmm_x86/component.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -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 _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 _destruct_handler; + Genode::Reconstructible _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); }