From 839183d2b6596604ca1fbe2dfbcd1962e9c5616c Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Tue, 9 Mar 2021 14:32:44 +0100 Subject: [PATCH] vbox6: unify EMT and vCPU entrypoint Issue #4031 --- repos/ports/recipes/src/vbox6/content.mk | 32 +-- repos/ports/src/virtualbox6/init.h | 2 + repos/ports/src/virtualbox6/libc.cc | 22 +- repos/ports/src/virtualbox6/main.cc | 1 + repos/ports/src/virtualbox6/pthread.cc | 267 ++++++++++++++++++++++ repos/ports/src/virtualbox6/pthread_emt.h | 38 +++ repos/ports/src/virtualbox6/sup.cc | 27 ++- repos/ports/src/virtualbox6/sup_drv.cc | 16 +- repos/ports/src/virtualbox6/sup_drv.h | 4 +- repos/ports/src/virtualbox6/sup_vm.cc | 1 - repos/ports/src/virtualbox6/target.mk | 5 +- repos/ports/src/virtualbox6/vcpu.cc | 92 ++++---- repos/ports/src/virtualbox6/vcpu.h | 29 +-- 13 files changed, 415 insertions(+), 121 deletions(-) create mode 100644 repos/ports/src/virtualbox6/pthread.cc create mode 100644 repos/ports/src/virtualbox6/pthread_emt.h diff --git a/repos/ports/recipes/src/vbox6/content.mk b/repos/ports/recipes/src/vbox6/content.mk index 08fb66186d..32d3ef2d62 100644 --- a/repos/ports/recipes/src/vbox6/content.mk +++ b/repos/ports/recipes/src/vbox6/content.mk @@ -29,21 +29,23 @@ src/virtualbox6_sdk: mkdir -p $(dir $@) cp -r $(PORT_DIR)/$@ $(dir $@) -MIRROR_FROM_LIBPORTS := lib/mk/libc-mem.mk \ - lib/mk/libc-common.inc \ - src/lib/libc/internal/init.h \ - src/lib/libc/internal/mem_alloc.h \ - src/lib/libc/internal/monitor.h \ - src/lib/libc/internal/pthread.h \ - src/lib/libc/internal/thread_create.h \ - src/lib/libc/internal/timer.h \ - src/lib/libc/internal/types.h \ - src/lib/libc/libc_mem_alloc.cc \ - lib/import/import-qemu-usb_include.mk \ - lib/mk/qemu-usb_include.mk \ - lib/mk/qemu-usb.mk \ - include/qemu \ - src/lib/qemu-usb +MIRROR_FROM_LIBPORTS := \ + include/qemu \ + lib/import/import-qemu-usb_include.mk \ + lib/mk/libc-common.inc \ + lib/mk/libc-mem.mk \ + lib/mk/qemu-usb.mk \ + lib/mk/qemu-usb_include.mk \ + src/lib/libc/internal/init.h \ + src/lib/libc/internal/mem_alloc.h \ + src/lib/libc/internal/monitor.h \ + src/lib/libc/internal/pthread.h \ + src/lib/libc/internal/thread_create.h \ + src/lib/libc/internal/timer.h \ + src/lib/libc/internal/types.h \ + src/lib/libc/libc_mem_alloc.cc \ + src/lib/libc/spec/x86_64/internal/call_func.h \ + src/lib/qemu-usb content: $(MIRROR_FROM_LIBPORTS) diff --git a/repos/ports/src/virtualbox6/init.h b/repos/ports/src/virtualbox6/init.h index 3eb048fbab..71b97fca39 100644 --- a/repos/ports/src/virtualbox6/init.h +++ b/repos/ports/src/virtualbox6/init.h @@ -19,6 +19,8 @@ namespace Genode { struct Env; } namespace Sup { void init(Genode::Env &); } +namespace Pthread { void init(Genode::Env &); } + namespace Network { void init(Genode::Env &); } namespace Xhci { void init(Genode::Env &); } diff --git a/repos/ports/src/virtualbox6/libc.cc b/repos/ports/src/virtualbox6/libc.cc index 69bc24bd0b..9f67043a5a 100644 --- a/repos/ports/src/virtualbox6/libc.cc +++ b/repos/ports/src/virtualbox6/libc.cc @@ -1,5 +1,5 @@ /* - * \brief VirtualBox runtime (RT) + * \brief VirtualBox libc runtime * \author Norman Feske * \author Christian Helmuth * \date 2013-08-20 @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include #include /* memset */ @@ -29,27 +27,11 @@ /* local includes */ #include -static bool const debug = true; +static bool const debug = true; /* required by stub_macros.h */ extern "C" { -int sched_yield() -{ - static unsigned long counter = 0; - - if (++counter % 100'000 == 0) - Genode::warning(__func__, " called ", counter, " times"); - - return 0; -} - -int sched_get_priority_max(int policy) TRACE(0) -int sched_get_priority_min(int policy) TRACE(0) -int pthread_setschedparam(pthread_t thread, int policy, - const struct sched_param *param) TRACE(0) -int pthread_getschedparam(pthread_t thread, int *policy, - struct sched_param *param) TRACE(0) int futimes(int fd, const struct timeval tv[2]) TRACE(0) int lutimes(const char *filename, const struct timeval tv[2]) TRACE(0) int lchown(const char *pathname, uid_t owner, gid_t group) TRACE(0) diff --git a/repos/ports/src/virtualbox6/main.cc b/repos/ports/src/virtualbox6/main.cc index b62d9e37e7..e6c1b548d9 100644 --- a/repos/ports/src/virtualbox6/main.cc +++ b/repos/ports/src/virtualbox6/main.cc @@ -338,6 +338,7 @@ void Libc::Component::construct(Libc::Env &env) environ = envp; + Pthread::init(env); Network::init(env); /* sidestep 'rtThreadPosixSelectPokeSignal' */ diff --git a/repos/ports/src/virtualbox6/pthread.cc b/repos/ports/src/virtualbox6/pthread.cc new file mode 100644 index 0000000000..25500b01fe --- /dev/null +++ b/repos/ports/src/virtualbox6/pthread.cc @@ -0,0 +1,267 @@ +/* + * \brief VirtualBox libc runtime: pthread adaptions + * \author Christian Helmuth + * \date 2021-03-03 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* libc includes */ +#include +#include +#include + +/* libc internal */ +#include /* Libc::pthread_create() */ +#include /* call_func() */ + +/* VirtualBox includes */ +#include +#include /* RTTHREADINT etc. */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* local includes */ +#include +#include +#include +#include + +static bool const debug = true; /* required by stub_macros.h */ + + +using namespace Genode; + + +extern "C" int sched_yield() +{ + static unsigned long counter = 0; + + if (++counter % 100'000 == 0) + warning(__func__, " called ", counter, " times"); + + return 0; +} + +extern "C" int sched_get_priority_max(int policy) TRACE(0) +extern "C" int sched_get_priority_min(int policy) TRACE(0) +extern "C" int pthread_setschedparam(pthread_t thread, int policy, + const struct sched_param *param) TRACE(0) +extern "C" int pthread_getschedparam(pthread_t thread, int *policy, + struct sched_param *param) TRACE(0) + + +namespace Pthread { + + struct Entrypoint; + struct Factory; + +} /* namespace Pthread */ + + +class Pthread::Entrypoint : public Pthread::Emt +{ + private: + + /* members initialized by constructing thread */ + + Sup::Cpu_index const _cpu; + size_t const _stack_size; /* stack size for EMT mode */ + + Genode::Entrypoint _ep; + Blockade _construction_finalized { }; + + void *(*_emt_start_routine) (void *); + void *_emt_arg; + + enum class Mode { VCPU, EMT } _mode { Mode::VCPU }; + + jmp_buf _vcpu_jmp_buf; + jmp_buf _emt_jmp_buf; + + /* members finally initialized by the entrypoint itself */ + + void *_emt_stack { nullptr }; + pthread_t _emt_pthread { }; + + void _finalize_construction() + { + Genode::Thread &myself = *Genode::Thread::myself(); + + _emt_stack = myself.alloc_secondary_stack(myself.name().string(), + _stack_size); + + Libc::pthread_create_from_thread(&_emt_pthread, myself, _emt_stack); + + _construction_finalized.wakeup(); + + /* switch to EMT mode and call pthread start_routine */ + if (setjmp(_vcpu_jmp_buf) == 0) { + _mode = Mode::EMT; + call_func(_emt_stack, (void *)_emt_start_routine, _emt_arg); + } + } + + Genode::Signal_handler _finalize_construction_sigh { + _ep, *this, &Entrypoint::_finalize_construction }; + + public: + + Entrypoint(Env &env, Sup::Cpu_index cpu, size_t stack_size, + char const *name, Affinity::Location location, + void *(*start_routine) (void *), void *arg) + : + _cpu(cpu), _stack_size(stack_size), + _ep(env, 64*1024, name, location), + _emt_start_routine(start_routine), _emt_arg(arg) + { + Signal_transmitter(_finalize_construction_sigh).submit(); + + _construction_finalized.block(); + } + + /* registered object must have virtual destructor */ + virtual ~Entrypoint() { } + + Sup::Cpu_index cpu() const { return _cpu; } + + pthread_t pthread() const { return _emt_pthread; } + + /* Pthread::Emt interface */ + + void switch_to_emt() override + { + Assert(_mode == Mode::VCPU); + + if (setjmp(_vcpu_jmp_buf) == 0) { + _mode = Mode::EMT; + longjmp(_emt_jmp_buf, 1); + } + } + + void switch_to_vcpu() override + { + Assert(pthread_self() == _emt_pthread); + Assert(_mode == Mode::EMT); + + if (setjmp(_emt_jmp_buf) == 0) { + _mode = Mode::VCPU; + longjmp(_vcpu_jmp_buf, 1); + } + } + + Genode::Entrypoint & genode_ep() override { return _ep; } +}; + + +class Pthread::Factory +{ + private: + + Env &_env; + + Registry> _entrypoints; + + Affinity::Space const _affinity_space { _env.cpu().affinity_space() }; + + public: + + Factory(Env &env) : _env(env) { } + + Entrypoint & create(Sup::Cpu_index cpu, size_t stack_size, char const *name, + void *(*start_routine) (void *), void *arg) + { + + Affinity::Location const location = + _affinity_space.location_of_index(cpu.value); + + return *new Registered(_entrypoints, _env, cpu, + stack_size, name, + location, start_routine, arg); + } + + struct Emt_for_cpu_not_found : Exception { }; + + Emt & emt_for_cpu(Sup::Cpu_index cpu) + { + Entrypoint *found = nullptr; + + _entrypoints.for_each([&] (Entrypoint &ep) { + if (ep.cpu().value == cpu.value) + found = &ep; + }); + + if (!found) + throw Emt_for_cpu_not_found(); + + return *found; + } +}; + + +static Pthread::Factory *factory; + + +Pthread::Emt & Pthread::emt_for_cpu(Sup::Cpu_index cpu) +{ + return factory->emt_for_cpu(cpu); +} + + +void Pthread::init(Env &env) +{ + factory = new Pthread::Factory(env); +} + + +static int create_emt_thread(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), + PRTTHREADINT rtthread) +{ + PUVMCPU pUVCpu = (PUVMCPU)rtthread->pvUser; + + Sup::Cpu_index const cpu { pUVCpu->idCpu }; + + size_t stack_size = 0; + + /* try to fetch configured stack size form attribute */ + pthread_attr_getstacksize(attr, &stack_size); + + Assert(stack_size); + + Pthread::Entrypoint &ep = + factory->create(cpu, stack_size, rtthread->szName, + start_routine, rtthread); + + *thread = ep.pthread(); + + return 0; +} + + + +extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg) +{ + PRTTHREADINT rtthread = reinterpret_cast(arg); + + /* + * Emulation threads (EMT) represent the guest CPU, so we implement them in + * dedicated entrypoints that also handle vCPU events in combination with + * user-level threading (i.e., setjmp/longjmp). + */ + if (rtthread->enmType == RTTHREADTYPE_EMULATION) + return create_emt_thread(thread, attr, start_routine, rtthread); + else + return Libc::pthread_create(thread, attr, start_routine, arg, rtthread->szName); +} diff --git a/repos/ports/src/virtualbox6/pthread_emt.h b/repos/ports/src/virtualbox6/pthread_emt.h new file mode 100644 index 0000000000..b8949b379f --- /dev/null +++ b/repos/ports/src/virtualbox6/pthread_emt.h @@ -0,0 +1,38 @@ +/* + * \brief Pthread helpers for emulation threads + * \author Christian Helmuth + * \date 2021-03-08 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _PTHREAD_EMT_H_ +#define _PTHREAD_EMT_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include + +namespace Genode { struct Entrypoint; } + +namespace Pthread { + + struct Emt : Genode::Interface + { + virtual void switch_to_emt() = 0; + virtual void switch_to_vcpu() = 0; + + virtual Genode::Entrypoint & genode_ep() = 0; + }; + + Emt & emt_for_cpu(Sup::Cpu_index cpu); +} + +#endif /* _PTHREAD_EMT_H_ */ diff --git a/repos/ports/src/virtualbox6/sup.cc b/repos/ports/src/virtualbox6/sup.cc index a830114c5c..3e8e5bca83 100644 --- a/repos/ports/src/virtualbox6/sup.cc +++ b/repos/ports/src/virtualbox6/sup.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include static bool const debug = true; @@ -171,20 +172,28 @@ static void ioctl(SUPVTCAPS &request) } +static void setup_vcpu_handler(Sup::Vm &vm, Sup::Cpu_index cpu) +{ + Pthread::Emt &emt = Pthread::emt_for_cpu(cpu); + + Sup::Vcpu_handler &handler = sup_drv->create_vcpu_handler(cpu, emt); + + vm.register_vcpu_handler(cpu, handler); +} + + static int vmmr0_gvmm_create_vm(GVMMCREATEVMREQ &request) { Sup::Cpu_count cpu_count { request.cCpus }; Sup::Vm &new_vm = Sup::Vm::create(request.pSession, cpu_count); - for (unsigned i = 0; i < cpu_count.value; i++) { + /* + * The first EMT thread creates the VM and must be registered implicitly. + * Additional EMTs register themselves via vmmr0_gvmm_register_vcpu(). + */ - Sup::Cpu_index const index { i }; - - Sup::Vcpu_handler &handler = sup_drv->create_vcpu_handler(index); - - new_vm.register_vcpu_handler(index, handler); - } + setup_vcpu_handler(new_vm, Sup::Cpu_index { 0 }); request.pVMR3 = &new_vm; request.pVMR0 = (PVMR0)request.pVMR3; @@ -195,7 +204,7 @@ static int vmmr0_gvmm_create_vm(GVMMCREATEVMREQ &request) static int vmmr0_gvmm_register_vcpu(PVMR0 pvmr0, uint32_t cpu) { - warning(__PRETTY_FUNCTION__, " cpu=", cpu); + Sup::Vm &vm = *(Sup::Vm *)pvmr0; /* * EMT threads for additional CPUs are registered on initialization. @@ -206,6 +215,8 @@ static int vmmr0_gvmm_register_vcpu(PVMR0 pvmr0, uint32_t cpu) * pGVM->aCpus[idCpu].hNativeThreadR0 = pGVM->aCpus[idCpu].hEMT = RTThreadNativeSelf(); */ + setup_vcpu_handler(vm, Sup::Cpu_index { cpu }); + return VINF_SUCCESS; } diff --git a/repos/ports/src/virtualbox6/sup_drv.cc b/repos/ports/src/virtualbox6/sup_drv.cc index a9fe8a67d4..7a1bc01231 100644 --- a/repos/ports/src/virtualbox6/sup_drv.cc +++ b/repos/ports/src/virtualbox6/sup_drv.cc @@ -17,7 +17,7 @@ /* local includes */ #include -#include +#include Sup::Cpu_freq_khz Sup::Drv::_cpu_freq_khz_from_rom() @@ -55,30 +55,24 @@ Sup::Drv::Cpu_virt Sup::Drv::_cpu_virt_from_rom() } -Sup::Vcpu_handler &Sup::Drv::create_vcpu_handler(Cpu_index cpu_index) +Sup::Vcpu_handler &Sup::Drv::create_vcpu_handler(Cpu_index cpu_index, + Pthread::Emt &emt) { Libc::Allocator alloc { }; - Affinity::Location const location = - _affinity_space.location_of_index(cpu_index.value); - - size_t const stack_size = 64*1024; - switch (_cpu_virt) { case Cpu_virt::VMX: return *new Vcpu_handler_vmx(_env, - stack_size, - location, cpu_index.value, + emt, _vm_connection, alloc); case Cpu_virt::SVM: return *new Vcpu_handler_svm(_env, - stack_size, - location, cpu_index.value, + emt, _vm_connection, alloc); diff --git a/repos/ports/src/virtualbox6/sup_drv.h b/repos/ports/src/virtualbox6/sup_drv.h index e19351e103..7bee94db87 100644 --- a/repos/ports/src/virtualbox6/sup_drv.h +++ b/repos/ports/src/virtualbox6/sup_drv.h @@ -29,6 +29,8 @@ namespace Sup { struct Drv; } +namespace Pthread { struct Emt; } + class Sup::Drv { public: @@ -71,7 +73,7 @@ class Sup::Drv /* * \throw Virtualization_support_missing */ - Vcpu_handler &create_vcpu_handler(Cpu_index); + Vcpu_handler &create_vcpu_handler(Cpu_index, Pthread::Emt &); }; #endif /* _SUP_DRV_H_ */ diff --git a/repos/ports/src/virtualbox6/sup_vm.cc b/repos/ports/src/virtualbox6/sup_vm.cc index e30b1a886f..e1637d4006 100644 --- a/repos/ports/src/virtualbox6/sup_vm.cc +++ b/repos/ports/src/virtualbox6/sup_vm.cc @@ -63,7 +63,6 @@ void Sup::Vm::init(PSUPDRVSESSION psession, Cpu_count cpu_count) cpu.hNativeThreadR0 = NIL_RTNATIVETHREAD; VM::apCpusR3[i] = &cpu; - log(this, ": apCpusR3[", i, "]=", apCpusR3[i]); } } diff --git a/repos/ports/src/virtualbox6/target.mk b/repos/ports/src/virtualbox6/target.mk index 9feca74957..1042d391dd 100644 --- a/repos/ports/src/virtualbox6/target.mk +++ b/repos/ports/src/virtualbox6/target.mk @@ -1,3 +1,5 @@ +REQUIRES = x86_64 + TARGET = virtualbox6 include $(REP_DIR)/lib/mk/virtualbox6-common.inc @@ -6,7 +8,7 @@ CC_WARN += -Wall SRC_CC := main.cc drivers.cc vcpu_gim.cc SRC_CC += libc.cc unimpl.cc dummies.cc pdm.cc devices.cc nem.cc dynlib.cc -SRC_CC += network.cc +SRC_CC += pthread.cc network.cc LIBS += base LIBS += stdcxx @@ -22,6 +24,7 @@ LIB_MK_FILES := $(notdir $(wildcard $(REP_DIR)/lib/mk/virtualbox6-*.mk) \ LIBS += $(LIB_MK_FILES:.mk=) INC_DIR += $(call select_from_repositories,src/lib/libc) +INC_DIR += $(call select_from_repositories,src/lib/libc)/spec/x86_64 INC_DIR += $(VBOX_DIR)/Runtime/include diff --git a/repos/ports/src/virtualbox6/vcpu.cc b/repos/ports/src/virtualbox6/vcpu.cc index e993bcdbcd..31420dd2bb 100644 --- a/repos/ports/src/virtualbox6/vcpu.cc +++ b/repos/ports/src/virtualbox6/vcpu.cc @@ -33,6 +33,7 @@ /* local includes */ #include +#include /* @@ -141,7 +142,6 @@ void Sup::Vcpu_handler_svm::_handle_exit() break; case VCPU_STARTUP: _svm_startup(); - _blockade_emt.wakeup(); /* pause - no resume */ break; default: @@ -158,7 +158,7 @@ void Sup::Vcpu_handler_svm::_handle_exit() } /* wait until EMT thread wake's us up */ - _sem_handler.down(); + /* TODO XXX _sem_handler.down(); */ /* resume vCPU */ _vm_state = RUNNING; @@ -190,23 +190,22 @@ int Sup::Vcpu_handler_svm::_vm_exit_requires_instruction_emulation(PCPUMCTX) } -Sup::Vcpu_handler_svm::Vcpu_handler_svm(Genode::Env &env, size_t stack_size, - Genode::Affinity::Location location, +Sup::Vcpu_handler_svm::Vcpu_handler_svm(Genode::Env &env, unsigned int cpu_id, + Pthread::Emt &emt, Genode::Vm_connection &vm_connection, Genode::Allocator &alloc) : - Vcpu_handler(env, stack_size, location, cpu_id), - _handler(_ep, *this, &Vcpu_handler_svm::_handle_exit), + Vcpu_handler(env, cpu_id, emt), + _handler(_emt.genode_ep(), *this, &Vcpu_handler_svm::_handle_exit), _vm_connection(vm_connection), _vcpu(_vm_connection, alloc, _handler, _exit_config) { _state = &_vcpu.state(); + /* run vCPU until initial startup exception */ _vcpu.run(); - - /* sync with initial startup exception */ - _blockade_emt.block(); + _emt.switch_to_vcpu(); } @@ -296,6 +295,8 @@ __attribute__((noreturn)) void Sup::Vcpu_handler_vmx::_vmx_invalid() " actv_state=", Genode::Hex(_state->actv_state.value())); Genode::error("invalid guest state - dead"); + + /* FIXME exit() cannot be called in VCPU mode */ exit(-1); } @@ -333,29 +334,37 @@ void Sup::Vcpu_handler_vmx::_handle_exit() case VMX_EXIT_XSETBV: _vmx_default(); break; case VMX_EXIT_TPR_BELOW_THRESHOLD: _vmx_default(); break; case VMX_EXIT_EPT_VIOLATION: _vmx_ept(); break; + case RECALL: recall_wait = Vcpu_handler::_recall_handler(); + if (!recall_wait) { + _vm_state = RUNNING; + /* XXX early return for resume */ + _run_vm(); + return; + } + + /* paused - no resume of vCPU */ break; + case VCPU_STARTUP: _vmx_startup(); - _blockade_emt.wakeup(); - /* pause - no resume */ + + /* paused - no resume of vCPU */ break; + default: Genode::error(__func__, " unknown exit - stop - ", Genode::Hex(exit)); _vm_state = PAUSED; + + /* XXX early return without resume */ return; } - if (exit == RECALL && !recall_wait) { - _vm_state = RUNNING; - _run_vm(); - return; - } - - /* wait until EMT thread wake's us up */ - _sem_handler.down(); + /* switch to EMT until next vCPU resume */ + Assert(_vm_state != RUNNING); + _emt.switch_to_emt(); /* resume vCPU */ _vm_state = RUNNING; @@ -408,23 +417,22 @@ int Sup::Vcpu_handler_vmx::_vm_exit_requires_instruction_emulation(PCPUMCTX pCtx } -Sup::Vcpu_handler_vmx::Vcpu_handler_vmx(Genode::Env &env, size_t stack_size, - Genode::Affinity::Location location, +Sup::Vcpu_handler_vmx::Vcpu_handler_vmx(Genode::Env &env, unsigned int cpu_id, + Pthread::Emt &emt, Genode::Vm_connection &vm_connection, Genode::Allocator &alloc) : - Vcpu_handler(env, stack_size, location, cpu_id), - _handler(_ep, *this, &Vcpu_handler_vmx::_handle_exit), + Vcpu_handler(env, cpu_id, emt), + _handler(_emt.genode_ep(), *this, &Vcpu_handler_vmx::_handle_exit), _vm_connection(vm_connection), _vcpu(_vm_connection, alloc, _handler, _exit_config) { _state = &_vcpu.state(); + /* run vCPU until initial startup exception */ _vcpu.run(); - - /* sync with initial startup exception */ - _blockade_emt.block(); + _emt.switch_to_vcpu(); } @@ -435,6 +443,7 @@ Sup::Vcpu_handler_vmx::Vcpu_handler_vmx(Genode::Env &env, size_t stack_size, Genode::Vm_connection::Exit_config const Sup::Vcpu_handler::_exit_config { /* ... */ }; +/* TODO move into Emt */ timespec Sup::Vcpu_handler::_add_timespec_ns(timespec a, ::uint64_t ns) const { enum { NSEC_PER_SEC = 1'000'000'000ull }; @@ -472,11 +481,8 @@ again: Assert(_vm_state == IRQ_WIN || _vm_state == PAUSED || _vm_state == NPT_EPT); Assert(_next_state == PAUSE_EXIT || _next_state == RUN); - /* wake up vcpu ep handler */ - _sem_handler.up(); - - /* wait for next exit */ - _blockade_emt.block(); + /* run vCPU until next exit */ + _emt.switch_to_vcpu(); /* next time run - recall() may change this */ _next_state = RUN; @@ -490,14 +496,6 @@ again: _state->discharge(); _irq_window_pthread(); goto again; - } else - if (_vm_state == NPT_EPT) { -// if (_npt_ept_unmap) { -// Genode::error("NPT/EPT unmap not supported - stop"); -// while (true) { -// _blockade_emt.block(); -// } -// } } if (!(_vm_state == PAUSED || _vm_state == NPT_EPT)) @@ -519,8 +517,6 @@ void Sup::Vcpu_handler::_default_handler() _vm_exits++; _vm_state = PAUSED; - - _blockade_emt.wakeup(); } @@ -759,7 +755,7 @@ bool Sup::Vcpu_handler::_state_to_vbox(VM *pVM, PVMCPU pVCpu) pVCpu->cpum.s.fUseFlags |= (CPUM_USED_FPU_GUEST); // CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM); // pVCpu->cpum.s.fUseFlags |= (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_SINCE_REM); - + if (_state->intr_state.value() != 0) { Assert(_state->intr_state.value() == INTERRUPT_STATE_BLOCKING_BY_STI || _state->intr_state.value() == INTERRUPT_STATE_BLOCKING_BY_MOV_SS); @@ -801,7 +797,6 @@ void Sup::Vcpu_handler::_irq_window() _vm_exits++; _vm_state = IRQ_WIN; - _blockade_emt.wakeup(); } @@ -814,7 +809,6 @@ void Sup::Vcpu_handler::_npt_ept() _vm_exits++; _vm_state = NPT_EPT; - _blockade_emt.wakeup(); } @@ -983,6 +977,7 @@ void Sup::Vcpu_handler::recall(VM &vm) } +/* TODO move into Emt */ void Sup::Vcpu_handler::halt(Genode::uint64_t const wait_ns) { /* calculate timeout */ @@ -997,6 +992,7 @@ void Sup::Vcpu_handler::halt(Genode::uint64_t const wait_ns) } +/* TODO move into Emt */ void Sup::Vcpu_handler::wake_up() { pthread_mutex_lock(&_mutex); @@ -1093,13 +1089,9 @@ int Sup::Vcpu_handler::run_hw(VM &vm) } -Sup::Vcpu_handler::Vcpu_handler(Env &env, size_t stack_size, - Affinity::Location location, - unsigned int cpu_id) +Sup::Vcpu_handler::Vcpu_handler(Env &env, unsigned int cpu_id, Pthread::Emt &emt) : - _ep(env, stack_size, - Genode::String<12>("EP-EMT-", cpu_id).string(), location), - _cpu_id(cpu_id) + _emt(emt), _cpu_id(cpu_id) { pthread_mutexattr_t _attr; pthread_mutexattr_init(&_attr); diff --git a/repos/ports/src/virtualbox6/vcpu.h b/repos/ports/src/virtualbox6/vcpu.h index eab629efa5..46ed948b24 100644 --- a/repos/ports/src/virtualbox6/vcpu.h +++ b/repos/ports/src/virtualbox6/vcpu.h @@ -30,6 +30,8 @@ namespace Sup { struct Vcpu_handler_svm; } +namespace Pthread { struct Emt; } + class Sup::Vcpu_handler : Genode::Noncopyable { @@ -37,16 +39,19 @@ class Sup::Vcpu_handler : Genode::Noncopyable static Genode::Vm_connection::Exit_config const _exit_config; - Genode::Entrypoint _ep; - Genode::Blockade _blockade_emt { }; - Genode::Semaphore _sem_handler; + Pthread::Emt &_emt; Genode::Vcpu_state *_state { nullptr }; bool _last_exit_triggered_by_wrmsr = false; + /* TODO move into Emt */ + /* halt/wake_up */ pthread_cond_t _cond_wait; pthread_mutex_t _mutex; + /* TODO move into Emt */ + timespec _add_timespec_ns(timespec a, ::uint64_t ns) const; + /* information used for NPT/EPT handling */ Genode::addr_t _npt_ept_exit_addr { 0 }; RTGCUINT _npt_ept_errorcode { 0 }; @@ -83,8 +88,6 @@ class Sup::Vcpu_handler : Genode::Noncopyable INTERRUPT_STATE_BLOCKING_BY_MOV_SS = 1U << 1, }; - timespec _add_timespec_ns(timespec a, ::uint64_t ns) const; - void _update_gim_system_time(); protected: @@ -99,8 +102,8 @@ class Sup::Vcpu_handler : Genode::Noncopyable Genode::addr_t _irq_drop = 0; struct { - unsigned intr_state; - unsigned ctrl[2]; + unsigned intr_state = 0; + unsigned ctrl[2] = { 0, 0 }; } _next_utcb; unsigned _ept_fault_addr_type; @@ -141,9 +144,7 @@ class Sup::Vcpu_handler : Genode::Noncopyable RECALL = 0xff, }; - Vcpu_handler(Genode::Env &env, size_t stack_size, - Genode::Affinity::Location location, - unsigned int cpu_id); + Vcpu_handler(Genode::Env &env, unsigned int cpu_id, Pthread::Emt &emt); unsigned int cpu_id() const { return _cpu_id; } @@ -187,9 +188,9 @@ class Sup::Vcpu_handler_vmx : public Vcpu_handler public: - Vcpu_handler_vmx(Genode::Env &env, size_t stack_size, - Genode::Affinity::Location location, + Vcpu_handler_vmx(Genode::Env &env, unsigned int cpu_id, + Pthread::Emt &emt, Genode::Vm_connection &vm_connection, Genode::Allocator &alloc); }; @@ -224,9 +225,9 @@ class Sup::Vcpu_handler_svm : public Vcpu_handler public: - Vcpu_handler_svm(Genode::Env &env, size_t stack_size, - Genode::Affinity::Location location, + Vcpu_handler_svm(Genode::Env &env, unsigned int cpu_id, + Pthread::Emt &emt, Genode::Vm_connection &vm_connection, Genode::Allocator &alloc); };