base: refactor VM/vCPU API

Issue #3554
This commit is contained in:
Christian Helmuth
2020-12-18 14:08:06 +01:00
committed by Norman Feske
parent 6e8728f2d3
commit 219809ffed
67 changed files with 3120 additions and 3016 deletions

View File

@ -158,7 +158,8 @@ class Genode::Platform_thread : Interface
/**
* Make thread to vCPU
*/
Foc::l4_cap_idx_t setup_vcpu(unsigned, Cap_mapping const &, Cap_mapping &);
Foc::l4_cap_idx_t setup_vcpu(unsigned, Cap_mapping const &,
Cap_mapping &, Region_map::Local_addr &);
/************************

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
* Copyright (C) 2018-2021 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.
@ -15,8 +15,10 @@
#define _CORE__VM_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/registry.h>
#include <base/rpc_server.h>
#include <base/heap.h>
#include <util/bit_allocator.h>
#include <vm_session/vm_session.h>
/* core includes */
@ -24,30 +26,46 @@
#include <dataspace_component.h>
#include <region_map_component.h>
#include <trace/source_registry.h>
#include <foc_native_vcpu/foc_native_vcpu.h>
namespace Genode { class Vm_session_component; struct Vcpu; }
namespace Genode
{
class Vm_session_component;
struct Vcpu;
enum { MAX_VCPU_IDS = (Platform::VCPU_VIRT_EXT_END -
Platform::VCPU_VIRT_EXT_START) / L4_PAGESIZE };
typedef Bit_allocator<MAX_VCPU_IDS> Vcpu_id_allocator;
}
struct Genode::Vcpu : List<Vcpu>::Element
struct Genode::Vcpu : Rpc_object<Vm_session::Native_vcpu, Vcpu>
{
private:
Constrained_ram_allocator &_ram_alloc;
Cap_quota_guard &_cap_alloc;
Ram_dataspace_capability _ds_cap { };
Vm_session::Vcpu_id const _id;
Cap_mapping _recall { true };
Rpc_entrypoint &_ep;
Constrained_ram_allocator &_ram_alloc;
Cap_quota_guard &_cap_alloc;
Vcpu_id_allocator &_vcpu_ids;
Cap_mapping _recall { true };
Foc::l4_cap_idx_t _task_index_client { };
Region_map::Local_addr _foc_vcpu_state { };
public:
Vcpu(Constrained_ram_allocator &ram_alloc,
Cap_quota_guard &cap_alloc, Vm_session::Vcpu_id const id);
Vcpu(Rpc_entrypoint &, Constrained_ram_allocator &, Cap_quota_guard &,
Platform_thread &, Cap_mapping &, Vcpu_id_allocator &);
~Vcpu();
bool match(Vm_session::Vcpu_id const id) const { return id.id == _id.id; }
Dataspace_capability ds_cap() { return _ds_cap; }
Cap_mapping &recall_cap() { return _recall; }
/*******************************
** Native_vcpu RPC interface **
*******************************/
Foc::l4_cap_idx_t task_index() const { return _task_index_client; }
Region_map::Local_addr foc_vcpu_state() const { return _foc_vcpu_state; }
};
@ -60,17 +78,19 @@ class Genode::Vm_session_component
{
private:
typedef Constrained_ram_allocator Con_ram_allocator;
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 _heap;
Avl_region _map { &_heap };
List<Vcpu> _vcpus { };
Avl_region _map { &_heap };
Cap_mapping _task_vcpu { true };
unsigned _id_alloc { 0 };
Vcpu_id_allocator _vcpu_ids { };
Registry<Registered<Vcpu>> _vcpus { };
/* helpers for vm_session_common.cc */
void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr);
void _detach_vm_memory(addr_t, size_t);
@ -94,25 +114,20 @@ class Genode::Vm_session_component
** Region_map_detach interface **
*********************************/
void detach(Region_map::Local_addr) override;
void unmap_region(addr_t, size_t) override;
/* used on destruction of attached dataspaces */
void detach(Region_map::Local_addr) override; /* vm_session_common.cc */
void unmap_region(addr_t, size_t) override; /* vm_session_common.cc */
/**************************
** Vm session interface **
**************************/
Dataspace_capability _cpu_state(Vcpu_id);
Capability<Native_vcpu> create_vcpu(Thread_capability);
void attach_pic(addr_t) override { /* unused on Fiasco.OC */ }
void _exception_handler(Signal_context_capability, Vcpu_id) { }
void _run(Vcpu_id) { }
void _pause(Vcpu_id) { }
void attach(Dataspace_capability, addr_t, Attach_attr) override;
void attach_pic(addr_t) override { }
void detach(addr_t, size_t) override;
Vcpu_id _create_vcpu(Thread_capability);
Capability<Native_vcpu> _native_vcpu(Vcpu_id) {
return Capability<Native_vcpu>(); }
void attach(Dataspace_capability, addr_t, Attach_attr) override; /* vm_session_common.cc */
void detach(addr_t, size_t) override; /* vm_session_common.cc */
};
#endif /* _CORE__VM_SESSION_COMPONENT_H_ */

View File

@ -349,8 +349,9 @@ Platform_thread::~Platform_thread()
}
Foc::l4_cap_idx_t Platform_thread::setup_vcpu(unsigned const vcpu_id,
Cap_mapping const &task_vcpu,
Cap_mapping &vcpu_irq)
Cap_mapping const &task_vcpu,
Cap_mapping &vcpu_irq,
Region_map::Local_addr &vcpu_state)
{
if (!_platform_pd)
return Foc::L4_INVALID_CAP;
@ -358,8 +359,11 @@ Foc::l4_cap_idx_t Platform_thread::setup_vcpu(unsigned const vcpu_id,
if (vcpu_id >= (Platform::VCPU_VIRT_EXT_END - Platform::VCPU_VIRT_EXT_START) / L4_PAGESIZE)
return Foc::L4_INVALID_CAP;
addr_t const vcpu_addr = Platform::VCPU_VIRT_EXT_START + L4_PAGESIZE*vcpu_id;
l4_fpage_t const vm_page = l4_fpage( vcpu_addr, L4_PAGESHIFT, L4_FPAGE_RW);
/* vCPU state attached by kernel syscall to client PD directly */
vcpu_state = Region_map::Local_addr(Platform::VCPU_VIRT_EXT_START +
L4_PAGESIZE * vcpu_id);
l4_fpage_t const vm_page = l4_fpage(vcpu_state, L4_PAGESHIFT, L4_FPAGE_RW);
l4_msgtag_t msg = l4_task_add_ku_mem(_platform_pd->native_task().data()->kcap(), vm_page);
if (l4_error(msg)) {
@ -367,7 +371,7 @@ Foc::l4_cap_idx_t Platform_thread::setup_vcpu(unsigned const vcpu_id,
return Foc::L4_INVALID_CAP;
}
msg = l4_thread_vcpu_control_ext(_thread.local.data()->kcap(), vcpu_addr);
msg = l4_thread_vcpu_control_ext(_thread.local.data()->kcap(), vcpu_state);
if (l4_error(msg)) {
error("vcpu_control_exit failed ", l4_error(msg));
return Foc::L4_INVALID_CAP;

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
* Copyright (C) 2018-2021 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.
@ -26,6 +26,67 @@
using namespace Genode;
struct Vcpu_creation_error : Exception { };
Vcpu::Vcpu(Rpc_entrypoint &ep,
Constrained_ram_allocator &ram_alloc,
Cap_quota_guard &cap_alloc,
Platform_thread &thread,
Cap_mapping &task_cap,
Vcpu_id_allocator &vcpu_alloc)
:
_ep(ep),
_ram_alloc(ram_alloc),
_cap_alloc(cap_alloc),
_vcpu_ids(vcpu_alloc)
{
Foc::l4_msgtag_t msg = l4_factory_create_irq(Foc::L4_BASE_FACTORY_CAP,
_recall.local.data()->kcap());
if (l4_error(msg)) {
Genode::error("vcpu irq creation failed", l4_error(msg));
throw Vcpu_creation_error();
}
try {
unsigned const vcpu_id = _vcpu_ids.alloc();
_task_index_client = thread.setup_vcpu(vcpu_id, task_cap, recall_cap(),
_foc_vcpu_state);
if (_task_index_client == Foc::L4_INVALID_CAP) {
vcpu_alloc.free(vcpu_id);
if (l4_error(Foc::l4_irq_detach(_recall.local.data()->kcap())))
error("cannot detach IRQ");
throw Vcpu_creation_error();
}
} catch (Vcpu_id_allocator::Out_of_indices) {
throw Vcpu_creation_error();
}
_ep.manage(this);
}
Vcpu::~Vcpu()
{
_ep.dissolve(this);
if (_task_index_client != Foc::L4_INVALID_CAP) {
if (l4_error(Foc::l4_irq_detach(_recall.local.data()->kcap())))
error("cannot detach IRQ");
}
if (_foc_vcpu_state) {
unsigned const vcpu_id = ((addr_t)_foc_vcpu_state -
Platform::VCPU_VIRT_EXT_START) / L4_PAGESIZE;
_vcpu_ids.free(vcpu_id);
}
}
/**************************
** Vm_session_component **
**************************/
Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
Resources resources,
Label const &,
@ -41,7 +102,7 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
_constrained_md_ram_alloc(ram, _ram_quota_guard(), _cap_quota_guard()),
_heap(_constrained_md_ram_alloc, local_rm)
{
_cap_quota_guard().withdraw(Cap_quota{1});
Cap_quota_guard::Reservation caps(_cap_quota_guard(), Cap_quota{1});
using namespace Foc;
l4_msgtag_t msg = l4_factory_create_vm(L4_BASE_FACTORY_CAP,
@ -54,15 +115,15 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
/* configure managed VM area */
_map.add_range(0, 0UL - 0x1000);
_map.add_range(0UL - 0x1000, 0x1000);
caps.acknowledge();
}
Vm_session_component::~Vm_session_component()
{
for (;Vcpu * vcpu = _vcpus.first();) {
_vcpus.remove(vcpu);
destroy(_heap, vcpu);
}
_vcpus.for_each([&] (Vcpu &vcpu) {
destroy(_heap, &vcpu); });
/* detach all regions */
while (true) {
@ -76,97 +137,34 @@ Vm_session_component::~Vm_session_component()
}
Vcpu::Vcpu(Constrained_ram_allocator &ram_alloc,
Cap_quota_guard &cap_alloc,
Vm_session::Vcpu_id const id)
:
_ram_alloc(ram_alloc),
_cap_alloc(cap_alloc),
_id(id)
Capability<Vm_session::Native_vcpu> Vm_session_component::create_vcpu(Thread_capability cap)
{
try {
/* create ds for vCPU state */
_ds_cap = _ram_alloc.alloc(0x1000, Cache_attribute::CACHED);
} catch (...) {
throw;
}
Foc::l4_msgtag_t msg = l4_factory_create_irq(Foc::L4_BASE_FACTORY_CAP,
_recall.local.data()->kcap());
if (l4_error(msg)) {
_ram_alloc.free(_ds_cap);
Genode::error("vcpu irq creation failed", l4_error(msg));
throw 1;
}
}
Vcpu::~Vcpu()
{
if (_ds_cap.valid())
_ram_alloc.free(_ds_cap);
}
Vm_session::Vcpu_id Vm_session_component::_create_vcpu(Thread_capability cap)
{
Vcpu_id ret;
if (!cap.valid())
return ret;
return { };
auto lambda = [&] (Cpu_thread_component *thread) {
/* allocate vCPU object */
Vcpu * vcpu = nullptr;
_ep.apply(cap, [&] (Cpu_thread_component *thread) {
if (!thread)
return;
/* allocate vCPU object */
Vcpu * vcpu = nullptr;
try {
vcpu = new (_heap) Vcpu(_constrained_md_ram_alloc,
_cap_quota_guard(),
Vcpu_id {_id_alloc});
Foc::l4_cap_idx_t task =
thread->platform_thread().setup_vcpu(_id_alloc, _task_vcpu, vcpu->recall_cap());
if (task == Foc::L4_INVALID_CAP)
throw 0;
_ep.apply(vcpu->ds_cap(), [&] (Dataspace_component *ds) {
if (!ds)
throw 1;
/* tell client where to find task cap */
*reinterpret_cast<Foc::l4_cap_idx_t *>(ds->phys_addr()) = task;
});
} catch (int) {
if (vcpu)
destroy(_heap, vcpu);
vcpu = new (_heap) Registered<Vcpu>(_vcpus,
_ep,
_constrained_md_ram_alloc,
_cap_quota_guard(),
thread->platform_thread(),
_task_vcpu,
_vcpu_ids);
} catch (Vcpu_creation_error) {
return;
} catch (...) {
if (vcpu)
destroy(_heap, vcpu);
throw;
}
});
_vcpus.insert(vcpu);
ret.id = _id_alloc++;
};
_ep.apply(cap, lambda);
return ret;
return vcpu ? vcpu->cap() : Capability<Vm_session::Native_vcpu> {};
}
Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
{
for (Vcpu *vcpu = _vcpus.first(); vcpu; vcpu = vcpu->next()) {
if (!vcpu->match(vcpu_id))
continue;
return vcpu->ds_cap();
}
return Dataspace_capability();
}
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
@ -202,6 +200,7 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
}
}
void Vm_session_component::_detach_vm_memory(addr_t guest_phys, size_t size)
{
Flexpage_iterator flex(guest_phys, size, guest_phys, size, 0);