2N/A; Copyright (C) 2011-2012 Oracle Corporation
2N/A; This file is part of VirtualBox Open Source Edition (OSE), as
2N/A; you can redistribute it
and/or modify it under the terms of the GNU
2N/A; General Public License (GPL) as published by the Free Software
2N/A; Foundation, in version 2 as it comes in the "COPYING" file of the
2N/A; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2N/A; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2N/A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2N/A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2N/A;; @todo Move this to a header?
2N/A .uTrapPC RTCCPTR_RES 1
2N/A .uResumePC RTCCPTR_RES 1
2N/A .au8Padding resb (RTCCPTR_CB*2 - 2)
2N/A %define arch_fxsave o64 fxsave
2N/A %define arch_fxrstor o64 fxrstor
2N/A %define arch_fxsave fxsave
2N/A %define arch_fxrstor fxrstor
2N/A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2N/A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2N/Aextern NAME(g_pbEfPage)
2N/Aextern NAME(g_pbEfExecPage)
2N/A db "abcdefghijklmnopqrstuvwxyz", 0
2N/A%define g_cchAlpha (g_szAlpha_end - NAME(g_szAlpha))
2N/A;; @name Floating point constants.
2N/Ag_r32_Eleven: dd 11.0
2N/Ag_r32_ThirtyTwo:dd 32.0
2N/Ag_r32_Min: dd 000800000h
2N/Ag_r32_Max: dd 07f7fffffh
g_r32_SNaN: dd 07f800001h
g_r32_SNaNMax: dd 07fbfffffh
g_r32_QNaN: dd 07fc00000h
g_r32_QNaNMax: dd 07fffffffh
g_r64_Min: dq 00010000000000000h
g_r64_Max: dq 07fefffffffffffffh
g_r64_Inf: dq 07ff0000000000000h
g_r64_SNaN: dq 07ff0000000000001h
g_r64_SNaNMax: dq 07ff7ffffffffffffh
g_r64_QNaN: dq 07ff8000000000000h
g_r64_QNaNMax: dq 07fffffffffffffffh
g_r64_DnMin: dq 00000000000000001h
g_r64_DnMax: dq 0000fffffffffffffh
g_r80_Min: dt 000018000000000000000h
g_r80_Max: dt 07ffeffffffffffffffffh
g_r80_Inf: dt 07fff8000000000000000h
g_r80_QNaN: dt 07fffc000000000000000h
g_r80_QNaNMax: dt 07fffffffffffffffffffh
g_r80_NegQNaN: dt 0ffffc000000000000000h
g_r80_SNaN: dt 07fff8000000000000001h
g_r80_SNaNMax: dt 07fffbfffffffffffffffh
g_r80_DnMin: dt 000000000000000000001h
g_r80_DnMax: dt 000007fffffffffffffffh
;; @name Upconverted Floating point constants
g_r80_r32_3dot2: dt 04000cccccd0000000000h
;g_r80_r32_Eleven: dt 11.0
;g_r80_r32_ThirtyTwo: dt 32.0
;; @name Decimal constants.
; The last global data item. We build this as we write the code.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Defined Constants And Macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%define REF(a_Name) a_Name wrt rip
%define REF(a_Name) a_Name
;; Reference a global variable
%define REF_EXTERN(a_Name) NAME(a_Name) wrt rip
%define REF_EXTERN(a_Name) NAME(a_Name)
; Macro for checking a memory value.
; @param 1 The size (byte, word, dword, etc)
; @param 2 The memory address expression.
; @param 3 The valued expected at the location.
%macro CheckMemoryValue 3
; Macro for recording a trapping instruction (simple).
; @param 1 The trap number.
; @param 2+ The instruction which should trap.
%%trapinfo: istruc TRAPINFO
; Macro for recording a trapping instruction in the exec page.
; @param 1 The trap number.
; @param 2 The offset into the exec page.
%macro ShouldTrapExecPage 2
lea xDX, [REF(NAME(g_aTrapInfoExecPage))]
mov xAX, [REF_EXTERN(g_pbEfExecPage)]
; Macro for recording a FPU instruction trapping on a following fwait.
; @param 1 The status flags that are expected to be set afterwards.
; @param 2
C0..C3 to mask out in case undefined.
; @param 3+ The instruction which should trap.
%%trapinfo: istruc TRAPINFO
FpuCheckFSW ((%1) | X86_FSW_ES | X86_FSW_B), %2
; Macro for recording checking the FSW value.
; @param 1 The status flags that are expected to be set afterwards.
; @param 2
C0..C3 to mask out in case undefined.
and eax, ~X86_FSW_TOP_MASK & ~(%2)
lea eax, [eax + __LINE__ * 100000]
; Checks that ST0 has a certain value
;; Checks that ST0 contains QNaN.
%define CheckSt0Value_QNaN CheckSt0Value 0x00000000, 0xc0000000, 0xffff
;; Checks that ST0 contains +Inf.
%define CheckSt0Value_PlusInf CheckSt0Value 0x00000000, 0x80000000, 0x7fff
;; Checks that ST0 contains 3 & 1/3.
%define CheckSt0Value_3_and_a_3rd CheckSt0Value 0x55555555, 0xd5555555, 0x4000
;; Checks that ST0 contains 3 & 1/3.
%define CheckSt0Value_3_and_two_3rds CheckSt0Value 0xaaaaaaab, 0xeaaaaaaa, 0x4000
;; Checks that ST0 contains 8.0.
%define CheckSt0Value_Eight CheckSt0Value 0x00000000, 0x80000000, 0x4002
; Macro for recording checking the FSW value of a FXSAVE image.
; @param 1 Address expression for the FXSAVE image.
; @param 2 The status flags that are expected to be set afterwards.
; @param 3
C0..C3 to mask out in case undefined.
and eax, ~X86_FSW_TOP_MASK & ~(%3)
mov eax, 100000000 + __LINE__
; Checks that ST0 is empty in an FXSAVE image.
; @param 1 Address expression for the FXSAVE image.
%macro FxSaveCheckSt0Empty 1
and eax, X86_FSW_TOP_MASK
shr eax, X86_FSW_TOP_SHIFT
mov eax, 200000000 + __LINE__
; Checks that ST0 is not-empty in an FXSAVE image.
; @param 1 Address expression for the FXSAVE image.
%macro FxSaveCheckSt0NonEmpty 1
and eax, X86_FSW_TOP_MASK
shr eax, X86_FSW_TOP_SHIFT
mov eax, 30000000 + __LINE__
; Checks that STn in a FXSAVE image has a certain value (empty or not
; @param 1 Address expression for the FXSAVE image.
; @param 2 The register number.
; @param 3 First dword of value.
; @param 4 Second dword of value.
; @param 5 Final word of value.
%macro FxSaveCheckStNValueEx 5
mov eax, 40000000 + __LINE__
; Checks if STn in a FXSAVE image has the same value as the specified
; floating point (80-bit) constant.
; @param 1 Address expression for the FXSAVE image.
; @param 2 The register number.
; @param 3 The address expression of the constant.
%macro FxSaveCheckStNValueConstEx 3
mov eax, 40000000 + __LINE__
; Checks that ST0 in a FXSAVE image has a certain value.
; @param 1 Address expression for the FXSAVE image.
; @param 2 First dword of value.
; @param 3 Second dword of value.
; @param 4 Final word of value.
%macro FxSaveCheckSt0Value 4
FxSaveCheckSt0NonEmpty %1
FxSaveCheckStNValueEx %1, 0, %2, %3, %4
; Checks that ST0 in a FXSAVE image is empty and that the value stored is the
; init value set by FpuInitWithCW.
; @param 1 Address expression for the FXSAVE image.
%macro FxSaveCheckSt0EmptyInitValue 1
FxSaveCheckStNValueEx %1, 0, 0x40404040, 0x40404040, 0xffff
; Checks that ST0 in a FXSAVE image is non-empty and has the same value as the
; specified constant (80-bit).
; @param 1 Address expression for the FXSAVE image.
; @param 2 The address expression of the constant.
%macro FxSaveCheckSt0ValueConst 2
FxSaveCheckSt0NonEmpty %1
FxSaveCheckStNValueConstEx %1, 0, %2
;; Checks that ST0 contains QNaN.
%define FxSaveCheckSt0Value_QNaN(p) FxSaveCheckSt0Value p, 0x00000000, 0xc0000000, 0xffff
;; Checks that ST0 contains +Inf.
%define FxSaveCheckSt0Value_PlusInf(p) FxSaveCheckSt0Value p, 0x00000000, 0x80000000, 0x7fff
;; Checks that ST0 contains 3 & 1/3.
%define FxSaveCheckSt0Value_3_and_a_3rd(p) FxSaveCheckSt0Value p, 0x55555555, 0xd5555555, 0x4000
;; Checks that ST0 contains 3 & 1/3.
%define FxSaveCheckSt0Value_3_and_two_3rds(p) FxSaveCheckSt0Value p, 0xaaaaaaab, 0xeaaaaaaa, 0x4000
; Checks that STn is empty in an FXSAVE image.
; @param 1 Address expression for the FXSAVE image.
; @param 2 The register number.
%macro FxSaveCheckStNEmpty 2
and eax, X86_FSW_TOP_MASK
shr eax, X86_FSW_TOP_SHIFT
and eax, X86_FSW_TOP_SMASK
mov eax, 20000000 + __LINE__
; Checks that STn is not-empty in an FXSAVE image.
; @param 1 Address expression for the FXSAVE image.
; @param 2 The register number.
%macro FxSaveCheckStNNonEmpty 2
and eax, X86_FSW_TOP_MASK
shr eax, X86_FSW_TOP_SHIFT
and eax, X86_FSW_TOP_SMASK
mov eax, 30000000 + __LINE__
; Checks that STn in a FXSAVE image has a certain value.
; @param 1 Address expression for the FXSAVE image.
; @param 2 The register number.
; @param 3 First dword of value.
; @param 4 Second dword of value.
; @param 5 Final word of value.
%macro FxSaveCheckStNValue 5
FxSaveCheckStNNonEmpty %1, %2
FxSaveCheckStNValueEx %1, %2, %3, %4, %5
; Checks that ST0 in a FXSAVE image is non-empty and has the same value as the
; specified constant (80-bit).
; @param 1 Address expression for the FXSAVE image.
; @param 2 The register number.
; @param 3 The address expression of the constant.
%macro FxSaveCheckStNValueConst 3
FxSaveCheckStNNonEmpty %1, %2
FxSaveCheckStNValueConstEx %1, %2, %3
;; Checks that ST0 contains QNaN.
%define FxSaveCheckStNValue_QNaN(p, iSt) FxSaveCheckStNValue p, iSt, 0x00000000, 0xc0000000, 0xffff
;; Checks that ST0 contains +Inf.
%define FxSaveCheckStNValue_PlusInf(p, iSt) FxSaveCheckStNValue p, iSt, 0x00000000, 0x80000000, 0x7fff
;; Checks that ST0 contains 3 & 1/3.
%define FxSaveCheckStNValue_3_and_a_3rd(p, iSt) FxSaveCheckStNValue p, iSt, 0x55555555, 0xd5555555, 0x4000
;; Checks that ST0 contains 3 & 1/3.
%define FxSaveCheckStNValue_3_and_two_3rds(p, iSt) FxSaveCheckStNValue p, iSt, 0xaaaaaaab, 0xeaaaaaaa, 0x4000
; Function prologue saving all registers except EAX and aligns the stack
; on a 16-byte boundrary.
%macro SAVE_ALL_PROLOGUE 0
; Function epilogue restoring all regisers except EAX.
%macro SAVE_ALL_EPILOGUE 0
; Loads all general registers except xBP and xSP with unique values.
x861_LoadUniqueRegValues:
mov rax, 00000000000000000h
mov rcx, 01111111111111111h
mov rdx, 02222222222222222h
mov rbx, 03333333333333333h
mov rsi, 06666666666666666h
mov rdi, 07777777777777777h
mov r8, 08888888888888888h
mov r9, 09999999999999999h
mov r10, 0aaaaaaaaaaaaaaaah
mov r11, 0bbbbbbbbbbbbbbbbh
mov r12, 0cccccccccccccccch
mov r13, 0ddddddddddddddddh
mov r14, 0eeeeeeeeeeeeeeeeh
mov r15, 0ffffffffffffffffh
; end x861_LoadUniqueRegValues
; Clears all general registers except xBP and xSP.
; Loads all MMX and SSE registers except xBP and xSP with unique values.
x861_LoadUniqueRegValuesSSE:
movdqu xmm0, [REF(._xmm0)]
movdqu xmm1, [REF(._xmm1)]
movdqu xmm2, [REF(._xmm2)]
movdqu xmm3, [REF(._xmm3)]
movdqu xmm4, [REF(._xmm4)]
movdqu xmm5, [REF(._xmm5)]
movdqu xmm6, [REF(._xmm6)]
movdqu xmm7, [REF(._xmm7)]
movdqu xmm8, [REF(._xmm8)]
movdqu xmm9, [REF(._xmm9)]
movdqu xmm10, [REF(._xmm10)]
movdqu xmm11, [REF(._xmm11)]
movdqu xmm12, [REF(._xmm12)]
movdqu xmm13, [REF(._xmm13)]
movdqu xmm14, [REF(._xmm14)]
movdqu xmm15, [REF(._xmm15)]
._xmm10: times 16 db 08ah
._xmm11: times 16 db 08bh
._xmm12: times 16 db 08ch
._xmm13: times 16 db 08dh
._xmm14: times 16 db 08eh
._xmm15: times 16 db 08fh
; end x861_LoadUniqueRegValuesSSE
; Clears all MMX and SSE registers.
movdqu xmm0, [REF(.zero)]
movdqu xmm1, [REF(.zero)]
movdqu xmm2, [REF(.zero)]
movdqu xmm3, [REF(.zero)]
movdqu xmm4, [REF(.zero)]
movdqu xmm5, [REF(.zero)]
movdqu xmm6, [REF(.zero)]
movdqu xmm7, [REF(.zero)]
movdqu xmm8, [REF(.zero)]
movdqu xmm9, [REF(.zero)]
movdqu xmm10, [REF(.zero)]
movdqu xmm11, [REF(.zero)]
movdqu xmm12, [REF(.zero)]
movdqu xmm13, [REF(.zero)]
movdqu xmm14, [REF(.zero)]
movdqu xmm15, [REF(.zero)]
; Loads all general, MMX and SSE registers except xBP and xSP with unique values.
x861_LoadUniqueRegValuesSSEAndGRegs:
call x861_LoadUniqueRegValuesSSE
call x861_LoadUniqueRegValues
; Clears all general, MMX and SSE registers except xBP and xSP.
x861_ClearRegistersSSEAndGRegs:
call x861_ClearRegistersSSE
%if 0 ; Seems to be so on AMD only
; upper word of a 'push cs' is cleared.
mov dword [esp - 4], 0f0f0f0fh
; upper word of a 'push ds' is cleared.
mov dword [esp - 4], 0f0f0f0fh
; upper word of a 'push es' is cleared.
mov dword [esp - 4], 0f0f0f0fh
; The upper part of a 'push fs' is cleared.
; The upper part of a 'push gs' is cleared.
;
REX.B works with 'push r64'.
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
; Zero extening when moving from a segreg as well as memory access sizes.
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
call x861_LoadUniqueRegValues
; Loading is always a word access.
mov xDI, [REF_EXTERN(g_pbEfPage)]
lea xDI, [xDI + 0x1000 - 2]
mov es, [xDI] ; should not crash
; Saving is always a word access.
mov xDI, [REF_EXTERN(g_pbEfPage)]
mov dword [xDI + 0x1000 - 4], -1
mov [xDI + 0x1000 - 2], ss ; Should not crash.
mov cx, [xDI + 0x1000 - 2]
; Check that the
rex.R and
rex.W bits don't have any influence over a memory write.
mov xDI, [REF_EXTERN(g_pbEfPage)]
mov dword [xDI + 0x1000 - 4], -1
mov [xDI + 0x1000 - 2], ss ; Should not crash.
mov cx, [xDI + 0x1000 - 2]
; Check what happens when both string prefixes are used.
; check that repne scasb (al=0) behaves like expected.
lea xDI, [REF(NAME(g_szAlpha))]
xor eax, eax ; find the end
; check that repe scasb (al=0) behaves like expected.
lea xDI, [REF(NAME(g_szAlpha))]
xor eax, eax ; find the end
; repne is last, it wins.
lea xDI, [REF(NAME(g_szAlpha))]
xor eax, eax ; find the end
lea xDI, [REF(NAME(g_szAlpha))]
xor eax, eax ; find the end
db 0f2h ; repne - ignored
; Check if stosb works with both prefixes.
mov xDI, [REF_EXTERN(g_pbEfPage)]
mov xDI, [REF_EXTERN(g_pbEfPage)]
mov xDI, [REF_EXTERN(g_pbEfPage)]
cmp dword [xDI], 0ffffffffh
mov xDI, [REF_EXTERN(g_pbEfPage)]
mov xDI, [REF_EXTERN(g_pbEfPage)]
cmp dword [xDI], 0fefefefeh
; String operations shouldn't crash because of an invalid address if rCX is 0.
mov xDI, [REF_EXTERN(g_pbEfPage)]
;
INS/OUTS will trap in ring-3 even when rCX is 0. (ASSUMES IOPL < 3)
ShouldTrap X86_XCPT_GP, rep insb
; SMSW can get to the whole of CR0.
; Will the CPU decode the whole r/m+sib stuff before signalling a lock
; prefix error? Use the EF exec page and a LOCK ADD CL,[rDI + disp32]
; instruction at the very end of it.
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
mov dword [xDI+3], 000000000h
ShouldTrap X86_XCPT_UD, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
mov dword [xDI+3], 000000000h
ShouldTrap X86_XCPT_UD, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, call xDI
; Tests the effect of prefix order in group 14.
; Check testcase preconditions.
call x861_LoadUniqueRegValuesSSEAndGRegs
db 00Fh, 073h, 0D0h, 080h ; psrlq mm0, 128
call .check_mm0_zero_and_xmm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 00Fh, 073h, 0D0h, 080h ; psrlq xmm0, 128
call .check_xmm0_zero_and_mm0_nz
; Real test - Inject other prefixes before the 066h and see what
; General checks that order does not matter, etc.
call x861_LoadUniqueRegValuesSSEAndGRegs
db 026h, 066h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 026h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 067h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 067h, 066h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 067h, 066h, 065h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 048h, 066h, 00Fh, 073h, 0D0h, 080h ;
REX.W call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 044h, 066h, 00Fh, 073h, 0D0h, 080h ;
REX.R call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 042h, 066h, 00Fh, 073h, 0D0h, 080h ;
REX.X call .check_xmm0_zero_and_mm0_nz
; Actually for REX, order does matter if the prefix is used.
call x861_LoadUniqueRegValuesSSEAndGRegs
db 041h, 066h, 00Fh, 073h, 0D0h, 080h ;
REX.B call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 041h, 00Fh, 073h, 0D0h, 080h ;
REX.B call .check_xmm8_zero_and_xmm0_nz
; Check all ignored prefixes (repeates some of the above).
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 026h, 00Fh, 073h, 0D0h, 080h ; es
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 065h, 00Fh, 073h, 0D0h, 080h ; gs
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 064h, 00Fh, 073h, 0D0h, 080h ; fs
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 02eh, 00Fh, 073h, 0D0h, 080h ; cs
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 036h, 00Fh, 073h, 0D0h, 080h ; ss
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 03eh, 00Fh, 073h, 0D0h, 080h ; ds
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 067h, 00Fh, 073h, 0D0h, 080h ; addr size
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 048h, 00Fh, 073h, 0D0h, 080h ;
REX.W call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 044h, 00Fh, 073h, 0D0h, 080h ;
REX.R call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 042h, 00Fh, 073h, 0D0h, 080h ;
REX.X call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 041h, 00Fh, 073h, 0D0h, 080h ;
REX.B - has actual effect on the instruction.
call .check_xmm8_zero_and_xmm0_nz
; Repeated prefix until we hit the max opcode limit.
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 066h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 066h, 066h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
ShouldTrap X86_XCPT_GP, db 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 066h, 00Fh, 073h, 0D0h, 080h
; Repeated REX is parsed, but only the last byte matters.
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 041h, 048h, 00Fh, 073h, 0D0h, 080h ;
REX.B,
REX.W call .check_xmm0_zero_and_mm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 048h, 041h, 00Fh, 073h, 0D0h, 080h ;
REX.B,
REX.W call .check_xmm8_zero_and_xmm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 048h, 044h, 042h, 048h, 044h, 042h, 048h, 044h, 042h, 041h, 00Fh, 073h, 0D0h, 080h
call .check_xmm8_zero_and_xmm0_nz
call x861_LoadUniqueRegValuesSSEAndGRegs
db 066h, 041h, 041h, 041h, 041h, 041h, 041h, 041h, 041h, 041h, 04eh, 00Fh, 073h, 0D0h, 080h
call .check_xmm0_zero_and_mm0_nz
; Undefined sequences with prefixes that counts.
ShouldTrap X86_XCPT_UD, db 0f0h, 066h, 00Fh, 073h, 0D0h, 080h ; LOCK
ShouldTrap X86_XCPT_UD, db 0f2h, 066h, 00Fh, 073h, 0D0h, 080h ; REPNZ
ShouldTrap X86_XCPT_UD, db 0f3h, 066h, 00Fh, 073h, 0D0h, 080h ; REPZ
ShouldTrap X86_XCPT_UD, db 066h, 0f2h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 066h, 0f3h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 066h, 0f3h, 0f2h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 066h, 0f2h, 0f3h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f2h, 066h, 0f3h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f3h, 066h, 0f2h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f3h, 0f2h, 066h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f2h, 0f3h, 066h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f0h, 0f2h, 066h, 0f3h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f0h, 0f3h, 066h, 0f2h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f0h, 0f3h, 0f2h, 066h, 00Fh, 073h, 0D0h, 080h
ShouldTrap X86_XCPT_UD, db 0f0h, 0f2h, 0f3h, 066h, 00Fh, 073h, 0D0h, 080h
.check_xmm0_zero_and_mm0_nz:
.check_mm0_zero_and_xmm0_nz:
.check_xmm8_zero_and_xmm0_nz:
; Tests how much fxsave and fxrstor actually accesses of their 512 memory
call x861_LoadUniqueRegValuesSSEAndGRegs
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
; Check testcase preconditions.
; 464:511 are available to software use. Check that they are left
.chech_software_area_loop:
jne .chech_software_area_done
jmp .chech_software_area_loop
.chech_software_area_done:
; Check that a save + restore + save cycle yield the same results.
mov xBX, [REF_EXTERN(g_pbEfExecPage)]
call x861_ClearRegistersSSEAndGRegs
mov xBX, [REF_EXTERN(g_pbEfExecPage)]
; 464:511 are available to software use. Let see how carefully access
; to the full 512 bytes are checked...
call x861_LoadUniqueRegValuesSSEAndGRegs
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 16]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 32]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 48]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 64]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 80]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 96]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 128]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 144]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 160]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 176]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 192]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 208]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 224]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 240]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 256]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 384]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 432]
ShouldTrap X86_XCPT_PF, fxsave [xDI + 496]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 16]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 32]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 48]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 64]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 80]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 96]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 128]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 144]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 160]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 176]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 192]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 208]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 224]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 240]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 256]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 384]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 432]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + 496]
; Unaligned accesses will cause #GP(0). This takes precedence over #PF.
ShouldTrap X86_XCPT_GP, fxsave [xDI + 1]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 2]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 3]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 4]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 5]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 6]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 7]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 8]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 9]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 10]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 11]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 12]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 13]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 14]
ShouldTrap X86_XCPT_GP, fxsave [xDI + 15]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 1]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 2]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 3]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 4]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 5]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 6]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 7]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 8]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 9]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 10]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 11]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 12]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 13]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 14]
ShouldTrap X86_XCPT_GP, fxrstor [xDI + 15]
; Lets check what a FP in fxsave changes ... nothing on intel.
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
add xDI, PAGE_SIZE - 512 * 2
ShouldTrap X86_XCPT_PF, fxsave [xSI + PAGE_SIZE - 512 + xBX]
jbe .fxsave_pf_effect_loop
; Lets check that a FP in fxrstor does not have any effect on the FPU or SSE state.
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
call x861_LoadUniqueRegValuesSSEAndGRegs
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
call x861_ClearRegistersSSEAndGRegs
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
lea xDI, [xDI + PAGE_SIZE - 512 + xBX]
rep movsb ; copy unique state to end of page.
call x861_ClearRegistersSSEAndGRegs
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_PF, fxrstor [xDI + PAGE_SIZE - 512 + xBX] ; try load unique state
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
lea xSI, [xDI + 512] ; point it to the clean state, which is what we expect.
fxsave [xDI] ; save whatever the fpu state currently is.
jnz .return ; it shouldn't be modified by faulting fxrstor,
i.e. a clean state.
jbe .fxrstor_pf_effect_loop
; Tests various multibyte NOP sequences.
; Intel recommended sequences.
db 00fh, 01fh, 040h, 000h
db 00fh, 01fh, 044h, 000h, 000h
db 066h, 00fh, 01fh, 044h, 000h, 000h
db 00fh, 01fh, 080h, 000h, 000h, 000h, 000h
db 00fh, 01fh, 084h, 000h, 000h, 000h, 000h, 000h
db 066h, 00fh, 01fh, 084h, 000h, 000h, 000h, 000h, 000h
; Check that the NOPs are allergic to lock prefixing.
ShouldTrap X86_XCPT_UD, db 0f0h, 090h ; lock prefixed NOP.
ShouldTrap X86_XCPT_UD, db 0f0h, 066h, 090h ; lock prefixed two byte NOP.
ShouldTrap X86_XCPT_UD, db 0f0h, 00fh, 01fh, 000h ; lock prefixed three byte NOP.
; Check the range of instructions that AMD marks as NOPs.
db 00fh, %1, 044h, 000h, 000h
db 066h, 00fh, %1, 044h, 000h, 000h
db 00fh, %1, 080h, 000h, 000h, 000h, 000h
db 00fh, %1, 084h, 000h, 000h, 000h, 000h, 000h
db 066h, 00fh, %1, 084h, 000h, 000h, 000h, 000h, 000h
ShouldTrap X86_XCPT_UD, db 0f0h, 00fh, %1, 000h
; The AMD P group, intel marks this as a NOP.
ShouldTrap X86_XCPT_UD, db 0xff, 11011000b
ShouldTrap X86_XCPT_UD, db 0xff, 11011001b
ShouldTrap X86_XCPT_UD, db 0xff, 11011010b
ShouldTrap X86_XCPT_UD, db 0xff, 11011011b
ShouldTrap X86_XCPT_UD, db 0xff, 11011100b
ShouldTrap X86_XCPT_UD, db 0xff, 11011101b
ShouldTrap X86_XCPT_UD, db 0xff, 11011110b
ShouldTrap X86_XCPT_UD, db 0xff, 11011111b
ShouldTrap X86_XCPT_UD, db 0xff, 11101000b
ShouldTrap X86_XCPT_UD, db 0xff, 11101001b
ShouldTrap X86_XCPT_UD, db 0xff, 11101010b
ShouldTrap X86_XCPT_UD, db 0xff, 11101011b
ShouldTrap X86_XCPT_UD, db 0xff, 11101100b
ShouldTrap X86_XCPT_UD, db 0xff, 11101101b
ShouldTrap X86_XCPT_UD, db 0xff, 11101110b
ShouldTrap X86_XCPT_UD, db 0xff, 11101111b
ShouldTrap X86_XCPT_GP, mov xAX, cr0
ShouldTrap X86_XCPT_UD, lock mov xAX, cr0
ShouldTrap X86_XCPT_GP, mov cr0, xAX
ShouldTrap X86_XCPT_UD, lock mov cr0, xAX
ShouldTrap X86_XCPT_UD, db 0x0f, 0x20,11001000b ; mov xAX, cr1
ShouldTrap X86_XCPT_UD, db 0x0f, 0x20,11101000b ; mov xAX, cr5
ShouldTrap X86_XCPT_UD, db 0x0f, 0x20,11110000b ; mov xAX, cr6
ShouldTrap X86_XCPT_UD, db 0x0f, 0x20,11111000b ; mov xAX, cr7
ShouldTrap X86_XCPT_GP, mov xAX, dr7
ShouldTrap X86_XCPT_UD, lock mov xAX, dr7
; The MOD is ignored by MOV CRx,GReg and MOV GReg,CRx
ShouldTrap X86_XCPT_GP, db 0x0f, 0x20,00000000b ; mov xAX, cr0
ShouldTrap X86_XCPT_GP, db 0x0f, 0x20,01000000b ; mov xAX, cr0
ShouldTrap X86_XCPT_GP, db 0x0f, 0x20,10000000b ; mov xAX, cr0
ShouldTrap X86_XCPT_GP, db 0x0f, 0x20,11000000b ; mov xAX, cr0
ShouldTrap X86_XCPT_GP, db 0x0f, 0x22,00000000b ; mov cr0, xAX
ShouldTrap X86_XCPT_GP, db 0x0f, 0x22,01000000b ; mov cr0, xAX
ShouldTrap X86_XCPT_GP, db 0x0f, 0x22,10000000b ; mov cr0, xAX
ShouldTrap X86_XCPT_GP, db 0x0f, 0x22,11000000b ; mov cr0, xAX
; mov eax, tr0, 0x0f 0x24
ShouldTrap X86_XCPT_UD, db 0x0f, 0x24, 0xc0 ; mov xAX, tr1
mov xAX, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrapExecPage X86_XCPT_UD, PAGE_SIZE - 3
mov xAX, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrapExecPage X86_XCPT_UD, PAGE_SIZE - 2
; Tests an reserved FPU encoding, checking that it does not affect the FPU or
call SaveFPUAndGRegsToStack
call CompareFPUAndGRegsOnStackIgnoreOpAndIp
; Used for marking encodings which has a meaning other than FNOP and
%macro FpuReservedEncoding 2
call SaveFPUAndGRegsToStack
arch_fxrstor [xSP + 1024]
call CompareFPUAndGRegsOnStackIgnoreOpAndIp
;arch_fxrstor [xSP + 1024]
; Saves the FPU and general registers to the stack area right next to the
; The required area size is 512 + 80h = 640.
; @uses Nothing, except stack.
; Must clear the FXSAVE area.
; Save GRegs (80h bytes).
mov [xSP + 512 + xS + 000h], xAX
mov [xSP + 512 + xS + 008h], xBX
mov [xSP + 512 + xS + 010h], xCX
mov [xSP + 512 + xS + 018h], xDX
mov [xSP + 512 + xS + 020h], xDI
mov [xSP + 512 + xS + 028h], xSI
mov [xSP + 512 + xS + 030h], xBP
mov [xSP + 512 + xS + 038h], r8
mov [xSP + 512 + xS + 040h], r9
mov [xSP + 512 + xS + 048h], r10
mov [xSP + 512 + xS + 050h], r11
mov [xSP + 512 + xS + 058h], r12
mov [xSP + 512 + xS + 060h], r13
mov [xSP + 512 + xS + 068h], r14
mov [xSP + 512 + xS + 070h], r15
mov [xSP + 512 + xS + 078h], rax
mov rax, [xSP + 512 + xS + 000h]
mov [xSP + 512 + xS + 000h], eax
mov [xSP + 512 + xS + 004h], eax
mov [xSP + 512 + xS + 008h], ebx
mov [xSP + 512 + xS + 00ch], ebx
mov [xSP + 512 + xS + 010h], ecx
mov [xSP + 512 + xS + 014h], ecx
mov [xSP + 512 + xS + 018h], edx
mov [xSP + 512 + xS + 01ch], edx
mov [xSP + 512 + xS + 020h], edi
mov [xSP + 512 + xS + 024h], edi
mov [xSP + 512 + xS + 028h], esi
mov [xSP + 512 + xS + 02ch], esi
mov [xSP + 512 + xS + 030h], ebp
mov [xSP + 512 + xS + 034h], ebp
mov [xSP + 512 + xS + 038h], eax
mov [xSP + 512 + xS + 03ch], eax
mov [xSP + 512 + xS + 040h], eax
mov [xSP + 512 + xS + 044h], eax
mov [xSP + 512 + xS + 048h], eax
mov [xSP + 512 + xS + 04ch], eax
mov [xSP + 512 + xS + 050h], eax
mov [xSP + 512 + xS + 054h], eax
mov [xSP + 512 + xS + 058h], eax
mov [xSP + 512 + xS + 05ch], eax
mov [xSP + 512 + xS + 060h], eax
mov [xSP + 512 + xS + 064h], eax
mov [xSP + 512 + xS + 068h], eax
mov [xSP + 512 + xS + 06ch], eax
mov [xSP + 512 + xS + 070h], eax
mov [xSP + 512 + xS + 074h], eax
mov [xSP + 512 + xS + 078h], eax
mov [xSP + 512 + xS + 07ch], eax
mov eax, [xSP + 512 + xS + 000h]
; Compares the current FPU and general registers to that found in the stack
; area prior to the return address.
; @returns eax is zero on success, eax is 1000000 * offset on failure.
; ZF reflects the eax value to save a couple of instructions...
CompareFPUAndGRegsOnStack:
lea xSP, [xSP - (1024 - xS)]
call SaveFPUAndGRegsToStack
lea xSP, [xSP + (1024 - xS)]
; Same as CompareFPUAndGRegsOnStack, except that it ignores the FOP and FPUIP
; @returns eax is zero on success, eax is 1000000 * offset on failure.
; ZF reflects the eax value to save a couple of instructions...
CompareFPUAndGRegsOnStackIgnoreOpAndIp:
lea xSP, [xSP - (1024 - xS)]
call SaveFPUAndGRegsToStack
lea xSP, [xSP + (1024 - xS)]
or word [xSP + 4], X86_FSW_C0 | X86_FSW_C1 | X86_FSW_C2 | X86_FSW_C3
; Tests some odd floating point instruction encodings.
ShouldTrap X86_XCPT_UD, db 0d9h, 008h
ShouldTrap X86_XCPT_UD, db 0d9h, 009h
ShouldTrap X86_XCPT_UD, db 0d9h, 00ah
ShouldTrap X86_XCPT_UD, db 0d9h, 00bh
ShouldTrap X86_XCPT_UD, db 0d9h, 00ch
ShouldTrap X86_XCPT_UD, db 0d9h, 00dh
ShouldTrap X86_XCPT_UD, db 0d9h, 00eh
ShouldTrap X86_XCPT_UD, db 0d9h, 00fh
ShouldTrap X86_XCPT_UD, db 0d9h, 0d1h
ShouldTrap X86_XCPT_UD, db 0d9h, 0d2h
ShouldTrap X86_XCPT_UD, db 0d9h, 0d3h
ShouldTrap X86_XCPT_UD, db 0d9h, 0d4h
ShouldTrap X86_XCPT_UD, db 0d9h, 0d5h
ShouldTrap X86_XCPT_UD, db 0d9h, 0d6h
ShouldTrap X86_XCPT_UD, db 0d9h, 0d7h
FpuReservedEncoding {db 0d9h, 0d8h}, { fstp st0 }
FpuReservedEncoding {db 0d9h, 0d9h}, { fstp st1 }
FpuReservedEncoding {db 0d9h, 0dah}, { fstp st2 }
FpuReservedEncoding {db 0d9h, 0dbh}, { fstp st3 }
FpuReservedEncoding {db 0d9h, 0dch}, { fstp st4 }
FpuReservedEncoding {db 0d9h, 0ddh}, { fstp st5 }
FpuReservedEncoding {db 0d9h, 0deh}, { fstp st6 }
;FpuReservedEncoding {db 0d9h, 0dfh}, { fstp st7 } ; This variant seems to ignore empty ST(0) values!
ShouldTrap X86_XCPT_UD, db 0d9h, 0e2h
ShouldTrap X86_XCPT_UD, db 0d9h, 0e3h
ShouldTrap X86_XCPT_UD, db 0d9h, 0e6h
ShouldTrap X86_XCPT_UD, db 0d9h, 0e7h
ShouldTrap X86_XCPT_UD, db 0d9h, 0efh
ShouldTrap X86_XCPT_UD, db 0d9h, 008h
ShouldTrap X86_XCPT_UD, db 0d9h, 00fh
ShouldTrap X86_XCPT_UD, db 0dah, 0e0h
ShouldTrap X86_XCPT_UD, db 0dah, 0e1h
ShouldTrap X86_XCPT_UD, db 0dah, 0e2h
ShouldTrap X86_XCPT_UD, db 0dah, 0e3h
ShouldTrap X86_XCPT_UD, db 0dah, 0e4h
ShouldTrap X86_XCPT_UD, db 0dah, 0e5h
ShouldTrap X86_XCPT_UD, db 0dah, 0e6h
ShouldTrap X86_XCPT_UD, db 0dah, 0e7h
ShouldTrap X86_XCPT_UD, db 0dah, 0e8h
ShouldTrap X86_XCPT_UD, db 0dah, 0eah
ShouldTrap X86_XCPT_UD, db 0dah, 0ebh
ShouldTrap X86_XCPT_UD, db 0dah, 0ech
ShouldTrap X86_XCPT_UD, db 0dah, 0edh
ShouldTrap X86_XCPT_UD, db 0dah, 0eeh
ShouldTrap X86_XCPT_UD, db 0dah, 0efh
ShouldTrap X86_XCPT_UD, db 0dah, 0f0h
ShouldTrap X86_XCPT_UD, db 0dah, 0f1h
ShouldTrap X86_XCPT_UD, db 0dah, 0f2h
ShouldTrap X86_XCPT_UD, db 0dah, 0f3h
ShouldTrap X86_XCPT_UD, db 0dah, 0f4h
ShouldTrap X86_XCPT_UD, db 0dah, 0f5h
ShouldTrap X86_XCPT_UD, db 0dah, 0f6h
ShouldTrap X86_XCPT_UD, db 0dah, 0f7h
ShouldTrap X86_XCPT_UD, db 0dah, 0f8h
ShouldTrap X86_XCPT_UD, db 0dah, 0f9h
ShouldTrap X86_XCPT_UD, db 0dah, 0fah
ShouldTrap X86_XCPT_UD, db 0dah, 0fbh
ShouldTrap X86_XCPT_UD, db 0dah, 0fch
ShouldTrap X86_XCPT_UD, db 0dah, 0fdh
ShouldTrap X86_XCPT_UD, db 0dah, 0feh
ShouldTrap X86_XCPT_UD, db 0dah, 0ffh
FpuNopEncoding db 0dbh, 0e0h ; fneni
FpuNopEncoding db 0dbh, 0e1h ; fndisi
FpuNopEncoding db 0dbh, 0e4h ; fnsetpm
ShouldTrap X86_XCPT_UD, db 0dbh, 0e5h
ShouldTrap X86_XCPT_UD, db 0dbh, 0e6h
ShouldTrap X86_XCPT_UD, db 0dbh, 0e7h
ShouldTrap X86_XCPT_UD, db 0dbh, 0f8h
ShouldTrap X86_XCPT_UD, db 0dbh, 0f9h
ShouldTrap X86_XCPT_UD, db 0dbh, 0fah
ShouldTrap X86_XCPT_UD, db 0dbh, 0fbh
ShouldTrap X86_XCPT_UD, db 0dbh, 0fch
ShouldTrap X86_XCPT_UD, db 0dbh, 0fdh
ShouldTrap X86_XCPT_UD, db 0dbh, 0feh
ShouldTrap X86_XCPT_UD, db 0dbh, 0ffh
ShouldTrap X86_XCPT_UD, db 0dbh, 020h
ShouldTrap X86_XCPT_UD, db 0dbh, 023h
ShouldTrap X86_XCPT_UD, db 0dbh, 030h
ShouldTrap X86_XCPT_UD, db 0dbh, 032h
FpuReservedEncoding {db 0dch, 0d0h}, { fcom st0 }
FpuReservedEncoding {db 0dch, 0d1h}, { fcom st1 }
FpuReservedEncoding {db 0dch, 0d2h}, { fcom st2 }
FpuReservedEncoding {db 0dch, 0d3h}, { fcom st3 }
FpuReservedEncoding {db 0dch, 0d4h}, { fcom st4 }
FpuReservedEncoding {db 0dch, 0d5h}, { fcom st5 }
FpuReservedEncoding {db 0dch, 0d6h}, { fcom st6 }
FpuReservedEncoding {db 0dch, 0d7h}, { fcom st7 }
FpuReservedEncoding {db 0dch, 0d8h}, { fcomp st0 }
FpuReservedEncoding {db 0dch, 0d9h}, { fcomp st1 }
FpuReservedEncoding {db 0dch, 0dah}, { fcomp st2 }
FpuReservedEncoding {db 0dch, 0dbh}, { fcomp st3 }
FpuReservedEncoding {db 0dch, 0dch}, { fcomp st4 }
FpuReservedEncoding {db 0dch, 0ddh}, { fcomp st5 }
FpuReservedEncoding {db 0dch, 0deh}, { fcomp st6 }
FpuReservedEncoding {db 0dch, 0dfh}, { fcomp st7 }
FpuReservedEncoding {db 0ddh, 0c8h}, { fxch st0 }
FpuReservedEncoding {db 0ddh, 0c9h}, { fxch st1 }
FpuReservedEncoding {db 0ddh, 0cah}, { fxch st2 }
FpuReservedEncoding {db 0ddh, 0cbh}, { fxch st3 }
FpuReservedEncoding {db 0ddh, 0cch}, { fxch st4 }
FpuReservedEncoding {db 0ddh, 0cdh}, { fxch st5 }
FpuReservedEncoding {db 0ddh, 0ceh}, { fxch st6 }
FpuReservedEncoding {db 0ddh, 0cfh}, { fxch st7 }
ShouldTrap X86_XCPT_UD, db 0ddh, 0f0h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f1h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f2h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f3h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f4h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f5h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f6h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f7h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f8h
ShouldTrap X86_XCPT_UD, db 0ddh, 0f9h
ShouldTrap X86_XCPT_UD, db 0ddh, 0fah
ShouldTrap X86_XCPT_UD, db 0ddh, 0fbh
ShouldTrap X86_XCPT_UD, db 0ddh, 0fch
ShouldTrap X86_XCPT_UD, db 0ddh, 0fdh
ShouldTrap X86_XCPT_UD, db 0ddh, 0feh
ShouldTrap X86_XCPT_UD, db 0ddh, 0ffh
ShouldTrap X86_XCPT_UD, db 0ddh, 028h
ShouldTrap X86_XCPT_UD, db 0ddh, 02fh
FpuReservedEncoding {db 0deh, 0d0h}, { fcomp st0 }
FpuReservedEncoding {db 0deh, 0d1h}, { fcomp st1 }
FpuReservedEncoding {db 0deh, 0d2h}, { fcomp st2 }
FpuReservedEncoding {db 0deh, 0d3h}, { fcomp st3 }
FpuReservedEncoding {db 0deh, 0d4h}, { fcomp st4 }
FpuReservedEncoding {db 0deh, 0d5h}, { fcomp st5 }
FpuReservedEncoding {db 0deh, 0d6h}, { fcomp st6 }
FpuReservedEncoding {db 0deh, 0d7h}, { fcomp st7 }
ShouldTrap X86_XCPT_UD, db 0deh, 0d8h
ShouldTrap X86_XCPT_UD, db 0deh, 0dah
ShouldTrap X86_XCPT_UD, db 0deh, 0dbh
ShouldTrap X86_XCPT_UD, db 0deh, 0dch
ShouldTrap X86_XCPT_UD, db 0deh, 0ddh
ShouldTrap X86_XCPT_UD, db 0deh, 0deh
ShouldTrap X86_XCPT_UD, db 0deh, 0dfh
FpuReservedEncoding {db 0dfh, 0c8h}, { fxch st0 }
FpuReservedEncoding {db 0dfh, 0c9h}, { fxch st1 }
FpuReservedEncoding {db 0dfh, 0cah}, { fxch st2 }
FpuReservedEncoding {db 0dfh, 0cbh}, { fxch st3 }
FpuReservedEncoding {db 0dfh, 0cch}, { fxch st4 }
FpuReservedEncoding {db 0dfh, 0cdh}, { fxch st5 }
FpuReservedEncoding {db 0dfh, 0ceh}, { fxch st6 }
FpuReservedEncoding {db 0dfh, 0cfh}, { fxch st7 }
FpuReservedEncoding {db 0dfh, 0d0h}, { fstp st0 }
FpuReservedEncoding {db 0dfh, 0d1h}, { fstp st1 }
FpuReservedEncoding {db 0dfh, 0d2h}, { fstp st2 }
FpuReservedEncoding {db 0dfh, 0d3h}, { fstp st3 }
FpuReservedEncoding {db 0dfh, 0d4h}, { fstp st4 }
FpuReservedEncoding {db 0dfh, 0d5h}, { fstp st5 }
FpuReservedEncoding {db 0dfh, 0d6h}, { fstp st6 }
FpuReservedEncoding {db 0dfh, 0d7h}, { fstp st7 }
FpuReservedEncoding {db 0dfh, 0d8h}, { fstp st0 }
FpuReservedEncoding {db 0dfh, 0d9h}, { fstp st1 }
FpuReservedEncoding {db 0dfh, 0dah}, { fstp st2 }
FpuReservedEncoding {db 0dfh, 0dbh}, { fstp st3 }
FpuReservedEncoding {db 0dfh, 0dch}, { fstp st4 }
FpuReservedEncoding {db 0dfh, 0ddh}, { fstp st5 }
FpuReservedEncoding {db 0dfh, 0deh}, { fstp st6 }
FpuReservedEncoding {db 0dfh, 0dfh}, { fstp st7 }
ShouldTrap X86_XCPT_UD, db 0dfh, 0e1h
ShouldTrap X86_XCPT_UD, db 0dfh, 0e2h
ShouldTrap X86_XCPT_UD, db 0dfh, 0e3h
ShouldTrap X86_XCPT_UD, db 0dfh, 0e4h
ShouldTrap X86_XCPT_UD, db 0dfh, 0e5h
ShouldTrap X86_XCPT_UD, db 0dfh, 0e6h
ShouldTrap X86_XCPT_UD, db 0dfh, 0e7h
ShouldTrap X86_XCPT_UD, db 0dfh, 0f8h
ShouldTrap X86_XCPT_UD, db 0dfh, 0f9h
ShouldTrap X86_XCPT_UD, db 0dfh, 0fah
ShouldTrap X86_XCPT_UD, db 0dfh, 0fbh
ShouldTrap X86_XCPT_UD, db 0dfh, 0fch
ShouldTrap X86_XCPT_UD, db 0dfh, 0fdh
ShouldTrap X86_XCPT_UD, db 0dfh, 0feh
ShouldTrap X86_XCPT_UD, db 0dfh, 0ffh
; Tests some floating point exceptions and such.
mov xDI, [REF_EXTERN(g_pbEfExecPage)]
add xDI, PAGE_SIZE ; invalid page.
; Check denormal numbers.
; Turns out the number is loaded onto the stack even if an exception is triggered.
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuShouldTrap X86_FSW_DE, 0, fld dword [REF(g_r32D0)]
CheckSt0Value 0x00000000, 0x80000000, 0x3f7f
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST | X86_FCW_DM
FpuCheckFSW X86_FSW_DE, 0
CheckSt0Value 0x00000000, 0x80000000, 0x3f7f
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuShouldTrap X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3, \
FpuShouldTrap X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3, \
ShouldTrap X86_XCPT_PF, fld dword [xDI]
; stack overflow vs denormal number
FpuShouldTrap X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3, \
; Mask the overflow exception. We should get QNaN now regardless of
; what we try to push (provided the memory is valid).
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST | X86_FCW_IM
FpuCheckFSW X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value 0x00000000, 0xc0000000, 0xffff
FpuCheckFSW X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value 0x00000000, 0xc0000000, 0xffff
; This is includes denormal values.
FpuCheckFSW X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value 0x00000000, 0xc0000000, 0xffff
; #PF vs previous stack overflow.
I.e. whether pending FPU exception
; is checked before fetching memory operands.
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST
ShouldTrap X86_XCPT_MF, fld dword [xDI]
; What happens when we unmask an exception and fwait?
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST | X86_FCW_IM
FpuCheckFSW X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckFSW X86_FSW_ES | X86_FSW_B | X86_FSW_IE | X86_FSW_SF | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
ShouldTrap X86_XCPT_MF, fwait
ShouldTrap X86_XCPT_MF, fwait
ShouldTrap X86_XCPT_MF, fwait
; Sets the current subtest.
lea rdi, [%%s_szName wrt rip]
lea rcx, [%%s_szName wrt rip]
; Checks the opcode and CS:IP FPU.
; @returns ZF=1 on success, ZF=0 on failure.
; @param xSP + xS fxsave image followed by fnstenv.
; @param xCX Opcode address (no prefixes).
; Check the opcode. This may be disabled.
; AMD64 doesn't seem to store anything at IP and DP, so use the
; fnstenv image instead even if that only contains the lower 32-bit.
; Checks a FPU instruction, no memory operand.
%macro FpuCheckOpcodeCsIp 1
fnstenv [xSP + 512] ; for the selectors (64-bit)
arch_fxrstor [xSP] ; fnstenv screws up the ES bit.
lea xCX, [REF(%%instruction)]
lea xAX, [xAX + __LINE__]
; Checks a trapping FPU instruction, no memory operand.
; Upon return, there is are two FXSAVE image on the stack at xSP.
; @param %1 The instruction.
%macro FpuTrapOpcodeCsIp 1
fxsave [xSP + 1024 +512] ; FPUDS and FPUCS for 64-bit hosts.
; WEIRD: When saved after FWAIT they are ZEROed! (64-bit Intel)
%%trapinfo: istruc TRAPINFO
lea xCX, [REF(%%instruction)]
lea xAX, [xAX + __LINE__]
; Checks the opcode, CS:IP and DS:DP of the FPU.
; @returns ZF=1 on success, ZF=0+EAX on failure.
; @param xSP + xS fxsave image followed by fnstenv.
; @param xCX Opcode address (no prefixes).
; @param xDX Memory address (DS relative).
; Check the memory operand.
; Let CheckOpcodeCsIp to the rest.
; AMD may leave all fields as ZERO in the FXSAVE image - figure
; if there is a flag controlling this anywhere...
; Checks a FPU instruction taking a memory operand.
; @uses xCX, xDX, xAX, Stack.
%macro FpuCheckOpcodeCsIpDsDp 2
fnstenv [xSP + 512] ; for the selectors (64-bit)
arch_fxrstor [xSP] ; fnstenv screws up the ES bit.
lea xCX, [REF(%%instruction)]
lea xAX, [xAX + __LINE__]
; Checks a trapping FPU instruction taking a memory operand.
; Upon return, there is are two FXSAVE image on the stack at xSP.
; @uses xCX, xDX, xAX, Stack.
; @param %1 The instruction.
; @param %2 Operand memory address (DS relative).
%macro FpuTrapOpcodeCsIpDsDp 2
fxsave [xSP + 1024 +512] ; FPUDS and FPUCS for 64-bit hosts.
; WEIRD: When saved after FWAIT they are ZEROed! (64-bit Intel)
%%trapinfo: istruc TRAPINFO
lea xCX, [REF(%%instruction)]
lea xAX, [xAX + __LINE__]
; Checks that the FPU and GReg state is completely unchanged after an instruction
; resulting in a CPU trap.
; @param 1 The trap number.
; @param 2+ The instruction which should trap.
%macro FpuCheckCpuTrapUnchangedState 2+
call SaveFPUAndGRegsToStack
call CompareFPUAndGRegsOnStack
lea xAX, [xAX + __LINE__]
; Initialize the FPU and set CW to %1.
call x861_LoadUniqueRegValuesSSE
; First bunch of FPU instruction tests.
BEGINPROC x861_TestFPUInstr1
; FDIV with 64-bit floating point memory operand.
; ## Normal operation. ##
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
CheckSt0Value 0x00000000, 0xcccccd00, 0x4000
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_One)] }, [REF(g_r64_One)]
FpuCheckFSW 0, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value 0x00000000, 0xcccccd00, 0x4000
; ## Masked exceptions. ##
; Masked stack underflow.
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_One)] }, [REF(g_r64_One)]
FpuCheckFSW X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Zero)] }, [REF(g_r64_Zero)]
FpuCheckFSW X86_FSW_ZE, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Inf)] }, [REF(g_r32_Inf)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Inf)] }, [REF(g_r64_Inf)]
FpuCheckFSW X86_FSW_IE, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Zero)] }, [REF(g_r32_Zero)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Zero)] }, [REF(g_r64_Zero)]
FpuCheckFSW X86_FSW_IE, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
; Masked precision exception, rounded down.
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Ten)] }, [REF(g_r32_Ten)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Three)] }, [REF(g_r64_Three)]
FpuCheckFSW X86_FSW_PE, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value_3_and_a_3rd
; Masked precision exception, rounded up.
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Eleven)] }, [REF(g_r32_Eleven)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Three)] }, [REF(g_r64_Three)]
FpuCheckFSW X86_FSW_PE | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value_3_and_two_3rds
; Masked overflow exception.
FpuCheckOpcodeCsIpDsDp { fld tword [REF(g_r80_Max)] }, [REF(g_r80_Max)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_0dot1)] }, [REF(g_r64_0dot1)]
FpuCheckFSW X86_FSW_PE | X86_FSW_OE | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
; Masked underflow exception.
FpuCheckOpcodeCsIpDsDp { fld tword [REF(g_r80_Min)] }, [REF(g_r80_Min)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Ten)] }, [REF(g_r64_Ten)]
FpuCheckFSW X86_FSW_PE | X86_FSW_UE | X86_FSW_C1, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckSt0Value 0xcccccccd, 0x0ccccccc, 0x0000
FpuCheckOpcodeCsIpDsDp { fld tword [REF(g_r80_One)] }, [REF(g_r80_One)]
FpuCheckOpcodeCsIpDsDp { fdiv qword [REF(g_r64_DnMax)] }, [REF(g_r64_DnMax)]
FxSaveCheckFSW xSP, X86_FSW_DE | X86_FSW_PE, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value xSP, 0x00000800, 0x80000000, 0x43fd
; ## Unmasked exceptions. ##
; Stack underflow - TOP and ST0 unmodified.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_One)] }, [REF(g_r64_One)]
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF | X86_FSW_B | X86_FSW_ES, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0EmptyInitValue xSP
; Zero divide - Unmodified ST0.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Zero)] }, [REF(g_r64_Zero)]
FxSaveCheckFSW xSP, X86_FSW_ZE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0ValueConst xSP, REF(g_r80_r32_3dot2)
; Invalid Operand (
Inf/Inf) - Unmodified ST0.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Inf)] }, [REF(g_r32_Inf)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Inf)] }, [REF(g_r64_Inf)]
FpuCheckFSW X86_FSW_IE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0ValueConst xSP, REF(g_r80_Inf)
; Invalid Operand (0/0) - Unmodified ST0.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Zero)] }, [REF(g_r32_Zero)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Zero)] }, [REF(g_r64_Zero)]
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0ValueConst xSP, REF(g_r80_Zero)
; Precision exception, rounded down.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Ten)] }, [REF(g_r32_Ten)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Three)] }, [REF(g_r64_Three)]
FxSaveCheckFSW xSP, X86_FSW_PE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value_3_and_a_3rd(xSP)
; Precision exception, rounded up.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_Eleven)] }, [REF(g_r32_Eleven)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Three)] }, [REF(g_r64_Three)]
FxSaveCheckFSW xSP, X86_FSW_PE | X86_FSW_C1 | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value_3_and_two_3rds(xSP)
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld tword [REF(g_r80_Max)] }, [REF(g_r80_Max)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_0dot1)] }, [REF(g_r64_0dot1)]
FxSaveCheckFSW xSP, X86_FSW_PE | X86_FSW_OE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value xSP, 0xfffffd7f, 0x9fffffff, 0x2002
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld tword [REF(g_r80_Min)] }, [REF(g_r80_Min)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_Ten)] }, [REF(g_r64_Ten)]
FxSaveCheckFSW xSP, X86_FSW_PE | X86_FSW_UE | X86_FSW_C1 | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value xSP, 0xcccccccd, 0xcccccccc, 0x5ffd
; Denormal operand - Unmodified ST0.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld tword [REF(g_r80_One)] }, [REF(g_r80_One)]
FpuTrapOpcodeCsIpDsDp { fdiv qword [REF(g_r64_DnMax)] }, [REF(g_r64_DnMax)]
FxSaveCheckFSW xSP, X86_FSW_DE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0ValueConst xSP, REF(g_r80_One)
;;; @todo exception priority checks.
; ## A couple of variations on the #PF theme. ##
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
mov xBX, [REF_EXTERN(g_pbEfExecPage)]
FpuCheckCpuTrapUnchangedState X86_XCPT_PF, fdiv qword [xBX + PAGE_SIZE]
; Check that a pending FPU exception takes precedence over a #PF.
fdiv qword [REF(g_r64_One)]
and word [xSP], ~(X86_FCW_IM)
mov xBX, [REF_EXTERN(g_pbEfExecPage)]
ShouldTrap X86_XCPT_MF, fdiv qword [xBX + PAGE_SIZE]
SetSubTest "FSUBRP STn, ST0"
; ## Normal operation. ##
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
FpuCheckOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckSt0ValueConst xSP, REF(g_r80_Zero)
; ## Masked exceptions. ##
; Masked stack underflow, both operands.
FpuCheckOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value_QNaN(xSP)
; Masked stack underflow, one operand.
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
FpuCheckOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value_QNaN(xSP)
fld tword [REF(g_r80_DnMax)]
fld tword [REF(g_r80_DnMin)]
FpuCheckOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckFSW xSP, X86_FSW_DE, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value xSP, 0xfffffffe, 0x7fffffff, 0x8000
; ## Unmasked exceptions. ##
; Stack underflow, both operands - no pop or change.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuTrapOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0EmptyInitValue xSP
; Stack underflow, one operand - no pop or change.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIpDsDp { fld dword [REF(g_r32_3dot2)] }, [REF(g_r32_3dot2)]
FpuTrapOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0ValueConst xSP, REF(g_r80_r32_3dot2)
; Denormal operand - no pop.
fld tword [REF(g_r80_DnMax)]
fld tword [REF(g_r80_DnMin)]
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuTrapOpcodeCsIp { fsubrp st1, st0 }
FxSaveCheckFSW xSP, X86_FSW_DE | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_DnMax)
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_DnMin)
SetSubTest "FSTP ST0, STn"
; ## Normal operation. ##
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_0dot1)]
fld tword [REF(g_r80_3dot2)]
FpuCheckOpcodeCsIp { fstp st2 }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_0dot1)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_3dot2)
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_Max)]
fld tword [REF(g_r80_Inf)]
FpuCheckOpcodeCsIp { fstp st3 }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_Max)
FxSaveCheckStNValueConst xSP, 2, REF(g_r80_Inf)
; Denormal register values doesn't matter get reasserted.
fld tword [REF(g_r80_DnMin)]
fld tword [REF(g_r80_DnMax)]
mov dword [xSP], X86_FCW_PC_64 | X86_FCW_RC_NEAREST
FpuCheckOpcodeCsIp { fstp st2 }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_DnMin)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_DnMax)
; Signaled NaN doesn't matter.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_SNaN)]
fld tword [REF(g_r80_SNaN)]
FpuCheckOpcodeCsIp { fstp st3 }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_SNaN)
FxSaveCheckStNValueConst xSP, 2, REF(g_r80_SNaN)
; Quiet NaN doesn't matter either
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_QNaN)]
fld tword [REF(g_r80_QNaN)]
FpuCheckOpcodeCsIp { fstp st4 }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_QNaN)
FxSaveCheckStNValueConst xSP, 3, REF(g_r80_QNaN)
; There is no overflow signalled.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_SNaNMax)]
fld tword [REF(g_r80_SNaNMax)]
FpuCheckOpcodeCsIp { fstp st1 }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_SNaNMax)
; ## Masked exceptions. ##
; Masked stack underflow.
FpuCheckOpcodeCsIp { fstp st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckSt0Value_QNaN(xSP)
FpuCheckOpcodeCsIp { fstp st0 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
; ## Unmasked exceptions. ##
; Stack underflow - no pop or change.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_0dot1)]
fld tword [REF(g_r80_3dot2)]
fld tword [REF(g_r80_Ten)]
FpuTrapOpcodeCsIp { fstp st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_3dot2)
FxSaveCheckStNValueConst xSP, 2, REF(g_r80_0dot1)
SetSubTest "FISTP M32I, ST0"
mov xBX, [REF_EXTERN(g_pbEfExecPage)]
lea xBX, [xBX + PAGE_SIZE - 4]
; ## Normal operation. ##
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_Ten)]
FpuCheckOpcodeCsIp { fistp dword [xBX] }
CheckMemoryValue dword, xBX, 10
; ## Masked exceptions. ##
; Masked stack underflow.
FpuCheckOpcodeCsIp { fistp dword [xBX] }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckMemoryValue dword, xBX, 0x80000000
fld tword [REF(g_r80_0dot1)]
fld tword [REF(g_r80_3dot2)]
fld tword [REF(g_r80_Ten)]
FpuCheckOpcodeCsIp { fistp dword [xBX] }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckMemoryValue dword, xBX, 0x80000000
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_3dot2)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_0dot1)
; ## Unmasked exceptions. ##
; Stack underflow - no pop or change.
FpuInitWithCW X86_FCW_PC_64 | X86_FCW_RC_NEAREST
fld tword [REF(g_r80_0dot1)]
fld tword [REF(g_r80_3dot2)]
fld tword [REF(g_r80_Ten)]
mov dword [xBX], 0xffeeddcc
FpuTrapOpcodeCsIp { fistp dword [xBX] }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF | X86_FSW_ES | X86_FSW_B, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
CheckMemoryValue dword, xBX, 0xffeeddcc
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_3dot2)
FxSaveCheckStNValueConst xSP, 2, REF(g_r80_0dot1)
; FPTAN - calc, store ST0, push 1.0.
; ## Normal operation. ##
FpuCheckOpcodeCsIp { fptan }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_One)
FxSaveCheckStNValue xSP, 1, 0x00000000, 0x80000000, 0x3fbf ; should be zero, so, this might fail due to precision later.
; Masked stack underflow - two QNaNs.
FpuCheckOpcodeCsIp { fptan }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_NegQNaN)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_NegQNaN)
; Masked stack overflow - two QNaNs
FpuCheckOpcodeCsIp { fptan }
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_NegQNaN)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_NegQNaN)
;; @todo Finish FPTAN testcase.
SetSubTest "FCMOVB ST0,STn"
; ## Normal operation. ##
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_C0 | X86_FSW_C1 | X86_FSW_C2 | X86_FSW_C3, 0 ; seems to be preserved...
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_Zero)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_Zero)
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_C0 | X86_FSW_C1 | X86_FSW_C2 | X86_FSW_C3, 0 ; seems to be preserved...
FxSaveCheckStNValueConst xSP, 0, REF(g_r80_One)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_Zero)
; ## Masked exceptions. ##
; Masked stack underflow - both.
; Note! #IE triggers regardless of the test result!
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValue_QNaN(xSP, 0)
FxSaveCheckStNEmpty xSP, 1
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValue_QNaN(xSP, 0)
FxSaveCheckStNEmpty xSP, 1
; Masked stack underflow - source.
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValue_QNaN(xSP, 0)
FxSaveCheckStNEmpty xSP, 1
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValue_QNaN(xSP, 0)
FxSaveCheckStNEmpty xSP, 1
; Masked stack underflow - destination.
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValue_QNaN(xSP, 0)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_Zero)
FpuCheckOpcodeCsIp { fcmovb st0,st1 }
FxSaveCheckFSW xSP, X86_FSW_IE | X86_FSW_SF, X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3
FxSaveCheckStNValue_QNaN(xSP, 0)
FxSaveCheckStNValueConst xSP, 1, REF(g_r80_Zero)
;; @todo Finish FCMOVB testcase.
ENDPROC x861_TestFPUInstr1
; Terminate the trap info array with a NIL entry.
GLOBALNAME g_aTrapInfoExecPage
GLOBALNAME g_aTrapInfoEnd