vbox: join emt and vcpu handler thread

Fixes #1129
This commit is contained in:
Alexander Boettcher 2014-04-24 10:55:09 +02:00 committed by Norman Feske
parent 4782fd34f6
commit 0ddc69d370
7 changed files with 282 additions and 394 deletions

View File

@ -3,6 +3,7 @@ include $(REP_DIR)/lib/mk/virtualbox-common.inc
SRC_CC = sup.cc
INC_DIR += $(call select_from_repositories,src/lib/libc)
INC_DIR += $(call select_from_repositories,src/lib/pthread)
INC_DIR += $(VBOX_DIR)/VMM/include
INC_DIR += $(REP_DIR)/src/virtualbox

View File

@ -25,6 +25,9 @@
#include "sup.h"
#include "vmm_memory.h"
/* Libc include */
#include <pthread.h>
/* VirtualBox SUPLib interface */
int SUPR3QueryVTxSupported(void)
@ -77,6 +80,16 @@ int SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned
}
extern "C"
bool create_emt_vcpu(pthread_t * thread, size_t stack_size,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
/* no hardware acceleration support */
return false;
}
/**
* Dummies and unimplemented stuff.
*/
@ -85,13 +98,12 @@ uint64_t genode_cpu_hz() {
return 1000000000ULL; /* XXX fixed 1GHz return value */
}
bool Vmm_memory::unmap_from_vm(RTGCPHYS GCPhys)
{
PWRN("%s unimplemented", __func__);
return false;
}
extern "C" int pthread_yield() {
PWRN("%s unimplemented", __func__);
return 0;
}
extern "C" void pthread_yield() { PWRN("%s unimplemented", __func__); }

View File

@ -18,6 +18,7 @@
#include <base/flex_iterator.h>
#include <rom_session/connection.h>
#include <timer_session/connection.h>
#include <os/attached_rom_dataspace.h>
#include <vmm/vcpu_thread.h>
#include <vmm/vcpu_dispatcher.h>
@ -51,129 +52,77 @@ static Genode::Semaphore *r0_halt_sem()
/* Genode specific function */
void SUPR3QueryHWACCLonGenodeSupport(VM * pVM) {
static Genode::Attached_rom_dataspace hip_rom("hypervisor_info_page");
void SUPR3QueryHWACCLonGenodeSupport(VM * pVM)
{
try {
using namespace Genode;
Rom_connection hip_rom("hypervisor_info_page");
Nova::Hip * const hip = env()->rm_session()->attach(hip_rom.dataspace());
if (!hip)
return;
Nova::Hip * hip = hip_rom.local_addr<Nova::Hip>();
pVM->hwaccm.s.svm.fSupported = hip->has_feature_svm();
pVM->hwaccm.s.vmx.fSupported = hip->has_feature_vmx();
PINF("support svm %u vmx %u", hip->has_feature_svm(), hip->has_feature_vmx());
} catch (...) {
PWRN("No hardware acceleration available - execution will be slow!");
} /* if we get an exception let hardware support off */
}
void SUPR3QueryHWACCLonGenodeCreateVM(VM * pVM)
{
bool svm = pVM->hwaccm.s.svm.fSupported;
if (!svm && !pVM->hwaccm.s.vmx.fSupported) {
PERR("SVM nor VMX supported by hardware accelerated code called !");
return;
}
Assert(!vcpu_handler);
if (svm)
vcpu_handler = new Vcpu_handler_svm();
else
vcpu_handler = new Vcpu_handler_vmx();
}
/* VirtualBox SUPLib interface */
int SUPR3QueryVTxSupported(void)
{
return VINF_SUCCESS;
}
int SUPR3QueryVTxSupported(void) { return VINF_SUCCESS; }
int SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
{
switch (uOperation)
{
case SUP_VMMR0_DO_HWACC_RUN:
{
VM * pVM = reinterpret_cast<VM *>(pVMR0);
PVMCPU pVCpu = &pVM->aCpus[idCpu];
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
return vcpu_handler->run_hw(pVMR0, idCpu);
}
default:
break;
switch (uOperation) {
case SUP_VMMR0_DO_HWACC_RUN:
return vcpu_handler->run_hw(pVMR0, idCpu);
}
return VERR_INTERNAL_ERROR;
return VERR_INTERNAL_ERROR;
}
int SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned
uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
{
static unsigned counter = 0;
switch (uOperation) {
switch(uOperation)
{
case VMMR0_DO_GVMM_CREATE_VM:
genode_VMMR0_DO_GVMM_CREATE_VM(pReqHdr);
return VINF_SUCCESS;
case VMMR0_DO_GVMM_CREATE_VM:
genode_VMMR0_DO_GVMM_CREATE_VM(pReqHdr);
return VINF_SUCCESS;
case VMMR0_DO_GVMM_SCHED_HALT:
// counter ++;
// PERR("halt %u", counter);
r0_halt_sem()->down();
// PERR("halt - done");
return VINF_SUCCESS;
case VMMR0_DO_GVMM_SCHED_HALT:
r0_halt_sem()->down();
return VINF_SUCCESS;
case VMMR0_DO_GVMM_SCHED_WAKE_UP:
// counter ++;
// PERR("sched wake up %u", counter);
r0_halt_sem()->up();
return VINF_SUCCESS;
case VMMR0_DO_GVMM_SCHED_WAKE_UP:
r0_halt_sem()->up();
return VINF_SUCCESS;
case VMMR0_DO_GVMM_SCHED_POLL:
/* called by 'vmR3HaltGlobal1Halt' */
// PDBG("SUPR3CallVMMR0Ex: VMMR0_DO_GVMM_SCHED_POLL");
return VINF_SUCCESS;
/* called by 'vmR3HaltGlobal1Halt' */
case VMMR0_DO_GVMM_SCHED_POLL:
return VINF_SUCCESS;
case VMMR0_DO_VMMR0_INIT:
{
VM * pVM = reinterpret_cast<VM *>(pVMR0);
SUPR3QueryHWACCLonGenodeSupport(pVM);
return VINF_SUCCESS;
}
case VMMR0_DO_HWACC_SETUP_VM:
{
VM * pVM = reinterpret_cast<VM *>(pVMR0);
SUPR3QueryHWACCLonGenodeCreateVM(pVM);
return VINF_SUCCESS;
}
case VMMR0_DO_HWACC_ENABLE:
return VINF_SUCCESS;
case VMMR0_DO_VMMR0_INIT:
SUPR3QueryHWACCLonGenodeSupport(reinterpret_cast<VM *>(pVMR0));
return VINF_SUCCESS;
case VMMR0_DO_GVMM_SCHED_POKE:
{
/* XXX only do one of it - either recall or up - not both XXX */
vcpu_handler->recall();
r0_halt_sem()->up();
return VINF_SUCCESS;
}
case VMMR0_DO_HWACC_SETUP_VM:
return VINF_SUCCESS;
default:
PERR("SUPR3CallVMMR0Ex: unhandled uOperation %d", uOperation);
return VERR_GENERAL_FAILURE;
case VMMR0_DO_HWACC_ENABLE:
return VINF_SUCCESS;
/* XXX only do one of it - either recall or up - not both XXX */
case VMMR0_DO_GVMM_SCHED_POKE:
vcpu_handler->recall();
r0_halt_sem()->up();
return VINF_SUCCESS;
default:
PERR("SUPR3CallVMMR0Ex: unhandled uOperation %d", uOperation);
return VERR_GENERAL_FAILURE;
}
}
@ -181,7 +130,8 @@ int SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned
/**
* Various support stuff - base-nova specific.
*/
uint64_t genode_cpu_hz() {
uint64_t genode_cpu_hz()
{
static uint64_t cpu_freq = 0;
if (!cpu_freq) {
@ -205,12 +155,6 @@ uint64_t genode_cpu_hz() {
}
extern "C" int pthread_yield() {
Nova::ec_ctrl(Nova::EC_YIELD);
return 0;
}
bool Vmm_memory::unmap_from_vm(RTGCPHYS GCPhys)
{
size_t const size = 1;
@ -232,3 +176,27 @@ bool Vmm_memory::unmap_from_vm(RTGCPHYS GCPhys)
return true;
}
extern "C" void pthread_yield(void) { Nova::ec_ctrl(Nova::EC_YIELD); }
extern "C"
bool create_emt_vcpu(pthread_t * pthread, size_t stack,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
Nova::Hip * hip = hip_rom.local_addr<Nova::Hip>();
if (!hip->has_feature_vmx() && !hip->has_feature_svm())
return false;
if (hip->has_feature_vmx())
vcpu_handler = new Vcpu_handler_vmx(stack, attr, start_routine, arg);
if (hip->has_feature_svm())
vcpu_handler = new Vcpu_handler_svm(stack, attr, start_routine, arg);
*pthread = vcpu_handler;
return true;
}

View File

@ -39,6 +39,12 @@
#include "guest_memory.h"
#include "vmm_memory.h"
/* Genode libc pthread binding */
#include "thread.h"
/* LibC includes */
#include <setjmp.h>
/*
* VirtualBox stores segment attributes in Intel format using a 32-bit
* value. NOVA represents the attributes in packet format using a 16-bit
@ -55,21 +61,22 @@ static inline Genode::uint32_t sel_ar_conv_from_nova(Genode::uint16_t v)
return (v & 0xff) | (((uint32_t )v << 4) & 0x1f000);
}
/*
* Used to map memory for virtual framebuffer to VM
*/
extern "C" int MMIO2_MAPPED_SYNC(PVM pVM, RTGCPHYS GCPhys, size_t cbWrite);
class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
{
private:
enum { STACK_SIZE = 4096 };
Genode::Cap_connection _cap_connection;
Vmm::Vcpu_other_pd _vcpu;
Genode::addr_t _ec_sel = 0;
void fpu_save(char * data) {
Assert(!(reinterpret_cast<Genode::addr_t>(data) & 0xF));
asm volatile ("fxsave %0" : "=m" (*data));
@ -82,41 +89,48 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
protected:
/* unlocked by first startup exception */
Genode::Lock _lock_startup;
Genode::Lock _signal_vcpu;
Genode::Lock _signal_emt;
struct {
Nova::mword_t mtd;
unsigned intr_state;
unsigned ctrl[2];
} next_utcb;
PVM _current_vm;
PVMCPU _current_vcpu;
unsigned _current_exit_cond;
PVM _current_vm;
PVMCPU _current_vcpu;
void * _stack_reply;
jmp_buf _env;
__attribute__((noreturn)) void _default_handler(unsigned cond)
void switch_to_hw(PCPUMCTX pCtx) {
unsigned long value;
if (!setjmp(_env)) {
_stack_reply = reinterpret_cast<void *>(&value - 1);
Nova::reply(_stack_reply);
}
}
__attribute__((noreturn)) void _irq_window(unsigned cond)
{
using namespace Nova;
using namespace Genode;
Nova::Utcb * utcb = reinterpret_cast<Nova::Utcb *>(Thread_base::utcb());
Thread_base *myself = Thread_base::myself();
Utcb *utcb = reinterpret_cast<Utcb *>(myself->utcb());
Assert(!(utcb->intr_state & 3));
Assert(utcb->flags & X86_EFL_IF);
/* tell caller what happened */
_current_exit_cond = cond;
if (irq_win(utcb)) {
/* reset mtd to not transfer anything back by accident */
utcb->mtd = 0;
/* inject IRQ */
if (inj_event(utcb, _current_vcpu))
Nova::reply(_stack_reply);
}
PVMCPU pVCpu = _current_vcpu;
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
/* go back to re-compiler */
longjmp(_env, 1);
}
fpu_save(reinterpret_cast<char *>(&pCtx->fpu));
/* unblock caller */
_signal_emt.unlock();
/* block myself */
_signal_vcpu.lock();
fpu_load(reinterpret_cast<char *>(&pCtx->fpu));
utcb->mtd |= Mtd::FPU;
Nova::reply(myself->stack_top());
__attribute__((noreturn)) void _default_handler()
{
longjmp(_env, 1);
}
@ -128,13 +142,16 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
using namespace Nova;
using namespace Genode;
addr_t stack_top;
Assert(utcb->actv_state == 0);
Assert(!(utcb->intr_state & 3));
Assert(!(utcb->inj_info & 0x80000000));
if (unmap) {
PERR("unmap not implemented\n");
/* deadlock until implemented */
_signal_vcpu.lock();
Nova::reply(myself->stack_top());
Nova::reply(reinterpret_cast<void *>(&stack_top));
}
Flexpage_iterator fli;
@ -159,26 +176,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
}
/* emulator has to take over if fault region is not ram */
if (!pv) {
/* tell caller what happened */
_current_exit_cond = NPT_EPT;
PVMCPU pVCpu = _current_vcpu;
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
fpu_save(reinterpret_cast<char *>(&pCtx->fpu));
/* unblock caller */
_signal_emt.unlock();
/* block myself */
_signal_vcpu.lock();
fpu_load(reinterpret_cast<char *>(&pCtx->fpu));
utcb->mtd |= Mtd::FPU;
Nova::reply(myself->stack_top());
}
if (!pv)
longjmp(_env, 1);
/* fault region is ram - so map it */
enum {
@ -210,7 +209,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
res = utcb->append_item(crd, flexpage.hotspot, USER_PD, GUEST_PGT);
} while (res);
Nova::reply(myself->stack_top());
Nova::reply(reinterpret_cast<void *>(&stack_top));
}
/**
@ -396,7 +395,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
}
inline void inj_event(Nova::Utcb * utcb, PVMCPU pVCpu)
inline bool inj_event(Nova::Utcb * utcb, PVMCPU pVCpu)
{
PCPUMCTX const pCtx = CPUMQueryGuestCtxPtr(pVCpu);
@ -409,7 +408,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
if (VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC))) {
if (!(utcb->flags & X86_EFL_IF)) {
if (!(pCtx->rflags.u & X86_EFL_IF)) {
unsigned vector = 0;
utcb->inj_info = 0x1000 | vector;
@ -430,9 +429,9 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
}
/* can an interrupt be dispatched ? */
if (!TRPMHasTrap(pVCpu) || !(utcb->flags & X86_EFL_IF) ||
if (!TRPMHasTrap(pVCpu) || !(pCtx->rflags.u & X86_EFL_IF) ||
VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
return;
return false;
#ifdef VBOX_STRICT
if (TRPMHasTrap(pVCpu)) {
@ -472,20 +471,44 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
utcb->inj_error = Event.n.u32ErrorCode;
utcb->mtd |= Nova::Mtd::INJ;
/*
PDBG("type:info:vector %x:%x:%x",
Vmm::printf("type:info:vector %x:%x:%x\n",
Event.n.u3Type, utcb->inj_info, u8Vector);
*/
return true;
}
inline void irq_win(Nova::Utcb * utcb, PVMCPU pVCpu)
inline bool irq_win(Nova::Utcb * utcb)
{
Assert(utcb->flags & X86_EFL_IF);
Assert(!(VMCPU_FF_ISSET(_current_vcpu, VMCPU_FF_INHIBIT_INTERRUPTS)));
Nova::mword_t const mtd = Nova::Mtd::INJ;
utcb->mtd = ~mtd;
uint32_t check_vm = VM_FF_HWACCM_TO_R3_MASK | VM_FF_REQUEST
| VM_FF_PGM_POOL_FLUSH_PENDING
| VM_FF_PDM_DMA;
uint32_t check_vcpu = VMCPU_FF_HWACCM_TO_R3_MASK
| VMCPU_FF_PGM_SYNC_CR3
| VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
| VMCPU_FF_REQUEST;
if (VM_FF_ISPENDING(_current_vm, check_vm)
|| VMCPU_FF_ISPENDING(_current_vcpu, check_vcpu))
{
Assert(VM_FF_ISPENDING(_current_vm, VM_FF_HWACCM_TO_R3_MASK) ||
VMCPU_FF_ISPENDING(_current_vcpu,
VMCPU_FF_HWACCM_TO_R3_MASK));
Assert(!(RT_UNLIKELY(VM_FF_ISPENDING(_current_vm,
VM_FF_PGM_NO_MEMORY))));
return false;
}
/* Is in Realmode ? */
if (!(utcb->cr0 & X86_CR0_PE))
return false;
return true;
}
virtual bool hw_load_state(Nova::Utcb *, VM *, PVMCPU) = 0;
@ -505,21 +528,16 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
};
Vcpu_handler()
Vcpu_handler(size_t stack_size, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
:
Vmm::Vcpu_dispatcher<Genode::Thread_base>(STACK_SIZE,
_cap_connection),
_ec_sel(Genode::cap_map()->insert()),
_lock_startup(Genode::Lock::LOCKED),
_signal_emt(Genode::Lock::LOCKED),
_signal_vcpu(Genode::Lock::LOCKED)
Vmm::Vcpu_dispatcher<pthread>(stack_size, _cap_connection,
attr ? *attr : 0, start_routine, arg),
_ec_sel(Genode::cap_map()->insert())
{ }
void start() {
_vcpu.start(_ec_sel);
/* wait until vCPU thread is up */
_lock_startup.lock();
}
void recall()
@ -623,23 +641,28 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(Thread_base::utcb());
Assert(Thread_base::utcb() == Thread_base::myself()->utcb());
/* take the utcb state prepared during the last exit */
utcb->mtd = next_utcb.mtd;
utcb->intr_state = next_utcb.intr_state;
utcb->actv_state = 0; /* XXX */
utcb->ctrl[0] = next_utcb.ctrl[0];
utcb->ctrl[1] = next_utcb.ctrl[1];
using namespace Nova;
Genode::Thread_base *myself = Genode::Thread_base::myself();
/* check whether to inject interrupts */
inj_event(utcb, pVCpu);
/* Transfer vCPU state from vBox to Nova format */
if (!vbox_to_utcb(utcb, pVM, pVCpu) ||
!hw_load_state(utcb, pVM, pVCpu)) {
PERR("loading vCPU state failed");
/* deadlock here */
_signal_emt.lock();
return VERR_INTERNAL_ERROR;
}
/* check whether to inject interrupts */
inj_event(utcb, pVCpu);
ResumeExecution:
/*
* Flag vCPU to be "pokeable" by external events such as interrupts
* from virtual devices. Only if this flag is set, the
@ -649,17 +672,24 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
*/
VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
this->_current_vm = pVM;
this->_current_vcpu = pVCpu;
/* write FPU state from pCtx to vCPU */
fpu_load(reinterpret_cast<char *>(&pCtx->fpu));
/* let vCPU run */
_signal_vcpu.unlock();
utcb->mtd |= Mtd::FPU;
/* waiting to be woken up */
_signal_emt.lock();
_current_vm = pVM;
_current_vcpu = pVCpu;
this->_current_vm = 0;
this->_current_vcpu = 0;
/* switch to hardware accelerated mode */
switch_to_hw(pCtx);
Assert(utcb->actv_state == 0);
_current_vm = 0;
_current_vcpu = 0;
/* write FPU state of vCPU to pCtx */
fpu_save(reinterpret_cast<char *>(&pCtx->fpu));
// CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
@ -668,89 +698,23 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread_base>
/* Transfer vCPU state from Nova to vBox format */
if (!utcb_to_vbox(utcb, pVM, pVCpu) ||
!hw_save_state(utcb, pVM, pVCpu)) {
PERR("saving vCPU state failed");
/* deadlock here */
_signal_emt.lock();
return VERR_INTERNAL_ERROR;
}
/* reset message transfer descriptor for next invocation */
utcb->mtd = 0;
next_utcb.mtd = 0;
next_utcb.intr_state = utcb->intr_state;
next_utcb.ctrl[0] = utcb->ctrl[0];
next_utcb.ctrl[1] = utcb->ctrl[1];
if (utcb->intr_state & 3) {
/*
PDBG("reset intr_state - exit reason %u", _current_exit_cond);
*/
utcb->intr_state &= ~3;
utcb->mtd |= Mtd::STA;
if (next_utcb.intr_state & 3) {
next_utcb.intr_state &= ~3U;
next_utcb.mtd |= Mtd::STA;
}
switch (_current_exit_cond)
{
case RECALL:
case VMX_EXIT_EPT_VIOLATION:
case VMX_EXIT_PORT_IO:
case VMX_EXIT_ERR_INVALID_GUEST_STATE:
case VMX_EXIT_HLT:
case SVM_EXIT_IOIO:
case SVM_NPT:
case SVM_EXIT_HLT:
case SVM_INVALID:
case SVM_EXIT_MSR:
case EMULATE_INSTR:
return VINF_EM_RAW_EMULATE_INSTR;
case SVM_EXIT_VINTR:
case VMX_EXIT_IRQ_WINDOW:
{
if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)) {
if (pCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
PERR("inhibit interrupts %x %x", pCtx->rip, EMGetInhibitInterruptsPC(pVCpu));
}
uint32_t check_vm = VM_FF_HWACCM_TO_R3_MASK | VM_FF_REQUEST
| VM_FF_PGM_POOL_FLUSH_PENDING
| VM_FF_PDM_DMA;
uint32_t check_vcpu = VMCPU_FF_HWACCM_TO_R3_MASK
| VMCPU_FF_PGM_SYNC_CR3
| VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
| VMCPU_FF_REQUEST;
if (VM_FF_ISPENDING(pVM, check_vm)
|| VMCPU_FF_ISPENDING(pVCpu, check_vcpu))
{
Assert(VM_FF_ISPENDING(pVM, VM_FF_HWACCM_TO_R3_MASK) ||
VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HWACCM_TO_R3_MASK));
if (RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)))
{
PERR(" no memory");
while (1) {}
}
// PERR(" em raw to r3");
return VINF_EM_RAW_TO_R3;
}
if ((utcb->intr_state & 3))
PERR("irq window with intr_state %x", utcb->intr_state);
irq_win(utcb, pVCpu);
goto ResumeExecution;
}
default:
PERR("unknown exit cond:ip:qual[0],[1] %lx:%lx:%llx:%llx",
_current_exit_cond, utcb->ip, utcb->qual[0], utcb->qual[1]);
while (1) {}
}
return VERR_INTERNAL_ERROR;
return VINF_EM_RAW_EMULATE_INSTR;
}
};

View File

@ -19,25 +19,10 @@ class Vcpu_handler_svm : public Vcpu_handler
{
private:
__attribute__((noreturn)) void _svm_default() { _default_handler(); }
__attribute__((noreturn)) void _svm_vintr() {
_default_handler(SVM_EXIT_VINTR);
}
__attribute__((noreturn)) void _svm_rdtsc() {
_default_handler(SVM_EXIT_RDTSC);
}
__attribute__((noreturn)) void _svm_msr() {
_default_handler(SVM_EXIT_MSR);
}
__attribute__((noreturn)) void _svm_recall()
{
_default_handler(SVM_INVALID);
}
__attribute__((noreturn)) void _svm_halt()
{
_default_handler(SVM_EXIT_HLT);
_irq_window(SVM_EXIT_VINTR);
}
__attribute__((noreturn)) void _svm_ioio()
@ -53,18 +38,14 @@ class Vcpu_handler_svm : public Vcpu_handler
PERR("invalid gueststate");
/* deadlock here */
_signal_vcpu.lock();
utcb->ctrl[0] = ctrl0;
utcb->ctrl[1] = 0;
utcb->mtd = Mtd::CTRL;
Nova::reply(myself->stack_top());
Nova::reply(_stack_reply);
}
_default_handler(SVM_EXIT_IOIO);
_default_handler();
}
template <unsigned X>
@ -84,40 +65,43 @@ class Vcpu_handler_svm : public Vcpu_handler
{
using namespace Nova;
Genode::Thread_base *myself = Genode::Thread_base::myself();
Utcb *utcb = reinterpret_cast<Utcb *>(myself->utcb());
/* enable VM exits for CPUID */
next_utcb.mtd = Nova::Mtd::CTRL;
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_CPUID;
next_utcb.ctrl[1] = 0;
/* we are ready, unlock our creator */
_lock_startup.unlock();
void *exit_status = _start_routine(_arg);
pthread_exit(exit_status);
/* wait until EMT thread say so */
_signal_vcpu.lock();
Nova::reply(myself->stack_top());
Nova::reply(nullptr);
}
public:
Vcpu_handler_svm()
Vcpu_handler_svm(size_t stack_size, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
: Vcpu_handler(stack_size, attr, start_routine, arg)
{
using namespace Nova;
typedef Vcpu_handler_svm This;
register_handler<RECALL, This,
&This::_svm_recall>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
&This::_svm_default>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_IOIO, This,
&This::_svm_ioio> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_VINTR, This,
&This::_svm_vintr> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_RDTSC, This,
&This::_svm_rdtsc> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
&This::_svm_default> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_MSR, This,
&This::_svm_msr> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
&This::_svm_default> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_NPT, This,
&This::_svm_npt<SVM_NPT>>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_HLT, This,
&This::_svm_halt>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
&This::_svm_default>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_CPUID, This,
&This::_svm_default> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
register_handler<VCPU_STARTUP, This,
&This::_svm_startup>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));

View File

@ -40,36 +40,24 @@ class Vcpu_handler_vmx : public Vcpu_handler
utcb->qual[1] & ~((1UL << 12) - 1));
}
__attribute__((noreturn)) void _vmx_default() { _default_handler(); }
__attribute__((noreturn)) void _vmx_startup()
{
Vmm::printf("%s\n", __func__);
using namespace Nova;
Genode::Thread_base *myself = Genode::Thread_base::myself();
Utcb *utcb = reinterpret_cast<Utcb *>(myself->utcb());
/* we are ready, unlock our creator */
_lock_startup.unlock();
/* wait until EMT thread say so */
_signal_vcpu.lock();
/* avoid as many as possible VM exits */
utcb->mtd |= Mtd::CTRL;
utcb->ctrl[0] = 0;
utcb->ctrl[1] = 0;
next_utcb.mtd = Nova::Mtd::CTRL;
next_utcb.ctrl[0] = 0;
next_utcb.ctrl[1] = 0;
Nova::reply(myself->stack_top());
}
void *exit_status = _start_routine(_arg);
pthread_exit(exit_status);
__attribute__((noreturn)) void _vmx_recall()
{
_default_handler(RECALL);
}
__attribute__((noreturn)) void _vmx_pause()
{
_default_handler(EMULATE_INSTR);
Nova::reply(nullptr);
}
__attribute__((noreturn)) void _vmx_triple()
@ -79,64 +67,19 @@ class Vcpu_handler_vmx : public Vcpu_handler
Vmm::printf("triple fault - dead\n");
_signal_vcpu.lock();
_default_handler(EMULATE_INSTR);
}
__attribute__((noreturn)) void _vmx_msr_write()
{
_default_handler(EMULATE_INSTR);
}
__attribute__((noreturn)) void _vmx_msr_read()
{
_default_handler(EMULATE_INSTR);
}
__attribute__((noreturn)) void _vmx_ioio()
{
_default_handler(VMX_EXIT_PORT_IO);
}
__attribute__((noreturn)) void _vmx_invalid()
{
_default_handler(VMX_EXIT_ERR_INVALID_GUEST_STATE);
}
__attribute__((noreturn)) void _vmx_init()
{
_default_handler(EMULATE_INSTR);
_default_handler();
}
__attribute__((noreturn)) void _vmx_irqwin()
{
_default_handler(VMX_EXIT_IRQ_WINDOW);
}
__attribute__((noreturn)) void _vmx_hlt()
{
_default_handler(VMX_EXIT_HLT);
}
__attribute__((noreturn)) void _vmx_cpuid()
{
_default_handler(EMULATE_INSTR);
}
__attribute__((noreturn)) void _vmx_rdtsc()
{
_default_handler(EMULATE_INSTR);
}
__attribute__((noreturn)) void _vmx_vmcall()
{
_default_handler(EMULATE_INSTR);
_irq_window(VMX_EXIT_IRQ_WINDOW);
}
public:
Vcpu_handler_vmx()
Vcpu_handler_vmx(size_t stack_size, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
: Vcpu_handler(stack_size, attr, start_routine, arg)
{
using namespace Nova;
@ -147,32 +90,33 @@ class Vcpu_handler_vmx : public Vcpu_handler
register_handler<VMX_EXIT_TRIPLE_FAULT, This,
&This::_vmx_triple> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_INIT_SIGNAL, This,
&This::_vmx_init> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_IRQ_WINDOW, This,
&This::_vmx_irqwin> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_CPUID, This,
&This::_vmx_cpuid> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_HLT, This,
&This::_vmx_hlt> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_RDTSC, This,
&This::_vmx_rdtsc> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_VMCALL, This,
&This::_vmx_vmcall> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_PORT_IO, This,
&This::_vmx_ioio> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_RDMSR, This,
&This::_vmx_msr_read> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_WRMSR, This,
&This::_vmx_msr_write> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_ERR_INVALID_GUEST_STATE, This,
&This::_vmx_invalid> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_PAUSE, This,
&This::_vmx_pause> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_EPT_VIOLATION, This,
&This::_vmx_ept<VMX_EXIT_EPT_VIOLATION>> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VCPU_STARTUP, This, &This::_vmx_startup>
(exc_base, Mtd::ALL | Mtd::FPU);
register_handler<RECALL, This, &This::_vmx_recall> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VCPU_STARTUP, This,
&This::_vmx_startup> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<RECALL, This,
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
start();
}

View File

@ -28,6 +28,14 @@
extern "C" {
/**
* Returns true if a vCPU could be started. If false we run without
* hardware acceleration support.
*/
bool create_emt_vcpu(pthread_t * pthread, size_t stack,
const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
{
@ -45,6 +53,13 @@ extern "C" {
"limit to %zu Bytes", rtthread->szName, rtthread->cbStack,
stack_size);
if (rtthread->enmType == RTTHREADTYPE_EMULATION) {
if (create_emt_vcpu(thread, stack_size, attr, start_routine, arg))
return 0;
/* no haredware support, create normal pthread thread */
}
pthread_t thread_obj = new (Genode::env()->heap())
pthread(attr ? *attr : 0, start_routine,
arg, stack_size, rtthread->szName, nullptr);