diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac | 1619 |
1 files changed, 1619 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac new file mode 100644 index 00000000..d9069b84 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac @@ -0,0 +1,1619 @@ +; $Id: bootsector2-common-init-traps.mac $ +;; @file +; Common bootsector code init, traps. +; +; This is included from bootsector2-common-init-code.mac and was split out of +; that file to keep the size manageable. +; + +; +; Copyright (C) 2007-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef BS2_WITH_TRAPS + %error "huh? BS2_WITH_TRAPS is not defined!" +%endif + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "bootsector2-structures.mac" +%include "bootsector2-api.mac" + + +;******************************************************************************* +;* Global Variables * +;******************************************************************************* +BEGINCODELOW +ALIGNDATA(8) +;; Where to resume execution after a trap (if g_fTrapPrepared is set). +; @internal +g_TrapResumeRIP: + dq 0 +;; Set if we've prepared for a trap. +; @internal +g_fTrapPrepared: + db 0 +;; Benchmark indicator. +; This is set to the expected trap number when we're benchmarking and 0ffh when +; we aren't benchmarking. +; @internal +g_u8TrapBenchmarkNo: + db 0ffh + db 0 ; alignment padding. +;; The last trap number. +GLOBALNAME g_u8LastTrapNo + db 0 +;; The number of traps since last call to Bs2TrapReset. +GLOBALNAME g_u32cTraps + dd 0 +;; The last trap error code. +GLOBALNAME g_u64LastTrapErr + dq 0 +;; The register frame of the last trap (BS2REGS). +GLOBALNAME g_LastTrapRegs + times (BS2REGS_size) db 0 + +;; The RFLAGS/EFLAGS inside last invoked trap handler. +GLOBALNAME g_u64LastTrapHandlerRFlags + dq 0 +;; The CS inside last invoked trap handler. +GLOBALNAME g_u16LastTrapHandlerCS + dw 0 +;; The SS inside last invoked trap handler. +GLOBALNAME g_u16LastTrapHandlerSS + dw 0 + dw 0,0 ; alignment +;; The RSP inside the last invoked trap handler, i.e. when bs2Trap_XX_32bit is +; entered, so including fake error code and vector number. +GLOBALNAME g_u64LastTrapHandlerRSP + dq 0 + +;; +; Pointer to an array of BS2TRAPREC1 records. +GLOBALNAME g_paTrapRecs + dq 0 +;; Number of entries in the array g_paTrapRecs points to. +GLOBALNAME g_cTrapRecs + dd 0 +;; The index of the last BS2TRAPREC1 we hit. +GLOBALNAME g_iTrapRecLast + dd 0 +;; The base address the BS2TRAPREC.offWhere values are relative to. +GLOBALNAME g_pTrapRecBase + dq 0 + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapReset_rm16 + push xBP + mov xBP, xSP + push ds + push word 0 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + + pop ds + leave + ret +ENDPROC Bs2TrapReset_rm16 + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapReset_p16 + push ds + push BS2_SEL_DS16 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + + pop ds + ret +ENDPROC Bs2TrapReset_p16 + + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2TrapReset_p32 + push ds + push BS2_SEL_DS32 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + + pop ds + ret +ENDPROC Bs2TrapReset_p32 + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODEHIGH +BITS 64 +BEGINPROC Bs2TrapReset_p64 + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov qword [g_u64LastTrapErr], 0 + mov qword [g_TrapResumeRIP], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + ret +ENDPROC Bs2TrapReset_p64 + + + +;; +; Prepare for a test that will trap. +; +; @param xAX Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapPrepare_rm16 + push xBP + mov xBP, xSP + push ds + push word 0 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov word [g_TrapResumeRIP], ax + mov word [g_TrapResumeRIP + 2], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + + pop ds + leave + ret +ENDPROC Bs2TrapPrepare_rm16 + + +;; +; Prepare for a test that will trap. +; +; @param ax Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapPrepare_p16 + push ds + push BS2_SEL_DS16 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov word [g_TrapResumeRIP], ax + mov word [g_TrapResumeRIP + 2], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + + pop ds + ret +ENDPROC Bs2TrapPrepare_p16 + + +;; +; Prepare for a test that will trap. +; +; @param eax Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2TrapPrepare_p32 + push ds + push BS2_SEL_DS32 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], eax + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + + pop ds + ret +ENDPROC Bs2TrapPrepare_p32 + + +;; +; Prepare for a test that will trap. +; +; @param rax Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODEHIGH +BITS 64 +BEGINPROC Bs2TrapPrepare_p64 + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov qword [g_u64LastTrapErr], 0 + mov qword [g_TrapResumeRIP], rax + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + ret +ENDPROC Bs2TrapPrepare_p64 + + +BEGINCODELOW ; The TSSes, IDTs and handlers must be 16-bit addressable. + +%ifdef BS2_INC_CMN_PM +; +; 32-bit TSS (X86TSS32). +; +ALIGNDATA(16) +bs2Tss32Bit: + dw 07fffh ; selPrev - Back link to previous task. (static) + dw 0h ; padding1; + dd BS2_R0_STACK_ADDR ; esp0 - Ring-0 stack pointer. (static) + dw BS2_SEL_SS32 ; ss0 + dw 0 ; padding + dd BS2_R1_STACK_ADDR ; esp1 - Ring-1 stack pointer. (static) + dw 0 ; ss1 + dw 0 ; padding + dd BS2_R2_STACK_ADDR ; esp2 - Ring-1 stack pointer. (static) + dw 0 ; ss2 + dw 0 ; padding + dd 0ffffffffh ; cr3 - Page directory for the task. (static) + dd 0 ; eip - EIP before task switch. + dd 0 ; eflags - EFLAGS before task switch. + dd 0 ; eax - EAX before task switch. + dd 0 ; ecx - ECX before task switch. + dd 0 ; edx - EDX before task switch. + dd 0 ; ebx - EBX before task switch. + dd 0 ; esp - ESP before task switch. + dd 0 ; ebp - EBP before task switch. + dd 0 ; esi - ESI before task switch. + dd 0 ; edi - EDI before task switch. + dw 0, 0 ; es,pad - ES before task switch. + dw 0, 0 ; cs,pad - CS before task switch. + dw 0, 0 ; ss,pad - SS before task switch. + dw 0, 0 ; ds,pad - DS before task switch. + dw 0, 0 ; fs,pad - FS before task switch. + dw 0, 0 ; gs,pad - GS before task switch. + dw 0, 0 ; ldt,pad - LDTR before task switch. + dw 0 ; fDebugTrap - Debug trap flag. + dw 7fffh ; offIoBitmap - Offset relative to the TSS of the + ; start of the I/O Bitmap and the end of the + ; interrupt redirection bitmap. + ; IntRedirBitmap - 32 bytes for the virtual interrupt redirection bitmap. (VME) +bs2Tss32BitEnd: +times (68h - (bs2Tss32BitEnd - bs2Tss32Bit)) db 0 +times ((bs2Tss32BitEnd - bs2Tss32Bit) - 68h) db 0 + + +; +; 32-bit TSS for #DF (X86TSS32). +; +ALIGNDATA(16) +bs2Tss32BitDf: + dw 07fffh ; selPrev - Back link to previous task. (static) + dw 0h ; padding1; + dd BS2_DF_R0_STACK_ADDR ; esp0 - Ring-0 stack pointer. (static) + dw BS2_SEL_SS32 ; ss0 + dw 0 ; padding + dd 0 ; esp1 - Ring-1 stack pointer. (static) + dw 0 ; ss1 + dw 0 ; padding + dd 0 ; esp2 - Ring-1 stack pointer. (static) + dw 0 ; ss2 + dw 0 ; padding + dd 0ffffffffh ; cr3 - Page directory for the task. (static) + dd bs2Trap_08h_32bit ; eip - EIP before task switch. */ + dd 0 ; eflags - EFLAGS before task switch. */ + dd 0 ; eax - EAX before task switch. */ + dd 0 ; ecx - ECX before task switch. */ + dd 0 ; edx - EDX before task switch. */ + dd 0 ; ebx - EBX before task switch. */ + dd BS2_DF_R0_STACK_ADDR ; esp - ESP before task switch. */ + dd 0 ; ebp - EBP before task switch. */ + dd 0 ; esi - ESI before task switch. */ + dd 0 ; edi - EDI before task switch. */ + dw BS2_SEL_DS32, 0 ; es,pad - ES before task switch. */ + dw BS2_SEL_CS32, 0 ; cs,pad - CS before task switch. */ + dw BS2_SEL_SS32, 0 ; ss,pad - SS before task switch. */ + dw BS2_SEL_DS32, 0 ; ds,pad - DS before task switch. */ + dw BS2_SEL_DS32, 0 ; fs,pad - FS before task switch. */ + dw BS2_SEL_DS32, 0 ; gs,pad - GS before task switch. */ + dw 0, 0 ; ldt,pad- LDTR before task switch. */ + dw 0 ; fDebugTrap - Debug trap flag. + dw 7fffh ; offIoBitmap - Offset relative to the TSS of the + ; start of the I/O Bitmap and the end of the + ; interrupt redirection bitmap. + ; IntRedirBitmap - 32 bytes for the virtual interrupt redirection bitmap. (VME) +bs2Tss32BitDfEnd: +times (68h - (bs2Tss32BitDfEnd - bs2Tss32BitDf)) db 0 +times ((bs2Tss32BitDfEnd - bs2Tss32BitDf) - 68h) db 0 + + +; +; 32-bit IDT (X86DESCGATE). +; +ALIGNDATA(16) +bs2Idt32bit: + dw bs2Trap_00h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_01h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_02h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate +bs2Idt32bit_BP: + dw bs2Trap_03h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_04h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_05h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_06h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_07h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw 0, BS2_SEL_TSS32_DF, 08500h, 00000h ; p=1 dpl=0 type=taskgate + dw bs2Trap_09h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0ah_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0bh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0ch_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0dh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0eh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0fh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_10h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_11h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_12h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_13h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_14h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_15h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_16h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_17h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_18h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_19h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1ah_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1bh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1ch_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1dh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1eh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1fh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2TrapService32bit,BS2_SEL_CS32,0ee00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=3 type=int32gate +%define BS2_TRAP_SERVICE_NO 30h +;; @todo +bs2Idt32bitEnd + +; +; 32-bit trap handlers. +; +BITS 32 +%macro bs2Trap_XX_32bit_macro 1 +bs2Trap_ %+ %1 %+ _32bit: + push %1 + jmp bs2Trap_XX_32bit +%endmacro +%macro bs2Trap_XX_32bit_macro_no_err 1 +bs2Trap_ %+ %1 %+ _32bit: + push 0 + push %1 + jmp bs2Trap_XX_32bit +%endmacro + bs2Trap_XX_32bit_macro_no_err 00h + bs2Trap_XX_32bit_macro_no_err 01h + bs2Trap_XX_32bit_macro_no_err 02h + bs2Trap_XX_32bit_macro_no_err 03h + bs2Trap_XX_32bit_macro_no_err 04h + bs2Trap_XX_32bit_macro_no_err 05h + bs2Trap_XX_32bit_macro_no_err 06h + bs2Trap_XX_32bit_macro_no_err 07h + bs2Trap_XX_32bit_macro 08h + bs2Trap_XX_32bit_macro_no_err 09h + bs2Trap_XX_32bit_macro 0ah + bs2Trap_XX_32bit_macro 0bh + bs2Trap_XX_32bit_macro 0ch + bs2Trap_XX_32bit_macro 0dh + bs2Trap_XX_32bit_macro 0eh + bs2Trap_XX_32bit_macro_no_err 0fh + bs2Trap_XX_32bit_macro_no_err 10h + bs2Trap_XX_32bit_macro 11h + bs2Trap_XX_32bit_macro_no_err 12h + bs2Trap_XX_32bit_macro_no_err 13h + bs2Trap_XX_32bit_macro_no_err 14h + bs2Trap_XX_32bit_macro_no_err 15h + bs2Trap_XX_32bit_macro_no_err 16h + bs2Trap_XX_32bit_macro_no_err 17h + bs2Trap_XX_32bit_macro_no_err 18h + bs2Trap_XX_32bit_macro_no_err 19h + bs2Trap_XX_32bit_macro_no_err 1ah + bs2Trap_XX_32bit_macro_no_err 1bh + bs2Trap_XX_32bit_macro_no_err 1ch + bs2Trap_XX_32bit_macro_no_err 1dh + bs2Trap_XX_32bit_macro_no_err 1eh + bs2Trap_XX_32bit_macro_no_err 1fh + +;; +; Common 32-bit trap handler. +; +; return GS ebp + 2ch - v86 +; return FS ebp + 28h - v86 +; return DS ebp + 24h - v86 +; return ES ebp + 20h - v86 +; return SS ebp + 1ch - higher privilege +; return ESP ebp + 18h - higher privilege +; return EFLAGS ebp + 14h +; return CS ebp + 10h +; return EIP ebp + 0ch +; error code ebp + 08h +; vector # ebp + 04h +BITS 32 +BEGINCODEHIGH +BEGINPROC bs2Trap_XX_32bit + push ebp ; ebp + 00h + mov ebp, esp + pushfd ; ebp - 04h + push eax ; ebp - 08h + push ebx ; ebp - 0ch + push ecx ; ebp - 10h + push ds ; ebp - 14h + + mov eax, ss ; load flat DS. Using SS here because of conforming IDTE.CS tests. + mov ds, ax + + pushfd ; Clear the AC flag. + and dword [esp], ~X86_EFL_AC + popfd + + ; + ; Benchmark mode? Then resume the action right away! + ; + mov eax, [ebp + 04h] + cmp [g_u8TrapBenchmarkNo], al + jne .test_mode + cmp byte [g_fTrapPrepared], 0 + je .test_mode + mov eax, [g_TrapResumeRIP] + mov [ebp + 0ch], eax + + pop ds + pop ecx + pop ebx + ;pop eax + ;popfd + leave + add esp, 08h ; Skip the vector # and error code. + xor eax, eax + iret + + + ; + ; Update the globals. + ; +.test_mode: + xor ecx, ecx ; zero register + inc dword [g_u32cTraps] + mov eax, [ebp + 04h] + mov [g_u8LastTrapNo], al + mov eax, [ebp + 08h] + mov [g_u64LastTrapErr], eax + mov [g_u64LastTrapErr + 4], ecx + mov eax, [ebp - 04h] + mov [g_u64LastTrapHandlerRFlags], eax + mov dword [g_u64LastTrapHandlerRFlags + 4], ecx + mov ax, cs + mov [g_u16LastTrapHandlerCS], ax + mov ax, ss + mov [g_u16LastTrapHandlerSS], ax + lea eax, [ebp + 4] + mov [g_u64LastTrapHandlerRSP], eax + mov [g_u64LastTrapHandlerRSP + 4], ecx + + ; + ; Save the registers. + ; + lea ebx, [g_LastTrapRegs] + mov eax, [ebp - 08h] + mov [ebx + BS2REGS.rax], eax + mov [ebx + BS2REGS.rax + 4], ecx + mov eax, [ebp - 0ch] + mov [ebx + BS2REGS.rbx], eax + mov [ebx + BS2REGS.rbx + 4], ecx + mov eax, [ebp - 10h] + mov [ebx + BS2REGS.rcx], eax + mov [ebx + BS2REGS.rcx + 4], ecx + mov [ebx + BS2REGS.rdx], edx + mov [ebx + BS2REGS.rdx + 4], ecx + mov [ebx + BS2REGS.rdi], edi + mov [ebx + BS2REGS.rdi + 4], ecx + mov [ebx + BS2REGS.rsi], esi + mov [ebx + BS2REGS.rsi + 4], ecx + mov eax, [ebp] + mov [ebx + BS2REGS.rbp], eax + mov [ebx + BS2REGS.rbp + 4], ecx + mov eax, [ebp + 0ch] + mov [ebx + BS2REGS.rip], eax + mov [ebx + BS2REGS.rip + 4], ecx + mov [ebx + BS2REGS.r8], ecx + mov [ebx + BS2REGS.r8 + 4], ecx + mov [ebx + BS2REGS.r9], ecx + mov [ebx + BS2REGS.r9 + 4], ecx + mov [ebx + BS2REGS.r10], ecx + mov [ebx + BS2REGS.r10 + 4], ecx + mov [ebx + BS2REGS.r11], ecx + mov [ebx + BS2REGS.r11 + 4], ecx + mov [ebx + BS2REGS.r12], ecx + mov [ebx + BS2REGS.r12 + 4], ecx + mov [ebx + BS2REGS.r13], ecx + mov [ebx + BS2REGS.r13 + 4], ecx + mov [ebx + BS2REGS.r14], ecx + mov [ebx + BS2REGS.r14 + 4], ecx + mov [ebx + BS2REGS.r15], ecx + mov [ebx + BS2REGS.r15 + 4], ecx + mov eax, [ebp + 14h] + mov [ebx + BS2REGS.rflags], eax + mov [ebx + BS2REGS.rflags+4],ecx + mov eax, [ebp + 10h] + mov [ebx + BS2REGS.cs], ax + mov [ebx + BS2REGS.cBits], byte 32 + + ; Part of the stack varies depending on the trap context. + test dword [ebx + BS2REGS.rflags], X86_EFL_VM + jnz .v86 + test ax, 7h + jz .ring0 + +.ring0: + lea eax, [ebp + 18h] + mov [ebx + BS2REGS.rsp], eax + mov [ebx + BS2REGS.rsp + 4], ecx + mov [ebx + BS2REGS.ss], ss + mov eax, [ebp - 14h] + mov [ebx + BS2REGS.ds], ax + mov [ebx + BS2REGS.es], es + mov [ebx + BS2REGS.fs], fs + mov [ebx + BS2REGS.gs], gs + jmp .do_crX + +.higher_privilege: + mov eax, [ebp + 18h] + mov [ebx + BS2REGS.rsp], eax + mov [ebx + BS2REGS.rsp + 4], ecx + mov eax, [ebp + 20h] + mov [ebx + BS2REGS.ss], ax + mov eax, [ebp - 14h] + mov [ebx + BS2REGS.ds], ax + mov [ebx + BS2REGS.es], es + mov [ebx + BS2REGS.fs], fs + mov [ebx + BS2REGS.gs], gs + jmp .do_crX + +.v86: + mov eax, [ebp + 18h] + mov [ebx + BS2REGS.rsp], eax + mov [ebx + BS2REGS.rsp + 4], ecx + mov eax, [ebp + 1ch] + mov [ebx + BS2REGS.ss], ax + mov eax, [ebp + 24h] + mov [ebx + BS2REGS.ds], ax + mov eax, [ebp + 20h] + mov [ebx + BS2REGS.es], ax + mov eax, [ebp + 28h] + mov [ebx + BS2REGS.fs], ax + mov eax, [ebp + 2ch] + mov [ebx + BS2REGS.gs], ax + ;jmp .do_crX + +.do_crX: + ; The CRx registers are only accessible from ring-0 (CS=conforming, CPL < 0) + test byte [ebx + BS2REGS.ss], 3 + jnz .skip_crX + mov eax, cr0 + mov [ebx + BS2REGS.cr0], eax + mov [ebx + BS2REGS.cr0 + 4], ecx + mov eax, cr2 + mov [ebx + BS2REGS.cr2], eax + mov [ebx + BS2REGS.cr2 + 4], ecx + mov eax, cr3 + mov [ebx + BS2REGS.cr3], eax + mov [ebx + BS2REGS.cr3 + 4], ecx + mov eax, cr4 + mov [ebx + BS2REGS.cr4], eax + mov [ebx + BS2REGS.cr4 + 4], ecx + mov [ebx + BS2REGS.cr8], ecx + mov [ebx + BS2REGS.cr8 + 4], ecx +.skip_crX: + + ; + ; Advance to a prepared resume position or panic. + ; + cmp byte [g_fTrapPrepared], 0 + je .no_resume_pos + mov byte [g_fTrapPrepared], 0 + mov eax, [g_TrapResumeRIP] + mov [ebp + 0ch], eax + +.resume: +%ifdef BS2_WITH_XCPT_DB_CLEARING_TF + cmp byte [ebp + 04h], X86_XCPT_DB ; make sure we won't trap again due to a TF. + jne .resume_no_clear_trap_flags + and word [ebp + 14h], ~X86_EFL_TF +.resume_no_clear_trap_flags: +%endif + pop ds + pop ecx + pop ebx + pop eax + ;popfd + leave + add esp, 8h + iret + + +.no_resume_pos: + ; + ; Look for a trap record. + ; + mov ecx, [g_cTrapRecs] ; the number of records. + test ecx, ecx + jz .panic + mov eax, [g_LastTrapRegs + BS2REGS.rip] + sub eax, [g_pTrapRecBase] ; the offWhere we're looking for. + jb .panic + + ; Look starting at the previous record first. + mov ebx, [g_iTrapRecLast] + sub ecx, ebx + jbe .traprec_loop2 ; g_iTrapRecLast is out of range. + shl ebx, BS2TRAPREC_SIZE_SHIFT + add ebx, [g_paTrapRecs] ; ebx points to the record we hit last time. +.traprec_loop1_next: + cmp [ebx + BS2TRAPREC.offWhere], eax + je .traprec_found + add ebx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop1_next + + ; Start searching from the start, stopping at the previous record. +.traprec_loop2: + mov ecx, [g_iTrapRecLast] + or ecx, ecx + jz .panic ; not found. + mov ebx, [g_paTrapRecs] +.traprec_loop2_next: + cmp [ebx + BS2TRAPREC.offWhere], eax + je .traprec_found + add ebx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop2_next + jmp .panic ; not found + +.traprec_found: + ; Remember the hit for the next trap. + mov eax, ebx + sub eax, [g_paTrapRecs] + shr eax, BS2TRAPREC_SIZE_SHIFT + mov [g_iTrapRecLast], eax + + ; + ; Fail the test if we got the wrong trap or error code. + ; + mov al, [g_u8LastTrapNo] + cmp al, [ebx + BS2TRAPREC.u8TrapNo] + je .traprec_ok_trap + push eax + movzx eax, byte [ebx + BS2TRAPREC.u8TrapNo] + push eax + push .s_szWrongTrap + call NAME(TestFailedF_p32) + add esp, 12 + +.traprec_ok_trap: + mov ax, [g_u64LastTrapErr] + cmp ax, [ebx + BS2TRAPREC.u16ErrCd] + je .traprec_ok_err_cd + push eax + movzx eax, word [ebx + BS2TRAPREC.u16ErrCd] + push eax + push .s_szWrongErrCd + call NAME(TestFailedF_p32) + add esp, 12 + +.traprec_ok_err_cd: + ; + ; Advance the EIP and resume execution. + ; + movzx eax, byte [ebx + BS2TRAPREC.offResumeAddend] + add eax, [g_LastTrapRegs + BS2REGS.rip] + mov [ebp + 0ch], eax + jmp .resume + + + ; + ; Write panic message and then halt. + ; +.panic: + push dword [g_LastTrapRegs + BS2REGS.rflags] + push dword [g_LastTrapRegs + BS2REGS.ss] + push dword [g_LastTrapRegs + BS2REGS.gs] + push dword [g_LastTrapRegs + BS2REGS.fs] + push dword [g_LastTrapRegs + BS2REGS.es] + push dword [g_LastTrapRegs + BS2REGS.ds] + push dword [g_LastTrapRegs + BS2REGS.cs] + ; line break + push dword [g_LastTrapRegs + BS2REGS.cr4] + push dword [g_LastTrapRegs + BS2REGS.cr3] + push dword [g_LastTrapRegs + BS2REGS.cr0] + push dword [g_LastTrapRegs + BS2REGS.rbp] + push dword [g_LastTrapRegs + BS2REGS.rsp] + push dword [g_LastTrapRegs + BS2REGS.rip] + ; line break + push dword [g_LastTrapRegs + BS2REGS.rdi] + push dword [g_LastTrapRegs + BS2REGS.rsi] + push dword [g_LastTrapRegs + BS2REGS.rdx] + push dword [g_LastTrapRegs + BS2REGS.rcx] + push dword [g_LastTrapRegs + BS2REGS.rbx] + push dword [g_LastTrapRegs + BS2REGS.rax] + ; line break + mov eax, [ebp + 08h] + push eax + mov eax, cr2 + push eax + mov eax, [ebp + 0ch] + push eax + movzx eax, word [ebp + 10h] + push eax + movzx eax, byte [ebp + 04h] + push eax + push .s_szPanicMsg + call NAME(TestFailedF_p32) + + call Bs2Panic + jmp .panic ; paranoia + +.s_szPanicMsg: + db 'trap #%RX8 at %RX16:%RX32 cr2=%RX32 err=%RX32', 13, 10 + db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10 + db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10 + db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 eflags=%RX32', 13, 10 + db 0 +.s_szWrongTrap: + db 'Expected trap %RX8 got %RX8', 13, 10, 0 +.s_szWrongErrCd: + db 'Expected errcd %RX16 got %RX16', 13, 10, 0 +ENDPROC bs2Trap_XX_32bit + +;; +; Service IRQ handler, 32-bit version. +; +; Takes requests in eax and later maybe parameters in other registers. +; +; return GS ebp + 24h - v86 +; return FS ebp + 20h - v86 +; return DS ebp + 1ch - v86 +; return ES ebp + 18h - v86 +; return SS ebp + 14h - higher privilege +; return ESP ebp + 10h - higher privilege +; return EFLAGS ebp + 0ch +; return CS ebp + 08h +; return EIP ebp + 04h +BEGINCODELOW +BEGINPROC bs2TrapService32bit + jmp .highsegment +BEGINCODEHIGH +.highsegment: + push ebp ; ebp + mov ebp, esp + push eax ; ebp - 04h + push edx ; ebp - 08h + push ecx ; ebp - 0ch + push ebx ; ebp - 10h + push ds ; ebp - 14h + + mov dx, ss + mov ds, dx + + ; + ; Classify the caller context in cl. + ;; @todo What if CS on the stack is conforming? + ; +%define BS2_TRP_SRV_CALLER_SAME_RING 0 +%define BS2_TRP_SRV_CALLER_OTHER_RING 1 +%define BS2_TRP_SRV_CALLER_VM 2 + test dword [ebp + 0ch], X86_EFL_VM + jnz .vm_ctx + + mov cx, ss + mov ch, [ebp + 08h] ; cs + and cx, 00303h + cmp ch, cl + jz .same_ctx + mov cl, BS2_TRP_SRV_CALLER_OTHER_RING + jmp .done_ctx +.vm_ctx: + mov cl, BS2_TRP_SRV_CALLER_VM + jmp .done_ctx +.same_ctx: + mov cl, BS2_TRP_SRV_CALLER_SAME_RING +.done_ctx: + + ; + ; Switch (eax). + ; + cmp eax, BS2_SYSCALL_TO_RING3 + jbe .to_ringX + + ; Unknown request. +.failure: + mov eax, -1 +.return: ; careful with ebp here! + pop ds + pop ebx + pop ecx + pop edx + ;pop eax + leave + iretd + + ; + ; Switching to the ring specified by eax. + ; Annoying that ss:esp isn't always restored. + ; +.to_ringX: + cmp cl, BS2_TRP_SRV_CALLER_VM + je .failure + sub al, BS2_SYSCALL_TO_RING0 + + ; Fake missing stack registers if necessary. + cmp cl, BS2_TRP_SRV_CALLER_SAME_RING + jnz .have_stack_regs + + sub esp, 8h + sub ebp, 8h + xor ebx, ebx +.move_more: + mov edx, [esp + 8 + ebx] + mov [esp + ebx], edx + add ebx, 4 + cmp ebx, 9*4 + jb .move_more + + mov dx, ss + mov [ebp + 14h], edx + lea edx, [ebp + 18h] + mov [ebp + 10h], edx + +.have_stack_regs: + ; Translate the selector registers + mov dx, [ebp - 14h] + call bs2SRegToRing + mov [ebp - 14h], dx + + mov dx, es + call bs2SRegToRing + mov es, dx + + mov dx, fs + call bs2SRegToRing + mov fs, dx + + mov dx, gs + call bs2SRegToRing + mov gs, dx + + mov dx, [ebp + 08h] ; cs + call bs2SRegToRing + mov [ebp + 08h], dx + + mov dx, [ebp + 14h] ; ss + call bs2SRegToRing + mov [ebp + 14h], dx + + or dword [ebp + 0ch], X86_EFL_IOPL ; set IOPL=3 + + ; If the desired target is ring-0 we cannot use iret. + cmp al, 0 + je .iret_to_ring_with_stack + +.done_success: + xor eax, eax + jmp .return + +.iret_to_ring_with_stack: + ; + ; Move the iret-to-same-ring to the desired return position. By also + ; moving the saved ebp we make the leave instruction do stack + ; adjusting/switching for us. + ; + cli ; paranoia, it's disable already. + mov eax, [ebp + 10h] + lea edx, [ebp + 18h] + cmp eax, edx + lea ecx, [ebp + 08h] ; same stack, just shifted 8 bytes + je .move_iret_and_ebp + mov ecx, [ebp + 10h] ; different stack. + sub ecx, 10h +.move_iret_and_ebp: + mov edx, [ebp + 0ch] + mov eax, [ebp + 08h] + mov [ecx + 0ch], edx + mov [ecx + 08h], eax + mov edx, [ebp + 04h] + mov eax, [ebp + 00h] + mov [ecx + 04h], edx + mov [ecx + 00h], eax + mov ebp, ecx + xor eax, eax + jmp .return + +ENDPROC bs2TrapService32bit + +%endif ; BS2_INC_CMN_PM + + +%ifdef BS2_INC_CMN_LM +; +; 64-bit TSS (X86TSS64). +; +BEGINCODELOW +ALIGNDATA(16) +bs2Tss64Bit: + dd 0 ; 00h - u32Reserved - Reserved. + dq BS2_R0_STACK_ADDR ; 04h - rsp0 - Ring-0 stack pointer. (static) + dq BS2_R1_STACK_ADDR ; 1ch - rsp1 - Ring-1 stack pointer. (static) + dq BS2_R2_STACK_ADDR ; 14h - rsp2 - Ring-2 stack pointer. (static) + dq 0 ; 2ch - reserved + dq BS2_DF_R0_STACK_ADDR ; 24h - ist1; + dq BS2_R0_STACK_ADDR ; 3ch - ist2; + dq BS2_R0_STACK_ADDR ; 34h - ist3; + dq BS2_R0_STACK_ADDR ; 4ch - ist4; + dq BS2_R0_STACK_ADDR ; 44h - ist5; + dq BS2_R0_STACK_ADDR ; 5ch - ist6; + dq BS2_R0_STACK_ADDR ; 54h - ist7; + dw 0,0,0,0,0 ; 6ch - reserved + dw 0 ; 76h - offIoBitmap - Offset relative to the TSS of the + ; 00h - start of the I/O Bitmap and the end of the + ; 00h - interrupt redirection bitmap. +bs2Tss64BitEnd: +times (68h - (bs2Tss64BitEnd - bs2Tss64Bit)) db 0 +times ((bs2Tss64BitEnd - bs2Tss64Bit) - 68h) db 0 + +; +; 64-bit IDT (X86DESC64GATE). +; +BEGINCODELOW +ALIGNDATA(16) +bs2Idt64bit: + dw bs2Trap_00h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_01h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_02h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate +bs2Idt64bit_BP: + dw bs2Trap_03h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_04h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_05h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_06h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_07h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_08h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_09h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0ah_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0bh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0ch_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0dh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0eh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0fh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_10h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_11h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_12h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_13h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_14h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_15h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_16h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_17h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_18h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_19h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1ah_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1bh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1ch_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1dh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1eh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1fh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2TrapService64bit,BS2_SEL_CS64,0ee00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=3 type=int64gate +bs2Idt64bitEnd + + +; +; 64-bit trap handlers. +; +BITS 64 +%macro bs2Trap_XX_64bit_macro 1 +BEGINCODELOW +bs2Trap_ %+ %1 %+ _64bit: + push %1 + jmp bs2Trap_XX_64bit +%endmacro +%macro bs2Trap_XX_64bit_macro_no_err 1 +bs2Trap_ %+ %1 %+ _64bit: + push 0 + push %1 + jmp bs2Trap_XX_64bit +%endmacro + bs2Trap_XX_64bit_macro_no_err 00h + bs2Trap_XX_64bit_macro_no_err 01h + bs2Trap_XX_64bit_macro_no_err 02h + bs2Trap_XX_64bit_macro_no_err 03h + bs2Trap_XX_64bit_macro_no_err 04h + bs2Trap_XX_64bit_macro_no_err 05h + bs2Trap_XX_64bit_macro_no_err 06h + bs2Trap_XX_64bit_macro_no_err 07h + bs2Trap_XX_64bit_macro 08h + bs2Trap_XX_64bit_macro_no_err 09h + bs2Trap_XX_64bit_macro 0ah + bs2Trap_XX_64bit_macro 0bh + bs2Trap_XX_64bit_macro 0ch + bs2Trap_XX_64bit_macro 0dh + bs2Trap_XX_64bit_macro 0eh + bs2Trap_XX_64bit_macro_no_err 0fh + bs2Trap_XX_64bit_macro_no_err 10h + bs2Trap_XX_64bit_macro 11h + bs2Trap_XX_64bit_macro_no_err 12h + bs2Trap_XX_64bit_macro_no_err 13h + bs2Trap_XX_64bit_macro_no_err 14h + bs2Trap_XX_64bit_macro_no_err 15h + bs2Trap_XX_64bit_macro_no_err 16h + bs2Trap_XX_64bit_macro_no_err 17h + bs2Trap_XX_64bit_macro_no_err 18h + bs2Trap_XX_64bit_macro_no_err 19h + bs2Trap_XX_64bit_macro_no_err 1ah + bs2Trap_XX_64bit_macro_no_err 1bh + bs2Trap_XX_64bit_macro_no_err 1ch + bs2Trap_XX_64bit_macro_no_err 1dh + bs2Trap_XX_64bit_macro_no_err 1eh + bs2Trap_XX_64bit_macro_no_err 1fh + +;; +; Common 64-bit trap handler. +; +; return SS rbp + 38h +; return RSP rbp + 30h +; return RFLAGS rbp + 28h +; return CS rbp + 20h +; return RIP rbp + 18h +; error code rbp + 10h +; vector # rbp + 08h +BEGINCODEHIGH +BEGINPROC bs2Trap_XX_64bit + push rbp ; rbp + 00h + mov rbp, rsp + pushfq ; rbp - 08h + push rax ; rbp - 10h + push rbx ; rbp - 18h + + ; + ; Benchmark mode? Then resume the action right away! + ; + mov rax, [rbp + 08h] + cmp [g_u8TrapBenchmarkNo], al + jne .test_mode + cmp byte [g_fTrapPrepared], 0 + je .test_mode + mov rax, [g_TrapResumeRIP] + mov [rbp + 18h], rax + + pop rbx + ;pop rax + ;popfq + leave + add rsp, 10h ; Skip the vector # and error code. + xor rax, rax + iretq + + ; + ; Save the trap information + ; +.test_mode: + inc dword [g_u32cTraps] + mov rax, [rbp + 08h] + mov [g_u8LastTrapNo], al + mov rax, [rbp + 10h] + mov [g_u64LastTrapErr], rax + mov rax, [rbp - 08h] + mov [g_u64LastTrapHandlerRFlags], rax + mov ax, cs + mov [g_u16LastTrapHandlerCS], ax + mov ax, ss + mov [g_u16LastTrapHandlerSS], ax + lea rax, [rbp + 8] + mov [g_u64LastTrapHandlerRSP], rax + + ; Save the registers. + lea rbx, [g_LastTrapRegs] + mov rax, [rbp - 10h] + mov [rbx + BS2REGS.rax], rax + mov rax, [rbp - 18h] + mov [rbx + BS2REGS.rbx], rax + mov [rbx + BS2REGS.rcx], rcx + mov [rbx + BS2REGS.rdx], rdx + mov [rbx + BS2REGS.rdi], rdi + mov [rbx + BS2REGS.rsi], rsi + mov rax, [rbp] + mov [rbx + BS2REGS.rbp], rax + mov rax, [rbp + 30h] + mov [rbx + BS2REGS.rsp], rax + mov rax, [rbp + 18h] + mov [rbx + BS2REGS.rip], rax + mov [rbx + BS2REGS.r8], r8 + mov [rbx + BS2REGS.r9], r9 + mov [rbx + BS2REGS.r10], r10 + mov [rbx + BS2REGS.r11], r11 + mov [rbx + BS2REGS.r12], r12 + mov [rbx + BS2REGS.r13], r13 + mov [rbx + BS2REGS.r14], r14 + mov [rbx + BS2REGS.r15], r15 + mov rax, [rbp + 28h] + mov [rbx + BS2REGS.rflags], rax + mov rax, [rbp + 20h] + mov [rbx + BS2REGS.cs], ax + mov [rbx + BS2REGS.ds], ds + mov [rbx + BS2REGS.es], es + mov [rbx + BS2REGS.fs], fs + mov [rbx + BS2REGS.gs], gs + mov rax, [rbp + 38h] + mov [rbx + BS2REGS.ss], ax + mov [rbx + BS2REGS.cBits], byte 64 + + ; The CRx registers are only accessible from ring-0 (CS=conforming, CPL < 0) + test byte [rbx + BS2REGS.ss], 3 + jnz .skip_crX + mov rax, cr0 + mov [rbx + BS2REGS.cr0], rax + mov rax, cr2 + mov [rbx + BS2REGS.cr2], rax + mov rax, cr3 + mov [rbx + BS2REGS.cr3], rax + mov rax, cr4 + mov [rbx + BS2REGS.cr4], rax + mov rax, cr8 + mov [rbx + BS2REGS.cr8], rax +.skip_crX: + + ; + ; Advance to a prepared resume position or panic. + ; + cmp byte [g_fTrapPrepared], 0 + je .no_resume_pos + mov byte [g_fTrapPrepared], 0 + mov rax, [g_TrapResumeRIP] + mov [rbp + 18h], rax + jmp .resume + +.resume: +%ifdef BS2_WITH_XCPT_DB_CLEARING_TF + cmp byte [rbp + 08h], X86_XCPT_DB ; make sure we won't trap again due to a TF. + jne .resume_no_clear_trap_flags + and word [rbp + 28h], ~X86_EFL_TF +.resume_no_clear_trap_flags: +%endif + pop rbx + pop rax + ;popfq + leave + add rsp, 10h + iretq + + +.no_resume_pos: + ; + ; Look for a trap record. + ; + push rcx + + mov ecx, [g_cTrapRecs] ; the number of records. + test ecx, ecx + jz .panic + mov rax, [g_LastTrapRegs + BS2REGS.rip] + sub rax, [g_pTrapRecBase] ; the offWhere we're looking for. + jb .panic + mov rbx, _4G + cmp rax, rbx + jae .panic ; out of range. + + ; Look starting at the previous record first. + mov ebx, [g_iTrapRecLast] + sub ecx, ebx + jbe .traprec_loop2 ; g_iTrapRecLast is out of range. + shl rbx, BS2TRAPREC_SIZE_SHIFT + add rbx, [g_paTrapRecs] ; ebx points to the record we hit last time. +.traprec_loop1_next: + cmp [rbx + BS2TRAPREC.offWhere], eax + je .traprec_found + add rbx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop1_next + + ; Start searching from the start, stopping at the previous record. +.traprec_loop2: + mov ecx, [g_iTrapRecLast] + or ecx, ecx + jz .panic ; not found. + mov rbx, [g_paTrapRecs] +.traprec_loop2_next: + cmp [rbx + BS2TRAPREC.offWhere], eax + je .traprec_found + add rbx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop2_next + jmp .panic ; not found + +.traprec_found: + ; Remember the hit for the next trap. + mov rax, rbx + sub rax, [g_paTrapRecs] + shr rax, BS2TRAPREC_SIZE_SHIFT + mov [g_iTrapRecLast], eax + + ; + ; Fail the test if we got the wrong trap or error code. + ; + mov al, [g_u8LastTrapNo wrt rip] + cmp al, [rbx + BS2TRAPREC.u8TrapNo] + je .traprec_ok_trap + push rax + movzx rax, byte [rbx + BS2TRAPREC.u8TrapNo] + push rax + push .s_szWrongTrap + call NAME(TestFailedF_p64) + add rsp, 24 + +.traprec_ok_trap: + mov ax, [g_u64LastTrapErr wrt rip] + cmp ax, [rbx + BS2TRAPREC.u16ErrCd] + je .traprec_ok_err_cd + push rax + movzx rax, word [rbx + BS2TRAPREC.u16ErrCd] + push rax + push .s_szWrongErrCd + call NAME(TestFailedF_p64) + add rsp, 24 + +.traprec_ok_err_cd: + ; + ; Advance the EIP and resume execution. + ; + movzx rax, byte [rbx + BS2TRAPREC.offResumeAddend] + add rax, [g_LastTrapRegs + BS2REGS.rip] + mov [rbp + 18h], rax + + pop rcx + jmp .resume + + + ; + ; Format a panic message and halt. + ; +.panic: + lea rbx, [g_LastTrapRegs] + ; line break + movzx eax, word [rbx + BS2REGS.ss] + push rax + movzx eax, word [rbx + BS2REGS.gs] + push rax + movzx eax, word [rbx + BS2REGS.fs] + push rax + movzx eax, word [rbx + BS2REGS.es] + push rax + movzx eax, word [rbx + BS2REGS.ds] + push rax + movzx eax, word [rbx + BS2REGS.cs] + push rax + ; line break + push qword [rbx + BS2REGS.rbp] + push qword [rbx + BS2REGS.rsp] + push qword [rbx + BS2REGS.rip] + ; line break + push qword [rbx + BS2REGS.rflags] + push qword [rbx + BS2REGS.r15] + push qword [rbx + BS2REGS.r14] + ; line break + push qword [rbx + BS2REGS.r13] + push qword [rbx + BS2REGS.r12] + push qword [rbx + BS2REGS.r11] + ; line break + push qword [rbx + BS2REGS.r10] + push qword [rbx + BS2REGS.r9] + push qword [rbx + BS2REGS.r8] + ; line break + push qword [rbx + BS2REGS.rdi] + push qword [rbx + BS2REGS.rsi] + push qword [rbx + BS2REGS.rdx] + ; line break + push qword [rbx + BS2REGS.rcx] + push qword [rbx + BS2REGS.rbx] + push qword [rbx + BS2REGS.rax] + ; line break + mov eax, [rbx + BS2REGS.cr8] + push rax + mov eax, [rbx + BS2REGS.cr4] + push rax + mov eax, [rbx + BS2REGS.cr3] + push rax + mov eax, [rbx + BS2REGS.cr0] + push rax + ; line break + push qword [rbp + 10h] + push qword [rbx + BS2REGS.cr2] + push qword [rbx + BS2REGS.rip] + movzx eax, word [rbp + BS2REGS.ss] + push rax + movzx eax, byte [rbp + 08h] + push rax + push .s_szPanicMsg + call NAME(TestFailedF_p64) + + call Bs2Panic + jmp .panic ; paranoia + +.s_szPanicMsg: + db 'trap #%RX8 at %RX16:%RX64 cr2=%RX64 err=%RX64', 13, 10 + db 'cr0=%RX64 cr3=%RX64 cr4=%RX64 cr8=%RX16', 13, 10 + db 'rax=%RX64 rbx=%RX64 rcx=%RX64', 13, 10 + db 'rdx=%RX64 rsi=%RX64 rdi=%RX64', 13, 10 + db 'r8 =%RX64 r9 =%RX64 r10=%RX64', 13, 10 + db 'r11=%RX64 r12=%RX64 r13=%RX64', 13, 10 + db 'r14=%RX64 r15=%RX64 rfl=%RX64', 13, 10 + db 'rip=%RX64 rsp=%RX64 rbp=%RX64 ', 13, 10 + db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16', 13, 10 + db 0 +.s_szWrongTrap: + db 'Expected trap %RX8 got %RX8', 13, 10, 0 +.s_szWrongErrCd: + db 'Expected errcd %RX16 got %RX16', 13, 10, 0 +ENDPROC bs2Trap_XX_64bit + + +;; +; Service IRQ handler. +; +; Takes requests in eax and later maybe parameters in other registers. +; +; return SS rbp + 28h +; return RSP rbp + 20h +; return RFLAGS rbp + 18h +; return CS rbp + 10h +; return RIP rbp + 08h +BEGINCODELOW +BEGINPROC bs2TrapService64bit + jmp .highsegment +BEGINCODEHIGH +.highsegment: + push rbp + mov rbp, rsp + push rax + push rdx + push rcx + + + ; + ; Switch (eax). + ; + cmp eax, BS2_SYSCALL_TO_RING3 + jbe .to_ringX + + ; Unknown request. + mov rax, -1 +.return: + pop rcx + pop rdx + ;pop rax + leave + iretq + + ; + ; Switching to the ring specified by eax. + ; +.to_ringX: + sub eax, BS2_SYSCALL_TO_RING0 ; al = new ring number. + + mov dx, ds + call bs2SRegToRing + mov ds, dx + + mov dx, es + call bs2SRegToRing + mov es, dx + + mov dx, fs + call bs2SRegToRing + mov fs, dx + + mov dx, gs + call bs2SRegToRing + mov gs, dx + + mov dx, [rbp + 10h] ; cs + call bs2SRegToRing + mov [rbp + 10h], dx + + mov dx, [rbp + 28h] ; ss + call bs2SRegToRing + mov [rbp + 28h], dx + + or dword [ebp + 18h], X86_EFL_IOPL ; set IOPL=3 + + jmp .done_success + +.done_success: + xor eax, eax + jmp .return + +ENDPROC bs2TrapService64bit + +%endif ; BS2_INC_CMN_LM + + +;; +; Converts a segment value (dx) to the ring specified by al. +; +; If the selector isn't a known CS, DS or SS selector it will be set to null. +; +; @returns dx +; @param al The desired ring. +; @param dx The segment to convert. +; +; @remarks WARNING! This has to work exactly the same both in 32-bit and 64-bit mode. +; +BEGINCODEHIGH +BITS 32 +BEGINPROC bs2SRegToRing + ; + ; Classify the incoming selector. + ; + cmp dx, BS2_SEL_R0_BASE + jb .null + cmp dx, BS2_SEL_R0_BASE + BS2_SEL_GRP_SIZE + jb .ring0 + + cmp dx, BS2_SEL_R1_BASE + jb .miss + cmp dx, BS2_SEL_R1_BASE + BS2_SEL_GRP_SIZE + jb .ring1 + + cmp dx, BS2_SEL_R2_BASE + jb .miss + cmp dx, BS2_SEL_R2_BASE + BS2_SEL_GRP_SIZE + jb .ring2 + + cmp dx, BS2_SEL_R3_BASE + jb .miss + cmp dx, BS2_SEL_R3_BASE + BS2_SEL_GRP_SIZE + jb .ring3 + jmp .miss + + ; + ; Convert the incoming selector to ring-0 and then from ring-0 to the + ; desired one. + ; +.ring0: + cmp al, 0 + je .done + + add dx, BS2_SEL_R1_BASE - BS2_SEL_R0_BASE + cmp al, 1 + je .done + + add dx, BS2_SEL_R2_BASE - BS2_SEL_R1_BASE + cmp al, 2 + je .done + + add dx, BS2_SEL_R3_BASE - BS2_SEL_R2_BASE + cmp al, 3 + je .done +.panic: + hlt + jmp .panic + +.ring1: + sub dx, BS2_SEL_R1_BASE - BS2_SEL_R0_BASE + jmp .ring0 +.ring2: + sub dx, BS2_SEL_R2_BASE - BS2_SEL_R0_BASE + jmp .ring0 +.ring3: + sub dx, BS2_SEL_R3_BASE - BS2_SEL_R0_BASE + jmp .ring0 + +.done: + and dl, ~3h + or dl, al ; set the RPL + ret + +.miss: +.null: + xor dx, dx + ret +ENDPROC bs2SRegToRing + +BEGINCODELOW + |