diff options
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac')
-rw-r--r-- | src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac new file mode 100644 index 00000000..46b218d0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac @@ -0,0 +1,501 @@ +; $Id: bootsector2-cpu-xcpt-2-template.mac $ +;; @file +; Bootsector test for debug exceptions - multi mode template. +; + +; +; Copyright (C) 2007-2019 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 + +;; Uncomment this to do lots more iterations (takes time!). +%define QUICK_TEST + + +;******************************************************************************* +;* Global Variables * +;******************************************************************************* +%ifndef CPU_XCPT_1_GLOBALS + %define CPU_XCPT_1_GLOBALS + +;; +; 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 + cli ; raw-mode hack + push dword __LINE__ + %ifdef TMPL_16BIT + push ds + %endif + push %%.s_szMsg + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB*2 + ;hlt + sti + jmp %%.ok + %%.s_szMsg: db %4, " (0x%RX32)", 0 + %%.ok: + %endmacro + +%endif + + +;; +; Disable the breakpoints as well as check RA1 bits. +; +; @changes DRx +; +BEGINPROC TMPL_NM(DisableBps) + push sAX + push sBX + sPUSHF + + xor eax, eax + mov dr7, sAX + mov dr6, sAX + mov dr0, sAX + mov dr1, sAX + mov dr2, sAX + mov dr3, sAX + + mov sAX, dr6 + mov ebx, X86_DR6_RA1_MASK + ASSERT_SIMPLE sAX, xBX, je, "Wrong DR6 value (RA1)." + mov sAX, dr7 + mov ebx, X86_DR7_RA1_MASK + ASSERT_SIMPLE sAX, sBX, je, "Wrong DR7 value (RA1)." + + sPOPF + pop sBX + pop sAX + ret +ENDPROC TMPL_NM(DisableBps) + + +;; +; Checks different gate types. +; +BEGINPROC TMPL_NM(TestStepping) + 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) + + + ; + ; Step one instruction a lot of times to catch DR6 mismanagement. + ; +%ifdef QUICK_TEST + mov ecx, 0x1000 +%else + mov ecx, 0x80000 +%endif +.the_1st_loop: + + mov eax, X86_DR6_INIT_VAL + mov dr6, sAX + mov eax, 0x12345678 + mov ebx, 0xaabbccdd + sPUSHF + or word [xSP], X86_EFL_TF + sPOPF + xchg ebx, eax + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0xaabbccdd, je, "xchg wasn't executed (eax)." + ASSERT_SIMPLE ebx, 0x12345678, je, "xchg wasn't executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS), je, "Wrong DR6 value." + + dec ecx + jnz .the_1st_loop + + ; + ; Check that certain bits in DR6 is preserved and others not. + ; +%ifdef QUICK_TEST + mov ecx, 0x200 +%else + mov ecx, 0x20000 +%endif +.the_2nd_loop: + mov eax, X86_DR6_INIT_VAL | X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BT | X86_DR6_BD + mov dr6, sAX + mov eax, 0x12345678 + mov ebx, 0xaabbccdd + sPUSHF + or word [xSP], X86_EFL_TF + sPOPF + xchg ebx, eax + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0xaabbccdd, je, "xchg wasn't executed (eax)." + ASSERT_SIMPLE ebx, 0x12345678, je, "xchg wasn't executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_BS | X86_DR6_INIT_VAL | X86_DR6_BT | X86_DR6_BD), je, "Wrong DR6 value." + + dec ecx + jnz .the_2nd_loop + + ; + ; Done. + ; + cli ; raw-mode hack + call TMPL_NM_CMN(TestSubDone) + sti + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', EFLAGS.TF stepping', 0 +ENDPROC TMPL_NM(TestGateType) + + +;; +; Check execution breakpoint. +; +BEGINPROC TMPL_NM(TestBpExec) + 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) + + + ; + ; Arm all 4 breakpoints and check DR6 management. + ; +%ifdef QUICK_TEST + mov ecx, 0x1000 +%else + mov ecx, 0x80000 +%endif + lea sAX, [.bp_dr0 xWrtRIP] + mov dr0, sAX + lea sAX, [.bp_dr1 xWrtRIP] + mov dr1, sAX + lea sAX, [.bp_dr2 xWrtRIP] + mov dr2, sAX + lea sAX, [.bp_dr3 xWrtRIP] + mov dr3, sAX + mov eax, X86_DR7_RA1_MASK | X86_DR7_G0 | X86_DR7_G1 | X86_DR7_G2 | X86_DR7_G3 | X86_DR7_GE + mov dr7, sAX + +.the_loop: + mov eax, X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD + mov dr6, sAX + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr0: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B0), je, "Wrong DR6 value (dr0)." + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr1: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B1), je, "Wrong DR6 value (dr1)." + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr2: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B2), je, "Wrong DR6 value (dr2)." + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr3: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B3), je, "Wrong DR6 value (dr3)." + + dec ecx + jnz .the_loop + + ; + ; Touch the code, making sure the BPs don't trigger on data access. + ; + mov al, [.bp_dr0 xWrtRIP] + mov [.bp_dr0 xWrtRIP], al + mov al, [.bp_dr1 xWrtRIP] + mov [.bp_dr1 xWrtRIP], al + mov al, [.bp_dr2 xWrtRIP] + mov [.bp_dr2 xWrtRIP], al + mov al, [.bp_dr3 xWrtRIP] + mov [.bp_dr3 xWrtRIP], al + + ; + ; Done. + ; + call TMPL_NM(DisableBps) + cli ; raw-mode hack + call TMPL_NM_CMN(TestSubDone) + sti + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', Exec BP', 0 +ENDPROC TMPL_NM(TestBpExec) + + +;; +; Check I/O breakpoints. +; +BEGINPROC TMPL_NM(TestBpIo) + 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) + + + ; + ; Arm all 4 breakpoints and check range handling and such. + ; + mov sAX, cr4 + or sAX, X86_CR4_DE + mov cr4, sAX + +%ifdef QUICK_TEST + mov ecx, 1000 +%else + mov ecx, 4096 +%endif + mov sAX, 84h + mov dr0, sAX + mov sAX, 85h + mov dr1, sAX + mov sAX, 86h + mov dr2, sAX + mov sAX, 8ch + mov dr3, sAX + mov eax, X86_DR7_RA1_MASK | X86_DR7_LE | X86_DR7_GE \ + | X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_IO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) \ + | X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW(1, X86_DR7_RW_IO) | X86_DR7_LEN(1, X86_DR7_LEN_WORD) \ + | X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW(2, X86_DR7_RW_IO) | X86_DR7_LEN(2, X86_DR7_LEN_DWORD) \ + | X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW(3, X86_DR7_RW_IO) | X86_DR7_LEN(3, X86_DR7_LEN_DWORD) + mov dr7, sAX + +.the_loop: + mov eax, X86_DR6_INIT_VAL + mov dr6, sAX + + mov eax, 0x12345678 + in eax, 84h + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B0), je, "Wrong DR6 value (dr0)." + + mov ebx, 0x12345678 + in eax, 85h + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B1), je, "Wrong DR6 value (dr1)." + + mov eax, 0x12345678 + in eax, 86h + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B2), je, "Wrong DR6 value (dr2)." + + mov eax, 0x12345678 + in eax, 8ch + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B3), je, "Wrong DR6 value (dr3)." + + dec ecx + jnz .the_loop + + ; + ; Done. + ; + call TMPL_NM(DisableBps) + cli ; raw-mode hack + call TMPL_NM_CMN(TestSubDone) + sti + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', I/O BP', 0 +ENDPROC TMPL_NM(TestBpIo) + + +;; +; 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 + pushf + sti ; raw-mode hacks + + ; + ; Do the testing. + ; + + call TMPL_NM(TestStepping) + call TMPL_NM(TestBpExec) + call TMPL_NM(TestBpIo) + + ; + ; Back to real mode. + ; + popf + 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" + |