base-hw: copy virtualization structure for x86_64

Ref #4826
This commit is contained in:
Benjamin Lamowski 2022-10-18 19:59:43 +02:00 committed by Christian Helmuth
parent 256a989550
commit 6ca7119267
8 changed files with 387 additions and 2 deletions

View File

@ -0,0 +1,30 @@
/*
* \brief Virtual machine state
* \author Benjamin Lamowski
* \date 2022-10-14
*/
/*
* Copyright (C) 2022 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 _INCLUDE__SPEC__PC__VM_STATE_H_
#define _INCLUDE__SPEC__PC__VM_STATE_H_
namespace Genode {
/**
* CPU context of a virtual machine
*/
struct Vm_state;
}
struct Genode::Vm_state
{
};
#endif /* _INCLUDE__SPEC__PC__VM_STATE_H_ */

View File

@ -8,6 +8,7 @@
# add include paths
REP_INC_DIR += src/core/board/pc
REP_INC_DIR += src/core/spec/x86_64
REP_INC_DIR += src/core/spec/x86_64/virtualization
LIBS += syscall-hw
@ -17,13 +18,17 @@ SRC_S += spec/x86_64/exception_vector.s
# add C++ sources
SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/vm_thread_off.cc
SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/x86_64/virtualization/kernel/vm.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
SRC_CC += spec/x86_64/kernel/thread_exception.cc
SRC_CC += spec/x86_64/platform_support.cc
SRC_CC += spec/x86/platform_services.cc
SRC_CC += spec/x86_64/virtualization/platform_services.cc
SRC_CC += spec/x86/io_port_session_component.cc
SRC_CC += spec/x86/io_port_session_support.cc

View File

@ -16,6 +16,8 @@
/* base-hw internal includes */
#include <hw/spec/x86_64/pc_board.h>
/* PC virtualization */
#include <spec/x86_64/virtualization/board.h>
/*
* As long as Board::NR_OF_CPUS is used as constant within pic.h

View File

@ -0,0 +1,51 @@
/*
* \brief Board with PC virtualization support
* \author Benjamin Lamowski
* \date 2022-10-14
*/
/*
* Copyright (C) 2022 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__BOARD_H_
#define _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_
/* base-hw core includes */
#include <kernel/configuration.h>
#include <kernel/irq.h>
#include <hw/spec/x86_64/page_table.h>
#include <cpu/vm_state_virtualization.h>
namespace Board {
using Vm_page_table = Hw::Page_table;
using Vm_page_table_array =
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
struct Vcpu_context;
using Vm_state = Genode::Vm_state;
enum {
VCPU_MAX = 16
};
};
namespace Kernel {
class Cpu;
class Vm;
};
struct Board::Vcpu_context
{
Vcpu_context(Kernel::Cpu & cpu);
};
#endif /* _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_ */

View File

@ -0,0 +1,33 @@
/*
* \brief Interface between kernel and hypervisor
* \author Benjamin Lamowski
* \date 2022-10-14
*/
/*
* Copyright (C) 2022 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 _SPEC__PC__VIRTUALIZATION_HYPERVISOR_H_
#define _SPEC__PC__VIRTUALIZATION_HYPERVISOR_H_
#include <base/stdint.h>
#include <base/log.h>
namespace Hypervisor {
using Call_arg = Genode::umword_t;
using Call_ret = Genode::umword_t;
inline void switch_world(Call_arg guest_state [[maybe_unused]],
Call_arg host_state [[maybe_unused]],
Call_arg pic_state [[maybe_unused]],
Call_arg ttbr [[maybe_unused]])
{
}
}
#endif /* _SPEC__PC__VIRTUALIZATION_HYPERVISOR_H_ */

View File

@ -0,0 +1,63 @@
/*
* \brief Kernel backend for x86 virtual machines
* \author Benjamin Lamowski
* \date 2022-10-14
*/
/*
* Copyright (C) 2022 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.
*/
#include <base/log.h>
#include <cpu/vm_state_virtualization.h>
#include <util/mmio.h>
#include <hw/assert.h>
#include <map_local.h>
#include <platform_pd.h>
#include <kernel/cpu.h>
#include <kernel/vm.h>
#include <kernel/main.h>
#include <spec/x86_64/virtualization/hypervisor.h>
using Genode::addr_t;
using Kernel::Cpu;
using Kernel::Vm;
Vm::Vm(Irq::Pool & user_irq_pool,
Cpu & cpu,
Genode::Vm_state & state,
Kernel::Signal_context & context,
Identity & id)
:
Kernel::Object { *this },
Cpu_job(Cpu_priority::min(), 0),
_user_irq_pool(user_irq_pool),
_state(state),
_context(context),
_id(id),
_vcpu_context(cpu)
{
affinity(cpu);
}
Vm::~Vm()
{
}
void Vm::exception(Cpu &)
{
}
void Vm::proceed(Cpu &)
{
}

View File

@ -0,0 +1,44 @@
/*
* \brief Platform specific services for x86
* \author Stefan Kalkowski
* \author Benjamin Lamowski
* \date 2012-10-26
*/
/*
* Copyright (C) 2012-2022 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 <base/service.h>
/* core includes */
#include <core_env.h>
#include <platform.h>
#include <platform_services.h>
#include <vm_root.h>
#include <io_port_root.h>
/*
* Add x86 specific ioport and virtualization service
*/
void Core::platform_add_local_services(Rpc_entrypoint &ep,
Sliced_heap &sliced_heap,
Registry<Service> &local_services,
Trace::Source_registry &trace_sources)
{
static Io_port_root io_port_root(*core_env().pd_session(),
platform().io_port_alloc(), sliced_heap);
static Vm_root vm_root(ep, sliced_heap, core_env().ram_allocator(),
core_env().local_rm(), trace_sources);
static Core_service<Vm_session_component> vm_service(local_services, vm_root);
static Core_service<Io_port_session_component>
io_port_ls(local_services, io_port_root);
}

View File

@ -0,0 +1,157 @@
/*
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \author Benjamin Lamowski
* \date 2015-02-17
*/
/*
* Copyright (C) 2015-2023 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>
#include <core_env.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, NO_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(); }
);
}
using Vmid_allocator = Genode::Bit_allocator<256>;
static Vmid_allocator &alloc()
{
static Vmid_allocator * allocator = nullptr;
if (!allocator) {
allocator = unmanaged_singleton<Vmid_allocator>();
/* reserve VM ID 0 for the hypervisor */
addr_t id = allocator->alloc();
assert (id == 0);
}
return *allocator;
}
Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
Resources resources,
Label const &,
Diag,
Ram_allocator &ram_alloc,
Region_map &region_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);}))),
_id({(unsigned)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(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);
alloc().free(_id.id);
}