mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-11 21:45:37 +00:00
hw: x86_64: refactor Vm_session_component
On x86, the `Vm_session_component` obscured the differences between SVM and VMX. Separate the implementations, factor out common functionality and address a number of long-standing issues in the process: - Allocate nested page tables from Core_ram_allocator as a more suitable abstraction and account for the required memory, subtract the necessary amount of RAM from the session's `Ram_quota` *before* constructing the session object, to make sure that the memory allocated from the `Core_ram_allocator` is available from the VMM's RAM quota. - Move the allocation of Vcpu_state and Vcpu_data into the Core::Vcpu class and use the Core RAM Allocator to allocate memory with a known physical address. - Remove the fixed number of virtual CPUs and the associated reservation of memory by using a Registry for a flexible amount of vCPUs. Issue #5221
This commit is contained in:
parent
922fdd1628
commit
05522696c7
@ -22,9 +22,6 @@ SRC_CC += kernel/vm_thread_on.cc
|
||||
SRC_CC += spec/x86_64/virtualization/kernel/vm.cc
|
||||
SRC_CC += spec/x86_64/virtualization/kernel/svm.cc
|
||||
SRC_CC += spec/x86_64/virtualization/kernel/vmx.cc
|
||||
SRC_CC += spec/x86_64/virtualization/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
SRC_CC += kernel/lock.cc
|
||||
SRC_CC += spec/x86_64/pic.cc
|
||||
SRC_CC += spec/x86_64/pit.cc
|
||||
|
275
repos/base-hw/src/core/guest_memory.h
Normal file
275
repos/base-hw/src/core/guest_memory.h
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* \brief Guest memory abstraction
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2024-11-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__GUEST_MEMORY_H_
|
||||
#define _CORE__GUEST_MEMORY_H_
|
||||
|
||||
/* base includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/allocator_avl.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
#include <dataspace/capability.h>
|
||||
|
||||
/* core includes */
|
||||
#include <dataspace_component.h>
|
||||
#include <region_map_component.h>
|
||||
|
||||
namespace Core { class Guest_memory; }
|
||||
|
||||
using namespace Core;
|
||||
|
||||
|
||||
class Core::Guest_memory
|
||||
{
|
||||
private:
|
||||
|
||||
using Avl_region = Allocator_avl_tpl<Rm_region>;
|
||||
|
||||
using Attach_attr = Genode::Vm_session::Attach_attr;
|
||||
|
||||
Sliced_heap _sliced_heap;
|
||||
Avl_region _map { &_sliced_heap };
|
||||
|
||||
uint8_t _remaining_print_count { 10 };
|
||||
|
||||
void _with_region(addr_t const addr, auto const &fn)
|
||||
{
|
||||
Rm_region *region = _map.metadata((void *)addr);
|
||||
if (region)
|
||||
fn(*region);
|
||||
else
|
||||
if (_remaining_print_count) {
|
||||
error(__PRETTY_FUNCTION__, " unknown region");
|
||||
_remaining_print_count--;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
enum class Attach_result {
|
||||
OK,
|
||||
INVALID_DS,
|
||||
OUT_OF_RAM,
|
||||
OUT_OF_CAPS,
|
||||
REGION_CONFLICT,
|
||||
};
|
||||
|
||||
|
||||
Attach_result attach(Region_map_detach &rm_detach,
|
||||
Dataspace_component &dsc,
|
||||
addr_t const guest_phys,
|
||||
Attach_attr attr,
|
||||
auto const &map_fn)
|
||||
{
|
||||
/*
|
||||
* unsupported - deny otherwise arbitrary physical
|
||||
* memory can be mapped to a VM
|
||||
*/
|
||||
if (dsc.managed())
|
||||
return Attach_result::INVALID_DS;
|
||||
|
||||
if (guest_phys & 0xffful || attr.offset & 0xffful ||
|
||||
attr.size & 0xffful)
|
||||
return Attach_result::INVALID_DS;
|
||||
|
||||
if (!attr.size) {
|
||||
attr.size = dsc.size();
|
||||
|
||||
if (attr.offset < attr.size)
|
||||
attr.size -= attr.offset;
|
||||
}
|
||||
|
||||
if (attr.size > dsc.size())
|
||||
attr.size = dsc.size();
|
||||
|
||||
if (attr.offset >= dsc.size() ||
|
||||
attr.offset > dsc.size() - attr.size)
|
||||
return Attach_result::INVALID_DS;
|
||||
|
||||
using Alloc_error = Range_allocator::Alloc_error;
|
||||
|
||||
Attach_result const retval = _map.alloc_addr(attr.size, guest_phys).convert<Attach_result>(
|
||||
|
||||
[&] (void *) {
|
||||
|
||||
Rm_region::Attr const region_attr
|
||||
{
|
||||
.base = guest_phys,
|
||||
.size = attr.size,
|
||||
.write = dsc.writeable() && attr.writeable,
|
||||
.exec = attr.executable,
|
||||
.off = attr.offset,
|
||||
.dma = false,
|
||||
};
|
||||
|
||||
/* store attachment info in meta data */
|
||||
try {
|
||||
_map.construct_metadata((void *)guest_phys,
|
||||
dsc, rm_detach, region_attr);
|
||||
|
||||
} catch (Allocator_avl_tpl<Rm_region>::Assign_metadata_failed) {
|
||||
if (_remaining_print_count) {
|
||||
error("failed to store attachment info");
|
||||
_remaining_print_count--;
|
||||
}
|
||||
return Attach_result::INVALID_DS;
|
||||
}
|
||||
|
||||
Rm_region ®ion = *_map.metadata((void *)guest_phys);
|
||||
|
||||
/* inform dataspace about attachment */
|
||||
dsc.attached_to(region);
|
||||
|
||||
return Attach_result::OK;
|
||||
},
|
||||
|
||||
[&] (Alloc_error error) {
|
||||
|
||||
switch (error) {
|
||||
|
||||
case Alloc_error::OUT_OF_RAM:
|
||||
return Attach_result::OUT_OF_RAM;
|
||||
case Alloc_error::OUT_OF_CAPS:
|
||||
return Attach_result::OUT_OF_CAPS;
|
||||
case Alloc_error::DENIED:
|
||||
{
|
||||
/*
|
||||
* Handle attach after partial detach
|
||||
*/
|
||||
Rm_region *region_ptr = _map.metadata((void *)guest_phys);
|
||||
if (!region_ptr)
|
||||
return Attach_result::REGION_CONFLICT;
|
||||
|
||||
Rm_region ®ion = *region_ptr;
|
||||
|
||||
bool conflict = false;
|
||||
region.with_dataspace([&] (Dataspace_component &dataspace) {
|
||||
(void)dataspace;
|
||||
if (!(dsc.cap() == dataspace.cap()))
|
||||
conflict = true;
|
||||
});
|
||||
if (conflict)
|
||||
return Attach_result::REGION_CONFLICT;
|
||||
|
||||
if (guest_phys < region.base() ||
|
||||
guest_phys > region.base() + region.size() - 1)
|
||||
return Attach_result::REGION_CONFLICT;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return Attach_result::OK;
|
||||
}
|
||||
);
|
||||
|
||||
if (retval == Attach_result::OK) {
|
||||
addr_t phys_addr = dsc.phys_addr() + attr.offset;
|
||||
size_t size = attr.size;
|
||||
|
||||
map_fn(guest_phys, phys_addr, size);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void detach(addr_t guest_phys,
|
||||
size_t size,
|
||||
auto const &unmap_fn)
|
||||
{
|
||||
if (!size || (guest_phys & 0xffful) || (size & 0xffful)) {
|
||||
if (_remaining_print_count) {
|
||||
warning("vm_session: skipping invalid memory detach addr=",
|
||||
(void *)guest_phys, " size=", (void *)size);
|
||||
_remaining_print_count--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
addr_t const guest_phys_end = guest_phys + (size - 1);
|
||||
addr_t addr = guest_phys;
|
||||
do {
|
||||
Rm_region *region = _map.metadata((void *)addr);
|
||||
|
||||
/* walk region holes page-by-page */
|
||||
size_t iteration_size = 0x1000;
|
||||
|
||||
if (region) {
|
||||
iteration_size = region->size();
|
||||
detach_at(region->base(), unmap_fn);
|
||||
}
|
||||
|
||||
if (addr >= guest_phys_end - (iteration_size - 1))
|
||||
break;
|
||||
|
||||
addr += iteration_size;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
Guest_memory(Constrained_ram_allocator &constrained_md_ram_alloc,
|
||||
Region_map ®ion_map)
|
||||
:
|
||||
_sliced_heap(constrained_md_ram_alloc, region_map)
|
||||
{
|
||||
/* configure managed VM area */
|
||||
_map.add_range(0UL, ~0UL);
|
||||
}
|
||||
|
||||
~Guest_memory()
|
||||
{
|
||||
/* detach all regions */
|
||||
while (true) {
|
||||
addr_t out_addr = 0;
|
||||
|
||||
if (!_map.any_block_addr(&out_addr))
|
||||
break;
|
||||
|
||||
detach_at(out_addr, [](addr_t, size_t) { });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void detach_at(addr_t addr,
|
||||
auto const &unmap_fn)
|
||||
{
|
||||
_with_region(addr, [&] (Rm_region ®ion) {
|
||||
|
||||
if (!region.reserved())
|
||||
reserve_and_flush(addr, unmap_fn);
|
||||
|
||||
/* free the reserved region */
|
||||
_map.free(reinterpret_cast<void *>(region.base()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void reserve_and_flush(addr_t addr,
|
||||
auto const &unmap_fn)
|
||||
{
|
||||
_with_region(addr, [&] (Rm_region ®ion) {
|
||||
|
||||
/* inform dataspace */
|
||||
region.with_dataspace([&] (Dataspace_component &dataspace) {
|
||||
dataspace.detached_from(region);
|
||||
});
|
||||
|
||||
region.mark_as_reserved();
|
||||
|
||||
unmap_fn(region.base(), region.size());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CORE__GUEST_MEMORY_H_ */
|
79
repos/base-hw/src/core/phys_allocated.h
Normal file
79
repos/base-hw/src/core/phys_allocated.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* \brief Allocate an object with a physical address
|
||||
* \author Norman Feske
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2024-12-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__PHYS_ALLOCATED_H_
|
||||
#define _CORE__PHYS_ALLOCATED_H_
|
||||
|
||||
/* base includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/attached_ram_dataspace.h>
|
||||
#include <util/noncopyable.h>
|
||||
|
||||
/* core-local includes */
|
||||
#include <types.h>
|
||||
|
||||
namespace Core {
|
||||
template <typename T>
|
||||
class Phys_allocated;
|
||||
}
|
||||
|
||||
using namespace Core;
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Core::Phys_allocated : Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Ram_allocator &_ram;
|
||||
Region_map &_rm;
|
||||
|
||||
Attached_ram_dataspace _ds { _ram, _rm, sizeof(T) };
|
||||
public:
|
||||
|
||||
T &obj = *_ds.local_addr<T>();
|
||||
|
||||
Phys_allocated(Rpc_entrypoint &ep,
|
||||
Ram_allocator &ram,
|
||||
Region_map &rm)
|
||||
:
|
||||
_ep(ep), _ram(ram), _rm(rm)
|
||||
{
|
||||
construct_at<T>(&obj);
|
||||
}
|
||||
|
||||
Phys_allocated(Rpc_entrypoint &ep,
|
||||
Ram_allocator &ram,
|
||||
Region_map &rm,
|
||||
auto const &construct_fn)
|
||||
:
|
||||
_ep(ep), _ram(ram), _rm(rm)
|
||||
{
|
||||
construct_fn(*this, &obj);
|
||||
}
|
||||
|
||||
~Phys_allocated() { obj.~T(); }
|
||||
|
||||
addr_t phys_addr() {
|
||||
addr_t phys_addr { };
|
||||
_ep.apply(_ds.cap(), [&](Dataspace_component *dsc) {
|
||||
phys_addr = dsc->phys_addr();
|
||||
});
|
||||
|
||||
return phys_addr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CORE__PHYS_ALLOCATED_H_ */
|
128
repos/base-hw/src/core/spec/x86_64/vcpu.h
Normal file
128
repos/base-hw/src/core/spec/x86_64/vcpu.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* \brief Vm_session vCPU
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2024-11-26
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__VCPU_H_
|
||||
#define _CORE__VCPU_H_
|
||||
|
||||
/* base includes */
|
||||
#include <base/attached_dataspace.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <hw_native_vcpu/hw_native_vcpu.h>
|
||||
#include <kernel/vm.h>
|
||||
|
||||
/* core includes */
|
||||
#include <phys_allocated.h>
|
||||
#include <region_map_component.h>
|
||||
|
||||
namespace Core { struct Vcpu; }
|
||||
|
||||
|
||||
class Core::Vcpu : public Rpc_object<Vm_session::Native_vcpu, Vcpu>
|
||||
{
|
||||
private:
|
||||
struct Data_pages {
|
||||
uint8_t _[Vcpu_data::size()];
|
||||
};
|
||||
|
||||
Kernel::Vm::Identity &_id;
|
||||
Rpc_entrypoint &_ep;
|
||||
Vcpu_data _vcpu_data { };
|
||||
Kernel_object<Kernel::Vm> _kobj { };
|
||||
Constrained_ram_allocator &_ram;
|
||||
Ram_dataspace_capability _ds_cap { };
|
||||
Region_map &_region_map;
|
||||
Affinity::Location _location;
|
||||
Phys_allocated<Data_pages> _vcpu_data_pages;
|
||||
|
||||
constexpr size_t vcpu_state_size()
|
||||
{
|
||||
return align_addr(sizeof(Board::Vcpu_state),
|
||||
get_page_size_log2());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Vcpu(Kernel::Vm::Identity &id,
|
||||
Rpc_entrypoint &ep,
|
||||
Constrained_ram_allocator &constrained_ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
Affinity::Location location)
|
||||
:
|
||||
_id(id),
|
||||
_ep(ep),
|
||||
_ram(constrained_ram_alloc),
|
||||
_ds_cap( {_ram.alloc(vcpu_state_size(), Cache::UNCACHED)} ),
|
||||
_region_map(region_map),
|
||||
_location(location),
|
||||
_vcpu_data_pages(ep, constrained_ram_alloc, region_map)
|
||||
{
|
||||
Region_map::Attr attr { };
|
||||
attr.writeable = true;
|
||||
_vcpu_data.vcpu_state = _region_map.attach(_ds_cap, attr).convert<Vcpu_state *>(
|
||||
[&] (Region_map::Range range) { return (Vcpu_state *)range.start; },
|
||||
[&] (Region_map::Attach_error) -> Vcpu_state * {
|
||||
error("failed to attach VCPU data within core");
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
if (!_vcpu_data.vcpu_state) {
|
||||
_ram.free(_ds_cap);
|
||||
|
||||
throw Attached_dataspace::Region_conflict();
|
||||
}
|
||||
|
||||
_vcpu_data.virt_area = &_vcpu_data_pages.obj;
|
||||
_vcpu_data.phys_addr = _vcpu_data_pages.phys_addr();
|
||||
|
||||
ep.manage(this);
|
||||
}
|
||||
|
||||
~Vcpu()
|
||||
{
|
||||
_region_map.detach((addr_t)_vcpu_data.vcpu_state);
|
||||
_ram.free(_ds_cap);
|
||||
_ep.dissolve(this);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
** Native_vcpu RPC interface **
|
||||
*******************************/
|
||||
|
||||
Capability<Dataspace> state() const { return _ds_cap; }
|
||||
Native_capability native_vcpu() { return _kobj.cap(); }
|
||||
|
||||
void exception_handler(Signal_context_capability handler)
|
||||
{
|
||||
using Genode::warning;
|
||||
if (!handler.valid()) {
|
||||
warning("invalid signal");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_kobj.constructed()) {
|
||||
warning("Cannot register vcpu handler twice");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned const cpu = _location.xpos();
|
||||
|
||||
if (!_kobj.create(cpu, (void *)&_vcpu_data,
|
||||
Capability_space::capid(handler), _id))
|
||||
warning("Cannot instantiate vm kernel object, invalid signal context?");
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CORE__VCPU_H_ */
|
@ -22,7 +22,6 @@
|
||||
#include <cpu.h>
|
||||
#include <cpu/vcpu_state_virtualization.h>
|
||||
#include <hw/spec/x86_64/x86_64.h>
|
||||
#include <spec/x86_64/virtualization/vm_page_table.h>
|
||||
#include <spec/x86_64/virtualization/svm.h>
|
||||
#include <spec/x86_64/virtualization/vmx.h>
|
||||
|
||||
@ -34,10 +33,6 @@ namespace Board {
|
||||
using Vcpu_data = Genode::Vcpu_data;
|
||||
using Vcpu_state = Genode::Vcpu_state;
|
||||
|
||||
enum {
|
||||
VCPU_MAX = 16
|
||||
};
|
||||
|
||||
enum Platform_exitcodes : uint64_t {
|
||||
EXIT_NPF = 0xfc,
|
||||
EXIT_INIT = 0xfd,
|
||||
|
@ -37,7 +37,7 @@ void Core::platform_add_local_services(Rpc_entrypoint &ep,
|
||||
|
||||
static Vm_root vm_root(ep, sliced_heap, core_ram, core_rm, trace_sources);
|
||||
|
||||
static Core_service<Vm_session_component> vm_service(local_services, vm_root);
|
||||
static Core_service<Session_object<Vm_session>> vm_service(local_services, vm_root);
|
||||
|
||||
static Core_service<Io_port_session_component> io_port_ls(local_services, io_port_root);
|
||||
}
|
||||
|
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* \brief SVM VM session component for 'base-hw'
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2024-09-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SVM_VM_SESSION_COMPONENT_H_
|
||||
#define _CORE__SVM_VM_SESSION_COMPONENT_H_
|
||||
|
||||
/* base includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/session_object.h>
|
||||
#include <base/registry.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
#include <dataspace/capability.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <spec/x86_64/virtualization/hpt.h>
|
||||
|
||||
/* core includes */
|
||||
#include <cpu_thread_component.h>
|
||||
#include <region_map_component.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <trace/source_registry.h>
|
||||
|
||||
#include <vcpu.h>
|
||||
#include <vmid_allocator.h>
|
||||
#include <guest_memory.h>
|
||||
#include <phys_allocated.h>
|
||||
|
||||
|
||||
namespace Core { class Svm_session_component; }
|
||||
|
||||
|
||||
class Core::Svm_session_component
|
||||
:
|
||||
public Session_object<Vm_session>
|
||||
{
|
||||
private:
|
||||
|
||||
using Vm_page_table = Hw::Hpt;
|
||||
|
||||
using Vm_page_table_array =
|
||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Svm_session_component(Svm_session_component const &);
|
||||
Svm_session_component &operator = (Svm_session_component const &);
|
||||
|
||||
struct Detach : Region_map_detach
|
||||
{
|
||||
Svm_session_component &_session;
|
||||
|
||||
Detach(Svm_session_component &session) : _session(session)
|
||||
{ }
|
||||
|
||||
void detach_at(addr_t at) override
|
||||
{
|
||||
_session._detach_at(at);
|
||||
}
|
||||
|
||||
void reserve_and_flush(addr_t at) override
|
||||
{
|
||||
_session._reserve_and_flush(at);
|
||||
}
|
||||
|
||||
void unmap_region(addr_t base, size_t size) override
|
||||
{
|
||||
Genode::error(__func__, " unimplemented ", base, " ", size);
|
||||
}
|
||||
} _detach { *this };
|
||||
|
||||
Registry<Registered<Vcpu>> _vcpus { };
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_ram_alloc;
|
||||
Region_map &_region_map;
|
||||
Heap _heap;
|
||||
Phys_allocated<Vm_page_table> _table;
|
||||
Phys_allocated<Vm_page_table_array> _table_array;
|
||||
Guest_memory _memory;
|
||||
Vmid_allocator &_vmid_alloc;
|
||||
Kernel::Vm::Identity _id;
|
||||
uint8_t _remaining_print_count { 10 };
|
||||
|
||||
void _detach_at(addr_t addr)
|
||||
{
|
||||
_memory.detach_at(addr,
|
||||
[&](addr_t vm_addr, size_t size) {
|
||||
_table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); });
|
||||
}
|
||||
|
||||
void _reserve_and_flush(addr_t addr)
|
||||
{
|
||||
_memory.reserve_and_flush(addr, [&](addr_t vm_addr, size_t size) {
|
||||
_table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); });
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Svm_session_component(Vmid_allocator & vmid_alloc,
|
||||
Rpc_entrypoint &ds_ep,
|
||||
Resources resources,
|
||||
Label const &label,
|
||||
Diag diag,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
Trace::Source_registry &)
|
||||
:
|
||||
Session_object(ds_ep, resources, label, diag),
|
||||
_ep(ds_ep),
|
||||
_constrained_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_region_map(region_map),
|
||||
_heap(_constrained_ram_alloc, region_map),
|
||||
_table(_ep, _constrained_ram_alloc, _region_map),
|
||||
_table_array(_ep, _constrained_ram_alloc, _region_map,
|
||||
[] (Phys_allocated<Vm_page_table_array> &table_array, auto *obj_ptr) {
|
||||
construct_at<Vm_page_table_array>(obj_ptr, [&] (void *virt) {
|
||||
return table_array.phys_addr() + ((addr_t) obj_ptr - (addr_t)virt);
|
||||
});
|
||||
}),
|
||||
_memory(_constrained_ram_alloc, region_map),
|
||||
_vmid_alloc(vmid_alloc),
|
||||
_id({(unsigned)_vmid_alloc.alloc(), (void *)_table.phys_addr()})
|
||||
{ }
|
||||
|
||||
~Svm_session_component()
|
||||
{
|
||||
_vcpus.for_each([&] (Registered<Vcpu> &vcpu) {
|
||||
destroy(_heap, &vcpu); });
|
||||
|
||||
_vmid_alloc.free(_id.id);
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
** Vm session interface **
|
||||
**************************/
|
||||
|
||||
void attach(Dataspace_capability cap, addr_t guest_phys, Attach_attr attr) override
|
||||
{
|
||||
bool out_of_tables = false;
|
||||
bool invalid_mapping = false;
|
||||
|
||||
auto const &map_fn = [&](addr_t vm_addr, addr_t phys_addr, size_t size) {
|
||||
Page_flags const pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED };
|
||||
|
||||
try {
|
||||
_table.obj.insert_translation(vm_addr, phys_addr, size, pflags, _table_array.obj.alloc());
|
||||
} catch(Hw::Out_of_tables &) {
|
||||
if (_remaining_print_count) {
|
||||
Genode::error("Translation table needs too much RAM");
|
||||
_remaining_print_count--;
|
||||
}
|
||||
out_of_tables = true;
|
||||
} catch(...) {
|
||||
if (_remaining_print_count) {
|
||||
Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ",
|
||||
Genode::Hex(vm_addr), " (", size, ")");
|
||||
}
|
||||
invalid_mapping = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (!cap.valid())
|
||||
throw Invalid_dataspace();
|
||||
|
||||
/* check dataspace validity */
|
||||
_ep.apply(cap, [&] (Dataspace_component *ptr) {
|
||||
if (!ptr)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
Dataspace_component &dsc = *ptr;
|
||||
|
||||
Guest_memory::Attach_result result =
|
||||
_memory.attach(_detach, dsc, guest_phys, attr, map_fn);
|
||||
|
||||
if (out_of_tables)
|
||||
throw Out_of_ram();
|
||||
|
||||
if (invalid_mapping)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
switch (result) {
|
||||
case Guest_memory::Attach_result::OK : break;
|
||||
case Guest_memory::Attach_result::INVALID_DS : throw Invalid_dataspace(); break;
|
||||
case Guest_memory::Attach_result::OUT_OF_RAM : throw Out_of_ram(); break;
|
||||
case Guest_memory::Attach_result::OUT_OF_CAPS : throw Out_of_caps(); break;
|
||||
case Guest_memory::Attach_result::REGION_CONFLICT: throw Region_conflict(); break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void attach_pic(addr_t) override
|
||||
{ }
|
||||
|
||||
void detach(addr_t guest_phys, size_t size) override
|
||||
{
|
||||
_memory.detach(guest_phys, size, [&](addr_t vm_addr, size_t size) {
|
||||
_table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); });
|
||||
}
|
||||
|
||||
Capability<Native_vcpu> create_vcpu(Thread_capability tcap) override
|
||||
{
|
||||
Affinity::Location vcpu_location;
|
||||
_ep.apply(tcap, [&] (Cpu_thread_component *ptr) {
|
||||
if (!ptr) return;
|
||||
vcpu_location = ptr->platform_thread().affinity();
|
||||
});
|
||||
|
||||
Vcpu &vcpu = *new (_heap)
|
||||
Registered<Vcpu>(_vcpus,
|
||||
_id,
|
||||
_ep,
|
||||
_constrained_ram_alloc,
|
||||
_region_map,
|
||||
vcpu_location);
|
||||
|
||||
return vcpu.cap();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CORE__SVM_VM_SESSION_COMPONENT_H_ */
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* \brief VM page table abstraction between VMX and SVM for x86
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2024-04-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_
|
||||
#define _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_
|
||||
|
||||
#include <base/log.h>
|
||||
#include <util/construct_at.h>
|
||||
#include <spec/x86_64/virtualization/ept.h>
|
||||
#include <spec/x86_64/virtualization/hpt.h>
|
||||
|
||||
namespace Board {
|
||||
using namespace Genode;
|
||||
|
||||
struct Vm_page_table
|
||||
{
|
||||
/* Both Ept and Hpt need to actually use this allocator */
|
||||
using Allocator = Genode::Page_table_allocator<1UL << SIZE_LOG2_4KB>;
|
||||
|
||||
template <class T, class U>
|
||||
struct is_same {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_same <T, T> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
static_assert(is_same<Allocator, Hw::Ept::Allocator>::value,
|
||||
"Ept uses different allocator");
|
||||
static_assert(is_same<Allocator, Hw::Hpt::Allocator>::value,
|
||||
"Hpt uses different allocator");
|
||||
|
||||
static constexpr size_t ALIGNM_LOG2 = Hw::SIZE_LOG2_4KB;
|
||||
|
||||
enum Virt_type {
|
||||
VIRT_TYPE_NONE,
|
||||
VIRT_TYPE_VMX,
|
||||
VIRT_TYPE_SVM
|
||||
};
|
||||
|
||||
union {
|
||||
Hw::Ept ept;
|
||||
Hw::Hpt hpt;
|
||||
};
|
||||
|
||||
void insert_translation(addr_t vo,
|
||||
addr_t pa,
|
||||
size_t size,
|
||||
Page_flags const & flags,
|
||||
Allocator & alloc)
|
||||
{
|
||||
if (virt_type() == VIRT_TYPE_VMX)
|
||||
ept.insert_translation(vo, pa, size, flags, alloc);
|
||||
else if (virt_type() == VIRT_TYPE_SVM)
|
||||
hpt.insert_translation(vo, pa, size, flags, alloc);
|
||||
}
|
||||
|
||||
void remove_translation(addr_t vo, size_t size, Allocator & alloc)
|
||||
{
|
||||
if (virt_type() == VIRT_TYPE_VMX)
|
||||
ept.remove_translation(vo, size, alloc);
|
||||
else if (virt_type() == VIRT_TYPE_SVM)
|
||||
hpt.remove_translation(vo, size, alloc);
|
||||
}
|
||||
|
||||
static Virt_type virt_type() {
|
||||
static Virt_type virt_type { VIRT_TYPE_NONE };
|
||||
|
||||
if (virt_type == VIRT_TYPE_NONE) {
|
||||
if (Hw::Virtualization_support::has_vmx())
|
||||
virt_type = VIRT_TYPE_VMX;
|
||||
else if (Hw::Virtualization_support::has_svm())
|
||||
virt_type = VIRT_TYPE_SVM;
|
||||
else
|
||||
error("Failed to detect Virtualization technology");
|
||||
}
|
||||
|
||||
return virt_type;
|
||||
}
|
||||
|
||||
Vm_page_table()
|
||||
{
|
||||
if (virt_type() == VIRT_TYPE_VMX)
|
||||
Genode::construct_at<Hw::Ept>(this);
|
||||
else if (virt_type() == VIRT_TYPE_SVM)
|
||||
Genode::construct_at<Hw::Hpt>(this);
|
||||
}
|
||||
};
|
||||
|
||||
using Vm_page_table_array =
|
||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__PC__VIRTUALIZATION__VM_PAGE_TABLE_H_ */
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* \brief VM session component for 'base-hw'
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2015-02-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2024 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/construct_at.h>
|
||||
|
||||
/* base internal includes */
|
||||
#include <base/internal/unmanaged_singleton.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/core_interface.h>
|
||||
#include <vm_session_component.h>
|
||||
#include <platform.h>
|
||||
#include <cpu_thread_component.h>
|
||||
|
||||
using namespace Core;
|
||||
|
||||
|
||||
static Core_mem_allocator & cma() {
|
||||
return static_cast<Core_mem_allocator&>(platform().core_mem_alloc()); }
|
||||
|
||||
|
||||
void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size)
|
||||
{
|
||||
using namespace Hw;
|
||||
|
||||
Page_flags pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED };
|
||||
|
||||
try {
|
||||
_table.insert_translation(vm_addr, phys_addr, size, pflags,
|
||||
_table_array.alloc());
|
||||
return;
|
||||
} catch(Hw::Out_of_tables &) {
|
||||
Genode::error("Translation table needs to much RAM");
|
||||
} catch(...) {
|
||||
Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ",
|
||||
Genode::Hex(vm_addr), " (", size, ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
|
||||
addr_t const vm_addr,
|
||||
Attach_attr const attribute)
|
||||
{
|
||||
_attach(dsc.phys_addr() + attribute.offset, vm_addr, attribute.size);
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::attach_pic(addr_t )
|
||||
{ }
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
/* get some aligned space for the translation table */
|
||||
return cma().alloc_aligned(sizeof(Board::Vm_page_table),
|
||||
Board::Vm_page_table::ALIGNM_LOG2).convert<void *>(
|
||||
[&] (void *table_ptr) {
|
||||
return table_ptr; },
|
||||
|
||||
[&] (Range_allocator::Alloc_error) -> void * {
|
||||
/* XXX handle individual error conditions */
|
||||
error("failed to allocate kernel object");
|
||||
throw Insufficient_ram_quota(); }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr)
|
||||
{
|
||||
/*
|
||||
* XXX these allocations currently leak memory on VM Session
|
||||
* destruction. This cannot be easily fixed because the
|
||||
* Core Mem Allocator does not implement free().
|
||||
*
|
||||
* Normally we would use constrained_md_ram_alloc to make the allocation,
|
||||
* but to get the physical address of the pages in virt_area, we need
|
||||
* to use the Core Mem Allocator.
|
||||
*/
|
||||
|
||||
Vcpu_data * vcpu_data = (Vcpu_data *) cma()
|
||||
.try_alloc(sizeof(Board::Vcpu_data))
|
||||
.convert<void *>(
|
||||
[&](void *ptr) { return ptr; },
|
||||
[&](Range_allocator::Alloc_error) -> void * {
|
||||
/* XXX handle individual error conditions */
|
||||
error("failed to allocate kernel object");
|
||||
throw Insufficient_ram_quota();
|
||||
});
|
||||
|
||||
vcpu_data->virt_area = cma()
|
||||
.alloc_aligned(Vcpu_data::size(), 12)
|
||||
.convert<void *>(
|
||||
[&](void *ptr) { return ptr; },
|
||||
[&](Range_allocator::Alloc_error) -> void * {
|
||||
/* XXX handle individual error conditions */
|
||||
error("failed to allocate kernel object");
|
||||
throw Insufficient_ram_quota();
|
||||
});
|
||||
|
||||
vcpu_data->vcpu_state = (Vcpu_state *) ds_addr;
|
||||
vcpu_data->phys_addr = (addr_t)cma().phys_addr(vcpu_data->virt_area);
|
||||
|
||||
return (Genode::addr_t) vcpu_data;
|
||||
}
|
||||
|
||||
|
||||
Vm_session_component::Vm_session_component(Vmid_allocator & vmid_alloc,
|
||||
Rpc_entrypoint &ds_ep,
|
||||
Resources resources,
|
||||
Label const &,
|
||||
Diag,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
unsigned,
|
||||
Trace::Source_registry &)
|
||||
:
|
||||
Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_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<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(*(new (cma()) Board::Vm_page_table_array([] (void * virt) {
|
||||
return (addr_t)cma().phys_addr(virt);}))),
|
||||
_vmid_alloc(vmid_alloc),
|
||||
_id({(unsigned)_vmid_alloc.alloc(), cma().phys_addr(&_table)})
|
||||
{
|
||||
/* configure managed VM area */
|
||||
_map.add_range(0UL, ~0UL);
|
||||
}
|
||||
|
||||
|
||||
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_at(out_addr);
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
for (unsigned i = 0; i < _vcpu_id_alloc; i++) {
|
||||
if (!_vcpus[i].constructed())
|
||||
continue;
|
||||
|
||||
Vcpu & vcpu = *_vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
_constrained_md_ram_alloc.free(vcpu.ds_cap);
|
||||
}
|
||||
}
|
||||
|
||||
/* free guest-to-host page tables */
|
||||
destroy(platform().core_mem_alloc(), &_table);
|
||||
destroy(platform().core_mem_alloc(), &_table_array);
|
||||
_vmid_alloc.free(_id.id);
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* \brief VMX VM session component for 'base-hw'
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2024-09-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__VMX_VM_SESSION_COMPONENT_H_
|
||||
#define _CORE__VMX_VM_SESSION_COMPONENT_H_
|
||||
|
||||
/* base includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/session_object.h>
|
||||
#include <base/registry.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
#include <dataspace/capability.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <spec/x86_64/virtualization/ept.h>
|
||||
|
||||
/* core includes */
|
||||
#include <cpu_thread_component.h>
|
||||
#include <region_map_component.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <trace/source_registry.h>
|
||||
|
||||
#include <vcpu.h>
|
||||
#include <vmid_allocator.h>
|
||||
#include <guest_memory.h>
|
||||
#include <phys_allocated.h>
|
||||
|
||||
|
||||
namespace Core { class Vmx_session_component; }
|
||||
|
||||
|
||||
class Core::Vmx_session_component
|
||||
:
|
||||
public Session_object<Vm_session>
|
||||
{
|
||||
private:
|
||||
|
||||
using Vm_page_table = Hw::Ept;
|
||||
|
||||
using Vm_page_table_array =
|
||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Vmx_session_component(Vmx_session_component const &);
|
||||
Vmx_session_component &operator = (Vmx_session_component const &);
|
||||
|
||||
struct Detach : Region_map_detach
|
||||
{
|
||||
Vmx_session_component &_session;
|
||||
|
||||
Detach(Vmx_session_component &session) : _session(session)
|
||||
{ }
|
||||
|
||||
void detach_at(addr_t at) override
|
||||
{
|
||||
_session._detach_at(at);
|
||||
}
|
||||
|
||||
void reserve_and_flush(addr_t at) override
|
||||
{
|
||||
_session._reserve_and_flush(at);
|
||||
}
|
||||
|
||||
void unmap_region(addr_t base, size_t size) override
|
||||
{
|
||||
Genode::error(__func__, " unimplemented ", base, " ", size);
|
||||
}
|
||||
} _detach { *this };
|
||||
|
||||
Registry<Registered<Vcpu>> _vcpus { };
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_ram_alloc;
|
||||
Region_map &_region_map;
|
||||
Heap _heap;
|
||||
Phys_allocated<Vm_page_table> _table;
|
||||
Phys_allocated<Vm_page_table_array> _table_array;
|
||||
Guest_memory _memory;
|
||||
Vmid_allocator &_vmid_alloc;
|
||||
Kernel::Vm::Identity _id;
|
||||
uint8_t _remaining_print_count { 10 };
|
||||
|
||||
void _detach_at(addr_t addr)
|
||||
{
|
||||
_memory.detach_at(addr,
|
||||
[&](addr_t vm_addr, size_t size) {
|
||||
_table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); });
|
||||
}
|
||||
|
||||
void _reserve_and_flush(addr_t addr)
|
||||
{
|
||||
_memory.reserve_and_flush(addr, [&](addr_t vm_addr, size_t size) {
|
||||
_table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); });
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Vmx_session_component(Vmid_allocator & vmid_alloc,
|
||||
Rpc_entrypoint &ds_ep,
|
||||
Resources resources,
|
||||
Label const &label,
|
||||
Diag diag,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
Trace::Source_registry &)
|
||||
:
|
||||
Session_object(ds_ep, resources, label, diag),
|
||||
_ep(ds_ep),
|
||||
_constrained_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_region_map(region_map),
|
||||
_heap(_constrained_ram_alloc, region_map),
|
||||
_table(_ep, _constrained_ram_alloc, _region_map),
|
||||
_table_array(_ep, _constrained_ram_alloc, _region_map,
|
||||
[] (Phys_allocated<Vm_page_table_array> &table_array, auto *obj_ptr) {
|
||||
construct_at<Vm_page_table_array>(obj_ptr, [&] (void *virt) {
|
||||
return table_array.phys_addr() + ((addr_t) obj_ptr - (addr_t)virt);
|
||||
});
|
||||
}),
|
||||
_memory(_constrained_ram_alloc, region_map),
|
||||
_vmid_alloc(vmid_alloc),
|
||||
_id({(unsigned)_vmid_alloc.alloc(), (void *)_table.phys_addr()})
|
||||
{ }
|
||||
|
||||
~Vmx_session_component()
|
||||
{
|
||||
_vcpus.for_each([&] (Registered<Vcpu> &vcpu) {
|
||||
destroy(_heap, &vcpu); });
|
||||
|
||||
_vmid_alloc.free(_id.id);
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
** Vm session interface **
|
||||
**************************/
|
||||
|
||||
void attach(Dataspace_capability cap, addr_t guest_phys, Attach_attr attr) override
|
||||
{
|
||||
bool out_of_tables = false;
|
||||
bool invalid_mapping = false;
|
||||
|
||||
auto const &map_fn = [&](addr_t vm_addr, addr_t phys_addr, size_t size) {
|
||||
Page_flags const pflags { RW, EXEC, USER, NO_GLOBAL, RAM, CACHED };
|
||||
|
||||
try {
|
||||
_table.obj.insert_translation(vm_addr, phys_addr, size, pflags, _table_array.obj.alloc());
|
||||
} catch(Hw::Out_of_tables &) {
|
||||
if (_remaining_print_count) {
|
||||
Genode::error("Translation table needs too much RAM");
|
||||
_remaining_print_count--;
|
||||
}
|
||||
out_of_tables = true;
|
||||
} catch(...) {
|
||||
if (_remaining_print_count) {
|
||||
Genode::error("Invalid mapping ", Genode::Hex(phys_addr), " -> ",
|
||||
Genode::Hex(vm_addr), " (", size, ")");
|
||||
}
|
||||
invalid_mapping = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (!cap.valid())
|
||||
throw Invalid_dataspace();
|
||||
|
||||
/* check dataspace validity */
|
||||
_ep.apply(cap, [&] (Dataspace_component *ptr) {
|
||||
if (!ptr)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
Dataspace_component &dsc = *ptr;
|
||||
|
||||
Guest_memory::Attach_result result =
|
||||
_memory.attach(_detach, dsc, guest_phys, attr, map_fn);
|
||||
|
||||
if (out_of_tables)
|
||||
throw Out_of_ram();
|
||||
|
||||
if (invalid_mapping)
|
||||
throw Invalid_dataspace();
|
||||
|
||||
switch (result) {
|
||||
case Guest_memory::Attach_result::OK : break;
|
||||
case Guest_memory::Attach_result::INVALID_DS : throw Invalid_dataspace(); break;
|
||||
case Guest_memory::Attach_result::OUT_OF_RAM : throw Out_of_ram(); break;
|
||||
case Guest_memory::Attach_result::OUT_OF_CAPS : throw Out_of_caps(); break;
|
||||
case Guest_memory::Attach_result::REGION_CONFLICT: throw Region_conflict(); break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void attach_pic(addr_t) override
|
||||
{ }
|
||||
|
||||
void detach(addr_t guest_phys, size_t size) override
|
||||
{
|
||||
_memory.detach(guest_phys, size, [&](addr_t vm_addr, size_t size) {
|
||||
_table.obj.remove_translation(vm_addr, size, _table_array.obj.alloc()); });
|
||||
}
|
||||
|
||||
Capability<Native_vcpu> create_vcpu(Thread_capability tcap) override
|
||||
{
|
||||
Affinity::Location vcpu_location;
|
||||
_ep.apply(tcap, [&] (Cpu_thread_component *ptr) {
|
||||
if (!ptr) return;
|
||||
vcpu_location = ptr->platform_thread().affinity();
|
||||
});
|
||||
|
||||
Vcpu &vcpu = *new (_heap)
|
||||
Registered<Vcpu>(_vcpus,
|
||||
_id,
|
||||
_ep,
|
||||
_constrained_ram_alloc,
|
||||
_region_map,
|
||||
vcpu_location);
|
||||
|
||||
return vcpu.cap();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CORE__VMX_VM_SESSION_COMPONENT_H_ */
|
99
repos/base-hw/src/core/spec/x86_64/vm_root.h
Normal file
99
repos/base-hw/src/core/spec/x86_64/vm_root.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* \brief x86_64 specific Vm root interface
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2012-10-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2024 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.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__INCLUDE__VM_ROOT_H_
|
||||
#define _CORE__INCLUDE__VM_ROOT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <root/component.h>
|
||||
|
||||
/* Hw includes */
|
||||
#include <hw/spec/x86_64/x86_64.h>
|
||||
|
||||
/* core includes */
|
||||
#include <virtualization/vmx_session_component.h>
|
||||
#include <virtualization/svm_session_component.h>
|
||||
|
||||
#include <vmid_allocator.h>
|
||||
|
||||
namespace Core { class Vm_root; }
|
||||
|
||||
|
||||
class Core::Vm_root : public Root_component<Session_object<Vm_session>>
|
||||
{
|
||||
private:
|
||||
|
||||
Ram_allocator &_ram_allocator;
|
||||
Region_map &_local_rm;
|
||||
Trace::Source_registry &_trace_sources;
|
||||
Vmid_allocator _vmid_alloc { };
|
||||
|
||||
protected:
|
||||
|
||||
Session_object<Vm_session> *_create_session(const char *args) override
|
||||
{
|
||||
Session::Resources resources = session_resources_from_args(args);
|
||||
|
||||
if (Hw::Virtualization_support::has_svm())
|
||||
return new (md_alloc())
|
||||
Svm_session_component(_vmid_alloc,
|
||||
*ep(),
|
||||
resources,
|
||||
session_label_from_args(args),
|
||||
session_diag_from_args(args),
|
||||
_ram_allocator, _local_rm,
|
||||
_trace_sources);
|
||||
|
||||
if (Hw::Virtualization_support::has_vmx())
|
||||
return new (md_alloc())
|
||||
Vmx_session_component(_vmid_alloc,
|
||||
*ep(),
|
||||
session_resources_from_args(args),
|
||||
session_label_from_args(args),
|
||||
session_diag_from_args(args),
|
||||
_ram_allocator, _local_rm,
|
||||
_trace_sources);
|
||||
|
||||
Genode::error( "No virtualization support detected.");
|
||||
throw Core::Service_denied();
|
||||
}
|
||||
|
||||
void _upgrade_session(Session_object<Vm_session> *vm, const char *args) override
|
||||
{
|
||||
vm->upgrade(ram_quota_from_args(args));
|
||||
vm->upgrade(cap_quota_from_args(args));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param session_ep entrypoint managing vm_session components
|
||||
* \param md_alloc meta-data allocator to be used by root component
|
||||
*/
|
||||
Vm_root(Rpc_entrypoint &session_ep,
|
||||
Allocator &md_alloc,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map &local_rm,
|
||||
Trace::Source_registry &trace_sources)
|
||||
:
|
||||
Root_component<Session_object<Vm_session>>(&session_ep, &md_alloc),
|
||||
_ram_allocator(ram_alloc),
|
||||
_local_rm(local_rm),
|
||||
_trace_sources(trace_sources)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _CORE__INCLUDE__VM_ROOT_H_ */
|
@ -17,7 +17,6 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <root/component.h>
|
||||
#include <base/heap.h>
|
||||
|
||||
/* core includes */
|
||||
#include <vm_session_component.h>
|
||||
|
@ -99,7 +99,7 @@ struct Genode::Vm_connection : Connection<Vm_session>, Rpc_client<Vm_session>
|
||||
long priority = Cpu_session::DEFAULT_PRIORITY,
|
||||
unsigned long affinity = 0)
|
||||
:
|
||||
Connection<Vm_session>(env, label, Ram_quota { 16*1024 }, Affinity(),
|
||||
Connection<Vm_session>(env, label, Ram_quota { 5*1024*1024 }, Affinity(),
|
||||
Args("priority=", Hex(priority), ", "
|
||||
"affinity=", Hex(affinity))),
|
||||
Rpc_client<Vm_session>(cap())
|
||||
|
Loading…
x
Reference in New Issue
Block a user