bootsector2-cpu-xcpt-1-template.mac revision cf22150eaeeb72431bf1cf65c309a431454fb22b
; $Id$
;; @file
; Bootsector test for basic exceptions - multi mode template.
;
;
; Copyright (C) 2007-2014 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
; you can redistribute it and/or modify it under the terms of the GNU
; General Public License (GPL) as published by the Free Software
; Foundation, in version 2 as it comes in the "COPYING" file of the
; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
;
; The contents of this file may alternatively be used under the terms
; of the Common Development and Distribution License Version 1.0
; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
; VirtualBox OSE distribution, in which case the provisions of the
; CDDL are applicable instead of those of the GPL.
;
; You may elect to license modified versions of this file under the
; terms and conditions of either the GPL or the CDDL or both.
;
%include "bootsector2-template-header.mac"
;*******************************************************************************
;* Defined Constants And Macros *
;*******************************************************************************
;;
; Some 32/64 macros.
;
%if TMPL_BITS == 32
%define bs2Idt_BP bs2Idt32bit_BP
%define MY_R0_CS BS2_SEL_CS32
%define MY_R1_CS BS2_SEL_R1_CS32
%define MY_R2_CS BS2_SEL_R2_CS32
%define MY_R3_CS BS2_SEL_R3_CS32
%define MY_R0_DS BS2_SEL_DS32
%define MY_R1_DS BS2_SEL_R1_DS32
%define MY_R2_DS BS2_SEL_R2_DS32
%define MY_R3_DS BS2_SEL_R3_DS32
%define MY_R0_SS BS2_SEL_SS32
%define MY_R1_SS BS2_SEL_R1_SS32
%define MY_R2_SS BS2_SEL_R2_SS32
%define MY_R3_SS BS2_SEL_R3_SS32
%else
%define bs2Idt_BP bs2Idt64bit_BP
%define MY_R0_CS BS2_SEL_CS64
%define MY_R1_CS BS2_SEL_R1_CS64
%define MY_R2_CS BS2_SEL_R2_CS64
%define MY_R3_CS BS2_SEL_R3_CS64
%define MY_R0_DS BS2_SEL_DS64
%define MY_R1_DS BS2_SEL_R1_DS64
%define MY_R2_DS BS2_SEL_R2_DS64
%define MY_R3_DS BS2_SEL_R3_DS64
%define MY_R0_SS BS2_SEL_SS64
%define MY_R1_SS BS2_SEL_R1_SS64
%define MY_R2_SS BS2_SEL_R2_SS64
%define MY_R3_SS BS2_SEL_R3_SS64
%endif
%ifdef TMPL_64BIT
%assign MY_IS_64BIT 1
%else
%assign MY_IS_64BIT 0
%endif
;*******************************************************************************
;* Global Variables *
;*******************************************************************************
%ifndef CPU_XCPT_1_GLOBALS
%define CPU_XCPT_1_GLOBALS
g_szWrongIfStateFmt:
db 'Wrong IF state (0x%RX32) on line 0x%RX32', 0
g_szWrongHandlerCsFmt:
db 'Wrong handler CS=%RX16, expected %RX16 (line 0x%RX32)', 0
g_szWrongCurCsFmt:
db 'Wrong CS=%RX16, expected %RX16 (line 0x%RX32)', 0
g_szWrongCurSRegFmt_fs:
db 'Wrong FS=%RX16, expected %RX16 (line 0x%RX32)', 0
g_szWrongCurSRegFmt_ss:
db 'Wrong SS=%RX16, expected %RX16 (line 0x%RX32)', 0
;;
; Asserts a test.
;
; @param %1 First cmp operand.
; @param %2 First cmp operand.
; @param %3 Which kind of conditional jump to make
; @param %4 The message to print (format string, no arguments please).
;
%macro ASSERT_SIMPLE 4
cmp %1, %2
%3 %%.ok
push dword __LINE__
%ifdef TMPL_16BIT
push ds
%endif
push %%.s_szMsg
call TMPL_NM_CMN(TestFailedF)
add xSP, sCB*2
jmp %%.ok
%%.s_szMsg: db %4, " (0x%RX32)", 0
%%.ok:
%endmacro
;;
; Asserts that the IF flag is set or clear when the trap handler was called.
;
; @param 1 jnz or jz.
;
; @uses rax, flags, and stack.
;
%macro ASSERT_TRAP_EFLAGS_IF 1
test word [g_u64LastTrapHandlerRFlags xWrtRIP], X86_EFL_IF
%1 %%.ok
%ifdef TMPL_LM64
push __LINE__
push qword [g_u64LastTrapHandlerRFlags xWrtRIP]
lea rax, [g_szWrongIfStateFmt wrt RIP]
push rax
call TMPL_NM_CMN(TestFailedF)
add xSP, 24
%elifdef TMPL_16
push dword __LINE__
push dword [g_u64LastTrapHandlerRFlags]
push cs
push g_szWrongIfStateFmt
call TMPL_NM_CMN(TestFailedF)
add xSP, 12
%else
push __LINE__
push dword [g_u64LastTrapHandlerRFlags]
push g_szWrongIfStateFmt
call TMPL_NM_CMN(TestFailedF)
add xSP, 12
%endif
%%.ok:
%endmacro
;;
; Asserts that a certain CS value when the trap handler was called.
;
; @param 1 The CS value.
;
; @uses rax, flags, and stack.
;
%macro ASSERT_TRAP_CS_VALUE 1
cmp word [g_u16LastTrapHandlerCS xWrtRIP], (%1)
je %%.ok
%ifdef TMPL_LM64
push __LINE__
push (%1)
movzx eax, word [g_u16LastTrapHandlerCS xWrtRIP]
push rax
lea rax, [g_szWrongHandlerCsFmt wrt RIP]
push rax
call TMPL_NM_CMN(TestFailedF)
add xSP, 32
%elifdef TMPL_16
push dword __LINE__
push word (%1)
push word [g_u16LastTrapHandlerCS]
push cs
push g_szWrongHandlerCsFmt
call TMPL_NM_CMN(TestFailedF)
add xSP, 12
%else
push __LINE__
push (%1)
movzx eax, word [g_u16LastTrapHandlerCS]
push eax
push g_szWrongHandlerCsFmt
call TMPL_NM_CMN(TestFailedF)
add xSP, 16
%endif
%%.ok:
%endmacro
;;
; Asserts that a certain CS value right now, CS being loaded in BX.
;
; @param bx The CS value.
; @param 1 The expected CS value.
;
; @uses rax, flags, and stack.
;
%macro ASSERT_CUR_CS_VALUE_IN_BX 1
cmp bx, (%1)
je %%.ok
%ifdef TMPL_LM64
push __LINE__
push (%1)
push rbx
lea rax, [g_szWrongCurCsFmt wrt RIP]
push rax
call TMPL_NM_CMN(TestFailedF)
add xSP, 32
%elifdef TMPL_16
push dword __LINE__
push word (%1)
push bx
push g_szWrongCurCsFmt
call TMPL_NM_CMN(TestFailedF)
add xSP, 12
%else
push __LINE__
push (%1)
push ebx
push g_szWrongCurCsFmt
call TMPL_NM_CMN(TestFailedF)
add xSP, 16
%endif
%%.ok:
%endmacro
;;
; Asserts that the given segment register has a certain value right now.
;
; @param 1 The segment register
; @param 2 The value.
;
; @uses rax, flags, and stack.
;
%macro ASSERT_CUR_SREG_VALUE 2
mov ax, %1
cmp ax, (%2)
je %%.ok
%ifdef TMPL_LM64
push __LINE__
push (%2)
push rax
lea rax, [g_szWrongCurSRegFmt_ %+ %1 wrt RIP]
push rax
call TMPL_NM_CMN(TestFailedF)
add xSP, 32
%elifdef TMPL_16
push dword __LINE__
push word (%2)
push ax
push g_szWrongCurSRegFmt_ %+ %1
call TMPL_NM_CMN(TestFailedF)
add xSP, 12
%else
push __LINE__
push (%2)
push eax
push g_szWrongCurSRegFmt_ %+ %1
call TMPL_NM_CMN(TestFailedF)
add xSP, 16
%endif
%%.ok:
%endmacro
%endif
;;
; Checks different gate types.
;
BEGINPROC TMPL_NM(TestGateType)
push xBP
mov xBP, xSP
push sAX
push xBX
push xCX
push xDX
push xDI
push xSI
mov xAX, .s_szSubTestName
call TMPL_NM_CMN(TestSub)
;
; Check that int3 works and save the IDTE before making changes.
;
; We'll be changing X86DESCGATE.u4Type, which starts at bit 0x28 (that
; is byte 5) and is 4-bit wide, and X86DESCGATE.u1DescType, which is
; at bit 2c.
;
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around...
%ifdef TMPL_LM64
push qword [bs2Idt_BP xWrtRIP]
push qword [bs2Idt_BP + 8 xWrtRIP]
%else
push dword [bs2Idt_BP xWrtRIP]
push dword [bs2Idt_BP + 4 xWrtRIP]
%endif
mov xDI, xSP ; for catching stack errors
;
; Check all kinds of none system selectors first (they should all GP(3+IDT))
;
%assign u4Type 0
%rep 16
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], RT_BIT(4) | u4Type
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
%assign u4Type (u4Type + 1)
%endrep
;
; Illegal system types.
;
%ifdef TMPL_LM64
%assign u4Type 0
%rep 14
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], u4Type
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
%assign u4Type (u4Type + 1)
%endrep
%else
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_286_TSS_AVAIL
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_LDT
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_286_TSS_BUSY
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_286_CALL_GATE
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED2
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TSS_AVAIL
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED3
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TSS_BUSY
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED4
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_CALL_GATE
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
%endif
;
; Legal types.
;
pushf
sti ; make sure interrupts are enabled.
%ifdef TMPL_LM64
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_EFLAGS_IF jz
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_TRAP_GATE
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_EFLAGS_IF jnz
%else
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_INT_GATE
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_EFLAGS_IF jz
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_EFLAGS_IF jnz
;; @todo X86_SEL_TYPE_SYS_TASK_GATE, X86_SEL_TYPE_SYS_286_INT_GATE, X86_SEL_TYPE_SYS_286_TRAP_GATE, X86_SEL_TYPE_SYS_386_CALL_GATE
%endif
popf
;
; Check that a not-present gate GPs. The not-present bit is 0x2f.
;
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
%ifdef TMPL_LM64
or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE
%else
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE
%endif
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2Idt_BP + 5 xWrtRIP], 07fh
BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; Restore the descriptor and make sure it works.
;
ASSERT_SIMPLE xDI, xSP, je, "Someone busted xSP during this test."
%ifdef TMPL_LM64
pop qword [bs2Idt_BP + 8 xWrtRIP]
pop qword [bs2Idt_BP xWrtRIP]
%else
pop dword [bs2Idt_BP + 4 xWrtRIP]
pop dword [bs2Idt_BP xWrtRIP]
%endif
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; Done.
;
call TMPL_NM_CMN(TestSubDone)
pop xSI
pop xDI
pop xDX
pop xCX
pop xBX
pop sAX
leave
ret
.s_szSubTestName:
db TMPL_MODE_STR, ', IDTE type checks', 0
ENDPROC TMPL_NM(TestGateType)
;;
; Checks different code selector types.
;
; @uses No registers, but BS2_SEL_SPARE0 is trashed.
;
BEGINPROC TMPL_NM(TestCodeSelector)
push xBP
mov xBP, xSP
push sAX
push xBX
push xCX
push xDX
push xDI
push xSI
mov xAX, .s_szSubTestName
call TMPL_NM_CMN(TestSub)
;
; Modify the first extra selector to be various kinds of invalid code
; selectors.
;
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around...
%ifdef TMPL_LM64
push qword [bs2Idt_BP xWrtRIP]
push qword [bs2Idt_BP + 8 xWrtRIP]
%else
push dword [bs2Idt_BP xWrtRIP]
push dword [bs2Idt_BP + 4 xWrtRIP]
%endif
mov ecx, [bs2Gdt + MY_R0_CS xWrtRIP]
mov [bs2GdtSpare0 xWrtRIP], ecx
mov ecx, [bs2Gdt + MY_R0_CS + 4 xWrtRIP]
mov [bs2GdtSpare0 + 4 xWrtRIP], ecx ; GdtSpare0 is a copy of the CS descriptor now.
mov word [bs2Idt_BP + 2 xWrtRIP], BS2_SEL_SPARE0
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check again to make sure the CS copy is fine.
; Data selector (u4Type starts at bit 0x28, that is byte 5) .
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO_ACC
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_ACC
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO_DOWN
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO_DOWN_ACC
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_DOWN
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_DOWN_ACC
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
; Executable selector types (works fine).
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO_ACC
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO_CONF
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO_CONF_ACC
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_CONF
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_CONF_ACC
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; Test with the code selector set to NULL.
;
mov word [bs2Idt_BP + 2 xWrtRIP], 0
BS2_TRAP_INSTR X86_XCPT_GP, 0, int3
mov word [bs2Idt_BP + 2 xWrtRIP], 1
BS2_TRAP_INSTR X86_XCPT_GP, 0, int3
mov word [bs2Idt_BP + 2 xWrtRIP], 2
BS2_TRAP_INSTR X86_XCPT_GP, 0, int3
mov word [bs2Idt_BP + 2 xWrtRIP], 3
BS2_TRAP_INSTR X86_XCPT_GP, 0, int3
mov word [bs2Idt_BP + 2 xWrtRIP], BS2_SEL_SPARE0 ; restore our CS
;
; Test with the code selector marked as not present but otherwise valid.
;
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 07fh
BS2_TRAP_INSTR X86_XCPT_NP, BS2_SEL_SPARE0, int3
;
; Invalid CS selector and not present, we should get a GP.
; Intel states that the present bit is checked after the type.
;
and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_DOWN_ACC
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
%ifdef TMPL_LM64
; Long mode variations on invalid (L and D bits) pitted against NP.
and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC
and byte [bs2GdtSpare0 + 6 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) ; (0x35=u1Long, 0x36=u1DefBig) = (0, 0)
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
or byte [bs2GdtSpare0 + 6 xWrtRIP], RT_BIT(6) ; (0x35=u1Long, 0x36=u1DefBig) = (0, 1)
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
or byte [bs2GdtSpare0 + 6 xWrtRIP], RT_BIT(5) ; (0x35=u1Long, 0x36=u1DefBig) = (1, 1)
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 6 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6))
or byte [bs2GdtSpare0 + 6 xWrtRIP], RT_BIT(5) ; restored
%endif
and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC | 080h ; restore CS to present & valid.
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; make sure this is so.
;
; Check the CS DPL vs IDTE DPL.
; X86DESCGENERIC.u2Dpl is at bit 0x2d (i.e. in byte 5).
;
and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6))
or byte [bs2GdtSpare0 + 5 xWrtRIP], 0 ; CS.DPL == 0 == CPL
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6))
or byte [bs2GdtSpare0 + 5 xWrtRIP], 1 << 5 ; CS.DPL == 1 < CPL
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6))
or byte [bs2GdtSpare0 + 5 xWrtRIP], 2 << 5 ; CS.DPL == 2 < CPL
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6))
or byte [bs2GdtSpare0 + 5 xWrtRIP], 3 << 5 ; CS.DPL == 3 < CPL
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
; Restore.
and byte [bs2GdtSpare0 + 5 xWrtRIP], 010h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC | 080h ; restore CS to present, valid and DPL=0
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; make sure it's restored.
;
; Is RPL is ignored? Yes, it is.
;
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL ; RPL = 0
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL
or byte [bs2Idt_BP + 2 xWrtRIP], 1 ; RPL = 1
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL
or byte [bs2Idt_BP + 2 xWrtRIP], 2 ; RPL = 2
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL
or byte [bs2Idt_BP + 2 xWrtRIP], 3 ; RPL = 3
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0
;
; Conforming CS.
;
or byte [bs2Idt_BP + 5 xWrtRIP], (3 << 5) ; IDTE.DPL = 3
and byte [bs2GdtSpare0 + 5 xWrtRIP], 090h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_CONF_ACC ; CS.DPL=0, code, read, conforming
call TMPL_NM_CMN(Bs2ToRing1)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 1
call TMPL_NM_CMN(Bs2ToRing2)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2
call TMPL_NM_CMN(Bs2ToRing3)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 3
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 0
; RPL is ignored. Only CPL matters.
or byte [bs2Idt_BP + 2 xWrtRIP], (3 << 5) ; IDTE.CS.RPL=3
call TMPL_NM_CMN(Bs2ToRing2)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL
or byte [bs2Idt_BP + 2 xWrtRIP], (1 << 5) ; IDTE.CS.RPL=1
call TMPL_NM_CMN(Bs2ToRing2)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL
or byte [bs2Idt_BP + 2 xWrtRIP], (2 << 5) ; IDTE.CS.RPL=2
call TMPL_NM_CMN(Bs2ToRing2)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2
; Change the CS.DPL to 1 and try it from ring-0.
and byte [bs2GdtSpare0 + 5 xWrtRIP], 09fh
or byte [bs2GdtSpare0 + 5 xWrtRIP], (1 << 5) ; CS.DPL=1
BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3
; Restore.
and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL
and byte [bs2Idt_BP + 5 xWrtRIP], 0x9f ; IDTE.DPL=0
and byte [bs2GdtSpare0 + 5 xWrtRIP], 010h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC | 080h ; restore CS to present, valid and DPL=0
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; make sure it's restored.
;
; Limit / canonical checks.
;
; Messing with X86DESCGENERIC.u16LimitLow which is at bit 0,
; X86DESCGENERIC.u4LimitHigh which is at bit 0x30, and
; X86DESCGENERIC.u1Granularity which is at bit 0x37.
;
mov word [bs2GdtSpare0 xWrtRIP], 0010h
and byte [bs2GdtSpare0 + 6 xWrtRIP], 070h ; setting limit to 0x10, ASSUMES IDTE.off > 0x10
%ifdef TMPL_LM64
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
%else
BS2_TRAP_INSTR X86_XCPT_GP, 0, int3
%endif
%ifdef TMPL_LM64
or dword [bs2Idt_BP + 8 xWrtRIP], 0x007f7f33
BS2_TRAP_INSTR X86_XCPT_GP, 0, int3
%endif
; Who takes precedence? CS NP or the above GP? NP does.
and byte [bs2GdtSpare0 + 5 xWrtRIP], 07fh
BS2_TRAP_INSTR X86_XCPT_NP, BS2_SEL_SPARE0, int3
%ifdef TMPL_LM64
; Who takes precedence? IDTE NP or the not canoncial GP? NP does.
or byte [bs2GdtSpare0 + 5 xWrtRIP], 80h
and byte [bs2Idt_BP + 5 xWrtRIP], 07fh
BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
%endif
;
; Restore the descriptor and make sure it works.
;
%ifdef TMPL_LM64
pop qword [bs2Idt_BP + 8 xWrtRIP]
pop qword [bs2Idt_BP xWrtRIP]
%else
pop dword [bs2Idt_BP + 4 xWrtRIP]
pop dword [bs2Idt_BP xWrtRIP]
%endif
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; Done.
;
call TMPL_NM_CMN(TestSubDone)
pop xSI
pop xDI
pop xDX
pop xCX
pop xBX
pop sAX
leave
ret
.s_szSubTestName:
db TMPL_MODE_STR, ', IDTE CS checks', 0
ENDPROC TMPL_NM(TestCodeSelector)
;;
; Checks that the IDTE type is checked before the CS type.
;
; @uses No registers, but BS2_SEL_SPARE0 is trashed.
;
BEGINPROC TMPL_NM(TestCheckOrderCsTypeVsIdteType)
push xBP
mov xBP, xSP
push sAX
push xBX
push xCX
push xDX
push xDI
push xSI
mov xAX, .s_szSubTestName
call TMPL_NM_CMN(TestSub)
;
; Check the int3 and save its IDTE.
;
; We'll be changing X86DESCGATE.u4Type, which starts at bit 0x28 (that
; is byte 5) and is 4-bit wide, and X86DESCGATE.u1DescType, which is
; at bit 2c.
;
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around...
%ifdef TMPL_LM64
push qword [bs2Idt_BP xWrtRIP]
push qword [bs2Idt_BP + 8 xWrtRIP]
%else
push dword [bs2Idt_BP xWrtRIP]
push dword [bs2Idt_BP + 4 xWrtRIP]
%endif
;
; Make a copy of our CS descriptor into spare one and make INT3 use it.
;
mov ecx, [bs2Gdt + MY_R0_CS xWrtRIP]
mov [bs2GdtSpare0 xWrtRIP], ecx
mov ecx, [bs2Gdt + MY_R0_CS + 4 xWrtRIP]
mov [bs2GdtSpare0 + 4 xWrtRIP], ecx ; GdtSpare0 is a copy of the CS descriptor now.
mov word [bs2Idt_BP + 2 xWrtRIP], BS2_SEL_SPARE0
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check again to make sure the CS copy is fine.
;
; Make both the IDTE type and CS invalid, we should end up with a IDT GP not the CS one.
; CS = data selector and IDTE invalid 0 type.
;
and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO
and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; Make the IDTE not-present but otherwise fine, keeping CS invalid.
;
and byte [bs2Idt_BP + 5 xWrtRIP], 070h
%ifdef TMPL_LM64
or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE
%else
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE
%endif
BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; Make the CS not present as well.
;
and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h
or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO
BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; CS not present, IDTE invalid but present.
;
and byte [bs2Idt_BP + 5 xWrtRIP], 0f0h
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED | 0x80
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; CS NULL, IDTE invalid but present.
;
mov word [bs2Idt_BP + 2 xWrtRIP], 0
BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; CS NULL, IDTE valid but not present.
;
and byte [bs2Idt_BP + 5 xWrtRIP], 070h
%ifdef TMPL_LM64
or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE
%else
or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE
%endif
BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3
;
; Restore the descriptor and make sure it works.
;
%ifdef TMPL_LM64
pop qword [bs2Idt_BP + 8 xWrtRIP]
pop qword [bs2Idt_BP xWrtRIP]
%else
pop dword [bs2Idt_BP + 4 xWrtRIP]
pop dword [bs2Idt_BP xWrtRIP]
%endif
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; Done.
;
call TMPL_NM_CMN(TestSubDone)
pop xSI
pop xDI
pop xDX
pop xCX
pop xBX
pop sAX
leave
ret
.s_szSubTestName:
db TMPL_MODE_STR, ', IDTE.type before CS.type', 0
ENDPROC TMPL_NM(TestCheckOrderCsTypeVsIdteType)
;;
; Checks stack switching behavior.
;
; @uses none
;
BEGINPROC TMPL_NM(TestStack)
push xBP
mov xBP, xSP
push sAX
push xBX
push xCX
push xDX
push xDI
push xSI
pushf
cli
mov xAX, .s_szSubTestName
call TMPL_NM_CMN(TestSub)
;
; Check the int3, save its IDTE, then make it ring-3 accessible.
;
; X86DESCGENERIC.u2Dpl is at bit 0x2d (i.e. in byte 5).
;
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around...
%ifdef TMPL_LM64
push qword [bs2Idt_BP xWrtRIP]
push qword [bs2Idt_BP + 8 xWrtRIP]
%else
push dword [bs2Idt_BP xWrtRIP]
push dword [bs2Idt_BP + 4 xWrtRIP]
%endif
and byte [bs2Idt_BP + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6))
or byte [bs2Idt_BP + 5 xWrtRIP], 3 << 5 ; DPL == 3
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; In ring-0 no stack switching is performed.
;
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov xBX, [g_u64LastTrapHandlerRSP]
%ifdef TMPL_64BIT
mov rax, rsp
and rax, ~15
sub rax, 7*8
%else
lea eax, [esp - 5*4]
%endif
ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-0 -> ring-0 int3."
mov bx, [g_u16LastTrapHandlerSS]
mov ax, ss
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0 -> ring-0 int3."
;
; Switch to ring-1 and watch stack switching take place.
;
call TMPL_NM_CMN(Bs2ToRing1)
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov xBX, [g_u64LastTrapHandlerRSP]
mov sAX, BS2_R0_STACK_ADDR
%ifdef TMPL_64BIT
and rax, ~15
sub rax, 7*8
%else
sub eax, 7*4
%endif
ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-1 -> ring-0 int3."
mov bx, [g_u16LastTrapHandlerSS]
%ifdef TMPL_64BIT
mov ax, 0
%else
mov ax, MY_R0_SS
%endif
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-1 -> ring-0 int3."
call TMPL_NM_CMN(Bs2ToRing0)
;
; Missaligned stack, ring-0 -> ring-0.
;
mov xDI, xSP ; save the stack pointer.
%rep 15
sub xSP, 1h
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov xBX, [g_u64LastTrapHandlerRSP]
%ifdef TMPL_64BIT
mov rax, rsp
and rax, ~15
sub rax, 7*8
%else
lea eax, [esp - 5*4]
%endif
ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-0 -> ring-0 int3, w/ unaligned stack."
mov bx, [g_u16LastTrapHandlerSS]
mov ax, ss
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0 -> ring-0 int3, w/ unaligned stack."
%endrep
mov xSP, xDI ; restore the stack pointer.
;
; Missaligned stack, ring-1 -> ring-0.
;
call TMPL_NM_CMN(Bs2ToRing1)
mov sSI, BS2_R0_STACK_ADDR - 16
%rep 16
add sSI, 1
%ifdef TMPL_64BIT
mov [bs2Tss64Bit + 4], sSI
%else
mov [bs2Tss32Bit + 4], sSI
%endif
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov xBX, [g_u64LastTrapHandlerRSP]
mov sAX, sSI
%ifdef TMPL_64BIT
and rax, ~15
sub rax, 7*8
%else
sub eax, 7*4
%endif
ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-1 -> ring-0 int3, w/ unaligned ring-0 stack."
mov bx, [g_u16LastTrapHandlerSS]
%ifdef TMPL_64BIT
mov ax, 0
%else
mov ax, MY_R0_SS
%endif
ASSERT_SIMPLE sAX, xBX, je, "Wrong SS value for ring-1 -> ring-0 int3, w/ unaligned ring-0 stack."
%endrep
call TMPL_NM_CMN(Bs2ToRing0)
%ifdef TMPL_64BIT
;
; Stack table (AMD64 only), ring-0 -> ring-0.
;
and byte [bs2Idt_BP + 4], ~7
or byte [bs2Idt_BP + 4], 3 ; IDTE.IST=3
mov rdi, [bs2Tss64Bit + X86TSS64.ist3]
mov rsi, BS2_R0_STACK_ADDR - 128
%rep 16
sub rsi, 1h
mov [bs2Tss64Bit + X86TSS64.ist3], rsi
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov rbx, [g_u64LastTrapHandlerRSP]
mov rax, rsi
and rax, ~15
sub rax, 7*8
ASSERT_SIMPLE rax, rbx, je, "Wrong xSP value for ring-0 -> ring-0 int3, w/ unaligned IST."
mov bx, [g_u16LastTrapHandlerSS]
mov ax, ss
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0 -> ring-0 int3, w/ unaligned IST."
%endrep
; Continue in ring-1,2,3.
%assign uCurRing 1
%rep 3
call TMPL_NM_CMN(Bs2ToRing %+ uCurRing)
%rep 16
sub rsi, 1h
mov [bs2Tss64Bit + X86TSS64.ist3], rsi
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov rbx, [g_u64LastTrapHandlerRSP]
mov rax, rsi
and rax, ~15
sub rax, 7*8
ASSERT_SIMPLE rax, rbx, je, "Wrong xSP value for ring-X -> ring-0 int3, w/ unaligned IST."
mov bx, [g_u16LastTrapHandlerSS]
mov ax, 0
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-X -> ring-0 int3, w/ unaligned IST."
%endrep
call TMPL_NM_CMN(Bs2ToRing0)
%assign uCurRing (uCurRing + 1)
%endrep
mov [bs2Tss64Bit + X86TSS64.ist3], rdi ; restore original value
and byte [bs2Idt_BP + 4], ~7 ; IDTE.IST=0
;
; Check SS handling when interrupting 32-bit code with a 64-bit handler.
;
call Bs2Thunk_lm64_lm32
BITS 32
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov bx, [g_u16LastTrapHandlerSS]
mov ax, ss
call Bs2Thunk_lm32_lm64
BITS 64
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0-32 -> ring-0-64 int3, w/ 32-bit stack."
call Bs2Thunk_lm64_lm32
BITS 32
mov cx, ss
mov ax, BS2_SEL_SS16
mov ss, ax
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
mov bx, [g_u16LastTrapHandlerSS]
mov ss, cx
call Bs2Thunk_lm32_lm64
BITS 64
ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0-32 -> ring-0-64 int3, w/ 16-bit stack."
%endif ; TMPL_64BIT
;
; Restore the descriptor and make sure it works.
;
%ifdef TMPL_LM64
pop qword [bs2Idt_BP + 8 xWrtRIP]
pop qword [bs2Idt_BP xWrtRIP]
%else
pop dword [bs2Idt_BP + 4 xWrtRIP]
pop dword [bs2Idt_BP xWrtRIP]
%endif
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; Done.
;
call TMPL_NM_CMN(TestSubDone)
popf
pop xSI
pop xDI
pop xDX
pop xCX
pop xBX
pop sAX
leave
ret
.s_szSubTestName:
db TMPL_MODE_STR, ', Stack switching', 0
ENDPROC TMPL_NM(TestStack)
;;
; Loads MY_R0_CS into CS.
;
; @uses stack, cs, flags
;
BEGINPROC TMPL_NM(TestLoadMyCS)
push 0
push xAX
; Make it a far return with MY_R0_CS + CPL.
mov xAX, [xSP + xCB*2]
mov [xSP + xCB*1], xAX
mov xAX, ss
%ifdef TMPL_64BIT
sub xAX, BS2_SEL_GRP_SS64 - BS2_SEL_GRP_CS64
%elifdef TMPL_32BIT
sub xAX, BS2_SEL_GRP_SS32 - BS2_SEL_GRP_CS32
%elifdef TMPL_16BIT
sub xAX, BS2_SEL_GRP_SS16 - BS2_SEL_GRP_CS16
%else
TMPL_xxBIT is not defined
%endif
mov [xSP + xCB*2], xAX
pop xAX
retf
ENDPROC TMPL_NM(TestLoadMyCS)
;;
; Checks our understanding of how conforming segments are handled.
;
; @uses No registers, but BS2_SEL_SPARE0 is trashed.
;
BEGINPROC TMPL_NM(TestConforming)
push xBP
mov xBP, xSP
push sAX
push xBX
push xCX
push xDX
push xDI
push xSI
mov xAX, .s_szSubTestName
call TMPL_NM_CMN(TestSub)
;
; Check the int3.
;
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around...
mov xDI, xSP ; save the stack pointer.
sub xSP, 20h
;
; In this test we will do various experiments with code using a
; conforming CS. The main purpose is to check that CS.RPL is always the
; same as CPL, despite earlier beliefs to the contrary. Because if it
; is different, iret cannot dermine the CPL to return to among other
; interesting problems.
;
mov ecx, [bs2Gdt + MY_R0_CS xWrtRIP]
mov [bs2GdtSpare0 xWrtRIP], ecx
mov ecx, [bs2Gdt + MY_R0_CS + 4 xWrtRIP]
mov [bs2GdtSpare0 + 4 xWrtRIP], ecx ; GdtSpare0 is a copy of the CS descriptor now.
and byte [bs2GdtSpare0 + 5], 0x90 ; DPL = 0
or byte [bs2GdtSpare0 + 5], X86_SEL_TYPE_ER_CONF_ACC
%assign uCurRing 0
%rep 4
; Far jumps.
%assign uSpecifiedRpl 0
%rep 4
call TMPL_NM_CMN(Bs2ToRing %+ uCurRing)
lea xAX, [.far_jmp_target_ %+ uSpecifiedRpl %+ uCurRing]
%ifdef TMPL_64BIT ; AMD doesn't have an jmp far m16:m64 instruction, it ignores REX.W apparently. Intel does though.
; Tested on: Bulldozer
mov dword [xSP + 4], BS2_SEL_SPARE0 | uSpecifiedRpl
mov [xSP], eax
jmp far dword [xSP]
%else
mov dword [xSP + xCB], BS2_SEL_SPARE0 | uSpecifiedRpl
mov [xSP], xAX
jmp far xPRE [xSP]
%endif
.far_jmp_target_ %+ uSpecifiedRpl %+ uCurRing:
mov bx, cs
call TMPL_NM(TestLoadMyCS)
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_CUR_CS_VALUE_IN_BX BS2_SEL_SPARE0 | uCurRing
%assign uSpecifiedRpl uSpecifiedRpl + 1
%endrep
; Far calls.
%assign uSpecifiedRpl 0
%rep 4
call TMPL_NM_CMN(Bs2ToRing %+ uCurRing)
mov xSI, xSP
lea xAX, [.far_call_target_ %+ uSpecifiedRpl %+ uCurRing]
%ifdef TMPL_64BIT ; AMD doesn't have an call far m16:m64 instruction, it ignores REX.W apparently. Intel does though.
; Tested on: Bulldozer
mov dword [xSP + 4], BS2_SEL_SPARE0 | uSpecifiedRpl
mov [xSP], eax
call far dword [xSP]
%else
mov dword [xSP + xCB], BS2_SEL_SPARE0 | uSpecifiedRpl
mov [xSP], xAX
call far xPRE [xSP]
%endif
.far_call_target_ %+ uSpecifiedRpl %+ uCurRing:
mov bx, cs
%ifdef TMPL_64BIT
add xSP, 4 * 2
%else
add xSP, xCB * 2
%endif
call TMPL_NM(TestLoadMyCS)
call TMPL_NM_CMN(Bs2ToRing0)
ASSERT_CUR_CS_VALUE_IN_BX BS2_SEL_SPARE0 | uCurRing
%assign uSpecifiedRpl uSpecifiedRpl + 1
%endrep
%assign uCurRing uCurRing + 1
%endrep
;
; While at it, lets check something about RPL and non-conforming
; segments. The check when loading is supposed to be RPL >= DPL,
; except for when loading SS, where RPL = DPL = CPL.
;
; ring-0
mov dx, MY_R0_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R0_DS | 0
mov dx, MY_R0_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
; ring-0 - Lower DPL isn't an issue, only RPL vs DPL.
mov dx, MY_R1_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 0
mov dx, MY_R1_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 1
mov dx, MY_R1_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
mov dx, MY_R2_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 0
mov dx, MY_R2_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 2
mov dx, MY_R2_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
mov dx, MY_R3_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0
mov dx, MY_R3_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1
mov dx, MY_R3_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2
mov dx, MY_R3_DS | 3
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3
; ring-0 - What works above doesn't work with ss.
mov dx, MY_R1_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx
mov dx, MY_R1_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx
mov dx, MY_R1_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx
mov dx, MY_R2_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx
mov dx, MY_R3_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
; ring-1
call TMPL_NM_CMN(Bs2ToRing1)
mov dx, MY_R1_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 0
mov dx, MY_R1_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 1
mov dx, MY_R1_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
mov dx, MY_R1_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
mov dx, MY_R0_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
; ring-1 - Lower DPL isn't an issue, only RPL vs DPL.
mov dx, MY_R2_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 0
mov dx, MY_R2_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 1
mov dx, MY_R2_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 2
mov dx, MY_R2_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
mov dx, MY_R3_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0
mov dx, MY_R3_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1
mov dx, MY_R3_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2
mov dx, MY_R3_DS | 3
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3
; ring-1 - What works above doesn't work with ss.
mov dx, MY_R1_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx
mov dx, MY_R1_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx
mov dx, MY_R2_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx
mov dx, MY_R3_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
; ring-2
call TMPL_NM_CMN(Bs2ToRing2)
mov dx, MY_R2_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 0
mov dx, MY_R2_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 1
mov dx, MY_R2_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 2
mov dx, MY_R2_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
mov dx, MY_R0_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R1_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
mov dx, MY_R1_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
; ring-2 - Lower DPL isn't an issue, only RPL vs DPL.
mov dx, MY_R3_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0
mov dx, MY_R3_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1
mov dx, MY_R3_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2
mov dx, MY_R3_DS | 3
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3
; ring-2 - What works above doesn't work with ss.
mov dx, MY_R2_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx
mov dx, MY_R2_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx
mov dx, MY_R3_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
; ring-3
call TMPL_NM_CMN(Bs2ToRing3)
mov dx, MY_R3_DS | 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0
mov dx, MY_R3_DS | 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1
mov dx, MY_R3_DS | 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2
mov dx, MY_R3_DS | 3
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3
mov dx, MY_R0_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R0_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx
mov dx, MY_R1_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
mov dx, MY_R1_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx
mov dx, MY_R2_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
mov dx, MY_R2_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
mov dx, MY_R2_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
mov dx, MY_R2_DS | 3
BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx
; ring-0 - What works above doesn't work with ss.
mov dx, MY_R3_DS | 0
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 1
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
mov dx, MY_R3_DS | 2
BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx
call TMPL_NM_CMN(Bs2ToRing0)
;
; One more odd thing, NULL selectors and RPL.
;
pushf
cli
%assign uCurRing 0
%rep 4
; Null sectors.
call TMPL_NM_CMN(Bs2ToRing %+ uCurRing)
mov si, ss
mov dx, 0
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, 0
%if MY_IS_64BIT == 0 || uCurRing != 0
%ifdef TMPL_64BIT ; AMD is doing something inconsistent.
%if uCurRing != 3
test byte [g_fCpuAmd], 1
jz .null_0_not_amd_ %+ uCurRing
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 0
jmp .null_0_next_ %+ uCurRing
.null_0_not_amd_ %+ uCurRing:
%endif
%endif
BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx
.null_0_next_ %+ uCurRing:
%else
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 0
%endif
mov ss, si
mov dx, 1
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, 1
%if MY_IS_64BIT == 0 || uCurRing != 1
%ifdef TMPL_64BIT ; AMD is doing something inconsistent.
%if uCurRing != 3
test byte [g_fCpuAmd], 1
jz .null_1_not_amd_ %+ uCurRing
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 1
jmp .null_1_next_ %+ uCurRing
.null_1_not_amd_ %+ uCurRing:
%endif
%endif
BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx
.null_1_next_ %+ uCurRing:
%else
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 1
%endif
mov ss, si
mov dx, 2
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, 2
%if MY_IS_64BIT == 0 || uCurRing != 2
%ifdef TMPL_64BIT ; AMD is doing something inconsistent.
%if uCurRing != 3
test byte [g_fCpuAmd], 1
jz .null_2_not_amd_ %+ uCurRing
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 2
jmp .null_2_next_ %+ uCurRing
.null_2_not_amd_ %+ uCurRing:
%endif
%endif
BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx
.null_2_next_ %+ uCurRing:
%else
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 2
%endif
mov ss, si
mov dx, 3
mov fs, dx
ASSERT_CUR_SREG_VALUE fs, 3
%ifdef TMPL_64BIT ; AMD is doing something inconsistent.
%if uCurRing != 3
test byte [g_fCpuAmd], 1
jz .null_3_not_amd_ %+ uCurRing
mov ss, dx
ASSERT_CUR_SREG_VALUE ss, 3
jmp .null_3_next_ %+ uCurRing
.null_3_not_amd_ %+ uCurRing:
%endif
%endif
BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx
.null_3_next_ %+ uCurRing:
mov ss, si
%assign uCurRing uCurRing + 1
%endrep
call TMPL_NM_CMN(Bs2ToRing0)
; Restore the selectors.
mov dx, MY_R0_DS
mov ds, dx
mov es, dx
mov fs, dx
mov gs, dx
popf
;
; Restore the descriptor and make sure it works.
;
mov xSP, xDI ; restore the stack pointer.
BS2_TRAP_INSTR X86_XCPT_BP, 0, int3
;
; Done.
;
call TMPL_NM_CMN(TestSubDone)
pop xSI
pop xDI
pop xDX
pop xCX
pop xBX
pop sAX
leave
ret
.s_szSubTestName:
db TMPL_MODE_STR, ', Conforming CS, ++', 0
ENDPROC TMPL_NM(TestConforming)
;;
; Returning from interrupt/trap/whatever handlers.
;
; @uses No registers, but BS2_SEL_SPARE0 is trashed.
;
BEGINPROC TMPL_NM(TestReturn)
push xBP
mov xBP, xSP
push sAX
push xBX
push xCX
push xDX
push xDI
push xSI
sub xSP, 80h ; iret stack frame space.
mov xSI, xSP ; Save the stack register.
mov xAX, .s_szSubTestName
call TMPL_NM_CMN(TestSub)
%ifdef TMPL_64BIT
pushfq
pop rdi ; rdi contains good flags register value.
;
; 64-bit mode: IRETQ unconditional pop of SS:RSP.
;
mov qword [rsp + 20h], MY_R0_SS
mov [rsp + 18h], rsp
mov [rsp + 10h], rdi
mov qword [rsp + 08h], MY_R0_CS
lea rax, [.resume1 wrt rip]
mov [rsp + 00h], rax
iretq
.resume1:
pushfq
pop rbx
ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETQ."
mov rsp, rsi
ASSERT_SIMPLE rbx, rdi, je, "Wrong flags after IRETQ."
mov ax, ss
ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETQ."
mov ax, cs
ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETQ."
; 64-bit mode: The NT flag causes #GP(0)
mov qword [rsp + 20h], MY_R0_SS
lea rax, [rsp - 100h]
mov [rsp + 18h], rax
mov [rsp + 10h], rdi
mov qword [rsp + 08h], MY_R0_CS
lea rax, [.resume2 wrt rip]
mov [rsp + 00h], rax
push rdi
or dword [rsp], X86_EFL_NT
popfq
BS2_TRAP_BRANCH_INSTR X86_XCPT_GP, 0, .resume2, iretq
pushfq
pop rbx
push rdi
popfq
ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETQ."
mov rsp, rsi
mov rax, rdi
or rax, X86_EFL_NT
ASSERT_SIMPLE rbx, rax, je, "Wrong flags after IRETQ GP(0)-NT."
mov ax, ss
ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETQ."
mov ax, cs
ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETQ."
; 64-bit mode: The VM flag is disregarded.
mov qword [rsp + 20h], MY_R0_SS
lea rax, [rsp - 88h]
mov [rsp + 18h], rax
mov [rsp + 10h], rdi
or dword [rsp + 10h], X86_EFL_VM
mov qword [rsp + 08h], MY_R0_CS
lea rax, [.resume3 wrt rip]
mov [rsp + 00h], rax
iretq
.resume3:
pushfq
pop rbx
add rsp, 88h
ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETQ."
mov rsp, rsi
mov rax, rdi
ASSERT_SIMPLE rbx, rax, je, "Wrong flags after IRETQ GP(0)-NT."
mov ax, ss
ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETQ."
mov ax, cs
ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETQ."
;
; 64-bit mode: IRETD unconditionally pops SS:ESP as well.
;
mov dword [rsp + 10h], MY_R0_SS
lea eax, [esp - 18h]
mov [rsp + 0ch], eax
mov [rsp + 08h], edi
mov dword [rsp + 04h], MY_R0_CS
lea eax, [.resume20 wrt rip]
mov [rsp + 00h], eax
iretd
.resume20:
pushfq
pop rbx
add rsp, 18h
ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETD."
mov rsp, rsi
ASSERT_SIMPLE rbx, rdi, je, "Wrong flags after IRETD."
mov ax, ss
ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETD."
mov ax, cs
ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETD."
;
; 64-bit mode: IRET unconditionally pops SS:SP as well.
;
mov word [rsp + 08h], MY_R0_SS
lea eax, [esp - 1ah]
mov [rsp + 06h], ax
mov [rsp + 04h], di
mov word [rsp + 02h], MY_R0_CS
mov word [rsp + 00h], .resume30
o16 iret
BEGINCODELOW
.resume30:
jmp .high1
BEGINCODEHIGH
.high1:
pushfq
pop rbx
add rsp, 1ah
ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRET."
mov rsp, rsi
ASSERT_SIMPLE rbx, rdi, je, "Wrong flags after IRET."
mov ax, ss
ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRET."
mov ax, cs
ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRET."
%elifdef TMPL_32BIT
; later...
%endif
;
; Returning to 16-bit code, what happens to upper ESP bits?
;
cli
mov xBX, xSP ; save the current stack address
mov sAX, BS2_SEL_R3_SS16 | 3
push sAX ; Return SS
movzx edi, bx
or edi, 0xdead0000
push sDI ; Return sSP
%ifdef TMPL_64BIT
pushfq
%else
pushfd
%endif
mov sAX, BS2_SEL_R3_CS16 | 3
push sAX ; Return CS
lea sAX, [.resume100 xWrtRIP]
push sAX ; Return sIP
%ifdef TMPL_64BIT
iretq
%else
iretd
%endif
BEGINCODELOW
BITS 16
.resume100:
xchg ebx, esp
call Bs2ToRing0_p16
call TMPL_NM(Bs2Thunk_p16)
BITS TMPL_BITS
jmp .high100
BEGINCODEHIGH
.high100:
and edi, 0ffffh
ASSERT_SIMPLE ebx, edi, je, "IRET to 16-bit didn't restore ESP as expected [#1]."
%ifndef TMPL_16BIT
;
; Take two on 16-bit return, does the high word of ESP leak?
;
cli
mov sBX, sSP ; save the current stack address
mov xSP, BS2_MUCK_ABOUT_BASE + 1000h
mov sAX, BS2_SEL_R3_SS16 | 3
push sAX ; Return SS
mov sDI, sBX
push sDI ; Return sSP
%ifdef TMPL_64BIT
pushfq
%else
pushfd
%endif
mov sAX, BS2_SEL_R3_CS16 | 3
push sAX ; Return CS
lea sAX, [.resume101 xWrtRIP]
push sAX ; Return sIP
%ifdef TMPL_64BIT
iretq
%else
iretd
%endif
BEGINCODELOW
BITS 16
.resume101:
xchg ebx, esp
call Bs2ToRing0_p16
call TMPL_NM(Bs2Thunk_p16)
BITS TMPL_BITS
jmp .high101
BEGINCODEHIGH
.high101:
or edi, (BS2_MUCK_ABOUT_BASE + 1000h) & 0ffff0000h
ASSERT_SIMPLE ebx, edi, je, "IRET to 16-bit didn't restore ESP as expected [#2]."
%endif ; Not 16-bit.
;
; Done.
;
call TMPL_NM_CMN(TestSubDone)
mov xSP, xSI
add xSP, 80h
pop xSI
pop xDI
pop xDX
pop xCX
pop xBX
pop sAX
leave
ret
.s_szSubTestName:
db TMPL_MODE_STR, ', IRET', 0
ENDPROC TMPL_NM(TestReturn)
;;
; Do the tests for this mode.
;
; @uses nothing
;
BEGINCODELOW
BITS 16
BEGINPROC TMPL_NM(DoTestsForMode_rm)
push bp
mov bp, sp
push ax
;
; Check if the mode and NX is supported, do the switch.
;
call TMPL_NM(Bs2IsModeSupported_rm)
jz .done
call TMPL_NM(Bs2EnterMode_rm)
BITS TMPL_BITS
;
; Test exception handler basics using INT3 and #BP.
;
call TMPL_NM(TestGateType)
call TMPL_NM(TestCodeSelector)
call TMPL_NM(TestCheckOrderCsTypeVsIdteType)
call TMPL_NM(TestStack)
call TMPL_NM(TestConforming)
call TMPL_NM(TestReturn)
;
; Back to real mode.
;
call TMPL_NM(Bs2ExitMode)
BITS 16
call Bs2DisableNX_r86
.done:
pop ax
leave
ret
ENDPROC TMPL_NM(DoTestsForMode_rm)
TMPL_BEGINCODE
BITS TMPL_BITS
%include "bootsector2-template-footer.mac"