From c9b5dcafbd77cb0ed067ee1986228ce230208b89 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Mon, 29 Apr 2019 17:43:45 +0200 Subject: [PATCH] vbox: save FPU state in 'EPT violation' exit handler Fixes #3359 --- repos/ports/src/virtualbox5/spec/nova/vcpu.h | 44 +++++++++++++++---- .../src/virtualbox5/spec/nova/vcpu_svm.h | 7 ++- .../src/virtualbox5/spec/nova/vcpu_vmx.h | 16 ++++--- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu.h b/repos/ports/src/virtualbox5/spec/nova/vcpu.h index 36368edb94..5b67b949d1 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu.h @@ -124,22 +124,37 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, INTERRUPT_STATE_NONE = 0U, }; + protected: + + void _fpu_save() + { + fpu_save(reinterpret_cast(&_guest_fpu_state)); + } + + void _fpu_load() + { + fpu_load(reinterpret_cast(&_guest_fpu_state)); + } + + __attribute__((noreturn)) void _longjmp() + { + longjmp(_env, 1); + } + /* * 'longjmp()' restores some FPU registers saved by 'setjmp()', * so we need to save the guest FPU state before calling 'longjmp()' */ __attribute__((noreturn)) void _fpu_save_and_longjmp() { - fpu_save(reinterpret_cast(&_guest_fpu_state)); - longjmp(_env, 1); + _fpu_save(); + _longjmp(); } int map_memory(RTGCPHYS GCPhys, size_t cbWrite, RTGCUINT vbox_fault_reason, Genode::Flexpage_iterator &fli, bool &writeable); - protected: - Genode::addr_t _vm_exits = 0; Genode::addr_t _recall_skip = 0; Genode::addr_t _recall_req = 0; @@ -170,6 +185,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, if (!setjmp(_env)) { _stack_reply = reinterpret_cast( Abi::stack_align(reinterpret_cast(&value))); + _fpu_load(); Nova::reply(_stack_reply); } } @@ -211,19 +227,21 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, /* got recall during irq injection and the guest is ready for * delivery of IRQ - just continue */ + _fpu_load(); Nova::reply(_stack_reply); } /* are we forced to go back to emulation mode ? */ if (!continue_hw_accelerated(utcb)) { /* go back to emulation mode */ - _fpu_save_and_longjmp(); + _longjmp(); } /* check whether we have to request irq injection window */ utcb->mtd = Nova::Mtd::FPU; if (check_to_request_irq_window(utcb, _current_vcpu)) { _irq_win = true; + _fpu_load(); Nova::reply(_stack_reply); } @@ -239,8 +257,10 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, utcb->mtd = Nova::Mtd::FPU; _irq_win = check_to_request_irq_window(utcb, _current_vcpu); - if (_irq_win) + if (_irq_win) { + _fpu_load(); Nova::reply(_stack_reply); + } } /* nothing to do at all - continue hardware accelerated */ @@ -262,6 +282,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, utcb->mtd |= Nova::Mtd::INJ; } + _fpu_load(); Nova::reply(_stack_reply); } @@ -281,6 +302,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, Nova::reply(_stack_reply); } + _fpu_save(); + enum { MAP_SIZE = 0x1000UL }; bool writeable = true; @@ -298,7 +321,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, /* event re-injection is not handled yet for this case */ Assert(!(utcb->inj_info & IRQ_INJ_VALID_MASK)); - _fpu_save_and_longjmp(); + _longjmp(); } /* fault region can be mapped - prepare utcb */ @@ -347,6 +370,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, "guestf fault at ", Genode::Hex(guest_fault)); } while (res); + _fpu_load(); + Nova::reply(_stack_reply); } @@ -656,6 +681,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, /* happens if PDMApicSetTPR (see above) mask IRQ */ utcb->inj_info = IRQ_INJ_NONE; utcb->mtd = Nova::Mtd::INJ | Nova::Mtd::FPU; + + _fpu_load(); Nova::reply(_stack_reply); } } @@ -707,6 +734,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, Genode::Hex(utcb->mtd)); */ utcb->mtd = Nova::Mtd::INJ | Nova::Mtd::FPU; + _fpu_load(); Nova::reply(_stack_reply); } @@ -911,7 +939,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, /* save current FPU state */ fpu_save(reinterpret_cast(&_emt_fpu_state)); /* write FPU state from pCtx to FPU registers */ - fpu_load(reinterpret_cast(pCtx->pXStateR3)); + memcpy(&_guest_fpu_state, pCtx->pXStateR3, sizeof(_guest_fpu_state)); /* tell kernel to transfer current fpu registers to vCPU */ utcb->mtd |= Mtd::FPU; diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu_svm.h b/repos/ports/src/virtualbox5/spec/nova/vcpu_svm.h index 35da7ae287..77f94b4380 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu_svm.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu_svm.h @@ -24,7 +24,11 @@ class Vcpu_handler_svm : public Vcpu_handler __attribute__((noreturn)) void _svm_default() { _default_handler(); } - __attribute__((noreturn)) void _svm_vintr() { _irq_window(); } + __attribute__((noreturn)) void _svm_vintr() + { + _fpu_save(); + _irq_window(); + } __attribute__((noreturn)) void _svm_ioio() { @@ -79,6 +83,7 @@ class Vcpu_handler_svm : public Vcpu_handler __attribute__((noreturn)) void _svm_recall() { + _fpu_save(); Vcpu_handler::_recall_handler(); } diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu_vmx.h b/repos/ports/src/virtualbox5/spec/nova/vcpu_vmx.h index 9e25b244ce..a16ab35714 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu_vmx.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu_vmx.h @@ -105,10 +105,15 @@ class Vcpu_handler_vmx : public Vcpu_handler exit(-1); } - __attribute__((noreturn)) void _vmx_irqwin() { _irq_window(); } + __attribute__((noreturn)) void _vmx_irqwin() + { + _fpu_save(); + _irq_window(); + } __attribute__((noreturn)) void _vmx_recall() { + _fpu_save(); Vcpu_handler::_recall_handler(); } @@ -140,8 +145,7 @@ class Vcpu_handler_vmx : public Vcpu_handler */ __attribute__((noreturn)) void _vmx_mov_crx() { - unsigned long value; - void *stack_reply = reinterpret_cast(&value - 1); + _fpu_save(); Genode::Thread *myself = Genode::Thread::myself(); Nova::Utcb *utcb = reinterpret_cast(myself->utcb()); @@ -149,7 +153,7 @@ class Vcpu_handler_vmx : public Vcpu_handler unsigned int cr = utcb->qual[0] & 0xf; if (cr == 8) - _default_handler(); + _longjmp(); _vm_exits ++; @@ -164,7 +168,9 @@ class Vcpu_handler_vmx : public Vcpu_handler utcb->mtd = Nova::Mtd::PDPTE | Nova::Mtd::FPU; - Nova::reply(stack_reply); + _fpu_load(); + + Nova::reply(_stack_reply); } public: