mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-23 01:08:55 +00:00
committed by
Norman Feske
parent
6e8728f2d3
commit
219809ffed
@ -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 &);
|
||||
|
||||
|
||||
/************************
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user