mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-11 11:51:46 +00:00
vbox: save the guest FPU state before 'longjmp()'
'longjmp()' restores the (partial) FPU state saved by 'setjmp()', so it's necessary to save the guest FPU state before calling 'longjmp()'. Fixes #1282
This commit is contained in:
parent
6afba00ad6
commit
e3fa8c9f22
@ -73,7 +73,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
X86FXSTATE _fpu_state __attribute__((aligned(0x10)));
|
X86FXSTATE _guest_fpu_state __attribute__((aligned(0x10)));
|
||||||
|
X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10)));
|
||||||
|
|
||||||
Genode::Cap_connection _cap_connection;
|
Genode::Cap_connection _cap_connection;
|
||||||
Vmm::Vcpu_other_pd _vcpu;
|
Vmm::Vcpu_other_pd _vcpu;
|
||||||
@ -107,6 +108,16 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
INTERRUPT_STATE_NONE = 0U,
|
INTERRUPT_STATE_NONE = 0U,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* '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<char *>(&_guest_fpu_state));
|
||||||
|
longjmp(_env, 1);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -120,7 +131,8 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
void * _stack_reply;
|
void * _stack_reply;
|
||||||
jmp_buf _env;
|
jmp_buf _env;
|
||||||
|
|
||||||
void switch_to_hw(PCPUMCTX pCtx) {
|
void switch_to_hw()
|
||||||
|
{
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
|
|
||||||
if (!setjmp(_env)) {
|
if (!setjmp(_env)) {
|
||||||
@ -129,7 +141,6 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void _default_handler()
|
__attribute__((noreturn)) void _default_handler()
|
||||||
{
|
{
|
||||||
Nova::Utcb * utcb = reinterpret_cast<Nova::Utcb *>(Thread_base::utcb());
|
Nova::Utcb * utcb = reinterpret_cast<Nova::Utcb *>(Thread_base::utcb());
|
||||||
@ -138,7 +149,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
Assert(!(utcb->inj_info & IRQ_INJ_VALID_MASK));
|
Assert(!(utcb->inj_info & IRQ_INJ_VALID_MASK));
|
||||||
|
|
||||||
/* go back to re-compiler */
|
/* go back to re-compiler */
|
||||||
longjmp(_env, 1);
|
_fpu_save_and_longjmp();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void _recall_handler()
|
__attribute__((noreturn)) void _recall_handler()
|
||||||
@ -162,7 +173,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
/* are we forced to go back to emulation mode ? */
|
/* are we forced to go back to emulation mode ? */
|
||||||
if (!continue_hw_accelerated(utcb))
|
if (!continue_hw_accelerated(utcb))
|
||||||
/* go back to emulation mode */
|
/* go back to emulation mode */
|
||||||
longjmp(_env, 1);
|
_fpu_save_and_longjmp();
|
||||||
|
|
||||||
/* check whether we have to request irq injection window */
|
/* check whether we have to request irq injection window */
|
||||||
utcb->mtd = 0;
|
utcb->mtd = 0;
|
||||||
@ -216,7 +227,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
|
|
||||||
/* emulator has to take over if fault region is not ram */
|
/* emulator has to take over if fault region is not ram */
|
||||||
if (!pv)
|
if (!pv)
|
||||||
longjmp(_env, 1);
|
_fpu_save_and_longjmp();
|
||||||
|
|
||||||
/* fault region is ram - so map it */
|
/* fault region is ram - so map it */
|
||||||
enum {
|
enum {
|
||||||
@ -675,7 +686,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
|
VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
|
||||||
|
|
||||||
/* save current FPU state */
|
/* save current FPU state */
|
||||||
fpu_save(reinterpret_cast<char *>(&_fpu_state));
|
fpu_save(reinterpret_cast<char *>(&_emt_fpu_state));
|
||||||
/* write FPU state from pCtx to FPU registers */
|
/* write FPU state from pCtx to FPU registers */
|
||||||
fpu_load(reinterpret_cast<char *>(&pCtx->fpu));
|
fpu_load(reinterpret_cast<char *>(&pCtx->fpu));
|
||||||
/* tell kernel to transfer current fpu registers to vCPU */
|
/* tell kernel to transfer current fpu registers to vCPU */
|
||||||
@ -685,7 +696,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
_current_vcpu = pVCpu;
|
_current_vcpu = pVCpu;
|
||||||
|
|
||||||
/* switch to hardware accelerated mode */
|
/* switch to hardware accelerated mode */
|
||||||
switch_to_hw(pCtx);
|
switch_to_hw();
|
||||||
|
|
||||||
Assert(utcb->actv_state == ACTIVITY_STATE_ACTIVE);
|
Assert(utcb->actv_state == ACTIVITY_STATE_ACTIVE);
|
||||||
|
|
||||||
@ -693,9 +704,10 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
|
|||||||
_current_vcpu = 0;
|
_current_vcpu = 0;
|
||||||
|
|
||||||
/* write FPU state of vCPU (in current FPU registers) to pCtx */
|
/* write FPU state of vCPU (in current FPU registers) to pCtx */
|
||||||
fpu_save(reinterpret_cast<char *>(&pCtx->fpu));
|
Genode::memcpy(&pCtx->fpu, &_guest_fpu_state, sizeof(X86FXSTATE));
|
||||||
|
|
||||||
/* load saved FPU state of EMT thread */
|
/* load saved FPU state of EMT thread */
|
||||||
fpu_load(reinterpret_cast<char *>(&_fpu_state));
|
fpu_load(reinterpret_cast<char *>(&_emt_fpu_state));
|
||||||
|
|
||||||
// CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
|
// CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user