From 0ddc69d37067fe385d5507b5665be609e4fae6dc Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 24 Apr 2014 10:55:09 +0200 Subject: [PATCH] vbox: join emt and vcpu handler thread Fixes #1129 --- ports/lib/mk/nova/virtualbox-hwaccl.mk | 1 + ports/src/virtualbox/accloff/sup.cc | 20 +- ports/src/virtualbox/nova/sup.cc | 168 ++++++-------- ports/src/virtualbox/nova/vcpu.h | 304 +++++++++++-------------- ports/src/virtualbox/nova/vcpu_svm.h | 58 ++--- ports/src/virtualbox/nova/vcpu_vmx.h | 110 +++------ ports/src/virtualbox/thread.cc | 15 ++ 7 files changed, 282 insertions(+), 394 deletions(-) diff --git a/ports/lib/mk/nova/virtualbox-hwaccl.mk b/ports/lib/mk/nova/virtualbox-hwaccl.mk index e908edddb..2a71f7700 100644 --- a/ports/lib/mk/nova/virtualbox-hwaccl.mk +++ b/ports/lib/mk/nova/virtualbox-hwaccl.mk @@ -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 diff --git a/ports/src/virtualbox/accloff/sup.cc b/ports/src/virtualbox/accloff/sup.cc index 4138c24e8..9f7730539 100644 --- a/ports/src/virtualbox/accloff/sup.cc +++ b/ports/src/virtualbox/accloff/sup.cc @@ -25,6 +25,9 @@ #include "sup.h" #include "vmm_memory.h" +/* Libc include */ +#include + /* 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__); } diff --git a/ports/src/virtualbox/nova/sup.cc b/ports/src/virtualbox/nova/sup.cc index fd755eb35..3cac721a1 100644 --- a/ports/src/virtualbox/nova/sup.cc +++ b/ports/src/virtualbox/nova/sup.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -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(); 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(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(pVMR0); - SUPR3QueryHWACCLonGenodeSupport(pVM); - return VINF_SUCCESS; - } - case VMMR0_DO_HWACC_SETUP_VM: - { - VM * pVM = reinterpret_cast(pVMR0); - SUPR3QueryHWACCLonGenodeCreateVM(pVM); - return VINF_SUCCESS; - } - case VMMR0_DO_HWACC_ENABLE: - return VINF_SUCCESS; + case VMMR0_DO_VMMR0_INIT: + SUPR3QueryHWACCLonGenodeSupport(reinterpret_cast(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(); + + 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; +} diff --git a/ports/src/virtualbox/nova/vcpu.h b/ports/src/virtualbox/nova/vcpu.h index bb8ff46d5..35f8d256b 100644 --- a/ports/src/virtualbox/nova/vcpu.h +++ b/ports/src/virtualbox/nova/vcpu.h @@ -39,6 +39,12 @@ #include "guest_memory.h" #include "vmm_memory.h" +/* Genode libc pthread binding */ +#include "thread.h" + +/* LibC includes */ +#include + /* * 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 +class Vcpu_handler : public Vmm::Vcpu_dispatcher { 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(data) & 0xF)); asm volatile ("fxsave %0" : "=m" (*data)); @@ -82,41 +89,48 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher 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(&value - 1); + Nova::reply(_stack_reply); + } + } + + __attribute__((noreturn)) void _irq_window(unsigned cond) { - using namespace Nova; - using namespace Genode; + Nova::Utcb * utcb = reinterpret_cast(Thread_base::utcb()); - Thread_base *myself = Thread_base::myself(); - Utcb *utcb = reinterpret_cast(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(&pCtx->fpu)); - - /* unblock caller */ - _signal_emt.unlock(); - - /* block myself */ - _signal_vcpu.lock(); - - fpu_load(reinterpret_cast(&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 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(&stack_top)); } Flexpage_iterator fli; @@ -159,26 +176,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher } /* 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(&pCtx->fpu)); - - /* unblock caller */ - _signal_emt.unlock(); - - /* block myself */ - _signal_vcpu.lock(); - - fpu_load(reinterpret_cast(&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 res = utcb->append_item(crd, flexpage.hotspot, USER_PD, GUEST_PGT); } while (res); - Nova::reply(myself->stack_top()); + Nova::reply(reinterpret_cast(&stack_top)); } /** @@ -396,7 +395,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher } - 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 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 } /* 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 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 }; - Vcpu_handler() + Vcpu_handler(size_t stack_size, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg) : - Vmm::Vcpu_dispatcher(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(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 Nova::Utcb *utcb = reinterpret_cast(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 */ 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(&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(&pCtx->fpu)); // CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH); @@ -668,89 +698,23 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher /* 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; } }; diff --git a/ports/src/virtualbox/nova/vcpu_svm.h b/ports/src/virtualbox/nova/vcpu_svm.h index 62237a955..77a45b6ae 100644 --- a/ports/src/virtualbox/nova/vcpu_svm.h +++ b/ports/src/virtualbox/nova/vcpu_svm.h @@ -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 @@ -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(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(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); + &This::_svm_default>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); + &This::_svm_default> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); + &This::_svm_default> (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); + &This::_svm_default>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); + register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); register_handler(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU)); diff --git a/ports/src/virtualbox/nova/vcpu_vmx.h b/ports/src/virtualbox/nova/vcpu_vmx.h index fcb04d27b..c8b63cd71 100644 --- a/ports/src/virtualbox/nova/vcpu_vmx.h +++ b/ports/src/virtualbox/nova/vcpu_vmx.h @@ -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(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 (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler (exc_base, Mtd::ALL | Mtd::FPU); + &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU); register_handler> (exc_base, Mtd::ALL | Mtd::FPU); - register_handler - (exc_base, Mtd::ALL | Mtd::FPU); - register_handler (exc_base, Mtd::ALL | Mtd::FPU); + register_handler (exc_base, Mtd::ALL | Mtd::FPU); + register_handler (exc_base, Mtd::ALL | Mtd::FPU); start(); } diff --git a/ports/src/virtualbox/thread.cc b/ports/src/virtualbox/thread.cc index b6bdb6702..2010be741 100644 --- a/ports/src/virtualbox/thread.cc +++ b/ports/src/virtualbox/thread.cc @@ -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);