diff --git a/repos/base-hw/include/spec/x86_64/cpu/vm_state_virtualization.h b/repos/base-hw/include/spec/x86_64/cpu/vm_state_virtualization.h new file mode 100644 index 0000000000..3eeed7bbb3 --- /dev/null +++ b/repos/base-hw/include/spec/x86_64/cpu/vm_state_virtualization.h @@ -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_ */ diff --git a/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk b/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk index bf44809ada..89f5ddb86d 100644 --- a/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk +++ b/repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk @@ -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 diff --git a/repos/base-hw/src/core/board/pc/board.h b/repos/base-hw/src/core/board/pc/board.h index c1646c04bb..32d4ebed23 100644 --- a/repos/base-hw/src/core/board/pc/board.h +++ b/repos/base-hw/src/core/board/pc/board.h @@ -16,6 +16,8 @@ /* base-hw internal includes */ #include +/* PC virtualization */ +#include /* * As long as Board::NR_OF_CPUS is used as constant within pic.h diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h new file mode 100644 index 0000000000..822b21f260 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h @@ -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 +#include + +#include +#include + +namespace Board { + + using Vm_page_table = Hw::Page_table; + using Vm_page_table_array = + Vm_page_table::Allocator::Array; + + 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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/hypervisor.h b/repos/base-hw/src/core/spec/x86_64/virtualization/hypervisor.h new file mode 100644 index 0000000000..4b378fbe62 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/hypervisor.h @@ -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 +#include + +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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc new file mode 100644 index 0000000000..21e3623e88 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +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 &) +{ +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc new file mode 100644 index 0000000000..094e10f65f --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/platform_services.cc @@ -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 + +/* core includes */ +#include +#include +#include +#include +#include + + +/* + * Add x86 specific ioport and virtualization service + */ +void Core::platform_add_local_services(Rpc_entrypoint &ep, + Sliced_heap &sliced_heap, + Registry &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_service(local_services, vm_root); + + static Core_service + io_port_ls(local_services, io_port_root); +} diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc new file mode 100644 index 0000000000..022043998c --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc @@ -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 + +/* base internal includes */ +#include + +/* core includes */ +#include +#include +#include +#include +#include + +using namespace Core; + + +static Core_mem_allocator & cma() { + return static_cast(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 *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(); + + /* 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 ®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(_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); +}