CPUMR0A.asm revision aae8a6a38fd27661046ab1d06cb2cb5c096c40ed
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; CPUM - Guest Context Assembly Routines.
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; Copyright (C) 2006-2015 Oracle Corporation
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; This file is part of VirtualBox Open Source Edition (OSE), as
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; available from http://www.virtualbox.org. This file is free software;
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; you can redistribute it and/or modify it under the terms of the GNU
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; General Public License (GPL) as published by the Free Software
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; Foundation, in version 2 as it comes in the "COPYING" file of the
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;* Header Files *
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%ifdef IN_RING3
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync %error "The jump table doesn't link on leopard."
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;* Defined Constants And Macros *
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;; The offset of the XMM registers in X86FXSTATE.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; Use define because I'm too lazy to convert the struct.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%define XMM_OFF_IN_X86FXSTATE 160
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%define IP_OFF_IN_X86FXSTATE 08h
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%define CS_OFF_IN_X86FXSTATE 0ch
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%define DS_OFF_IN_X86FXSTATE 14h
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;* External Symbols *
4e46eee5a96078ebec6cb36939b794a391f1ade0vboxsync;*******************************************************************************
4e46eee5a96078ebec6cb36939b794a391f1ade0vboxsync%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
4e46eee5a96078ebec6cb36939b794a391f1ade0vboxsyncextern NAME(SUPR0AbsIs64bit)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsyncextern NAME(SUPR0Abs64bitKernelCS)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsyncextern NAME(SUPR0Abs64bitKernelSS)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsyncextern NAME(SUPR0Abs64bitKernelDS)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsyncextern NAME(SUPR0AbsKernelCS)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;* Global Variables *
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;*******************************************************************************
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
e06cbb510db6f327856cabc016398e4fda505809vboxsync; Store the SUPR0AbsIs64bit absolute value here so we can cmp/test without
e06cbb510db6f327856cabc016398e4fda505809vboxsync; needing to clobber a register. (This trick doesn't quite work for PE btw.
4896726d903f56fe43eb13e2ba27ae1d63b8c40evboxsync; but that's not relevant atm.)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsyncGLOBALNAME g_fCPUMIs64bitHost
4896726d903f56fe43eb13e2ba27ae1d63b8c40evboxsync dd NAME(SUPR0AbsIs64bit)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;; Macro for FXSAVE/FXRSTOR leaky behaviour on AMD CPUs, see cpumR3CheckLeakyFpu().
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; Cleans the FPU state, if necessary, before restoring the FPU.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; This macro ASSUMES CR0.TS is not set!
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; @remarks Trashes xAX!!
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; Changes here should also be reflected in CPUMRCA.asm's copy!
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%macro CLEANFPU 0
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync test dword [xDX + CPUMCPU.fUseFlags], CPUM_USE_FFXSR_LEAKY
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync jz .nothing_to_clean
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync xor eax, eax
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync fnstsw ax ; Get FSW
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync test eax, RT_BIT(7) ; If FSW.ES (bit 7) is set, clear it to not cause FPU exceptions
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; while clearing & loading the FPU bits in 'clean_fpu'
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync jz .clean_fpu
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ffree st7 ; Clear FPU stack register(7)'s tag entry to prevent overflow if a wraparound occurs
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; for the upcoming push (load)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync fild dword [xDX + CPUMCPU.Guest.fpu] ; Explicit FPU load to overwrite FIP, FOP, FDP registers in the FPU.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync.nothing_to_clean:
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync;; Macro for FXSAVE for the guest FPU but tries to figure out whether to
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; save the 32-bit FPU state or 64-bit FPU state.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync; @remarks Requires CPUMCPU pointer in RDX
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%macro SAVE_32_OR_64_FPU 0
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync o64 fxsave [rdx + CPUMCPU.Guest.fpu]
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; Shouldn't be necessary to check if the entire 64-bit FIP is 0 (i.e. guest hasn't used its FPU yet) because it should
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; be taken care of by the calling code, i.e. hmR0[Vmx|Svm]LoadSharedCR0() and hmR0[Vmx|Svm]ExitXcptNm() which ensure
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; we swap the guest FPU state when it starts using it (#NM). In any case it's only a performance optimization.
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; cmp qword [rdx + CPUMCPU.Guest.fpu + IP_OFF_IN_X86FXSTATE], 0
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync ; je short %%save_done
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync cmp dword [rdx + CPUMCPU.Guest.fpu + CS_OFF_IN_X86FXSTATE], 0
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync jne short %%save_done
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync sub rsp, 20h ; Only need 1ch bytes but keep stack aligned otherwise we #GP(0)
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync fnstenv [rsp]
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync movzx eax, word [rsp + 10h]
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync mov [rdx + CPUMCPU.Guest.fpu + CS_OFF_IN_X86FXSTATE], eax
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync movzx eax, word [rsp + 18h]
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync mov [rdx + CPUMCPU.Guest.fpu + DS_OFF_IN_X86FXSTATE], eax
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync add rsp, 20h
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync mov dword [rdx + CPUMCPU.Guest.fpu + X86_OFF_FXSTATE_RSVD], X86_FXSTATE_RSVD_32BIT_MAGIC
9e201d78ac6efdd08550263f2e146cdb76e9d49bvboxsync%%save_done:
cmp dword [rdx + CPUMCPU.Guest.fpu + X86_OFF_FXSTATE_RSVD], X86_FXSTATE_RSVD_32BIT_MAGIC
fxrstor [rdx + CPUMCPU.Guest.fpu]
o64 fxrstor [rdx + CPUMCPU.Guest.fpu]
; Saves the host FPU/XMM state and restores the guest state.
cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
or dword [xDX + CPUMCPU.fUseFlags], (CPUM_USED_FPU | CPUM_USED_FPU_SINCE_REM)
o64 fxsave [rdx + CPUMCPU.Host.fpu] ; ASSUMES that all VT-x/AMD-V boxes sports fxsave/fxrstor (safe assumption)
test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
fxrstor [rdx + CPUMCPU.Guest.fpu]
fxsave [edx + CPUMCPU.Host.fpu] ; ASSUMES that all VT-x/AMD-V boxes sports fxsave/fxrstor (safe assumption)
fxrstor [edx + CPUMCPU.Guest.fpu]
lea r11, [xDX + CPUMCPU.Host.fpu + XMM_OFF_IN_X86FXSTATE]
o64 fxsave [rdx + CPUMCPU.Host.fpu]
test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
fxrstor [rdx + CPUMCPU.Guest.fpu]
; Saves the host FPU/XMM state
cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
or dword [xDX + CPUMCPU.fUseFlags], (CPUM_USED_FPU | CPUM_USED_FPU_SINCE_REM)
fxsave [xDX + CPUMCPU.Host.fpu] ; ASSUMES that all VT-x/AMD-V boxes support fxsave/fxrstor (safe assumption)
; Saves the guest FPU/XMM state and restores the host state.
test dword [xDX + CPUMCPU.fUseFlags], CPUM_USED_FPU
cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
fxsave [rdx + CPUMCPU.Guest.fpu]
o64 fxrstor [rdx + CPUMCPU.Host.fpu]
fxsave [edx + CPUMCPU.Guest.fpu] ; ASSUMES that all VT-x/AMD-V boxes support fxsave/fxrstor (safe assumption)
fxrstor [edx + CPUMCPU.Host.fpu]
and dword [xDX + CPUMCPU.fUseFlags], ~CPUM_USED_FPU
test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
fxsave [rdx + CPUMCPU.Guest.fpu]
o64 fxrstor [rdx + CPUMCPU.Host.fpu]
; Sets the host's FPU/XMM state
test dword [xDX + CPUMCPU.fUseFlags], CPUM_USED_FPU
cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
o64 fxrstor [xDX + CPUMCPU.Host.fpu]
fxrstor [xDX + CPUMCPU.Host.fpu]
and dword [xDX + CPUMCPU.fUseFlags], ~CPUM_USED_FPU
o64 fxrstor [rdx + CPUMCPU.Host.fpu]