mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 11:55:24 +00:00
parent
c67e78a7f0
commit
839183d2b6
@ -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)
|
||||
|
||||
|
@ -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 &); }
|
||||
|
@ -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 <sys/times.h>
|
||||
#include <unistd.h>
|
||||
#include <aio.h>
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h> /* memset */
|
||||
@ -29,27 +27,11 @@
|
||||
/* local includes */
|
||||
#include <stub_macros.h>
|
||||
|
||||
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)
|
||||
|
@ -338,6 +338,7 @@ void Libc::Component::construct(Libc::Env &env)
|
||||
|
||||
environ = envp;
|
||||
|
||||
Pthread::init(env);
|
||||
Network::init(env);
|
||||
|
||||
/* sidestep 'rtThreadPosixSelectPokeSignal' */
|
||||
|
267
repos/ports/src/virtualbox6/pthread.cc
Normal file
267
repos/ports/src/virtualbox6/pthread.cc
Normal file
@ -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 <errno.h>
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* libc internal */
|
||||
#include <internal/thread_create.h> /* Libc::pthread_create() */
|
||||
#include <internal/call_func.h> /* call_func() */
|
||||
|
||||
/* VirtualBox includes */
|
||||
#include <VBox/vmm/uvm.h>
|
||||
#include <internal/thread.h> /* RTTHREADINT etc. */
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/env.h>
|
||||
#include <base/entrypoint.h>
|
||||
#include <base/registry.h>
|
||||
#include <util/string.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
/* local includes */
|
||||
#include <init.h>
|
||||
#include <pthread_emt.h>
|
||||
#include <sup.h>
|
||||
#include <stub_macros.h>
|
||||
|
||||
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<Entrypoint> _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<Registered<Pthread::Entrypoint>> _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<Entrypoint>(_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<PRTTHREADINT>(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);
|
||||
}
|
38
repos/ports/src/virtualbox6/pthread_emt.h
Normal file
38
repos/ports/src/virtualbox6/pthread_emt.h
Normal file
@ -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 <util/interface.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sup.h>
|
||||
|
||||
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_ */
|
@ -34,6 +34,7 @@
|
||||
#include <init.h>
|
||||
#include <sup_drv.h>
|
||||
#include <sup_vm.h>
|
||||
#include <pthread_emt.h>
|
||||
#include <stub_macros.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
/* local includes */
|
||||
#include <sup_drv.h>
|
||||
#include <vcpu.h>
|
||||
#include <pthread_emt.h>
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
/* local includes */
|
||||
#include <vcpu.h>
|
||||
#include <pthread_emt.h>
|
||||
|
||||
|
||||
/*
|
||||
@ -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<VMX_EXIT_EPT_VIOLATION>(); 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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user